0

It seems that wordpress will cache all the data including the meta values of all the posts in the current page by _prime_post_caches:

As shown, it tried to fetch information for posts id within (76-100).

While in my project, most of the data of the post are saved in another table rather than the wp_posts table or wp_posts_meta table by my custom plugin. So the above query will cache only the basic information of the posts.

So wordpress will try to trigger a sql query for each post in the page:

Even I have used the wp_cache_add() to ensure this kind of query for a certain post will be queried only once, I think it maybe better if I can select them all by one sql query.

However through the docs of _prime_post_caches, this method is private, and I did not find any actions can be used to cache them.

Any idea?

Update1 :

Why I use separate tables to save the data is that these data are generated by another system which is out of my control. While that system does not have the view model, so I use WordPress here.

And I use $wpdb to communicate with the database. Actually, there are two tables joined by a key to get the full information for a single record.

Update 2:

Here is how I use the hooks to get my own data:

add_filter("the_title", function ($origin_content, $id) {
    $info = my_get_info($id);
    return $info["name"];
}, 10, 2);
add_filter("the_content", function ($origin_content) {
    $info = my_get_info(get_the_ID());
    return $info["summary"];
});


function movie4oy_get_info($post_id)

{

    $guid = get_the_guid($post_id);
    $result = wp_cache_get($guid, "_my_post_info");
    if (!$result) {
        $data = _my_get_info_db($guid);
        if ($data) {
            wp_cache_add($guid, $data, "_my_post_info");
            $result = $data;
        }
    }
    return $result;
}

function _my_get_info_db($guid)
{
    global $SQL;
    global $wpdb;

    $row = $wpdb->get_row($wpdb->prepare($SQL,$guid), ARRAY_A);
    $data = array(
        ......
    );
    return $data;
}
4
  • Can you provide some context, such as why you're using a separate table, what type of data is stored in it, and how you access it? Do you use wpdb? direct mysqli calls? Update your question with all of these details
    – Tom J Nowell
    Nov 3, 2016 at 13:36
  • @Tom J Nowell, I have updated that.
    – hguser
    Nov 3, 2016 at 14:37
  • not sure what is the issue. If you want to cache things which are not accessable by wordpress API you need to write the caching for that yourself. Not sure how you expect core to help you in that except for having the wp_cahce_* APIs? Nov 3, 2016 at 15:03
  • @hguser the code in your question uses WP_Cache already, I don't see what the problem is? With a persistent object cache this shouldn't be an issue, as for the hooks, those run after the post has been gotten, afterall it's a filter, the content had to come from somewhere
    – Tom J Nowell
    Nov 7, 2016 at 1:10

2 Answers 2

1

These bits of caching are generally considered inadvisable to be messed with. If I remember right you can somewhat control the behavior by query arguments and wrapping related code in wp_suspend_cache_addition() calls.

From look through the source it doesn't seem to be meant to carry custom logic. If you would like similar behavior for your custom data from non–native table you will likely have to implement caching logic for it yourself.

6
  • You are right, implement caching logic is what I need. But I can not find the entry point to cache all the posts data for a single request. One can only use the hooks provided by wordpress inside the theme or plugin.
    – hguser
    Nov 4, 2016 at 1:12
  • On top of my head sets of queried posts pass through the_posts in WP_Query, you could hook into that, check which aren't cached yet and load up your custom data cache for those.
    – Rarst
    Nov 4, 2016 at 9:10
  • Sorry, but I am not exactly sure what you are meaning, can you provide more? Or figure out which action can be used to hook that?
    – hguser
    Nov 4, 2016 at 12:24
  • the_posts is the name of the hook here. Whenever WP_Query is used the resulting set of posts will pass through it.
    – Rarst
    Nov 4, 2016 at 12:33
  • It seems that when the the_posts filter is triggered, the posts have been fetched which means sqls to another table to fetch my data have been triggered yet, the data has been cached . I update my post.
    – hguser
    Nov 7, 2016 at 0:21
2

Your filtering doesn't work because the filtering of the content and title happen after they've been cached, not before. the_title and the_content are used when displaying that data. If they work how you expected, it would be impossible to filter the content different ways on the same page.

e.g. here is the ordering of things:

  • WP_Query class makes a request
    • request is processed by database
    • results are stored in WP_Cache
  • Template loops over each post
    • template calls the_title
      • A last chance to modify the titles output in this template happens in the_title filter
    • template calls the_content
      • A last chance to modify the contents output in this template happens in the_content filter

These filters are were OEmbeds and shortcodes happen. By this point, the caching has already happened. These filters aren't a chance to change the content before it's cached, they're a chance to modify the final content.

For your filters to work, you'd need to hook into filters during the WP_Query phase. This is why your code functions and gives you the correct result, but isn't performant.

To top that off, without a persistent object cache, WP_Cache will do very little for you. Requesting the same data a second time will avoid a second query, but once the page is finished loading all that data dies. The next page load will need to fetch it again. An object cache backed by Redis/Memcached/etc will solve this.

Instead, you need to take a very different approach, by replicating the data.

Store the title in the posts title, and the content in the posts content, so that they behave as standard normal posts with no filters or special mysql calls. This immediately saves you 2 expensive SQL calls, eliminates the need to write any SQL queries in WordPress, and lets you take full advantage of all the caching WordPress can do.

In your other system, when content changes, ping the WordPress install indicating that a particular piece of content is stale, and send the new data along with it. A REST API endpoint should work well for this.

Add in some code to make sure that the title and content can't be changed from WordPress, and you're sorted. Now you have normal standard posts that work the way they do on every other WordPress site.

If you can't push, consider pulling the data from a regular cron job instead ( less efficient, has a timing trade off ).

9
  • The filter did work in my system now. Just too slow.
    – hguser
    Nov 7, 2016 at 5:54
  • @hguser those filters don't let you change what gets cached, they let you change how it's displayed. They're 'display' filters, in the same way you might alter a suit on purchase. You're looking to make changes at the suit factory, instead you're modifying all the suits on purchase. By the time those filters run, the caching has already happened long ago, hence your original question. Instead you need to change your approach as I suggested in my answer, my proposed solution eliminates this problem entirely
    – Tom J Nowell
    Nov 7, 2016 at 14:00
  • @hguser I've adjusted my answer to better explain the problem and the benefits
    – Tom J Nowell
    Nov 7, 2016 at 14:10
  • Thanks for your detailed answer. I got it, in fact I know that the WP_cache only works during the page loading. And your suggestion of replicating the data is what I did before:create a post with title,content,tags only when data changed in another system, however there are so many fields other than title,content to be displayed, so when retrieve these value, the same sql will be triggered. Now I use the the_post action to read all the data for posts in the current page which will trigger a single sql. Better than before though still slow.
    – hguser
    Nov 8, 2016 at 0:29
  • Can the other system not send the data when it tells WP that things have changed? Then WP loops over all the fields storing them as post meta with a prefix, except the title and content which are handled as special cases? If it's still slow even without the SQL queries then you have other issues than this to deal with
    – Tom J Nowell
    Nov 8, 2016 at 0:45

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.