WORDPRESS
#wordpress#json-ld#custom-post-type#schema-org#blogposting#wp_head#seo

WordPress: JSON-LD BlogPosting — класс для Custom Post Type

Генератор JSON-LD разметки типа BlogPosting для CPT через wp_head. Защита от дублей через did_action, сериализация через wp_json_encode. По официальной документации WordPress и schema.org/BlogPosting.

Как использовать

  1. Создайте файл includes/class-jsonld-cpt.php в теме или плагине.
  2. Замените массив target_post_types на ваши CPT (articles, news и т.д.).
  3. В functions.php добавьте: require_once get_stylesheet_directory() . '/includes/class-jsonld-cpt.php';

Генерация JSON-LD разметки BlogPosting для страниц Custom Post Type. Hook wp_head выводит разметку в <head>. Сериализация через wp_json_encode() предотвращает поломку JSON из-за кавычек в заголовке. did_action() защищает от дублей при использовании с SEO-плагинами.

Класс и подключение

Файл includes/class-jsonld-cpt.php:

<?php
/**
 * JSON-LD Generator for Custom Post Types
 * Place in: wp-content/themes/your-theme/includes/class-jsonld-cpt.php
 * Or: wp-content/plugins/your-plugin/includes/class-jsonld-cpt.php
 */

class JSONLD_CPT_Generator {

    private $target_post_types = ['articles', 'news', 'publications'];

    public function __construct() {
        add_action('wp_head', [$this, 'output_jsonld'], 10);
    }

    public function output_jsonld() {
        if (!is_singular($this->target_post_types)) {
            return;
        }

        global $post;
        if (!$post) {
            return;
        }

        if (did_action('jsonld_cpt_output')) {
            return;
        }

        $jsonld = $this->build_blogposting_schema($post);

        if ($jsonld) {
            echo "\n" . '<script type="application/ld+json">' . "\n";
            echo wp_json_encode($jsonld, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
            echo "\n" . '</script>' . "\n";
            do_action('jsonld_cpt_output');
        }
    }

    private function build_blogposting_schema($post) {
        $author_id = $post->post_author;
        $author_name = get_the_author_meta('display_name', $author_id);
        $author_url = get_author_posts_url($author_id);

        $publish_date = get_the_date('c', $post);
        $modified_date = get_the_modified_date('c', $post);

        $image_id = get_post_thumbnail_id($post->ID);
        $image_url = $image_id
            ? wp_get_attachment_image_url($image_id, 'full')
            : get_stylesheet_directory_uri() . '/assets/images/og-default.png';

        $categories = get_the_terms($post->ID, 'category');
        $section = $categories && !is_wp_error($categories)
            ? $categories[0]->name
            : 'General';

        $schema = [
            '@context' => 'https://schema.org',
            '@type' => 'BlogPosting',
            'mainEntityOfPage' => [
                '@type' => 'WebPage',
                '@id' => get_permalink($post->ID)
            ],
            'headline' => get_the_title($post->ID),
            'description' => get_the_excerpt($post->ID),
            'image' => [
                '@type' => 'ImageObject',
                'url' => $image_url,
                'width' => 1200,
                'height' => 630
            ],
            'datePublished' => $publish_date,
            'dateModified' => $modified_date,
            'author' => [
                '@type' => 'Person',
                'name' => $author_name,
                'url' => $author_url
            ],
            'publisher' => [
                '@type' => 'Organization',
                'name' => get_bloginfo('name'),
                'logo' => [
                    '@type' => 'ImageObject',
                    'url' => get_stylesheet_directory_uri() . '/assets/images/logo.png',
                    'width' => 600,
                    'height' => 60
                ]
            ],
            'articleSection' => $section,
            'wordCount' => str_word_count($post->post_content)
        ];

        $tags = get_the_terms($post->ID, 'post_tag');
        if ($tags && !is_wp_error($tags)) {
            $keywords = wp_list_pluck($tags, 'name');
            $schema['keywords'] = implode(', ', $keywords);
        }

        return $schema;
    }
}

new JSONLD_CPT_Generator();

В functions.php темы:

<?php
// wp-content/themes/your-theme/functions.php
require_once get_stylesheet_directory() . '/includes/class-jsonld-cpt.php';

Замечания

  • target_post_types — укажите slug вашего CPT. Для таксономий, привязанных к стандартному post, категории и теги подтянутся; для CPT с кастомными таксономиями при необходимости доработайте get_the_terms().
  • Проверка разметки: Google Rich Results Test (официальный инструмент Google Search).

Подробнее: WordPress: JSON-LD для CPT — дубли и ошибки.