article($post); } $pairs = AEO_Bob_Lite_Text::get_instance()->faq_pairs((string) $post->post_content); if ($pairs) { $questions = array(); foreach ($pairs as $pair) { $questions[] = array( '@type' => 'Question', 'name' => $pair[0], 'acceptedAnswer' => array('@type' => 'Answer', 'text' => $pair[1]), ); } $graph[] = array('@type' => 'FAQPage', 'mainEntity' => $questions); } return array('graph' => $graph, 'article_by' => $by, 'questions' => count($pairs)); } private function article($post) { $description = ''; foreach (array('_aeo_bob_meta_description', '_yoast_wpseo_metadesc', '_aioseo_description', '_rank_math_description') as $key) { $value = get_post_meta($post->ID, $key, true); if (!empty($value) && is_string($value)) { $description = $value; break; } } if ('' === $description) { $description = wp_trim_words(wp_strip_all_tags(strip_shortcodes((string) $post->post_content)), 25); } $article = array( '@type' => 'Article', 'headline' => wp_strip_all_tags((string) $post->post_title), 'description' => $description, 'author' => array('@type' => 'Person', 'name' => get_the_author_meta('display_name', $post->post_author)), 'publisher' => array('@type' => 'Organization', 'name' => get_bloginfo('name')), 'datePublished' => get_the_date('c', $post->ID), 'dateModified' => get_the_modified_date('c', $post->ID), 'mainEntityOfPage' => array('@type' => 'WebPage', '@id' => get_permalink($post->ID)), ); $icon = get_site_icon_url(); if ($icon) { $article['publisher']['logo'] = array('@type' => 'ImageObject', 'url' => $icon); } if (has_post_thumbnail($post->ID)) { $image = wp_get_attachment_image_url(get_post_thumbnail_id($post->ID), 'full'); if ($image) { $article['image'] = array('@type' => 'ImageObject', 'url' => $image); } } return $article; } /** * Build, store and describe this post's schema. * * @return string one-line result for the box, '' when the post does not exist */ public function generate($post_id) { $post = get_post($post_id); if (!$post) { return ''; } $b = $this->build($post); $stored = array('@context' => 'https://schema.org', '@graph' => $b['graph'], 'article_by' => $b['article_by']); update_post_meta($post->ID, self::META, wp_slash(wp_json_encode($stored))); $parts = array(); if ('' === $b['article_by']) { $parts[] = 'Article'; } if ($b['questions']) { /* translators: %d: number of FAQ questions in the schema */ $parts[] = sprintf(_n('FAQPage (%d question)', 'FAQPage (%d questions)', $b['questions'], 'aeo-bob-lite'), $b['questions']); } $line = $parts /* translators: %s: schema types, e.g. "Article + FAQPage (3 questions)" */ ? sprintf(__('Schema added: %s', 'aeo-bob-lite'), implode(' + ', $parts)) : __('Schema: no FAQ section found for FAQPage', 'aeo-bob-lite'); if ('' !== $b['article_by']) { /* translators: %s: SEO plugin name, e.g. "Yoast SEO" */ $line .= ' ยท ' . sprintf(__('Article schema comes from %s', 'aeo-bob-lite'), $b['article_by']); } return $line; } /** Keep stored schema in step with the post (only for posts that already have it). */ public function refresh_on_save($post_id, $post = null) { if (wp_is_post_revision($post_id) || (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE)) { return; } if ('' === (string) get_post_meta($post_id, self::META, true)) { return; } $this->generate($post_id); } /** The stored schema of a post, decoded, or null. */ public static function stored($post_id) { $data = json_decode((string) get_post_meta($post_id, self::META, true), true); return is_array($data) ? $data : null; } /** JSON-LD in the head of the post's own page. */ public function output() { if (!is_singular()) { return; } $data = self::stored(get_queried_object_id()); if (!$data || empty($data['@graph']) || !is_array($data['@graph'])) { return; } $json = wp_json_encode(array('@context' => 'https://schema.org', '@graph' => $data['@graph']), JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_HEX_TAG | JSON_HEX_AMP); if ($json) { echo "\n\n\n"; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- JSON encoded with JSON_HEX_TAG } } }