Generateblocks_query_loop_args slowing pages way down

I have a mix of evergreen and time-sensitive content on my site.

The time-sensitive content has a post field with the expiration date, with the goal being to drop those off the home page once they are no longer topical.

I’ve set up the recommended filter using a css class and generateblocks_query_loop_args, but it changes from the page loading almost immediately to taking about 5 seconds to load. If I remove the class, it’s back to loading fast.

Is the query loop filtering all 9000+ published posts to display the 30 I am displaying? If so, is there a way to avoid that?

Or is something else going on?

Suggestions for making this more efficient appreciated :slight_smile:

//this adjusts the get posts query loop using the generateblocks plugin so that
//posts with an expiration date are not displayed in generateblock that include the class remExp in the grid

	add_filter( 'generateblocks_query_loop_args', 'removeExpired', 10, 2);

		function removeExpired ( $query_args, $attributes ) {

	//if the css class is 'remExp' used (it's a 'css' class, but it removes the posts server side)

    if (! is_admin() && ! empty( $attributes['className'] ) && strpos( $attributes['className'], 'remExp' ) !== false) {

	        $query_args['meta_query'] = array(
				'relation' => 'OR', //if one OR the other qualifications is met, display post

					array( // checks for expiration date and includes those posts if it has not expired
        				'key'     => 'expire_date',
        				'value'   => date("Y-m-d"),
        				'type'    => 'DATE',
        				'compare' => '>=',
    					),
					array( //include posts that don't have an expiration date set
            			'key'     => 'expire_date',
            			'compare' => 'NOT EXISTS'
       					 )			
								);
     								   }
    				return $query_args;
	}
1 Like

@Christopheran hey man, can you share your block query params as well? Or all $query_args you receive inside your if statement.

That’s all of it, though as I mentioned, I have a custom post field for the expiration date,

Chris

Can you install https://querymonitor.com/ on your site and load the page you are experiencing low responses, the plugin should list all the queries running for that page. This can give you more insight into the low times so we can try to find a better solution for your problem.

I believe that the query is slow, but could also be some leak in our code. Either way, we can solve that in a couple of ways.

Thanks for taking a look. This is what I’m getting, but I don’t know if it says anything helpful -

Basically, it’s saying the query is taking 5.5 seconds to return the results, which explains the page taking that long to load.

Since you have quite a lot of posts (9k) there are a couple of options you can go to fix this, but I don’t know your level/confidence with PHP

1 - First option would be to cache the page, using some well-known cache plugin. It’s easy to implement, but your cache must regenerate every day, to remove the newly expired posts, also, if you post something new during the day you must also regenerate the cache to have an effect.

2 - Option two way more complicated would be to create a cron job that every day runs in the background to flag the expired posts, for example, all expired posts can have another meta value expired = 1, and the query to retrieve your posts would be faster, cause you just need to get posts that don’t have this meta value.

3 - Option three is to extend the GB core class that renders the query loop and manually cache the results, quite complicated as well if you don’t understand concepts of PHP OOP and WP transient API.

Personally, I would try solution two, but either option will require some testing to see what makes better performance in general. Let me know, I can help you with some code snippets to give some directions

Thanks for taking a look JeanPaiva.

I do cache locally and use cloudflare, so except for the first hit after a new post is published, it loads very quickly.

My concern is more for Google crawling through pagination. Those pages aren’t loaded as often, so as Google crawls pages 2 - 600, for the home and the category pages, ugh, that’s going to hurt seo wise plus put that strain on my server.

I’ve considered the cron idea. The goal is to publish multiple articles throughout each day, so that also feels like it’s putting a lot of unnecessary cpu time into multiple recrawls a day.

Option three is over my head.

It seems like there should be a pretty simple solution… but apparently there’s not.

What I may do is give up on GenerateBlocks and go back to using WP Show Posts, as in addition to this issue, I’ve had pagination issues with GenerateBlocks.

I hate to do that since Show Posts is no longer supported, but it certainly displayed results faster and the pagination worked the way I needed it to, (though I’m told pagination will work out better for my purpose when GeneratePress pro 2.2 comes out),

Chris

edit - of course Show Posts was faster, I wasn’t trying to filter those. Ugh, sorry, been down with a cold, I’ll blame the meds for my lame thinking when I was writing that :slight_smile:

No worries mate, once your data starts to grow this kind of issue is always a pain to resolve properly, and eventually, you’ll have to get your hands dirty. lol

If you really need that filter, I strongly suggest you fix, cause will get even worse as your post count goes up.

Been pondering this… GB has a setting in the query loop for post type.

What if I ran a cron job that looked up my exp_date field, and if that date has passed, change the post type to a custom post type.

That way I could have the setting set to display posts, but not those custom posts, while keeping the posts published, and then recycle them next year when it’s appropriate to have them on the front page again.

That should display the query faster, correct? If I can figure out how to change the post type with a cron job like that, researching that now…

@Christopheran to handle the cron job I suggest you take a look at WP-Control plugin it will help you manage the cron job.

If you want to use the meta key solution, something like the code below might help you.

First thing: Backup your database before running the code below.
I strongly suggest running this on a staging/dev server before production.
I didn’t tested this code, it may need some tweaking :slight_smile:

function flag_expired_posts() {
	$expired_posts = new WP_Query( array(
		'post_type' => 'post',
		// We need to limit the result to avoid overcharging the server. Tweak as you see fit.
		'posts_per_page' => 25,
		'meta_query' => [
			'relation' => 'AND',
			// Get all posts that have the "expire_date" meta value
			array(
				'key' => 'expire_date',
				'compare' => 'EXISTS',
			),
			// And get all posts that have lower expiration date than today
			array(
				'key'     => 'expire_date',
				'value'   => date("Y-m-d"),
				'type'    => 'DATE',
				'compare' => '<',
			),
		],
	) );

	if ( $expired_posts->posts ) {
		// Loop the posts and add the meta key.
		foreach ( $expired_posts->posts as $expired_post ) {
			add_post_meta( $expired_post->ID, 'has_expired_date', 1 );
		}
	}
}

This function will have to run multiple times at first to loop all your posts, but once all the old posts have the correct values you just need to run one per day to mark the newly expired posts.

In your Query loop, you just have to filter for the posts that don’t have the meta field:

array(
  'key'     => 'has_expired_date',
  'compare' => 'NOT EXISTS'
),

Hopefully, this can help you. :slight_smile:

References:

2 Likes

Thank you JeanPaiva!

Thats awsome.
We can now have basic event listing without the plugin. :smiley:
Thanks