diff --git a/src/wp-includes/canonical.php b/src/wp-includes/canonical.php index 6b8c17c07d55a..72d5680f9a862 100644 --- a/src/wp-includes/canonical.php +++ b/src/wp-includes/canonical.php @@ -65,6 +65,36 @@ function redirect_canonical( $requested_url = null, $do_redirect = true ) { return null; } + $redirect_post_id = 0; + foreach ( array( 'p', 'page_id', 'attachment_id' ) as $query_var ) { + $redirect_post_id = get_query_var( $query_var ); + + if ( $redirect_post_id ) { + $redirect_post_id = absint( $redirect_post_id ); + break; + } + } + + if ( $redirect_post_id ) { + $redirect_post = get_post( $redirect_post_id ); + + if ( + ( + $redirect_post && + 'future' === get_post_status( $redirect_post ) + ) + || + ( + $redirect_post && + 'attachment' === $redirect_post->post_type && + $redirect_post->post_parent && + 'future' === get_post_status( $redirect_post->post_parent ) + ) + ) { + return null; + } + } + if ( ! $requested_url && isset( $_SERVER['HTTP_HOST'] ) ) { // Build the URL in the address bar. $requested_url = is_ssl() ? 'https://' : 'http://'; diff --git a/src/wp-includes/link-template.php b/src/wp-includes/link-template.php index 54b78a028d745..17586605bbacb 100644 --- a/src/wp-includes/link-template.php +++ b/src/wp-includes/link-template.php @@ -127,6 +127,11 @@ function wp_force_plain_post_permalink( $post = null, $sample = null ) { if ( // Publicly viewable links never have plain permalinks. is_post_status_viewable( $post_status_obj ) || + ( + // Scheduled posts use their future pretty permalink. + 'future' === $post->post_status && + is_post_type_viewable( $post_type_obj ) + ) || ( // Private posts don't have plain permalinks if the user can read them. $post_status_obj->private && diff --git a/src/wp-includes/post.php b/src/wp-includes/post.php index 005ccadd62e34..5bf4006901e88 100644 --- a/src/wp-includes/post.php +++ b/src/wp-includes/post.php @@ -7351,8 +7351,12 @@ function wp_check_for_changed_slugs( $post_id, $post, $post_before ) { return; } - // We're only concerned with published, non-hierarchical objects. - if ( ! ( 'publish' === $post->post_status || ( 'attachment' === $post->post_type && 'inherit' === $post->post_status ) ) + // We're only concerned with published or scheduled non-hierarchical objects. + if ( + ! ( + in_array( $post->post_status, array( 'publish', 'future' ), true ) || + ( 'attachment' === $post->post_type && 'inherit' === $post->post_status ) + ) || is_post_type_hierarchical( $post->post_type ) ) { return; @@ -7399,8 +7403,12 @@ function wp_check_for_changed_dates( $post_id, $post, $post_before ) { return; } - // We're only concerned with published, non-hierarchical objects. - if ( ! ( 'publish' === $post->post_status || ( 'attachment' === $post->post_type && 'inherit' === $post->post_status ) ) + // We're only concerned with published or scheduled non-hierarchical objects. + if ( + ! ( + in_array( $post->post_status, array( 'publish', 'future' ), true ) || + ( 'attachment' === $post->post_type && 'inherit' === $post->post_status ) + ) || is_post_type_hierarchical( $post->post_type ) ) { return; diff --git a/src/wp-includes/query.php b/src/wp-includes/query.php index 592e70e0290a3..244f047daa34b 100644 --- a/src/wp-includes/query.php +++ b/src/wp-includes/query.php @@ -1096,6 +1096,10 @@ function wp_old_slug_redirect() { return; } + if ( 'future' === get_post_status( $id ) ) { + return; + } + $link = get_permalink( $id ); if ( get_query_var( 'paged' ) > 1 ) { diff --git a/tests/phpunit/tests/canonical/postStatus.php b/tests/phpunit/tests/canonical/postStatus.php index 7620ccfdd19f7..558d1b4a713c1 100644 --- a/tests/phpunit/tests/canonical/postStatus.php +++ b/tests/phpunit/tests/canonical/postStatus.php @@ -871,6 +871,19 @@ public function test_canonical_redirects_to_pretty_permalinks( $post_key, $user_ $this->assertCanonical( $requested, $expected ); } + /** + * @ticket 49871 + */ + public function test_canonical_does_not_redirect_plain_permalink_for_scheduled_post() { + wp_set_current_user( 0 ); + $this->set_permalink_structure( '/%year%/%monthnum%/%day%/%postname%/' ); + + $post = self::$posts['future']; + clean_post_cache( $post->ID ); + + $this->assertCanonical( '/?p=' . $post->ID, '/?p=' . $post->ID ); + } + /** * Data provider for test_canonical_redirects_to_pretty_permalinks. * diff --git a/tests/phpunit/tests/link.php b/tests/phpunit/tests/link.php index d05a6b210f636..f42df0235ecea 100644 --- a/tests/phpunit/tests/link.php +++ b/tests/phpunit/tests/link.php @@ -77,29 +77,30 @@ public function test_wp_get_shortlink_with_home_page() { /** * @ticket 30910 + * @ticket 49871 */ - public function test_get_permalink_should_not_reveal_post_name_for_post_with_post_status_future() { - update_option( 'permalink_structure', '/%year%/%monthnum%/%day%/%postname%/' ); - - flush_rewrite_rules(); + public function test_get_permalink_should_return_pretty_permalink_for_post_with_post_status_future() { + $this->set_permalink_structure( '/%year%/%monthnum%/%day%/%postname%/' ); $p = self::factory()->post->create( array( - 'post_status' => 'publish', - 'post_date' => date_format( date_create( '+1 day' ), 'Y-m-d H:i:s' ), + 'post_status' => 'future', + 'post_name' => 'message-from-the-past', + 'post_date' => '2037-12-09 20:19:00', ) ); - $non_pretty_permalink = add_query_arg( 'p', $p, trailingslashit( home_url() ) ); + $pretty_permalink = home_url( '/2037/12/09/message-from-the-past/' ); - $this->assertSame( $non_pretty_permalink, get_permalink( $p ) ); + $this->assertSame( $pretty_permalink, get_permalink( $p ) ); } /** * @ticket 30910 + * @ticket 49871 */ - public function test_get_permalink_should_not_reveal_post_name_for_cpt_with_post_status_future() { - update_option( 'permalink_structure', '/%year%/%monthnum%/%day%/%postname%/' ); + public function test_get_permalink_should_return_pretty_permalink_for_cpt_with_post_status_future() { + $this->set_permalink_structure( '/%year%/%monthnum%/%day%/%postname%/' ); register_post_type( 'wptests_pt', array( 'public' => true ) ); @@ -109,19 +110,14 @@ public function test_get_permalink_should_not_reveal_post_name_for_cpt_with_post array( 'post_status' => 'future', 'post_type' => 'wptests_pt', + 'post_name' => 'future-cpt', 'post_date' => date_format( date_create( '+1 day' ), 'Y-m-d H:i:s' ), ) ); - $non_pretty_permalink = add_query_arg( - array( - 'post_type' => 'wptests_pt', - 'p' => $p, - ), - trailingslashit( home_url() ) - ); + $pretty_permalink = home_url( '/wptests_pt/future-cpt/' ); - $this->assertSame( $non_pretty_permalink, get_permalink( $p ) ); + $this->assertSame( $pretty_permalink, get_permalink( $p ) ); } /** diff --git a/tests/phpunit/tests/rest-api/rest-posts-controller.php b/tests/phpunit/tests/rest-api/rest-posts-controller.php index 212ddde70dd83..ba70110b41418 100644 --- a/tests/phpunit/tests/rest-api/rest-posts-controller.php +++ b/tests/phpunit/tests/rest-api/rest-posts-controller.php @@ -2167,6 +2167,30 @@ public function test_get_item() { $this->check_get_post_response( $response, 'view' ); } + /** + * @ticket 49871 + */ + public function test_get_item_should_return_pretty_permalink_for_scheduled_post() { + $this->set_permalink_structure( '/%year%/%monthnum%/%day%/%postname%/' ); + wp_set_current_user( self::$editor_id ); + + $post_id = self::factory()->post->create( + array( + 'post_status' => 'future', + 'post_name' => 'message-from-the-past', + 'post_date' => '2037-12-09 20:19:00', + ) + ); + + $request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/posts/%d', $post_id ) ); + $request->set_param( 'context', 'edit' ); + $response = rest_get_server()->dispatch( $request ); + $data = $response->get_data(); + + $this->assertSame( 200, $response->get_status() ); + $this->assertSame( home_url( '/2037/12/09/message-from-the-past/' ), $data['link'] ); + } + /** * @dataProvider data_readable_http_methods * @ticket 56481 diff --git a/tests/phpunit/tests/rewrite/oldDateRedirect.php b/tests/phpunit/tests/rewrite/oldDateRedirect.php index 963f103a4fdf4..8082e0e56a294 100644 --- a/tests/phpunit/tests/rewrite/oldDateRedirect.php +++ b/tests/phpunit/tests/rewrite/oldDateRedirect.php @@ -67,6 +67,68 @@ public function test_old_date_redirect() { $this->assertSame( $permalink, $this->old_date_redirect_url ); } + /** + * @ticket 49871 + */ + public function test_old_date_redirect_should_not_redirect_scheduled_post() { + $post_id = self::factory()->post->create( + array( + 'post_status' => 'future', + 'post_name' => 'scheduled-old-date', + 'post_date' => '2037-12-09 20:19:00', + ) + ); + + $old_permalink = user_trailingslashit( get_permalink( $post_id ) ); + $time = '2037-12-10 20:19:00'; + + wp_update_post( + array( + 'ID' => $post_id, + 'post_date' => $time, + 'post_date_gmt' => get_gmt_from_date( $time ), + ) + ); + + $this->assertContains( '2037-12-09', get_post_meta( $post_id, '_wp_old_date' ) ); + + $this->go_to( $old_permalink ); + wp_old_slug_redirect(); + $this->assertNull( $this->old_date_redirect_url ); + } + + /** + * @ticket 49871 + */ + public function test_old_date_redirect_should_redirect_scheduled_post_after_publication() { + $post_id = self::factory()->post->create( + array( + 'post_status' => 'future', + 'post_name' => 'scheduled-publish-old-date', + 'post_date' => '2037-12-09 20:19:00', + ) + ); + + $old_permalink = user_trailingslashit( get_permalink( $post_id ) ); + $time = '2037-12-10 20:19:00'; + + wp_update_post( + array( + 'ID' => $post_id, + 'post_date' => $time, + 'post_date_gmt' => get_gmt_from_date( $time ), + ) + ); + + wp_publish_post( $post_id ); + + $permalink = user_trailingslashit( get_permalink( $post_id ) ); + + $this->go_to( $old_permalink ); + wp_old_slug_redirect(); + $this->assertSame( $permalink, $this->old_date_redirect_url ); + } + public function test_old_date_slug_redirect() { $old_permalink = user_trailingslashit( get_permalink( self::$post_id ) ); diff --git a/tests/phpunit/tests/rewrite/oldSlugRedirect.php b/tests/phpunit/tests/rewrite/oldSlugRedirect.php index cf38ba452eabf..b3f20ae56882d 100644 --- a/tests/phpunit/tests/rewrite/oldSlugRedirect.php +++ b/tests/phpunit/tests/rewrite/oldSlugRedirect.php @@ -55,6 +55,64 @@ public function test_old_slug_redirect() { $this->assertSame( $permalink, $this->old_slug_redirect_url ); } + /** + * @ticket 49871 + */ + public function test_old_slug_redirect_should_not_redirect_scheduled_post() { + $post_id = self::factory()->post->create( + array( + 'post_status' => 'future', + 'post_name' => 'scheduled-old-slug', + 'post_date' => '2037-12-09 20:19:00', + ) + ); + + $old_permalink = user_trailingslashit( get_permalink( $post_id ) ); + + wp_update_post( + array( + 'ID' => $post_id, + 'post_name' => 'scheduled-new-slug', + ) + ); + + $this->assertContains( 'scheduled-old-slug', get_post_meta( $post_id, '_wp_old_slug' ) ); + + $this->go_to( $old_permalink ); + wp_old_slug_redirect(); + $this->assertNull( $this->old_slug_redirect_url ); + } + + /** + * @ticket 49871 + */ + public function test_old_slug_redirect_should_redirect_scheduled_post_after_publication() { + $post_id = self::factory()->post->create( + array( + 'post_status' => 'future', + 'post_name' => 'scheduled-publish-old-slug', + 'post_date' => '2037-12-09 20:19:00', + ) + ); + + $old_permalink = user_trailingslashit( get_permalink( $post_id ) ); + + wp_update_post( + array( + 'ID' => $post_id, + 'post_name' => 'scheduled-publish-new-slug', + ) + ); + + wp_publish_post( $post_id ); + + $permalink = user_trailingslashit( get_permalink( $post_id ) ); + + $this->go_to( $old_permalink ); + wp_old_slug_redirect(); + $this->assertSame( $permalink, $this->old_slug_redirect_url ); + } + /** * @ticket 36723 */