Создание Провайдера для Карты сайта
Система Карты сайта WordPress, как и многие другие части, позволяет довольно просто расширять функциональность и добавлять произвольные ссылки в существующую Карту сайта. Ниже рассмотрим как это делается.
Что кастомное автоматически добавляется в Карту сайта?
Если вы создаете дополнительные (кастомные) типы записей или таксономии, то эти сущности автоматически попадут в Карту сайта WordPress. Единственное что для этого нужно, это чтобы новый тип записи или таксономия были «публичные»: имели параметры public = true и publicly_queryable = true. Эти параметры указываются при регистрации типа записи или таксономии.
Создание своего провайдера для Карты сайта
Но если ваш плагин или тема, имеют какие-то свои сущности, которые нужно добавить в карту сайта, то для них нужно будет создать нового провайдера. Это пользовательский класс PHP, который расширяет абстрактный класс WP_Sitemaps_Provider.
Созданный Класс, нужно зарегистрировать (подключить) с помощью функции wp_register_sitemap_provider():
add_filter( 'init', function(){ $provider = new Awesome_Plugin_Sitemaps_Provider(); wp_register_sitemap_provider( 'awesome-plugin', $provider ); } );
Этот провайдер будет отвечать за отображение всех новых Карт сайта, их пагинацию вывод карт для отдельных элементов (ссылок).
Примеры создания Провайдеров
#1 Свой провайдер с двумя типами и кастомной таблицей
Допустим у нас в БД есть таблица, в которой хранятся медиа данные об audio и video сущностях. Каждая такая сущность имеет свою страницу на фронте. Нам нужно добавить все эти страницы в Карту сайта.
Создадим своего провайдера, назовем его megamedia
. Для этого создадим в теме файл class-Megamedia_Sitemaps_Provider.php
со следующим кодом:
class Media_Sitemaps_Provider extends WP_Sitemaps_Provider { // make visibility not protected public $name; /** * Constructor. Sets name, object_type properties. * * $name Provider name. Uses in URL (must be unique). * $object_type The object name that the provider works with. * Passes into the hooks (must be unique). */ public function __construct() { $this->name = 'megamedia'; $this->object_type = 'megamedia'; } /** * Returns the list of supported object subtypes exposed by the provider. * * @return array List of object subtypes objects keyed by their name. */ public function get_object_subtypes() { return array( 'audio' => new stdClass(), 'video' => new stdClass() ); } /** * Gets a URL list for a sitemap. * * @param int $page_num Page of results. * @param string $subtype Optional. Object subtype name. Default empty. * * @return array Array of URLs for a sitemap. */ public function get_url_list( $page_num, $subtype = '' ) { $result = $this->db_query( [ 'subtype' => $subtype, 'paged' => $page_num, ] ); $url_list = array(); foreach ( $result as $megamedia ) { $sitemap_entry = [ 'loc' => home_url( "/megamedia/$subtype/$megamedia->id" ), // 'priority' => 0.5, // 'changefreq' => 'monthly', ]; $url_list[] = $sitemap_entry; } return $url_list; } /** * Gets the max number of pages available for the object type. * * @param string $subtype Optional. Object subtype. Default empty. * @return int Total number of pages. */ public function get_max_num_pages( $subtype = '' ) { $total = $this->db_query( [ 'subtype' => $subtype, 'count' => true, ] ); return (int) ceil( $total / wp_sitemaps_get_max_urls( $this->object_type ) ); } /** * Returns the SQL query result. * * @return array Array of query arguments. */ protected function db_query( $args ) { global $wpdb; $arg = (object) array_merge( [ 'paged' => 1, 'subtype' => 'audio', 'count' => false, ], $args ); $SELECT = $arg->count ? 'count(*)' : '*'; $WHERE = []; $WHERE[] = 'post_id = 0'; $WHERE[] = $wpdb->prepare( "media_type = %s", $arg->subtype ); $WHERE = implode( ' AND ', $WHERE ); $per_page = wp_sitemaps_get_max_urls( $this->object_type ); $offset = ( $arg->paged - 1 ) * $per_page; $LIMIT = sprintf( "LIMIT %d, %d", $offset,$per_page ); $sql = "SELECT $SELECT FROM $wpdb->wp_core_data WHERE $WHERE $LIMIT"; $result = $arg->count ? $wpdb->get_var( $sql ) : $wpdb->get_results( $sql ); return $result; } }
Теперь подключим (зарегистрируем) созданного провайдера в файле functions.php.
add_filter( 'init', 'wpkama_register_sitemap_providers' ); function wpkama_register_sitemap_providers(){ require_once __DIR__ .'/class-Megamedia_Sitemaps_Provider.php'; $provider = new Megamedia_Sitemaps_Provider(); wp_register_sitemap_provider( $provider->name, $provider ); }
Переходим в Карту сайта и видим:
Заметки:
ВАЖНО: первый параметр функции wp_register_sitemap_provider() должен быть такой же как свойство $name у провайдера! И состоять это имя может только из символов a-z
!
Свойства класса WP_Sitemaps_Provider:
- $this->name
Имя провайдера. Используется в URL карты сайта. Должно быть уникальным.
ВАЖНО! Разрешаются только символы
a-z
. Т.е. нельзя использовать тире, пробелы и строчные. Неправильно:similar_posts
,similar-posts
,Similar
. Правильноsimilarposts
.- $this->object_type
- Имя объекта с которым работает провайдер (post, term, user). Используется в хуках. Должно быть уникальным.
Методы класса Media_Sitemaps_Provider и WP_Sitemaps_Provider:
- get_object_subtypes()
- Должен вернуть список подтипов, например у постов это типы постов. Возвращает массив объектов, в ключах находятся имена подтипов.
- get_url_list( $page_num, $subtype = '' )
Должен вернуть список ссылок для каждой карты — список данных для XML тегов <url>. Выглядит этот список как массив массивов, каждый вложенный массив - это каждая ссылка. Например:
$url_list = [ [ 'loc'=> 'https://example.com/megamedia/audio/2610735' ], [ 'loc'=> 'https://example.com/megamedia/audio/9514241' ], ... ];
- get_max_num_pages( $subtype = '' )
- Должен вернуть число - общее кол-во элементов для переданного подтипа. Например для записей WP - это сколько всего записей указанного типа записи, например, сколько всего страниц (page).
- db_query( $args )
- Это произвольный свой метод класса, который создает запрос в БД и получает данные по переданным параметрам, в том числе тут учитывается подтип и пагинация.
Используемые Функции:
- wp_sitemaps_get_max_urls()
- Внешняя функция, которая возвращает макс. кол-во элементов в каждой карте сайта. По умолчанию 2000.
#2 Провайдер на основе постов
Допустим мы доработали URL постов и теперь если в конец ссылки поста дописать /similar_posts/
мы попадаем на страницу с похожими записями. Нам нужно добавить все такие ссылки в Карту сайта.
Назовем провайдера similarposts
(в названии нельзя указывать пробелы и тире!) и создадим класс провайдера, так:
class Similar_Posts_Sitemaps_Provider extends WP_Sitemaps_Provider { // make visibility not protected public $name; public function __construct() { $this->name = 'similarposts'; $this->object_type = 'similarposts'; } public function get_url_list( $page_num, $subtype = '' ) { $args = $this->wp_query_args(); $args['paged'] = $page_num; $query = new WP_Query( $args ); $url_list = array(); foreach ( $query->posts as $post ) { $sitemap_entry = [ 'loc' => user_trailingslashit( untrailingslashit( get_permalink( $post ) ) .'/similar_posts/' ), ]; $url_list[] = $sitemap_entry; } return $url_list; } public function get_max_num_pages( $subtype = '' ) { $args = $this->wp_query_args(); $args['fields'] = 'ids'; $args['no_found_rows'] = false; $query = new WP_Query( $args ); return $query->max_num_pages; } protected function wp_query_args(){ return array( 'orderby' => 'ID', 'order' => 'ASC', 'post_type' => 'post', 'posts_per_page' => wp_sitemaps_get_max_urls( $this->object_type ), 'post_status' => array( 'publish' ), 'no_found_rows' => true, 'update_post_term_cache' => false, 'update_post_meta_cache' => false, ); } }
Теперь зарегистрируем его:
add_filter( 'init', 'wpkama_register_sitemap_providers' ); function wpkama_register_sitemap_providers(){ require_once __DIR__ .'/class-Similar_Posts_Sitemaps_Provider.php'; $provider = new Similar_Posts_Sitemaps_Provider(); wp_register_sitemap_provider( $provider->name, $provider ); }
Готово! Идем в карту сайта:
#3 Примеры из ядра
Из коробки в WP есть три провайдера (поставщика) карт сайтов для разных типов. Их код можно взять за основу для создания своего провайдера.
posts
— WP_Sitemaps_Posts{}taxonomies
— WP_Sitemaps_Taxonomies{}users
— WP_Sitemaps_Users{}