Make WordPress Core

Opened 11 years ago

Last modified 3 months ago

#32322 assigned defect (bug)

Custom permalink structure incorrect for Future posts

Reported by: greencode's profile greencode Owned by: kdoole's profile kdoole
Milestone: Future Release Priority: normal
Severity: normal Version: 4.2
Component: Permalinks Keywords: has-unit-tests needs-dev-note good-first-bug has-test-info has-patch
Focuses: Cc:

Description

From V4.2 there is a bug with custom permalink structures used for Future posts that are visible on the front end.

Example:

  • You have your custom permalink structure set up as "Post name".
  • "Published" posts show up with the correct permalink structure i.e. mysite.com/single-post/
  • "posts marked as "Future" but visible in the front end (i.e. if you're wanting to show posts that are scheduled) show up with the default permalink structure i.e. mysite.com/?p=618

Rolling back through the versions of WordPress, all was working correctly in v4.1.5 and then stopped working from v4.2

Attachments (5)

link-template.diff (1.1 KB) - added by kdoole 10 years ago.
adds a filter to the list of post types which should not receive fancy permalinks
link-template-2.diff (2.5 KB) - added by kdoole 10 years ago.
32322-unit-tests.diff (1.5 KB) - added by kdoole 10 years ago.
32322.diff (2.1 KB) - added by andraganescu 6 years ago.
Refreshed patch
32322-2.diff (2.4 KB) - added by andraganescu 6 years ago.
tabs and spaces fixed in patch

Download all attachments as: .zip

Change History (31)

#1 @greencode
11 years ago

  • Summary changed from Default permalink structure showing for Future posts to Custom permalink structure incorrect for Future posts

#2 @SergeyBiryukov
11 years ago

Hi @greencode, welcome to Trac!

Looks like this was an intended change in #30910.

#3 follow-up: @greencode
11 years ago

Thanks for the quick reply. I've had a look at the link you sent but and whilst that appears to be exactly the issue I'm talking about, I'm unsure how to rectify the issue so that the pretty permalink is shown instead of the default permalink. I'm using

<?php the_permalink(); ?>

to generate the link.

#4 in reply to: ↑ 3 @rob.page
11 years ago

Hi, I'm in the same boat as @greencode. I'm unclear how to modify our pages to workaround this change. We have an events page that is now showing the numeric permalink for future events, both as a result of the_permalink() as well as the {PERMALINK} shortcode used in a widget.

How should I be modifying our pages to show the "pretty" permalink?

Thanks.

Replying to greencode:

Thanks for the quick reply. I've had a look at the link you sent but and whilst that appears to be exactly the issue I'm talking about, I'm unsure how to rectify the issue so that the pretty permalink is shown instead of the default permalink. I'm using

<?php the_permalink(); ?>

to generate the link.

#5 follow-up: @johnbillion
11 years ago

  • Keywords needs-patch good-first-bug needs-unit-tests added
  • Type changed from defect (bug) to enhancement

There isn't a simple way to do it. Maybe we need a filter around the array of post statuses in the get_permalink() function to control which statuses get a pretty permalink.

#6 in reply to: ↑ 5 @kdoole
10 years ago

Howdy,

@johnbillion, you made it too easy! :) Here's an initial patch, just to see how this looks. Hope i'm doing this right...

I swapped the if and else here -- it seemed to make sense asking "should we use a short link" instead of "should we not use a fancy link."

Besides the several opportunities in get_permalink to clean up the code style, how's this look?

@kdoole
10 years ago

adds a filter to the list of post types which should not receive fancy permalinks

#7 @kreatif
10 years ago

  • Type changed from enhancement to defect (bug)

I have the same problem with the post status,
i updated the link-template with the patch above but this is nog working for me.

For the post i'm using custom post type ui plugin, needs this a other patch to fix it ?

#8 @kdoole
10 years ago

hi @kreatif,

With this patch, you would need to add a filter to your theme. Something like,

add_filter( 'shortlink_post_statuses', 'prettylink_future_posts' );
function prettylink_future_posts( $post_statuses ) {
	$future_index = array_search( 'future', $post_statuses );
	unset( $post_statuses[ $future_index ] );
	return $post_statuses;
}

#9 @johnbillion
10 years ago

  • Keywords has-patch added; needs-patch removed

This is probably the best approach.

The filter will need inline filter documentation and some more unit tests along with those in the Tests_Link class.

#10 @kdoole
10 years ago

  • Added inline filter docs.
  • Added the filter to get_post_permalink, which i missed at first.
  • I also spent a moment creating unit tests; it feels a bit overly verbose -- is this making sense?

On that note, there's a bit of duplication going on in here, this piece:

$statuses_which_should_shortlink = apply_filters( 'shortlink_post_statuses', array(
	'draft',
	'pending',
	'auto-draft',
	'future'
) );

It was already duplicated, and now with the filter it's a touch longer. Does it make any sense pulling this out into a function?

#11 @kreatif
10 years ago

@kdool, Thanks, works like a charm
I've one bug that is related to this, but don't know if this is a wordpress bug or custom post type ui bug;

When i click on a post i get a blank page (with post status => furure).
Two other post types with post status => published dont't have this problem

Error that i get: Failed to load resource: the server responded with a status of 404 (Not Found)
When i'm visiting the post via edit post -> view post, i can see the post

#12 @kdoole
10 years ago

@kreatif, formatting the permalink is one thing, but enabling non-logged in users to view future posts is another. I did a very quick search and found this plugin, which seems to work by doing the following:

add_filter( 'the_posts', 'show_future_posts' );
function show_future_posts( $posts ) {
   global $wp_query, $wpdb;

   if ( is_single() && $wp_query->post_count == 0 ) {
      $posts = $wpdb->get_results( $wp_query->request );
   }

   return $posts;
}

#13 @kreatif
10 years ago

  • Resolution set to worksforme
  • Status changed from new to closed

@kdoole Thanks the add filter code solved the problem.
I didn't kwow about the non-logged users can see the future posts.
Learned something new, Thanks!

#14 @DrewAPicture
10 years ago

  • Resolution worksforme deleted
  • Status changed from closed to reopened

#15 @obenland
10 years ago

  • Owner set to kdoole
  • Status changed from reopened to assigned

#16 @johnbillion
10 years ago

There's further inconsistency here. For a scheduled post, the permalink used in various places is inconsistent.

  • On the post listing screen, the 'View' link looks like example.com?p=123&preview=true
  • On the post editing screen, the 'View Post' link in the admin toolbar looks like example.com?p=123
  • On the post editing screen, the 'View Post' button next to the slug editor is the pretty permalink

Whichever URL you view the post at, the is_preview() conditional is true, so the non-pretty links should always be in the format example.com?p=123&preview=true.

#17 in reply to: ↑ description @bryancave
8 years ago

Is there any progress on this? Still seems to be an issue.

#18 @andraganescu
7 years ago

  • Keywords needs-refresh added; needs-unit-tests removed
  • Milestone changed from Awaiting Review to 5.3

This patch still works and while it doesn't solve everything, as @johnbillion noted four years ago, it does add a good filter instead of the hardcoded statuses as they are now:

if ( '' != $permalink && ! in_array( $post->post_status, array( 'draft', 'pending', 'auto-draft', 'future' ) ) ) {

I wouldn't change anything else though, except run that array through a filter twice. Wouldn't need to rename the $draft_or_pending var nor change the conditional at line 159.

/**
 * Filters the list of post statuses which should use shortlinks and avoid fancy permalinks.
 *
 * @since 4.3.0
 *
 * @param array $statuses The list of statuses
 */
$auto_short_link_statuses = apply_filters( 'shortlink_post_statuses', array(
        'draft',
        'pending',
        'auto-draft',
        'future'
) );

if ( '' != $permalink && ! in_array( $post->post_status, $auto_short_link_statuses ) ) {

and later in the file just:

$auto_short_link_statuses = apply_filters( 'shortlink_post_statuses', array(
        'draft',
        'pending',
        'auto-draft',
        'future'
) );
$draft_or_pending = get_post_status( $post ) && in_array( get_post_status( $post ), $auto_short_link_statuses );

and that's that.

There still is the issue with the inconsistency of preview link but it is a separate issue.

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


6 years ago

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


6 years ago

@andraganescu
6 years ago

Refreshed patch

#21 @andraganescu
6 years ago

  • Keywords needs-testing has-unit-tests needs-dev-note added; good-first-bug needs-refresh removed

32322-2.diff

I have refreshed the patch with the noted from my previous comments. Not sure of what adding a new filter needs to have done other than the code comments. Also, some more testing would be nice.

Last edited 6 years ago by andraganescu (previous) (diff)

@andraganescu
6 years ago

tabs and spaces fixed in patch

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


6 years ago

#23 @davidbaumwald
6 years ago

  • Milestone changed from 5.3 to Future Release

With 5.3 RC1 releasing today and work still left on this ticket, it is being moved to Future Release. If any committer feels this can be worked in quickly for 5.3 or can assume ownership in 5.4, feel free to move it back up.

#24 @SirLouen
5 months ago

  • Keywords needs-refresh good-first-bug needs-patch has-test-info added; has-patch needs-testing removed

Reproduction Report

Description

✅ This report validates that the issue can be reproduced.

Environment

  • WordPress: 6.9-alpha-60093-src
  • PHP: 8.2.28
  • Server: nginx/1.27.5
  • Database: mysqli (Server: 8.4.5 / Client: mysqlnd 8.2.28)
  • Browser: Chrome 137.0.0.0
  • OS: Windows 10/11
  • Theme: Twenty Twenty 2.9
  • MU Plugins: None activated
  • Plugins:
    • Test Reports 1.2.0

Reproduction Instructions

  1. Got to Settings > Permalinks
  2. Set it to Post Name
  3. Create a new post, Schedule it to some day in the future
  4. Check the URL for the scheduled post under Slug in the right bar
  5. Click on the permalink
  6. 🐞 Permalink redirects to the non-permalink version of the URL

Actual Results

  1. ✅ Error condition occurs (reproduced).

Additional Notes

  • Although going directly to the permalink, in this case /future-post, works well without redirection
  • Current patch is not applying any more. $draft_or_pending was removed in [50132]. New logic should be reviewed in order to re-apply this patch. Given that the last patch was delivered 6-years ago, it could be taken as a reference, but to promo this report back, I will add back the needs-patch.cc @andraganescu

This ticket was mentioned in PR #9247 on WordPress/wordpress-develop by @kush123.


4 months ago
#25

  • Keywords has-patch added; needs-refresh needs-patch removed

# Allow Customization of Post Statuses That Use Plain Permalinks

## Overview

This pull request introduces a new filter wp_force_plain_post_permalink_statuses that allows developers to customize which post statuses should use plain permalinks (e.g., /?p=123) instead of pretty permalinks (e.g., /my-post-title/).

This addresses the long-standing issue where scheduled posts show inconsistent permalink formats - pretty permalinks in the admin interface but plain permalinks in theme templates and functions like the_permalink().

## Trac Ticket: #32322

---

## Issue Fixed

### Scheduled Posts Show Inconsistent Permalink Formats

  • Problem: Scheduled posts (status = future) display different permalink formats in different contexts:
    • Admin interface: Shows pretty permalinks (/my-scheduled-post/)
    • Theme templates: Shows plain permalinks (/?p=123)
    • Direct access: Pretty permalink URLs work without redirection
  • Root Cause: The wp_force_plain_post_permalink() function treats all protected post statuses (including future) as requiring plain permalinks for security, but this creates user confusion since scheduled posts are meant to be public eventually.
  • Solution: Introduced a filterable array of post statuses that should use plain permalinks, allowing developers to customize this behavior on a per-site basis while maintaining security for truly sensitive content.

---

## Code Changes

### New Filter Implementation

/**
 * Filters the post statuses that should use plain permalinks instead of pretty permalinks.
 *
 * By default, posts with 'draft', 'pending', 'auto-draft', and 'future' statuses
 * will use plain permalinks (e.g., /?p=123) for security and consistency reasons.
 *
 * To allow scheduled posts to use pretty permalinks, you can remove 'future' from this array:
 *
 * add_filter( 'wp_force_plain_post_permalink_statuses', function( $statuses ) {
 *     return array_diff( $statuses, [ 'future' ] );
 * });
 *
 * @since 6.9.0
 *
 * @param string[] $statuses Array of post status names that should use plain permalinks.
 * @param WP_Post  $post     The post object.
 */
$plain_permalink_statuses = apply_filters(
    'wp_force_plain_post_permalink_statuses',
    array( 'draft', 'pending', 'auto-draft', 'future' ),
    $post
);

### Updated Logic

if (
    // Publicly viewable links never have plain permalinks.
    is_post_status_viewable( $post_status_obj ) ||
    (
        // Private posts don't have plain permalinks if the user can read them.
        $post_status_obj->private &&
        current_user_can( 'read_post', $post->ID )
    ) ||
    // Protected posts don't have plain links if getting a sample URL.
    ( $post_status_obj->protected && $sample ) ||
    // Allow customization of which post statuses should use plain permalinks.
    ! in_array( $post->post_status, $plain_permalink_statuses, true )
) {
    return false;
}

## Usage Examples

### Basic: Allow Scheduled Posts Pretty Permalinks

add_filter( 'wp_force_plain_post_permalink_statuses', function( $statuses ) {
    return array_diff( $statuses, [ 'future' ] );
});

### Advanced: Selective by Post Type

add_filter( 'wp_force_plain_post_permalink_statuses', function( $statuses, $post ) {
    // Only allow pretty permalinks for future posts of type 'post'
    if ( 'future' === $post->post_status && 'post' === $post->post_type ) {
        return array_diff( $statuses, [ 'future' ] );
    }
    return $statuses;
}, 10, 2 );

### Conditional by User Capability

add_filter( 'wp_force_plain_post_permalink_statuses', function( $statuses, $post ) {
    // Allow editors to see pretty permalinks for future posts
    if ( 'future' === $post->post_status && current_user_can( 'edit_others_posts' ) ) {
        return array_diff( $statuses, [ 'future' ] );
    }
    return $statuses;
}, 10, 2 );

---

## Testing Instructions

### Test Case 1: Default Behavior (Unchanged)

  1. Create a scheduled post with future publication date
  2. View the post in admin - should show pretty permalink
  3. Use the_permalink() in a theme template - should show plain permalink
  4. Expected: No change from current behavior

### Test Case 2: Enable Pretty Permalinks for Future Posts

  1. Add the filter to remove 'future' from plain permalink statuses
  2. Create a scheduled post with future publication date
  3. Use the_permalink() in a theme template
  4. Expected: Shows pretty permalink (/my-scheduled-post/)

### Test Case 3: Selective Application

  1. Add the filter with post type condition (only 'post', not 'page')
  2. Create a scheduled post and scheduled page
  3. Check permalinks for both
  4. Expected: Post shows pretty permalink, page shows plain permalink

### Test Case 4: Security Maintained

  1. Apply filter to allow future posts pretty permalinks
  2. Create draft and pending posts
  3. Check their permalinks
  4. Expected: Draft and pending posts still use plain permalinks

### Test Case 5: Direct Access

  1. Enable pretty permalinks for future posts
  2. Create a scheduled post
  3. Try accessing the pretty permalink URL directly
  4. Expected: Should work without redirection (existing behavior)

---

#26 @Mamaduka
3 months ago

Cross-linking this recent report from Gutenberg - https://github.com/WordPress/gutenberg/issues/71102.

Note: See TracTickets for help on using tickets.