urls - Allow duplicate slugs for pages and posts

admin2025-04-19  0

My use case is: I have a two pages, they each have a meta information "language". Posts and pages having same language cannot have the same slug, but with different slugs it is totally fine. Currently I have this code:

add_filter( 'wp_unique_post_slug', 'allow_duplicate_slugs', 10, 6 );
function allow_duplicate_slugs( $slug, $post_id, $post_status, $post_type, $post_parent, $original_slug ) {
  global $wpdb, $wp_rewrite;

  $post_language = get_post_meta( $post->ID, 'language', true);

  $pto = get_post_type_object( $post_type );
  # If our post type isn't hierarchical, we don't need to worry about it:
  if ( !$pto->hierarchical )
   return $slug;
  # If our slug doesn't end with a number, we don't need to worry about it:
  if ( !preg_match( '|[0-9]$|', $slug ) )
    return $slug;
  # Most of this code is pulled straight from wp_unique_post_slug(). Just the post type check has changed.
  $feeds = $wp_rewrite->feeds;

  if ( ! is_array( $feeds ) )
    $feeds = array();

  $check_sql = "
  SELECT post_name
  FROM $wpdb->posts
  JOIN $wpdb->postmeta
  ON $wpdb->posts.ID = $wpdb->postmeta.post_id
  AND $wpdb->postmeta.meta_key = 'language' AND $wpdb->postmeta.meta_value = '$post_language'
  WHERE post_name = %s
  AND post_type = %s
  AND ID != %d
  AND post_parent = %d
  LIMIT 1
  ";

  $post_name_check = $wpdb->get_var( $wpdb->prepare( $check_sql, $original_slug, $post_type, $post_id, $post_parent ) );

  if ( $post_name_check || in_array( $original_slug, $feeds ) || preg_match( "@^($wp_rewrite->pagination_base)?\d+$@", $original_slug )  || apply_filters( 'wp_unique_post_slug_is_bad_hierarchical_slug', false, $original_slug, $post_type, $post_parent ) ) {
    $suffix = 2;
    do {
    $alt_post_name = substr( $original_slug, 0, 200 - ( strlen( $suffix ) + 1 ) ) . "-$suffix";
    $post_name_check = $wpdb->get_var( $wpdb->prepare( $check_sql, $alt_post_name, $post_type, $post_id, $post_parent ) );
    $suffix++;
  } while ( $post_name_check );
    $slug = $alt_post_name;
  } else {
    $slug = $original_slug;
  }

  return $slug;
}

The problem is that when there are two pages with different slugs, only the one is being shown, the other one shows 404. Using Query Monitor (/) I could find out that the query actually finds always the same page with the same ID. Example debugged sql:

SELECT wp_posts.*
FROM wp_posts
INNER JOIN wp_postmeta
ON ( wp_posts.ID = wp_postmeta.post_id )
WHERE 1=1
AND (wp_posts.ID = '8')
AND ( ( wp_postmeta.meta_key = 'language'
AND wp_postmeta.meta_value = 'en' ) )
AND wp_posts.post_type = 'page'
GROUP BY wp_posts.ID
ORDER BY wp_posts.post_date DESC

The debugged sql is always the same, if visiting pages with the same slug.

Then I wrote:

add_action('pre_get_posts', function($query) {
  if(!is_admin()) {
    $meta_query = [
      'RELATION' => 'AND',
      [
        'key' => 'language',
        'value' => get_current_language(),
        'compare' => '='
      ]
    ];
    $query->set('meta_query', $meta_query);
  }
});

But it does not seem to work. I am trying to tell the query, that it has to include also this meta information, but debugging the sql (as shown above) gives always the same result when visiting two pages with the same slug.

Maybe someone here has an idea an could help me out? Many thanks!

转载请注明原文地址:http://conceptsofalgorithm.com/Algorithm/1745066721a283031.html

最新回复(0)