wp_resolve_numeric_slug_conflicts

Resolve numeric slugs that collide with date permalinks.

Description

(array) wp_resolve_numeric_slug_conflicts( (array) $query_vars = array() ); 

Permalinks of posts with numeric slugs can sometimes look to WP_Query::parse_query() like a date archive, as when your permalink structure is /%year%/%postname%/ and a post with post_name 05. has the URL /2015/05/.

This function detects conflicts of this type and resolves them in favor of the post permalink.

Note that, since 4.3.0, wp_unique_post_slug() prevents the creation of post slugs that would result in a date archive conflict. The resolution performed in this function is primarily for legacy content, as well as cases when the admin has changed the site's permalink structure in a way that introduces URL conflicts.

Returns (array)

Returns the original array of query vars, with date/post conflicts resolved.

Parameters (1)

0. $query_vars — Optional. (array) => array()
Query variables for setting up the loop, as determined in WP::parse_request(). Default empty array.

Usage

  1. if ( !function_exists( 'wp_resolve_numeric_slug_conflicts' ) ) { 
  2. require_once ABSPATH . WPINC . '/rewrite.php'; 
  3.  
  4. // Optional. Query variables for setting up the loop, as determined in 
  5. // WP::parse_request(). Default empty array. 
  6. $query_vars = array(); 
  7.  
  8. // NOTICE! Understand what this does before running. 
  9. $result = wp_resolve_numeric_slug_conflicts($query_vars); 
  10.  

Defined (1)

The function is defined in the following location(s).

/wp-includes/rewrite.php  
  1. function wp_resolve_numeric_slug_conflicts( $query_vars = array() ) { 
  2. if ( ! isset( $query_vars['year'] ) && ! isset( $query_vars['monthnum'] ) && ! isset( $query_vars['day'] ) ) { 
  3. return $query_vars; 
  4.  
  5. // Identify the 'postname' position in the permastruct array. 
  6. $permastructs = array_values( array_filter( explode( '/', get_option( 'permalink_structure' ) ) ) ); 
  7. $postname_index = array_search( '%postname%', $permastructs ); 
  8.  
  9. if ( false === $postname_index ) { 
  10. return $query_vars; 
  11.  
  12. /** 
  13. * A numeric slug could be confused with a year, month, or day, depending on position. To account for 
  14. * the possibility of post pagination (eg 2015/2 for the second page of a post called '2015'), our 
  15. * `is_*` checks are generous: check for year-slug clashes when `is_year` *or* `is_month`, and check 
  16. * for month-slug clashes when `is_month` *or* `is_day`. 
  17. */ 
  18. $compare = ''; 
  19. if ( 0 === $postname_index && ( isset( $query_vars['year'] ) || isset( $query_vars['monthnum'] ) ) ) { 
  20. $compare = 'year'; 
  21. } elseif ( '%year%' === $permastructs[ $postname_index - 1 ] && ( isset( $query_vars['monthnum'] ) || isset( $query_vars['day'] ) ) ) { 
  22. $compare = 'monthnum'; 
  23. } elseif ( '%monthnum%' === $permastructs[ $postname_index - 1 ] && isset( $query_vars['day'] ) ) { 
  24. $compare = 'day'; 
  25.  
  26. if ( ! $compare ) { 
  27. return $query_vars; 
  28.  
  29. // This is the potentially clashing slug. 
  30. $value = $query_vars[ $compare ]; 
  31.  
  32. $post = get_page_by_path( $value, OBJECT, 'post' ); 
  33. if ( ! ( $post instanceof WP_Post ) ) { 
  34. return $query_vars; 
  35.  
  36. // If the date of the post doesn't match the date specified in the URL, resolve to the date archive. 
  37. if ( preg_match( '/^([0-9]{4})\-([0-9]{2})/', $post->post_date, $matches ) && isset( $query_vars['year'] ) && ( 'monthnum' === $compare || 'day' === $compare ) ) { 
  38. // $matches[1] is the year the post was published. 
  39. if ( intval( $query_vars['year'] ) !== intval( $matches[1] ) ) { 
  40. return $query_vars; 
  41.  
  42. // $matches[2] is the month the post was published. 
  43. if ( 'day' === $compare && isset( $query_vars['monthnum'] ) && intval( $query_vars['monthnum'] ) !== intval( $matches[2] ) ) { 
  44. return $query_vars; 
  45.  
  46. /** 
  47. * If the located post contains nextpage pagination, then the URL chunk following postname may be 
  48. * intended as the page number. Verify that it's a valid page before resolving to it. 
  49. */ 
  50. $maybe_page = ''; 
  51. if ( 'year' === $compare && isset( $query_vars['monthnum'] ) ) { 
  52. $maybe_page = $query_vars['monthnum']; 
  53. } elseif ( 'monthnum' === $compare && isset( $query_vars['day'] ) ) { 
  54. $maybe_page = $query_vars['day']; 
  55. // Bug found in #11694 - 'page' was returning '/4' 
  56. $maybe_page = (int) trim( $maybe_page, '/' ); 
  57.  
  58. $post_page_count = substr_count( $post->post_content, '<!--nextpage-->' ) + 1; 
  59.  
  60. // If the post doesn't have multiple pages, but a 'page' candidate is found, resolve to the date archive. 
  61. if ( 1 === $post_page_count && $maybe_page ) { 
  62. return $query_vars; 
  63.  
  64. // If the post has multiple pages and the 'page' number isn't valid, resolve to the date archive. 
  65. if ( $post_page_count > 1 && $maybe_page > $post_page_count ) { 
  66. return $query_vars; 
  67.  
  68. // If we've gotten to this point, we have a slug/date clash. First, adjust for nextpage. 
  69. if ( '' !== $maybe_page ) { 
  70. $query_vars['page'] = intval( $maybe_page ); 
  71.  
  72. // Next, unset autodetected date-related query vars. 
  73. unset( $query_vars['year'] ); 
  74. unset( $query_vars['monthnum'] ); 
  75. unset( $query_vars['day'] ); 
  76.  
  77. // Then, set the identified post. 
  78. $query_vars['name'] = $post->post_name; 
  79.  
  80. // Finally, return the modified query vars. 
  81. return $query_vars;