Make WordPress Core

Opened 3 years ago

Last modified 3 years ago

#54020 new enhancement

Add a filter to allow updating post without changing the modified dates

Reported by: pbearne's profile pbearne Owned by:
Milestone: Awaiting Review Priority: normal
Severity: normal Version: 5.9
Component: Posts, Post Types Keywords: has-unit-tests has-dev-note dev-feedback has-patch
Focuses: Cc:

Description

wp_update_post calls wp_insert_post which has code that always changes the modified date
this causes problems when trying to fix posts via batch/wp-cli type operations

<?php
if ( $update || '0000-00-00 00:00:00' === $post_date ) {
   $post_modified     = current_time( 'mysql' );
   $post_modified_gmt = current_time( 'mysql', 1 );
} else {
   $post_modified     = $post_date;
   $post_modified_gmt = $post_date_gmt;
}

So you end with code like this to work around this

<?php
// get the date from the current post and reset it via the filter
$function = function ( $data ) use ( $id ) {
        $post = get_post( $id );
        $data['post_modified']     = $post->post_date_gmt;
        $data['post_modified_gmt'] = $post->post_date_gmt;

        return $data;
};

add_filter( 'wp_insert_post_data', $function, 10, 2 );
$updated = wp_update_post( $args );
remove_filter( 'wp_insert_post_data', $function );

This function needs to make get_post() call for each insert and this slows the process in a big way

I have added a filter that allows us to turn off the modification and set the date if needed

<?php
if ( $update || '0000-00-00 00:00:00' === $post_date ) {
                /**
                 * Filters whether to preserve the modified dates when updating posts.
                 * Optionally allow you to set the date
                 *
                 * @since 2.9.0
                 *
                 * @param bool $trigger whether to preserve the modified date default: false
                 * @param array $postarr that will be saved.
                 *
                 * @return Bool|string|array true to keep the current date, String to set both date to same value
                 * keyed array to set both array( 'post_date' => date1, 'post_date_gmt' => date2 )
                 */
                $update_date = apply_filters( 'wp_update_post_preserve_dates', false, $postarr );
                if( false === $update_date ) {
                        $post_modified     = current_time( 'mysql' );
                        $post_modified_gmt = current_time( 'mysql', 1 );
                } elseif ( ! is_array( $update_date ) && strtotime( $update_date ) ){
                        $post_modified     = $update_date;
                        $post_modified_gmt = get_gmt_from_date( $update_date );
                } elseif ( is_array( $update_date ) && isset( $update_date['post_modified'] ) && isset( $update_date['post_modified_gmt'] ) ){
                        $post_modified      = $update_date['post_modified'];
                        $post_modified_gmt  = $update_date['post_modified_gmt'];
                } else {
                        $post_modified     = $postarr['post_modified'];
                        $post_modified_gmt = $postarr['post_modified_gmt'];
                }
        } else {
                $post_modified     = $post_date;
                $post_modified_gmt = $post_date_gmt;
        }

Change History (9)

#1 follow-ups: @Ipstenu
3 years ago

this causes problems when trying to fix posts via batch/wp-cli type operations

What kind of problem? The post was modified, even if it was by a batch job, so shouldn't it reflect that?

(Note: This isn't for or against the idea, just ... what problem are we actually solving?)

This ticket was mentioned in PR #1623 on WordPress/wordpress-develop by pbearne.


3 years ago
#2

  • Keywords has-patch added

#3 @re.ardestani
3 years ago

It seems helpful, possible use case:

I have lots of posts, now I need to add a prefix to post titles.

  • Post 1 -> [Bug] Post 1
  • post 2 -> [Feature] Post 2

It's seems like an update but it's not an real update and I don't want the modification date to change.

Version 0, edited 3 years ago by re.ardestani (next)

#4 in reply to: ↑ 1 @pbearne
3 years ago

Replying to Ipstenu:

this causes problems when trying to fix posts via batch/wp-cli type operations

What kind of problem? The post was modified, even if it was by a batch job, so shouldn't it reflect that?

(Note: This isn't for or against the idea, just ... what problem are we actually solving?)

I have been working on a site where we have to need to fix few items like add sponsored to the rel attr to links that provide referral income. The client uses the modified date to order posts in the archives. So had to use the workaround to control the dates which give the size of the made very slow

#5 @SergeyBiryukov
3 years ago

  • Component changed from General to Posts, Post Types

#6 @peterwilsoncc
3 years ago

I'm a little unclear on the advantage the proposed filter offers over wp_insert_post_data.

With the exception of posts that have been untrashed, the get_post() call within the sample code should be in the object cache and be relatively quick.

The complexity of the if statement in the proposed patch seems a lot to include for what appears to be a niche use case.

A number of actions and filters in wp_insert_post() include the post object before any changes, would this be helpful to include in wp_insert_attachment_data and wp_insert_post_data?

#7 in reply to: ↑ 1 @kasparsd
3 years ago

What kind of problem? The post was modified, even if it was by a batch job, so shouldn't it reflect that?

There are many instances when wp_update_post() needs to be called without the intention of updating the actual post content:

  • changing the comment_status and ping_status,
  • changing the post slug,
  • changing the menu order,
  • changing the post parent.

I feel like that's enough use-cases to provide a simple way to disable any changes to the post_modified and post_modified_gmt dates. For legacy reasons, it should default to the current behaviour but it would be nice to have a parameter flag or a filter to disable the date change behaviour.

We already have the edit_date flag to clear the date data for drafts, for example.

Could we add a filter before the if ( $update || '0000-00-00 00:00:00' === $post_date ) { conditional that generates a date-specific update flag $update_post_modified_date based on a filter value?

How about something like this:

<?php
$update_post_modified_date = apply_filters( 
    'wp_insert_post_update_post_modified_date', 
    ( $update || '0000-00-00 00:00:00' === $post_date ), // Default to the current logic.
    $postarr
);

if ( $update_post_modified_date ) {
    // ...

This ticket was mentioned in Slack in #core by pbearne. View the logs.


3 years ago

#9 @pbearne
3 years ago

Happy to create a simple on/off filter if that is felt to be the best

Note: See TracTickets for help on using tickets.