*/ class Shapla_Structured_Data { /** * @var array */ private $structured_data = array(); /** * @var array */ private $breadcrumb_data = array(); /** * The instance of the class * * @var self */ private static $instance; /** * Only one instance of the class can be loaded * * @return self */ public static function init() { if ( is_null( self::$instance ) ) { self::$instance = new self(); if ( false === shapla_get_option( 'show_structured_data', true ) ) { return self::$instance; } add_action( 'shapla_loop_post', array( self::$instance, 'init_structured_data' ), 40 ); add_action( 'shapla_single_post', array( self::$instance, 'init_structured_data' ), 40 ); add_action( 'shapla_page', array( self::$instance, 'init_structured_data' ), 40 ); add_action( 'shapla_breadcrumb', array( self::$instance, 'generate_breadcrumb_data' ), 10 ); add_action( 'wp_footer', array( self::$instance, 'get_structured_data' ), 10 ); add_action( 'wp_footer', array( self::$instance, 'get_breadcrumb_structured_data' ), 10 ); } return self::$instance; } /** * Generates structured data. * * Hooked into the following action hooks: * * - `shapla_loop_post` * - `shapla_single_post` * - `shapla_page` * * Applies `shapla_structured_data` filter hook for structured data customization :) */ public function init_structured_data() { // Post's structured data. if ( is_home() || is_category() || is_date() || is_search() || is_single() && ( shapla_is_woocommerce_activated() && ! is_woocommerce() ) ) { $image = wp_get_attachment_image_src( get_post_thumbnail_id( get_the_ID() ), 'normal' ); $logo = wp_get_attachment_image_src( shapla_get_option( 'custom_logo' ), 'full' ); $json['@type'] = 'BlogPosting'; $json['mainEntityOfPage'] = array( '@type' => 'webpage', '@id' => get_the_permalink(), ); if ( $logo ) { $json['publisher'] = array( '@type' => 'organization', 'name' => get_bloginfo( 'name' ), 'logo' => array( '@type' => 'ImageObject', 'url' => $logo[0], 'width' => $logo[1], 'height' => $logo[2], ), ); } $json['author'] = array( '@type' => 'person', 'name' => get_the_author(), ); if ( $image ) { $json['image'] = array( '@type' => 'ImageObject', 'url' => $image[0], 'width' => $image[1], 'height' => $image[2], ); } $json['datePublished'] = get_post_time( 'c' ); $json['dateModified'] = get_the_modified_date( 'c' ); $json['name'] = get_the_title(); $json['headline'] = $json['name']; $json['description'] = get_the_excerpt(); // Page's structured data. } elseif ( is_page() ) { $json['@type'] = 'WebPage'; $json['url'] = get_the_permalink(); $json['name'] = get_the_title(); $json['description'] = get_the_excerpt(); } if ( isset( $json ) ) { $this->set_structured_data( apply_filters( 'shapla_structured_data', $json ) ); } } /** * Generates BreadcrumbList structured data. * * Hooked into `shapla_breadcrumb` action hook. * * @param \Shapla\Helpers\Breadcrumb $breadcrumbs */ public function generate_breadcrumb_data( $breadcrumbs ) { $crumbs = $breadcrumbs->get_breadcrumb(); if ( empty( $crumbs ) || ! is_array( $crumbs ) ) { return; } $markup = array(); $markup['@type'] = 'BreadcrumbList'; $markup['itemListElement'] = array(); foreach ( $crumbs as $key => $crumb ) { $markup['itemListElement'][ $key ] = array( '@type' => 'ListItem', 'position' => $key + 1, 'item' => array( 'name' => $crumb[0], ), ); if ( ! empty( $crumb[1] ) && sizeof( $crumbs ) !== $key + 1 ) { $markup['itemListElement'][ $key ]['item'] += array( '@id' => $crumb[1] ); } } $this->set_breadcrumb_structured_data( apply_filters( 'shapla_structured_data_breadcrumb', $markup, $breadcrumbs ) ); } /** * Sets `$this->structured_data`. * * @param array $json */ public function set_structured_data( $json ) { if ( ! is_array( $json ) ) { return; } $this->structured_data[] = $json; } /** * Outputs structured data. * * Hooked into `wp_footer` action hook. */ public function get_structured_data() { if ( ! $this->structured_data ) { return; } $structured_data['@context'] = 'https://schema.org/'; if ( count( $this->structured_data ) > 1 ) { $structured_data['@graph'] = $this->structured_data; } else { $structured_data = $structured_data + $this->structured_data[0]; } echo '' . PHP_EOL; } /** * Sanitizes structured data. * * @param array $data * * @return array */ public function sanitize_structured_data( $data ) { $sanitized = array(); foreach ( $data as $key => $value ) { if ( is_array( $value ) ) { $sanitized_value = $this->sanitize_structured_data( $value ); } else { $sanitized_value = sanitize_text_field( $value ); } $sanitized[ sanitize_text_field( $key ) ] = $sanitized_value; } return $sanitized; } /** * Sets `$this->breadcrumb_data`. * * @param array $data */ private function set_breadcrumb_structured_data( $data ) { if ( ! is_array( $data ) ) { return; } $this->breadcrumb_data = $data; } /** * Outputs breadcrumb structured data. * * Hooked into `wp_footer` action hook. */ public function get_breadcrumb_structured_data() { if ( ! $this->breadcrumb_data ) { return; } $structured_data['@context'] = 'https://schema.org/'; $structured_data = $structured_data + $this->breadcrumb_data; echo '' . PHP_EOL; } } } Shapla_Structured_Data::init();