最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

urls - Allow duplicate slugs for pages and posts

programmeradmin1浏览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!

发布评论

评论列表(0)

  1. 暂无评论