Создаем кастомный тип записи (Custom Post Type) с кастомными категориями (Custom Taxonomy). Живой поиск на Битрикс

В этой статье я покажу, как можно создавать многоуровневое меню на PHP и MySQL . Безусловно, вариантов его создания можно придумать много, но, судя по количеству Ваших вопросов на эту тему, Вам нужен пример. И его я приведу в этой статье. Сразу отмечу, что данная статья имеет смысл только для тех, кто знает PHP и умеет работать с MySQL . Всем остальным сначала надо пройти этот , либо прочитать какие-нибудь книги по PHP и MySQL .

Для начала создадим таблицу в базе данных со следующими полями:

  • id - уникальный идентификатор.
  • title - анкор ссылки в меню.
  • link - адрес, на который будет вести пункт меню.
  • parent_id - родительский ID. Если родительского пункта нет, то здесь будет NULL (либо можно ещё 0 поставить).

С таблицей разобрались, теперь пришло время PHP-кода . Полный PHP-код приведён ниже:

$mysqli = new mysqli("localhost", "root", "", "db"); // Подключаемся к БД
$result_set = $mysqli->query("SELECT * FROM `menu`"); // Делаем выборку всех записей из таблицы с меню
$items = array(); // Массив для пунктов меню
while (($row = $result_set->fetch_assoc()) != false) $items[$row["id"]] = $row; // Заполняем массив выборкой из БД
$childrens = array(); // Массив для соответствий дочерних элементов их родительским
foreach ($items as $item) {
if ($item["parent_id"]) $childrens[$item["id"]] = $item["parent_id"]; // Заполняем массив
}
function printItem($item, $items, $childrens) {
/* Выводим пункт меню */
echo "

  • ";
    echo "".$item["title"]."";
    $ul = false; // Выводились ли дочерние элементы?
    while (true) {
    /* Бесконечный цикл, в котором мы ищем все дочерние элементы */
    $key = array_search($item["id"], $childrens); // Ищем дочерний элемент
    if (!$key) {
    /* Дочерних элементов не найдено */
    if ($ul) echo ""; // Если выводились дочерние элементы, то закрываем список
    break; // Выходим из цикла
    }
    unset($childrens[$key]); // Удаляем найденный элемент (чтобы он не выводился ещё раз)
    if (!$ul) {
    echo "
      "; // Начинаем внутренний список, если дочерних элементов ещё не было
      $ul = true; // Устанавливаем флаг
      }
      echo printItem($items[$key], $items, $childrens); // Рекурсивно выводим все дочерние элементы
      }
      echo "";
      }
      ?>

      Этот код полностью рабочий, однако, Вы должны понимать, что так никто не пишет (в частности, вывод через echo HTML-тегов ). И Ваша задача взять алгоритм из этого кода, но не сам код. А дальше этот алгоритм подключить к своему движку. Я постарался тщательно прокомментировать код вывода многоуровневого меню на PHP и MySQL , но, безусловно, он не самый прозрачный и требует уже неплохих начальных знаний. Если Вы ещё плохо знаете PHP и MySQL , то сначала настоятельно рекомендую пройти этот

      template

      Имя шаблона, по которому следует выводить результаты поиска по сайту. В XSLT-шаблонизаторе игнорируется.

      Search_string

      Поисковая фраза. Если значение не задано, оно берётся из переданного через форму поиска запроса.

      Search_types

      Список идентификаторов иерархических типов для поиска (указываются через пробел). Если значение не указано, поиск оcуществляется по всем типам.

      Search_branches

      Список разделов в которых будет осуществляться поиск (указываются через пробел). Если значение не указано, поиск осуществляется по всем разделам. Параметр может принимать как id страниц, так и их URL.

      Per_page

      Количество результатов на странице. Если параметр не задан, будет взято значение, указанное в настройках модуля "Поиск".

      %total%

      Выводит общее количество новостей в ленте. Можно использовать для макроса %system numpages()% .

      %per_page%

      Выводит значение параметра per_page. Можно использовать для макроса %system numpages()% .

      %list-class-first%

      в случае, если элемент первый, выводит "first"

      %list-class-last%

      в случае, если элемент последний, выводит "last"

      %list-class-odd%

      в случае, если элемент четный, выводит "odd"

      %list-class-even%

      в случае, если элемент нечетный, выводит "even"

      %list-position%

      вставляет порядковый номер в списке

      search_empty_result

      Используется в том случае, если в результате поиска не найдено ни одной страницы. В таком случае этот блок выводится вместо блока search_block .

      %last_search_string%

      Выводит предыдущий поисковый запрос, если такой был.

      search_block_line_quant

      Выводит некий разделитель, который вставляется между результатами поиска.

      Примеры использования

      Найдено %total% страниц.

      %lines%

      %system numpages(%total%, %per_page%)%

      END; $FORMS ["search_block_line" ] = << %num%. %name% %context%

      END; $FORMS ["search_empty_result" ] = <<Извините. По данному запросу ничего не найдено.

      END; ?>

      SSY stands for "Siddha Samadhi Yoga" (often expanded as ‘Science of Silence Yoga’) where Siddha means ‘something (i.e., knowledge) that is proven or accomplished’, Samadhi means ‘a state in which the intellect is equanimous’ and Yoga means ‘union with one’s higher self’.

      SSY is the fundamental knowledge of life. Our ancient rishis had formulated a unique mode of training called Brahmopadesam, which is an instruction on the science of non-doing and experiencing stillness within and abundance without. It brings about a sea change in one’s outlook towards life and effects remarkable maturity in the individual. SSY is nothing but the present-day version of this ancient science of Brahmopadesam.

      SSY as a training programme is offered by Life Yessence Academy (LiYA) , and it is the flagship programme of the institution. Being the flagship programme, it has become synonymous with the name of the organisation. Trainings of this great knowledge are taught in many places in the world by teachers of LiYA. The Indian chapter of LiYA is called Rishi Samskruti Vidya Kendra (RSVK ).

      “I am the Body” is the first notion that kills the awakening. SSY is the process
      To enter into Samadhi, the state of total detachment.
      "
      -Guruji

      Создаем кастомный тип записи (Custom Post Type) Articles с кастомными категориями (Custom Taxonomy) Articles Category .

      В моем случае все стандартные записи – это Товары, поэтому Статьи выведем через кастомные записи.

      В файле функций functions.php регистрируем кастомный тип записи Articles:

      Function wptp_create_post_type() { $labels = array("name" => __("Articles"), "singular_name" => __("Articles"), "add_new" => __("New Article"), "add_new_item" => __("Add New Article"), "edit_item" => __("Edit Article"), "new_item" => __("New Article"), "view_item" => __("View Article"), "search_items" => __("Search Articles"), "not_found" => __("No Articles Found"), "not_found_in_trash" => __("No Articles found in Trash"),); $args = array("labels" => $labels, "has_archive" => true, "public" => true, "hierarchical" => false, "menu_position" => 5, "supports" => array("title", "editor", "excerpt", "custom-fields", "thumbnail"),); register_post_type("articles", $args); } add_action("init", "wptp_create_post_type");

      Если вы хотите, чтобы в кастомных постах выводились стандартные категории, тогда привяжите их к таксономии Категорий:

      "taxonomies" => array("category"),

      Если для кастомных постов вы создаете еще и кастомные таксономии, то связывать их надо с созданными таксономиями, если брать пример ниже, то это будут articles_category

      "taxonomies" => array("articles_category"),

      Затем для кастомного типа записи Articles регистрируем таксономии ‘Article Category’, чтобы разные записи могли принадлежать разным категориям.

      Function wptp_register_taxonomy() { register_taxonomy("articles_category", "articles", array("labels" => array("name" => "Article Categories", "singular_name" => "Article Category", "search_items" => "Search Article Categories", "all_items" => "All Article Categories", "edit_item" => "Edit Article Categories", "update_item" => "Update Article Category", "add_new_item" => "Add New Article Category", "new_item_name" => "New Article Category Name", "menu_name" => "Article Category",), "hierarchical" => true, "sort" => true, "args" => array("orderby" => "term_order"), "show_admin_column" => true)); } add_action("init", "wptp_register_taxonomy");

      Для кастомной таксономии можно изменить слаг на более красивый, чтобы он не был articles_category , но нужно учесть, чтобы таких слдагов больше не было на других страницах или постах, иначе будут проблемы:

      "rewrite" => array("slug" => "blog"),

      При изменении слагов необходимо обновить настройки “Постоянных ссылок” в админке, иначе будете получать 404 ошибку вместо нужной страницы.

      Больше примеров можно найти и . Но привести весь этот код в порядок помогла , за что автору большая благодарность.

      За внешний вид кастомной записи отвечает файл single.php , но чтобы изменить вид кастомной записи можно создать файл single-{post_type}.php – в моем случае будет single-articles.php со своим содержимым.

      Теперь нужно вывести кастомные записи на странице. По умолчанию за отображение архива кастомных записей отвечает файл index.php . Но можно создать файл, который будет отвечать за вывод кастомных записей в своей таксономии.

      Вариант 1 – самый правильный. Выводим записи в таксономии так же как и в обычной категории.

      Для этого создаем файл taxonomy-{taxonomy}.php – в моем случае будет taxonomy-articles_category.php и в нем выводим обычный цикл, как и для стандартных записей в категории:

      В файле tax-item.php выводим данные, которые нам нужно получить из каждой записи, например, заголовок, ссылку на запись, миниатюру и excerpt.

      В файле pagination.php выводим пагинацию вот такого формата .

      Цикл не изменяем, пагинация отлично работает. Это самый оптимальный вариант для отображения Кастомных Таксономий.

      Вариант 2 – если нет кастомных таксономий, то можно просто получить все кастомные записи в виде Архива

      Для этого в шаблоне создаем файл archive-{post_type}.php – в моем случае будет archive-articles.php , в котором точно так же как и в таксономии выводим обычный цикл, только вместо заголовка Таксономии выводим имя кастомного типа записи :

      При этом варианте, если не создана страница архива для кастомной записи, тогда получить список всех кастомных записей можно по прямой ссылке BLOG_URL?post_type={post_type} или в моем случае http://site.com/articles/ .

      Вариант 3. Просто выводим все кастомные записи Articles на странице с заданным шаблоном

      "articles", "posts_per_page" => -1); $loop = new WP_Query($args); while ($loop->have_posts()) : $loop->the_post(); get_template_part("include/tax-item"); endwhile; ?>

      get_template_part("include/tax-item"); – в файле tax-item.php я вывожу содержимое записи, которое нужно мне для отображения записей внутри цикла (заголовок, миниатюру, дату, цитату и т.д.)

      Этот вариант выводит все записи Articles на странице, не зависимо от таксономий (категорий).

      А если нам нужно вывести каждую категорию отдельно со своими новостями, тогда используем первый вариант, описанный выше.

      При этом, если вы используете плагин Yoast SEO и используете его хлебные крошки:

      Тогда при выборе в настройках плагина таксономии “Articles Category” в “Taxonomy to show in breadcrumbs for post types”, в хлебных крошках вы получите ссылку на категорию, к которой принадлежит Новость, при других вариантах вывода кастомных записей это не получалось сделать.

      Основные задачи:

      • реализовать поиск таким образом, чтобы после ввода поискового запроса в строку, ниже этой строки появились результаты поиска
      • запрос на получение результата должен происходить только после окончания ввода поискового запроса

      Окей, поехали!

      Примерная вёрстка самого блока с поисковой строкой и div-ником, куда будем добавлять результаты поиска:

      Т.к. поиск доступен в шапке сайта, добавим соответствующие скрипты поиска и стилизации результатов:

      //подрубаем поиск: $APPLICATION->AddHeadScript("/search/ajax_search.js"); $APPLICATION->AddHeadScript("/search/jquery.mCustomScrollbar.js"); $APPLICATION->SetAdditionalCSS(SITE_TEMPLATE_PATH . "/css/ajax_search.css"); $APPLICATION->SetAdditionalCSS(SITE_TEMPLATE_PATH . "/css/jquery.mCustomScrollbar.min.css");

      Теперь посмотрим, что лежит в нашем ajax_search.js:

      Function get_result (){ //очищаем результаты поиска $("#search_result").html(""); //пока не получили результаты поиска - отобразим прелоадер $("#search_result").append("

      "); $.ajax({ type: "POST", url: "/search/ajax_search.php", data: "q="+q, dataType: "json", success: function(json){ //очистим прелоадер $("#search_result").html(""); $("#search_result").append(""); //добавляем каждый элемент массива json внутрь div-ника с class="live-search" (вёрстку можете использовать свою) $.each(json, function(index, element) { $("#search_result").find(".live-search").append(""+element.TITLE+""+element.BODY_FORMATED+""); //console.log (element.BODY_FORMATED); }); //стилизуем скроллинг $(".live-search").mCustomScrollbar({ scrollInertia: 500 }); } }); } var timer = 0; var q = ""; $(document).ready(function() { $("#q").keyup(function() { q = this.value; clearTimeout(timer); timer = setTimeout(get_result, 1000); }); $("#reset_live_search").click(function() { $("#search_result").html(""); }); });

      keyup функция осуществляем вызов функции get_result(), которая собственно и заполняет div-ник с id=»search_result» по аяксу.

      mCustomScrollbar — это просто вызов стилизации (можете отключить).

      Данные от /search/ajax_search.php мы получаем в формате JSON.

      С JS составляющей всё понятно, теперь посмотрим, что происходит в ajax_search.php:

      Search(array("QUERY" => $q, "SITE_ID" => LANG, "MODULE_ID" => "iblock", "CHECK_DATES" => "Y", "PARAM2" => "8")); $result = array(); while ($res = $obSearch->GetNext()){ $id = $res["ITEM_ID"]; //если нашли раздел: if (strripos($id, "S")!==false){ $result_item["TITLE"] = $res["TITLE"]; $result_item["URL"] = $res["URL"]; $result_item["BODY_FORMATED"] = $res["TITLE_FORMATED"]; $result = $result_item; } //если S-ки нету, то else{ $result_item["TITLE"] = $res["TITLE"]; $result_item["URL"] = $res["URL"]; $result_item["BODY_FORMATED"] = $res["BODY_FORMATED"]; $result = $result_item; } } echo json_encode($result); } ?>

      В данном случае поиск осуществляется методом Search Битриксового класса CSearch. В PARAM2 пишем в каком инфоблоке ищем. Результаты поиска запихиваем в массив $result. Обратите внимание, что в $res[‘ITEM_ID’] может быть как элемент, так и раздел. В зависимости от того, что нашли, в $result_item[‘BODY_FORMATED’] пихаем либо название раздела, либо кусок текста из найдённого элемента инфоблока.