Querying sanatized data with meta_query in Wordpress - php

After Googeling this for a while, I've found that this should work ref., but I don't seem to get it running.
On the backend I have a custom field on commments for setting a list of userIDs of who liked it. It is stored sanatized in the DB this way:
a:2:{i:0;s:1:"1";i:1;s:1:"2";}
which translates into
Array (
[0] => 1
[1] => 2
)
A pretty straight forward flat array where the values 1 and 2 are the user IDs of two likes. Now, I want to query comments liked by userID 1
$args = array(
'status' => 'approve',
'post_status' => 'publish',
'meta_query' => array(
array(
'key' => 'liked_by',
'value' => array(1),
'compare' => 'IN',
'type' => 'numeric'
)
)
);
// The Query
$comments_query = new WP_Comment_Query;
$comments = $comments_query->query( $args );
And I get no comments in return, why is that?
Here is the query generated:
SELECT * FROM wp_comments JOIN wp_posts ON wp_posts.ID = wp_comments.comment_post_ID INNER JOIN wp_commentmeta ON ( wp_comments.comment_ID = wp_commentmeta.comment_id ) WHERE ( comment_approved = '1' ) AND wp_posts.post_status = 'publish' AND (
( wp_commentmeta.meta_key = 'liked_by' AND CAST(wp_commentmeta.meta_value AS SIGNED) IN ('1') )
) GROUP BY wp_comments.comment_ID ORDER BY comment_date_gmt DESC

I wanted to do this over serialized data even though I cited an URL that said
don't store array of ids in one row instead loop through ids array and
normalize your likes data manually Don't serialize data into a
database field.
This is because I used ACF and added an Users field, which used serialized data. I solved my problem by avoiding ACF and just using the comment meta API.
// UserID 1 likes commentID 9
add_comment_meta(9, 'like', 1, false);
// Get comments liked by userID 1
$args = array(
'status' => 'approve',
'post_status' => 'publish',
'meta_query' => array(
array(
'key' => 'like',
'value' => 1,
'compare' => '=',
'type' => 'numeric'
)
)
);
// The Query
$comments_query = new WP_Comment_Query;
$comments = $comments_query->query( $args );
// Surprise, it's commentID 9
Notice how I use add_comment_meta with unique=false for every like instead of serializing an array into the database, making it unavailable for queries.

Related

Count posts that include the current users email in a meta field

I was hoping someone could please assist with my below code. I have a field called pds_project_manager and it contains the email address of my users assigned to projects(posts), I am wanting to count the number of posts that have the field with the current users email in it. The below code works, but if there is more than just the current users email address in the field pds_project_manager it ignores it and does note count it. The field will often have multiple email addresses in it.
$current_user = wp_get_current_user();
$display_name = $current_user->display_name;
$args_pm = array(//number of posts by pm
'posts_per_page' => -1,
'post_type' => 'project',
'meta_query' => array(
'relation' => 'AND',
array(
'key' => 'status',
'value' => '1'
),
array(
'key' => 'pds_project_manager',
'value' => $current_user->user_email,
)
)
);
$posts_pm = get_posts($args_pm);
$pm_count = count($posts_pm);//number of posts by pm
echo "$display_name's Active Projects: $pm_count";
Assuming that you have a serialized array represented as a string and stored in Database for your pds_project_manager field, use LIKE in your query like this:
...
array(
'key' => 'pds_project_manager',
'value' => $current_user->user_email,
'compare' => 'LIKE'
)
...
There is a good article why not to use LIKE or not to store serialized data in Database, in case you want to know alternatives: https://wordpress.stackexchange.com/questions/16709/meta-query-with-meta-values-as-serialize-arrays

WP_Query: second parameter in meta_query being ignored

The second meta_query parameter is being ignored in this query.
$query = new WP_Query(array(
'post_type' => 'events',
'meta_query' => array(
'relation' => 'OR',
array(
'key' => 'event_date',
'value' => date('Ymd'),
'compare' => '>=',
),
array(
'key' => 'end_date',
'value' => date('Ymd'),
'compare' => '>=',
)
)
));
There is no mention of end_date in the resulting SQL
SELECT SQL_CALC_FOUND_ROWS inx9uju_posts.ID
FROM inx9uju_posts
INNER JOIN inx9uju_postmeta ON ( inx9uju_posts.ID = inx9uju_postmeta.post_id )
INNER JOIN inx9uju_postmeta AS mt1 ON ( inx9uju_posts.ID = mt1.post_id )
WHERE 1=1
AND ( inx9uju_postmeta.meta_key = 'event_date' AND ( mt1.meta_key = 'event_date' AND CAST(mt1.meta_value AS SIGNED) > '20180703' ) )
AND inx9uju_posts.post_type = 'events'
AND (inx9uju_posts.post_status = 'publish'
OR inx9uju_posts.post_status = 'acf-disabled'
OR inx9uju_posts.post_status = 'private')
GROUP BY inx9uju_posts.ID
ORDER BY inx9uju_postmeta.meta_value+0 ASC LIMIT 0, 30
I've spent some time checking syntax and referring to the codex but I can't see what is wrong with my code. I can't see any reason why it would be ignoring the end_date part of the meta_query parameters.
UPDATE
In this particular case I was overriding the meta_query part of the query in a separate function which was hooking into pre_get_posts. Once I updated that function, the issue was resolved.
If this is stored as an AFC, you must use the ACF syntax of Ymd (20180703).
You must also realise that WordPress can detect the BETWEEN meta_compare to detect two dates as such.

WordPress How to sort by a custom meta key using a key inside it?

On my WordPress site, each user has a custom meta key named 'user_details' which is an array and has the following structure:
$user_details = array('age'=>10,'gender'=>'male');
in the following example, how can I sort users in an ASC order according to each user 'age'?
<?php
//get all users above 10 years
$args = array(
'meta_query' => array(
'meta_key' => array(
'key' => 'user_details',
'value' => '',
'type' => 'CHAR',
'compare' => '!=',
),
),
'orderby' => array( 'meta_key' => 'ASC' ),
);
$users = get_users( $args );
?>
SO, the line
array( 'meta_key' => 'ASC' ) does not sort the retrieved users according to 'age', how can I sort the retrieved users according to the age?
Thanks.
Power,
there are 2 options:
1) IF you store an array into the user meta VALUE (not the key) as you appear to have done, THEN you will have to query the records and then sort the array retrieved AFTER the query - lookup php array sorting functions.
2) AN alternative is to store the user details more cleanly in separate meta records eg:
meta-key: user-age
meta-key: user-gender
THEN you can query and sort at the same time.
If you look at how the data is stored in phpmyadmin and try to write a MYSQL query to extract that data, you will gain a better appreciation of the situation.

Wordpress Query by Custom Field with date type

I want to create a query where all posts should be displayed where the custom field "expiration_date' is larger than the date from today.
Short form: if the expiration date of the post is reached, it should no longer displayed in the query
I tried with this snippet:
<?php
$today = date("Y-m-d");
$args= array(
'tag' => 'Pinnwand',
'meta_query' => array(
'key' => 'expiration_date',
'type' => 'DATE',
'value' => $today,
'compare' => '>'
)
);
$my_query = new WP_Query($args); ?>
the expiration date is in the format (2014-10-04) for example.
But I tried also the format "Ymd" on both sides, change the compare type, or set the type as "NUMERIC" and nothing helps. The result is, that the post will always be displayed.
It would be great if somebody could help me!
Okay I found the mistake!
The correct query needs one more array(). I don't know exactly why, but in other cases the query couldn't work with it. So here is the code
$args= array(
'tag' => 'Pinnwand',
'meta_query' => array(
array(
'key' => 'expiration',
'type' => 'DATE',
'value' => $today,
'compare' => '>'
),
),
);
$my_query = new WP_Query($args); ?>
You could do a two-query exclusion. First query finds all the posts you want to exclude, then loop through those and store the post IDs in an array, then call second query excluding them using 'post__not_in' with the ID array as the argument.
I would use the $wpdb object for this because it's very efficient.
For reference material:
http://codex.wordpress.org/Class_Reference/WP_Query and
http://codex.wordpress.org/Class_Reference/wpdb
This chunk of code SHOULD do what you're trying to do or get you close to it, and I kept your tag part of the query in there too.
// first query to find exclusions
$today = date("Y-m-d");
$exclusions = $wpdb->get_results("SELECT * FROM $wpdb->posts WHERE expiration_date < ".$today);
if ( $exclusions ) {
foreach ( $exclusions as $exclusion ) {
$excludeIDs[] = $exclusion->ID;
}
}
// second query using exclusion array
$args= array(
'tag' => 'Pinnwand',
'post__not_in' => $excludeIDs,
);
$my_query = new WP_Query($args);
You can do it simpler, as stated on http://codex.wordpress.org/Class_Reference/WP_Query#Custom_Field_Parameters:
$args= array(
'tag' => 'Pinnwand',
'meta_key' => 'expiration',
'meta_type' => 'DATE',
'meta_value' => $today,
'meta_compare' => '>'
);

SQL Query for multiple values and multiple keys in the same table

Every post has two post meta: year and month (custom)
I need SQL query to pull all posts that have
wp_postmeta.meta_key = year AND wp_postmeta.meta_value = 2013
AND AT THE SAME TIME another meta_key / meta_value pair
wp_postmeta.meta_key = month AND wp_postmeta.meta_value BETWEEN 1 AND 12 ;
SELECT * FROM wp_postmeta
WHERE (meta_key = 'agam_post_options_year' AND meta_value = 2013)
OR (meta_key = 'agam_post_options_month' AND meta_value BETWEEN 0 AND 12 )
GROUP BY meta_value;
This is something I tried and a couple of more variations but it doesn't do much... this specifically gives me one post that has year 2013 and 12 posts that have either 1 or ... to 12 for month field}
Please replace _PUT_YOUR_POST_ID_FIELD_HERE_ by something appropriate field from that table and try to run...
SELECT Y.meta_value, M.meta_value FROM wp_postmeta as Y
JOIN wp_postmeta AS M USING (_PUT_YOUR_POST_ID_FIELD_HERE_)
WHERE (Y.meta_key = 'agam_post_options_year' AND Y.meta_value = 2013)
AND (M.meta_key = 'agam_post_options_month' AND M.meta_value BETWEEN 0 AND 12 )
GROUP BY Y.meta_value, M.meta_value;
OK It was all good. The reason it took out the "duplicates" was because we didn't group by Y.meta_id and instead we used meta_value
If you don't really need a pure SQL query and you're getting these posts for using them in WordPress, you could use meta_query array passed as a part of args to WP_Query class or get_posts() function.
$args = array(
'posts_per_page' => -1,
'post_type' => 'your-post-type', // default 'post'
'meta_query' => array(
relation => 'AND', // default 'AND' it might be 'OR'
array(
'key' => 'agam_post_options_year',
'value' => '2013',
'compare'=> '=',
'type' => 'NUMERIC' // see docs for more types
),
array(
'key' => 'agam_post_options_month',
'value' => array( 0, 12 ),
'compare' => 'BETWEEN',
'type' => 'NUMERIC' // see docs for more types
)
)
);
$posts = get_posts( $args ); // returns an array of posts objects
//OR
$query = new WP_Query( $args ); // returns a new WP_Query object
Hope it helps! : )

Categories