WordPress.org

Make WordPress Core

Opened 8 months ago

Last modified 8 months ago

#42148 new enhancement

url_to_postid plain permalinks for CPTs

Reported by: soulseekah Owned by:
Milestone: Awaiting Review Priority: normal
Severity: normal Version: 1.0
Component: Permalinks Keywords: needs-patch needs-unit-tests
Focuses: Cc:

Description

Would be nice to have url_to_postid working with plain permalinks for custom post types.

There's are currently some issues in url_to_postid where the wrong ID is returned for custom post type plain permalinks (query-based).

<?php
add_action( 'init', function() {
	/** Register a post type */
	register_post_type( 'findme', array(
		'public' => true
	) );

	/** Create a post */
	$post_id = wp_insert_post( array( 'post_type' => 'findme', 'post_status' => 'publish' ) );
	$findme = get_permalink( $post_id );
	$found = url_to_postid( $findme );

	/** Guess it */
	printf( "%s (%s) == %s (%s)", $post_id, $findme, $found, get_permalink( $found ) );
	exit;
} );

30 (http://localhost:8080/?findme=30) == 0 () and 30 (http://localhost:8080/?findme=30) == 2 (http://localhost:8080/) if the frontpage is setup to point ot a post.

Why is it not working? Why is the frontpage post being returned? Let's see how the {{url_to_postid}} function works:

// First, check to see if there is a 'p=N' or 'page_id=N' to match against
if ( preg_match('#[?&](p|page_id|attachment_id)=(\d+)#', $url, $values) ) {
  $id = absint($values[2]);
  if ( $id )
    return $id;
}

Then?

if ( trim( $url, '/' ) === home_url() && 'page' == get_option( 'show_on_front' ) ) {
  $page_on_front = get_option( 'page_on_front' );
  if ( $page_on_front && get_post( $page_on_front ) instanceof WP_Post ) {
    return (int) $page_on_front;
  }
}

Uh, wait what... already? So a short-circuit without checking the custom post types. And that's understandable, since there is inherently no support for custom post type ID mappings as pointed out by:

// Check to see if we are using rewrite rules
$rewrite = $wp_rewrite->wp_rewrite_rules();

// Not using rewrite rules, and 'p=N' and 'page_id=N' methods failed, so we're out of options
if ( empty($rewrite) )
  return 0;

What stands in our way to find the URL earlier?

  1. The query var is not one of p, page_id, attachment_id
  2. The query var value for CPTs is not necessarily, and most often not numeric (the post_title)

A proposed solution would be to look at the query parameters much higher, maybe by injecting the custom ones, ones that support slugs as well, since WordPress sets the page_title for a CPT itself, so that \d+ check would fail.

Use case? Well, this was encountered when trying to paste plain oEmbed URLs for a custom post type (https://github.com/gravityview/GravityView/issues/927).

Change History (1)

#1 @swissspidy
8 months ago

  • Keywords needs-patch needs-unit-tests added
  • Version changed from trunk to 1.0
Note: See TracTickets for help on using tickets.