Ask your WordPress questions! Pay money and get answers fast! Comodo Trusted Site Seal
Official PayPal Seal

wp query with multiple of same meta keys WordPress

  • SOLVED

I have a wp_query and the posts will have multiple of the same meta keys; I'm looking for an easy way to not show posts that contain a meta key with the ID of the user. The issue is this does not work I still get posts that have a meta key with the users id in it. Basically they have already voted don't show them the post anymore.

$args = array(
'post_type' => 'posts',
'posts_per_page' => -1,
'post_status' => array('publish'),
'meta_query' => array(
array(
'key' => 'boxes',
'value' => array('22','23'),
'compare' => 'IN',
),
array(
'key' => 'operations_type',
'compare' => 'NOT EXISTS',
),
array(
'key' => 'votes',
'value' => $id,
'compare' => '!=',
),
),
);

Answers (4)

2022-07-21

Mohamed Ahmed answers:

Hello there,

if you store the "votes" key as an array you must edit the code to be


$args = array(
'post_type' => 'posts',
'posts_per_page' => -1,
'post_status' => array('publish'),
'meta_query' => array(
'relation' => 'AND', /* You can use AND for all conditions / Use OR if any condition is true */
array(
'key' => 'boxes',
'value' => array('22','23'),
'compare' => 'IN',
),
array(
'key' => 'operations_type',
'compare' => 'NOT EXISTS',
),
array(
'key' => 'votes',
'value' => $id,
'compare' => 'NOT IN',
),
),
);


User179751 comments:

that does not appear to work as it only looks at the first value. I'm using add_post_meta to create the new unique items but the query of IN does not work.


User179751 comments:

sorry NOT IN


Mohamed Ahmed comments:

Could you add the code that restore the votes?
or send it to my email
[email protected]

That will help to write the code that meet your requirements

Regards


User179751 comments:

this works as part of an endpoint; this is a simple test, you create vote or you don't. if you have voted I don't want you to see post.

function add_vote(){

$data = json_decode(file_get_contents('php://input'), true);

$api = array(
'id' => $data['id'],
'user_id' => $data['user_id'],
);


if( !empty($api['id'])){

add_post_meta($api['id'], 'votes', $api['user_id']);

$result = array(
'code' => 'rest_valid_update',
'message' => 'Added vote',
'data' => array(
'status' => '200',
),
);


}else{

$result = array(
'code' => 'rest_invalid_update',
'message' => 'Error unable to vote',
'data' => array(
'status' => '400',
),
);

}

return json_encode($result);
die();

}


User179751 comments:

ensure that you test who votes first, whoever is first in the list the query works and does not show the post because you have voted if they are second or anything else does not work. Data is stored in wp like this using add_post_meta

[votes] => Array
(
[0] => 6603
[1] => 2623
)


Mohamed Ahmed comments:

Could you try this code?


$args = array(
'post_type' => 'posts',
'posts_per_page' => -1,
'post_status' => array('publish'),
'meta_query' => array(
'relation' => 'AND', /* You can use AND for all conditions / Use OR if any condition is true */
array(
'key' => 'boxes',
'value' => array('22','23'),
'compare' => 'IN',
),
array(
'key' => 'operations_type',
'compare' => 'NOT EXISTS',
),
array(
'key' => 'votes',
'value' => $id,
'compare' => 'NOT IN',
),
),
);


Mohamed Ahmed comments:

Sorry*

Try my first answer code


User179751 comments:

doe snot work unless the person who's loading the posts their ID is first.


Mohamed Ahmed comments:

Di you tried?

'compare' => 'NOT IN',


User179751 comments:

yes first thing I tried because its an array. My thinking is that I need to construct the array and then search rather than using add_post_meta to do it. eg: get meta append item to array and save it again. Otherwise I assume the way wp saves data it must not be able to look over values in a query,


Mohamed Ahmed comments:

1- Could you try it now again?
2- Could you add this result of this code here

$meta_values = get_post_meta( get_the_ID() );
var_dump( $meta_values );

2022-07-21

Andrea P answers:

Hello!
I have a feeling that the metafield "votes" would be an array containing the ids of all the users that voted the post, isn't it?
If that is the case it should be
'compare' => 'NOT IN'

another thing maybe try to specify the parameter "relation" on top of the metaquery, like:
'meta_query' => array(
'relation' => 'AND',
array(
...


User179751 comments:

yes I tested NOT IN doe snot work adding 'relation' => 'AND', does not change things either.


User179751 comments:

it all depends on what ID is first; if you try it you will see that if the ID is first it might work however if your ID is second then it wont see other values. Like its only comparing the first item in array of ids


Andrea P comments:

from what you say and the code you pasted in the other answer, I feel that the problem is the code that stores the value of the vote.

It seems that every time that someone votes a post, that code is overwriting the value of "votes" and storing only the id of the user who is voting at that moment.
so there is always only one user_id stored in the votes, but instead you'll need to have an array of ids.

so this:
add_post_meta($api['id'], 'votes', $api['user_id']);

should be something like:
// get current list of votes
$value = get_post_meta($api['id'], 'votes', true);
// ensure we have an array if the field didn't exist yet
if (!$value) {
$value = array();
}
// add the id of the user who is voting now
$value[] = $api['user_id'];
// update the value of the metafield (will create the metafield if not yet existing)
update_post_meta($api['id'], 'votes', $api['user_id']);


User179751 comments:

No its not overridden, I can see it in the meta data I print all the meta to the posts page as a admin notice so I can see it. its all there, also note that app_post_meta will create a new item each time.


Andrea P comments:

ok I just read that add_post_meta will indeed create a new metafield with the same meta_key if one already exists.

I am not sure in which scenario someone would want to have such behaviour and I think it should just update the existent one, but I think this behaviour is actually the problem with your code.

if you have multiple metafields with same name, when you do get_post_meta() or when you do a WP meta query, the system will get confused because there is more than one metafield with the same name.
And it looks like it will choose to consider only the latest one (the metafield with the higher meta_id).

I suggest you to try storing the ids into a single meta_field as an array of user_ids.

then use the "NOT IN" compare in the meta query and your code should work.


User179751 comments:

so this wont work either, my first method was the correct way to do things. The reason is because wp will serialize the data and you can search through the data. So we are back to a new method although not ideal we are looking for a variable keyname based on the user id with a value of boolean


User179751 comments:

that is you can't search meta data when its serialized. that said my new method was to create a unique key like so vote_{id} so that I can query the unique key this works well.


Andrea P comments:

it is true that WP will serialise the array, but then WP query should be able to look into that array anyways. It's not going to behave like a raw sql using "IN".

this is the standard way to handle this kind of things, and proof is that we all thought the same when we saw your code querying for "votes" as if it wasn't an array, while we expected it to be an array.

if it doesn't work there is probably something else wrong.

having metafields with the same meta_key for the same post_id it's a bug and it cannot work because in get_post_meta and in meta_query you don't specify the meta_id and therefore there is no way for the code to know which one of those metafields you want if they have the same name.

if you don't like the array solution (or you cannot make it work), you could do as you mentioned, and create one metafield for each user, ensuring that they all have a unique name.

so like you store something like this

add_post_meta($api['id'], 'voted_' . $api['user_id'], 1);

and then in the query you do something like this

array(
'key' => 'voted_' $id,
'value' => 1,
'compare' => '!=',
),


though be warned that if you have a lot of voters this will create a lot of entries in the database and will slow down your site at some point because everything in wp goes through the postmetas table...

2022-07-21

Naveen Chand answers:

You may need to get the values of the votes into an array.


//get all values regardless of the key
$all_values = get_post_meta(get_the_ID(), '', true);

//you could do print_r($all_values) to see how the array is structured. It will most likely be like this:
// //Array ( [votes] => Array ( [0] => value_1 ), [another_key] => Array ( [0] => value_2 ) )

//based on this array, you can now loop
$votes_array = $all_values['votes'];


and then you can use the compare as "NOT IN"


User179751 comments:

not following. example please ?

2022-07-22

Ali mosbah answers:

If you want a query that return result from multiple meta keys


$args = array(
'post_type' => 'posts',
'posts_per_page' => -1,
'post_status' => array('publish'),
'meta_query' => array(
'relation' => 'AND',
array(
'key' => 'boxes',
'value' => array('22','23'),
'compare' => 'IN',
),
array(
'key' => 'operations_type',
'compare' => 'NOT EXISTS',
),
array(
'key' => 'votes',
'value' => $id,
'compare' => 'NOT IN',
),
),
);


I hope it would be helpful