Home › Forums › Add-ons › Repeater Field › Mistake in documentation ? : Query posts by custom fields
Hi,
(sorry for my english :})
On http://www.advancedcustomfields.com/resources/query-posts-custom-fields/
Section 4 contains information about searching sub fields.
Excerpt:
In this example, we will find all posts that have a post_type of ‘event’ where the current date is within a repeater field’s start and end date.
OK so for the example we are the 2015/10/14.
And we have an event with theses dates : (first date is start, last is end)
0 : 2015/10/10 – 2015/10/12
1 : 2015/10/20 – 2015/10/22
So today the event is closed but the code in documentation returns the event.
Indeed, because of the like, the request uses dates_0_start_date and dates_1_end_date meta_key! You see the problem ?
So i’m looking for the correct solution.
I could use a loop to repeat meta keys in array like this :
$args = array(
'numberposts' => -1,
'post_type' => 'event',
'meta_query' => array(
'relation' => 'OR'
)
);
$max = 10;
for ($row=0; $row<$max; $row++) {
$row_query = array(
'relation' = 'AND',
array(
'key' => 'dates__'.$row.'_start_date',
'value' => 'value to search for',
'compare' => '<=',
),
array(
'key' => 'dates__'.$row.'_end_date',
'value' => 'value to search for',
'compare' => '>=',
),
);
$args['meta_query'][] = $row_query;
}
This code has not been tested, so it can contain some errors
However I would prefer a more elegant solution.
That is a solution to the problem I had not thought of, and it may be the only way to actually do this, at least using WP_Query. The problem will come in when you have more than 10 rows in a repeater.
The only error I see is that you have an extra underscore in you meta keys, they should be.
'key' => 'dates_'.$row.'_start_date',
Sometimes there is no elegant solution. My only concern for this would might be the length of time it takes the query to run, that might give you a problem.
That’s what i thought :/
But you confirm there is a mistake in documentation ? How we can report the error ?
There isn’t really a mistake in the documentation, I guess other than that it does not say that the query does not differentiate between fields in different rows. I’ll mark this thread for the developer to look at but not sure what can be done, or if anything will be done about it.
If the query does not differentiate between fields in different rows, i don’t understand why there is a repeater field. One field stat_date and one field end_field are enough ^^’.
Finally, WP_Query is too slow : 17 seconds with 2 rows and timeout with 3 rows and i don’t know why, the request does not seem so complicated :
Array
(
[post_type] => distributeur
[posts_per_page] => 1
[meta_query] => Array
(
[relation] => AND
[0] => Array
(
[key] => code pays
[value] => fr
)
[1] => Array
(
[relation] => OR
[0] => Array
(
[relation] => AND
[0] => Array
(
[key] => rc_cp_min_0
[value] => 7000
[type] => numeric
[compare] => <=
)
[1] => Array
(
[key] => rc_cp_max_0
[value] => 7000
[type] => numeric
[compare] => >=
)
)
[1] => Array
(
[relation] => AND
[0] => Array
(
[key] => rc_cp_min_1
[value] => 7000
[type] => numeric
[compare] => <=
)
[1] => Array
(
[key] => rc_cp_max_1
[value] => 7000
[type] => numeric
[compare] => >=
)
)
[2] => Array
(
[relation] => AND
[0] => Array
(
[key] => rc_cp_min_2
[value] => 7000
[type] => numeric
[compare] => <=
)
[1] => Array
(
[key] => rc_cp_max_2
[value] => 7000
[type] => numeric
[compare] => >=
)
)
)
)
[error] =>
[m] =>
[p] => 0
[post_parent] =>
[subpost] =>
[subpost_id] =>
[attachment] =>
[attachment_id] => 0
[name] =>
[static] =>
[pagename] =>
[page_id] => 0
[second] =>
[minute] =>
[hour] =>
[day] => 0
[monthnum] => 0
[year] => 0
[w] => 0
[category_name] =>
[tag] =>
[cat] =>
[tag_id] =>
[author] =>
[author_name] =>
[feed] =>
[tb] =>
[paged] => 0
[comments_popup] =>
[meta_key] =>
[meta_value] =>
[preview] =>
[s] =>
[sentence] =>
[fields] =>
[menu_order] =>
[...]
[ignore_sticky_posts] =>
[suppress_filters] =>
[cache_results] => 1
[update_post_term_cache] => 1
[update_post_meta_cache] => 1
[nopaging] =>
[comments_per_page] => 50
[no_found_rows] =>
[order] => DESC
)
SQL :
SELECT SQL_CALC_FOUND_ROWS
wp_posts.ID
FROM
wp_posts
INNER JOIN
wp_postmeta ON (wp_posts.ID = wp_postmeta.post_id)
INNER JOIN
wp_postmeta AS mt1 ON (wp_posts.ID = mt1.post_id)
INNER JOIN
wp_postmeta AS mt2 ON (wp_posts.ID = mt2.post_id)
INNER JOIN
wp_postmeta AS mt3 ON (wp_posts.ID = mt3.post_id)
INNER JOIN
wp_postmeta AS mt4 ON (wp_posts.ID = mt4.post_id)
INNER JOIN
wp_postmeta AS mt5 ON (wp_posts.ID = mt5.post_id)
INNER JOIN
wp_postmeta AS mt6 ON (wp_posts.ID = mt6.post_id)
WHERE
1 = 1
AND ((wp_postmeta.meta_key = 'code pays'
AND CAST(wp_postmeta.meta_value AS CHAR) = 'fr')
AND (((mt1.meta_key = 'rc_cp_min_0'
AND CAST(mt1.meta_value AS SIGNED) <= '7000')
AND (mt2.meta_key = 'rc_cp_max_0'
AND CAST(mt2.meta_value AS SIGNED) >= '7000'))
OR ((mt3.meta_key = 'rc_cp_min_1'
AND CAST(mt3.meta_value AS SIGNED) <= '7000')
AND (mt4.meta_key = 'rc_cp_max_1'
AND CAST(mt4.meta_value AS SIGNED) >= '7000'))
OR ((mt5.meta_key = 'rc_cp_min_2'
AND CAST(mt5.meta_value AS SIGNED) <= '7000')
AND (mt6.meta_key = 'rc_cp_max_2'
AND CAST(mt6.meta_value AS SIGNED) >= '7000'))))
AND wp_posts.post_type = 'distributeur'
AND (wp_posts.post_status = 'publish'
OR wp_posts.post_status = 'acf-disabled'
OR wp_posts.post_status = 'future'
OR wp_posts.post_status = 'draft'
OR wp_posts.post_status = 'pending')
GROUP BY wp_posts.ID
ORDER BY wp_posts.post_date DESC
LIMIT 0 , 1
Yes it’s a little more complicated than ACF example and they are postal codes and not dates but principle is the same.
This is the reason it times out
FROM
wp_posts
INNER JOIN
wp_postmeta ON (wp_posts.ID = wp_postmeta.post_id)
INNER JOIN
wp_postmeta AS mt1 ON (wp_posts.ID = mt1.post_id)
INNER JOIN
wp_postmeta AS mt2 ON (wp_posts.ID = mt2.post_id)
INNER JOIN
wp_postmeta AS mt3 ON (wp_posts.ID = mt3.post_id)
INNER JOIN
wp_postmeta AS mt4 ON (wp_posts.ID = mt4.post_id)
INNER JOIN
wp_postmeta AS mt5 ON (wp_posts.ID = mt5.post_id)
INNER JOIN
wp_postmeta AS mt6 ON (wp_posts.ID = mt6.post_id)
This is why I said
My only concern for this would might be the length of time it takes the query to run, that might give you a problem.
There is a known issue in WP with multiple joins on the meta table.
I’m not sure that there is a solution, at least I have not seen one so far, at least not a direct solution.
Finally i used wpdb to execute this request:
SELECT
wp_posts.ID
FROM
wp_posts
INNER JOIN wp_postmeta ON (wp_posts.ID = wp_postmeta.post_id)
LEFT JOIN wp_postmeta AS mt1 ON (wp_posts.ID = mt1.post_id AND mt1.meta_key = 'rc_cp_min_0')
LEFT JOIN wp_postmeta AS mt2 ON (wp_posts.ID = mt2.post_id AND mt2.meta_key = 'rc_cp_max_0')
LEFT JOIN wp_postmeta AS mt3 ON (wp_posts.ID = mt3.post_id AND mt3.meta_key = 'rc_cp_min_1')
LEFT JOIN wp_postmeta AS mt4 ON (wp_posts.ID = mt4.post_id AND mt4.meta_key = 'rc_cp_max_1')
LEFT JOIN wp_postmeta AS mt5 ON (wp_posts.ID = mt5.post_id AND mt5.meta_key = 'rc_cp_min_2')
LEFT JOIN wp_postmeta AS mt6 ON (wp_posts.ID = mt6.post_id AND mt6.meta_key = 'rc_cp_max_2')
WHERE
1 = 1
AND (wp_postmeta.meta_key = 'code pays'
AND wp_postmeta.meta_value = 'fr')
AND ((mt1.meta_value <= 7000 AND mt2.meta_value >= 7000)
OR (mt3.meta_value <= 7000 AND mt4.meta_value >= 7000)
OR (mt5.meta_value <= 7000 AND mt6.meta_value >= 7000))
AND wp_posts.post_type = 'distributeur'
AND wp_posts.post_status = 'publish'
LIMIT 0 , 1
Duration: 0.031 sec
It’s exactly the same code except that meta_key conditions are on join and not on where and i replaced INNER JOIN by LEFT JOIN.
My knowledge of Mysql optimization is limited so i don’t know exactly why it’s really faster but it works 🙂
This is great information. I know just enough MySQL to be dangerous so this will help. Now if we could only package this up into a filter that alters the query…
You must be logged in to reply to this topic.
Welcome to the Advanced Custom Fields community forum.
Browse through ideas, snippets of code, questions and answers between fellow ACF users
Helping others is a great way to earn karma, gain badges and help ACF development!
ACF wouldn’t be so widely used in WordPress if it didn’t have some pretty amazing capabilities. In this article, we look at a few of the features we’ll discuss during “7 things you didn’t know you could do with ACF” at #WPEDecode later this month. https://t.co/5lnsTxp81j pic.twitter.com/Yf0ThPG1QG
— Advanced Custom Fields (@wp_acf) March 16, 2023
© 2023 Advanced Custom Fields.
We use cookies to offer you a better browsing experience, analyze site traffic and personalize content. Read about how we use cookies and how you can control them in our Cookie Policy. If you continue to use this site, you consent to our use of cookies.