Как решить конфликт между одинаковыми алиасами пользовательского типа контента и обычной страницы?

Добрый день.
Ситуация такова: есть кастомный тип контента с алиасом products. Архивной страницы у него нет (has_archive = false), это сделано потому, что по адресу /products находится обычная страница со своим контентом и своей логикой вывода собственно продуктов. Каждый продукт размещен по адресу /products/product-title. Это все работает прекрасно.

Однако сейчас требуется добавить по адресу /products/page-title страницу. Но если так сделать, она будет недоступна из-за того, что алиас products занят пользовательским типом, и вордпресс считает, что раз продукта по этому адресу нет, то ничего там быть в принципе не может.

Из придуманных вариантов - переписывать rewrite_rules (геморно и непросто), либо в шаблоне проверять, является ли текущий пост страницей, и если да - выводить страницу (смахивает на костыль и в принципе некрасиво). Вариант создать эту страницу как отдельный пост типа products еще более некрасив, чем предыдущие.

Что можно сделать в данной ситуации, как выйти из нее наиболее красивым способом?
Спасибо.
  • Вопрос задан
  • 281 просмотр
Решения вопроса 1
Heian
@Heian Автор вопроса
Ашот
Работающее решение проблемы. Если тип поста отличается от дефолтных, но он не найден, проверяем, существует ли страница с таким адресом.

function loop_cpt_filter($wp_query) {
  // Variables
  $post_slug = null;
  $query_vars = $wp_query->query_vars;

  // If CPT is set but post not found
  if(!$wp_query->post_count && isset($query_vars['post_type'])) {
    $post_type = $query_vars['post_type'];
    $cpt_object = get_post_type_object($post_type);

    if(isset($query_vars[$post_type])) {
      $post_slug = trim($cpt_object->rewrite['slug'] . '/' . $query_vars[$post_type], '/');
    }

    // If page by that slug exists, set post to the current query
    if($post_slug && ($page = get_page_by_path($post_slug))) {     
      $wp_query->set('post_type', 'page');
      $wp_query->set('p', null);
      $wp_query->set('page_id', $page->ID);
    }
  }
}
add_action('pre_get_posts', 'loop_cpt_filter', 100, 1);
Ответ написан
Комментировать
Пригласить эксперта
Ответы на вопрос 2
littleguga
@littleguga
Не стыдно не знать, а стыдно не интересоваться.
Небольшое замечание по логике - /products/product-title, лучше будет сделать /product/product-title.
Как с БД, в единственном числе.
Также, в данном случае страница /products(которая, как я думаю, представляет собой набор доступных товаров, будет спокойно доступна).

И то и то костыль. Лучше правильно продумать логику. К чему должна относиться /products/page-title?
Ответ написан
HeadOnFire
@HeadOnFire
PHP, Laravel & WordPress Evangelist
Ваше решение рабочее, и никакой это не костыль - вы абсолютно нормальным, хоть и не самым оптимальным способом решили задачу. Если же решать более оптимально - то таки правильно использовать rewrite rules, переписывать их не надо, достаточно добавить 1 новое правило конкретно для этого адреса в начало всех правил.
function add_my_rewrite_rules( $rules ) {
    $new_rule = array(
        'products/(page-name)/$' => 'index.php?pagename=$matches[1]' // page-name замените
    );
    $rules = $new_rule + $rules;
    return $rules;
}
add_filter( 'rewrite_rules_array', 'add_my_rewrite_rules' );
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы