Make WordPress Core

Changeset 42401


Ignore:
Timestamp:
12/15/2017 08:30:50 AM (7 years ago)
Author:
pento
Message:

Canonical URLs: Redirect to the correct URL when the post date changes.

When a post slug is changed, we store a copy of the old slug, so that we can redirect visitors visiting the old URL to the new URL.

In the same way, this stores a copy of the old date, when the post date changes, so we can redirect visitors to the new URL.

Props nickmomrik.
Fixes #15397 for trunk.

Location:
trunk
Files:
1 added
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/default-filters.php

    r42343 r42401  
    355355add_action( 'attachment_updated', 'wp_check_for_changed_slugs', 12, 3 );
    356356
     357// Redirect Old Dates
     358add_action( 'post_updated',       'wp_check_for_changed_dates', 12, 3 );
     359add_action( 'attachment_updated', 'wp_check_for_changed_dates', 12, 3 );
     360
    357361// Nonce check for Post Previews
    358362add_action( 'init', '_show_post_preview' );
  • trunk/src/wp-includes/post.php

    r42398 r42401  
    57095709
    57105710/**
     5711 * Check for changed dates for published post objects and save the old date.
     5712 *
     5713 * The function is used when a post object of any type is updated,
     5714 * by comparing the current and previous post objects.
     5715 *
     5716 * If the date was changed and not already part of the old dates then it will be
     5717 * added to the post meta field ('_wp_old_date') for storing old dates for that
     5718 * post.
     5719 *
     5720 * The most logically usage of this function is redirecting changed post objects, so
     5721 * that those that linked to an changed post will be redirected to the new post.
     5722 *
     5723 * @since 4.9.2
     5724 *
     5725 * @param int     $post_id     Post ID.
     5726 * @param WP_Post $post        The Post Object
     5727 * @param WP_Post $post_before The Previous Post Object
     5728 */
     5729function wp_check_for_changed_dates( $post_id, $post, $post_before ) {
     5730    $previous_date = date( 'Y-m-d', strtotime( $post_before->post_date ) );
     5731    $new_date = date( 'Y-m-d', strtotime( $post->post_date ) );
     5732    // Don't bother if it hasn't changed.
     5733    if ( $new_date == $previous_date ) {
     5734        return;
     5735    }
     5736    // We're only concerned with published, non-hierarchical objects.
     5737    if ( ! ( 'publish' === $post->post_status || ( 'attachment' === get_post_type( $post ) && 'inherit' === $post->post_status ) ) || is_post_type_hierarchical( $post->post_type ) ) {
     5738        return;
     5739    }
     5740    $old_dates = (array) get_post_meta( $post_id, '_wp_old_date' );
     5741    // If we haven't added this old date before, add it now.
     5742    if ( ! empty( $previous_date ) && ! in_array( $previous_date, $old_dates ) ) {
     5743        add_post_meta( $post_id, '_wp_old_date', $previous_date );
     5744    }
     5745    // If the new slug was used previously, delete it from the list.
     5746    if ( in_array( $new_date, $old_dates ) ) {
     5747        delete_post_meta( $post_id, '_wp_old_date', $new_date );
     5748    }
     5749}
     5750
     5751/**
    57115752 * Retrieve the private post SQL based on capability.
    57125753 *
  • trunk/src/wp-includes/query.php

    r42355 r42401  
    846846 *
    847847 * @since 2.1.0
    848  *
    849  * @global wpdb $wpdb WordPress database abstraction object.
    850848 */
    851849function wp_old_slug_redirect() {
    852850    if ( is_404() && '' !== get_query_var( 'name' ) ) {
    853         global $wpdb;
    854 
    855851        // Guess the current post_type based on the query vars.
    856852        if ( get_query_var( 'post_type' ) ) {
     
    876872        }
    877873
    878         $query = $wpdb->prepare( "SELECT post_id FROM $wpdb->postmeta, $wpdb->posts WHERE ID = post_id AND post_type = %s AND meta_key = '_wp_old_slug' AND meta_value = %s", $post_type, get_query_var( 'name' ) );
    879 
    880         // if year, monthnum, or day have been specified, make our query more precise
    881         // just in case there are multiple identical _wp_old_slug values
    882         if ( get_query_var( 'year' ) ) {
    883             $query .= $wpdb->prepare( ' AND YEAR(post_date) = %d', get_query_var( 'year' ) );
     874        $id = _find_post_by_old_slug( $post_type );
     875
     876        if ( ! $id ) {
     877            $id = _find_post_by_old_date( $post_type );
    884878        }
    885         if ( get_query_var( 'monthnum' ) ) {
    886             $query .= $wpdb->prepare( ' AND MONTH(post_date) = %d', get_query_var( 'monthnum' ) );
    887         }
    888         if ( get_query_var( 'day' ) ) {
    889             $query .= $wpdb->prepare( ' AND DAYOFMONTH(post_date) = %d', get_query_var( 'day' ) );
    890         }
    891 
    892         $id = (int) $wpdb->get_var( $query );
     879
     880        /**
     881         * Filters the old slug redirect post ID.
     882         *
     883         * @since 4.9.2
     884         *
     885         * @param string $id The redirect post ID.
     886         */
     887        $id = apply_filters( 'old_slug_redirect_post_id', $id );
    893888
    894889        if ( ! $id ) {
     
    923918
    924919/**
     920 * Find the post ID for redirecting an old slug.
     921 *
     922 * @see wp_old_slug_redirect()
     923 *
     924 * @since 4.9.2
     925 * @access private
     926 *
     927 * @global wpdb $wpdb WordPress database abstraction object.
     928 *
     929 * @param string $post_type The current post type based on the query vars.
     930 * @return int $id The Post ID.
     931 */
     932function _find_post_by_old_slug( $post_type ) {
     933    global $wpdb;
     934
     935    $query = $wpdb->prepare( "SELECT post_id FROM $wpdb->postmeta, $wpdb->posts WHERE ID = post_id AND post_type = %s AND meta_key = '_wp_old_slug' AND meta_value = %s", $post_type, get_query_var( 'name' ) );
     936
     937    // if year, monthnum, or day have been specified, make our query more precise
     938    // just in case there are multiple identical _wp_old_slug values
     939    if ( get_query_var( 'year' ) ) {
     940        $query .= $wpdb->prepare( " AND YEAR(post_date) = %d", get_query_var( 'year' ) );
     941    }
     942    if ( get_query_var( 'monthnum' ) ) {
     943        $query .= $wpdb->prepare( " AND MONTH(post_date) = %d", get_query_var( 'monthnum' ) );
     944    }
     945    if ( get_query_var( 'day' ) ) {
     946        $query .= $wpdb->prepare( " AND DAYOFMONTH(post_date) = %d", get_query_var( 'day' ) );
     947    }
     948
     949    $id = (int) $wpdb->get_var( $query );
     950
     951    return $id;
     952}
     953
     954/**
     955 * Find the post ID for redirecting an old date.
     956 *
     957 * @see wp_old_slug_redirect()
     958 *
     959 * @since 4.9.2
     960 * @access private
     961 *
     962 * @global wpdb $wpdb WordPress database abstraction object.
     963 *
     964 * @param string $post_type The current post type based on the query vars.
     965 * @return int $id The Post ID.
     966 */
     967
     968function _find_post_by_old_date( $post_type ) {
     969    global $wpdb;
     970
     971    $date_query = '';
     972    if ( get_query_var( 'year' ) ) {
     973        $date_query .= $wpdb->prepare( " AND YEAR(pm_date.meta_value) = %d", get_query_var( 'year' ) );
     974    }
     975    if ( get_query_var( 'monthnum' ) ) {
     976        $date_query .= $wpdb->prepare( " AND MONTH(pm_date.meta_value) = %d", get_query_var( 'monthnum' ) );
     977    }
     978    if ( get_query_var( 'day' ) ) {
     979        $date_query .= $wpdb->prepare( " AND DAYOFMONTH(pm_date.meta_value) = %d", get_query_var( 'day' ) );
     980    }
     981
     982    $id = 0;
     983    if ( $date_query ) {
     984        $id = (int) $wpdb->get_var( $wpdb->prepare( "SELECT post_id FROM $wpdb->postmeta AS pm_date, $wpdb->posts WHERE ID = post_id AND post_type = %s AND meta_key = '_wp_old_date' AND post_name = %s" . $date_query, $post_type, get_query_var( 'name' ) ) );
     985
     986        if ( ! $id ) {
     987            // Check to see if an old slug matches the old date
     988            $id = (int) $wpdb->get_var( $wpdb->prepare( "SELECT ID FROM $wpdb->posts, $wpdb->postmeta AS pm_slug, $wpdb->postmeta AS pm_date WHERE ID = pm_slug.post_id AND ID = pm_date.post_id AND post_type = %s AND pm_slug.meta_key = '_wp_old_slug' AND pm_slug.meta_value = %s AND pm_date.meta_key = '_wp_old_date'" . $date_query, $post_type, get_query_var( 'name' ) ) );
     989        }
     990    }
     991
     992    return $id;
     993}
     994
     995/**
    925996 * Set up global post data.
    926997 *
Note: See TracChangeset for help on using the changeset viewer.