Sometimes we need a function to run on every page load, so as i understand there are to options:

  • hook it with(say init)
  • Call directly within functions.php

when it would be good to use one of them.

because i have this code which i need to run always to check condition and do stuff, so i added to functions.php like this

$args = [
    'post_type'=> 'product',
    'numberposts'=> -1,
    'meta_key'=> 'hfx_datepicker',
    'fields'      =>'ids',
$products = get_posts($args);

foreach($products as $productID){

    $event = 'workshop_event_schedual_'.$productID;

    if (! has_action ( $event )) {
        add_action($event, function() use($productID){
                add_option('student_expiry_set_'.$productID, true);




So i had do think why don't use init but no change will happen, and i started to ask myself which is best practice. When to be recommended to choose one over another?

1 Answer 1


If we take your code at face value, there are some consequences:

  • it runs on every request, be that a page, an AJAX call, a REST API request, even XMLRPC
  • It's a super expensive post query that involves post meta, with no upper limit on the number of results
  • You are filtering a post query by a posts meta values, but that's not what post meta is for. That's what the taxonomy tables are for. If you ever need to search for a post by it's X or Y, then X/Y need to be custom taxonomies, or you'll get awful performance.
  • schedule is misspelt
  • Options are being used to store data that should be stored as either user meta or post meta ( or in this case, as a taxonomy term )

So you're already in a bad place as far as performance is concerned, and to top it off, because it's in functions.php and not in any kind of functions, it can't be overrode or unhooked by a child theme or plugin.

Instead by only firing it on a hook we separate the "what" from the "when", and can conditionally hook it in.

For example, you could hook into admin_init if it only runs on the backend.

By hooking it in, that also means it can be unhooked if needed

But looking at what you're actually doing here, this will not scale. As the number of product posts increases, the site will get slower and slower ( regardless of how many results are found, it's the searching that's expensive )

What's more, this shouldn't be happening on every page load, it should be happening in a cron job and in batches.

Additionally, by relying on the options table to set expiry times, your options table will balloon in size. It'll quickly become incompatible or slow with a lot of object cache drop ins due to the way auto-loaded options are cached and loaded on every page request.

All in all, I would expect this to work fine with 4 or 5 products, but quickly get out of hand once it goes past 100 posts. There are significant performance gains to be had by changing how this works

  • Yes sure it is all about performance, and you are right that loading something like this will harm performance i got it, but i need to depend on meta key, because i am building workshops system that needs every workshop has product connected to it for payment, so i store the product id relates to a workshop(bbpress forum) into meta value so i need to rely on this approach... If you can advice with better way to connect two different post types, i will be grateful.. but the point has come clear.. thank you Jan 4, 2019 at 17:00
  • @MohamedOmar I don't really understand your code. Two things come to mind anyway: Schedule the event (and use a proper cron to execute your scheduled tasks), or hook to an action that is related to this behaviour
    – kero
    Jan 4, 2019 at 17:15
  • @MohamedOmar taxonomy terms are no different, you can store data and edit it given a post ID just as you would post meta. The difference being that one is super fast, one is not. There is no technical reason not to use it, especially if your goal is to connect things together. Instead of get_post_meta and update_post_meta, it's wp_get_object_terms and wp_set_object_terms, it's even easier to query for, and it lets you do the reverse too, e.g. show all posts that have a hfx_datepicker or X or show all hfx_datepicker a post has. It can be as much as 1000x faster
    – Tom J Nowell
    Jan 4, 2019 at 17:19
  • @Tom J Nowell but you can't connect two different post types with terms Jan 4, 2019 at 18:35
  • you can but in your case it would be easier to do it via post parents. To do it with terms just use the post ID as the name of the term
    – Tom J Nowell
    Jan 5, 2019 at 20:01

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.