1

I have the following bit of code that is called from the the the_post hook. This code works fine on one of our live sites, but I'm trying to develop the plugin further locally and this is no longer working.

public function fetch_post_data( $post ) { 
  $post->post_content = 'This is a test.';
}

add_action('the_post', 'fetch_post_data');

This is of course very simplified, but it gets the point across. I am modifying the post object, attempting to alter the content before it is output on the page. Like I said, this is working on our live sites just fine, but for some reason isn't working on my local development server. The crazy thing is that if I var_dump($post); I can see that the $post object has indeed been updated with my new content. Is there a better way to do this and that's the reason this isn't working? Any help would be greatly appreciated.

I know that this code works, as it's being used on a live site already, and I know it's modifying the object, because when I dump it, it displays the new value correctly, and I know other people are doing this by googling (IE https://stackoverflow.com/questions/30007523/modifying-post-post-content-in-wordpress). I'm just confused on why when WP outputs the content on the local server, it isn't taking the updated object into account.

If I issue the following, the first line outputs my new, modified content, and the second line outputs the old, unmodified content. Why aren't they the same?

var_dump($post->post_content);
echo get_the_content();
  • Is there a php version difference between the environments? (this is why you should be using docker, but that's a subject matter of another day). – sandrodz Feb 16 '18 at 19:09
  • The development, staging, and live servers are identical configuration-wise. The only thing that differs is that the live server is running a slightly older version of WP, but that shouldn't make a difference here, because this API hasn't changed as far as I can tell. Additionally, the code IS working because the post object is being modified before output. But for some reason, when it is actually output, it contains its old content. Is there an object cache that needs clearing when manipulating the post object directly? – Kevin Feb 16 '18 at 19:12
  • Additionally, editing $post->post_title directly IS working. It's only the post_content that isn't working for some reason. – Kevin Feb 16 '18 at 19:15
1

get_the_content() doesn't actually return the post_content property from the global $post object. Instead it returns the first page of the global variable $pages, which is set before the_post hook is fired. See L287 of wp-includes/post-template.

To reset the $pages global, you can use the setup_postdata() method from the WP_Query object passed from the the_post hook.

add_action( 'the_post', 'wpse_the_post', 10, 2 );
function wpse_the_post( $post, $query ) {
  $post->post_title = 'Foo';
  $post->post_content = 'Yolo';

  //* To prevent infinite loop
  remove_action( 'the_post', 'wpse_the_post' );
  $query->setup_postdata( $post );
  add_action( 'the_post', 'wpse_the_post', 10, 2 );
}

This is kind of backwards since you're then setting up the post data twice. But if you're intent on using the_post hook...

I'd use two different filters instead (the_title and the_content).

  • I ended up using the_post hook and then calling the_title and the_content filters from it. Still very odd that this old code is working 100% as intended on a few live sites, and has been for years. But thank you for your explanation of how they work in the backend! – Kevin Feb 16 '18 at 23:39
0

I was able to solve this with the following. I don't know if this is proper, and I don't really understand why it's necessary, but it is doing what I need it to do now:

public function fetch_post_data($post) {
    add_filter( 'the_title', function( $title) use ($post) {
            if(is_singular() && in_the_loop() && is_main_query() && $post->post_type === 'my_cpt') {
                return $post->post_title;
            }
            return $title;
        } );

        add_filter( 'the_content', function( $content ) use ($post) {
            if(is_singular() && in_the_loop() && is_main_query() && $post->post_type === 'my_cpt') {
                return $post->post_content;
            }
            return $content;
        } );
}

If anyone has any input on why this is now necessary, I would love to hear it.

  • I actually need to modify both the title AND the content. That's why I have been using the_post. – Kevin Feb 16 '18 at 19:04

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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