I'm trying to write an action that will modify some WooCommerce product on its display.
This is my simple code
function do_some_modifications($post)
{
if (is_singular('product')) {
// do some action
}
return $post;
}
add_action('the_post', 'do_some_modifications');
But the page contains two related products and "the_post" is called for them as well. How can I avoid running that code for additional products displayed on the main product page?
Thank you!
I'm trying to write an action that will modify some WooCommerce product on its display.
This is my simple code
function do_some_modifications($post)
{
if (is_singular('product')) {
// do some action
}
return $post;
}
add_action('the_post', 'do_some_modifications');
But the page contains two related products and "the_post" is called for them as well. How can I avoid running that code for additional products displayed on the main product page?
Thank you!
Share Improve this question edited Jun 23, 2014 at 19:12 Konstantin Bodnia asked Jun 23, 2014 at 13:11 Konstantin BodniaKonstantin Bodnia 1732 silver badges6 bronze badges5 Answers
Reset to default 1Okay. Here we go!
I needed this to be implemented within only one plugin, not inside the template.
So I found out how to get the ID of current post outside the loop. The great function get_queried_object() and get_queried_object_id() will seal the deal!
It might not seem the quickiest way (it queries the database) but in my case it is a perfect solution since I'm running this code not for every page and not every time it's loaded.
And the final code is
function do_some_modifications($post)
{
if (is_singular('product') and get_queried_object_id() == $post->ID) {
// do some action
}
return $post;
}
add_action('the_post', 'do_some_modifications');
replace
if (is_singular('product')){
// do some action
}
with
if (is_singular('product') && is_main_query()){
// do some action
}
The simplest way to implement it would be to add the callback before main loop in template and remove after. Not too tidy from template perspective however.
Working purely with hooks you might want to check it if the post is present in $wp_query->posts
, however that would misfire on duplicates.
In the past I remember doing this by adding custom marker property to the post object, but that was before WP_Post
class was introduced and I am not sure it's viable technique anymore.
In this scenario, for this Stack question asked, the magic built in in_the_loop()
does the job for me:
function do_some_modifications($post){
if(is_singular('product') && in_the_loop()) {
// do some action
}
}
add_action('the_post', 'do_some_modifications');
You can skip return $post
as this action is passing $post
by reference.
I think the do_action('the_post')
is the way to go here, not fibbling around inserting template actions, specially not woocommerce, they have templates for everything and changing them all the time.
I had a similar situation when my official plugin should do stuff before a shared template is called. Here I dont know in advanced what template the Theme would use, so I needed exactly as in this case, target the archive product listing, but not related product listings below or other widgets that may use the same template.
In case some other resourcing about this, to target sidebars only, set the conditional the opposite way !in_the_loop()
and you may have to examine the $post
before you do your stuff
The simplest and most reliable way I can think of, is using the second parameter of the the_post
action:
function do_some_modifications( $post, $query ) {
if ( $query->is_main_query() && $query->is_singular( 'product' ) ) {
// do some action
}
}
add_action( 'the_post', 'do_some_modifications', 10, 2 );
Some notes:
The second parameter of the filter callback provides the actual WP_Query object that is currently processed.
Also,
the_post
is an action and therefore does not need a return value. Instead of returning the $post value, you can directly modify the $post variable (it is a reference to the actual object that WordPress uses)When you use the function
is_singular()
it will always check the main WP_Query object. If you want to check the query that's currently processed bythe_post
then you need to use$query->is_singular()
.