woocommerce/includes/class-wc-structured-data.php

203 lines
6.1 KiB
PHP
Raw Normal View History

2016-07-17 02:42:46 +00:00
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
/**
* Structured data's handler and generator using JSON-LD format.
*
2016-07-19 19:36:52 +00:00
* @class WC_Structured_Data
2016-07-17 02:42:46 +00:00
* @version 2.7.0
* @package WooCommerce/Classes
* @category Class
* @author Clement Cazaud
*/
2016-07-19 19:36:52 +00:00
class WC_Structured_Data {
2016-07-18 21:31:29 +00:00
2016-07-17 02:42:46 +00:00
/**
* @var array Partially formatted structured data
*/
2016-07-19 19:36:52 +00:00
private $data;
2016-07-18 21:31:29 +00:00
2016-07-17 02:42:46 +00:00
/**
2016-07-19 19:36:52 +00:00
* Checks if the passed $json variable is an array and stores it into $this->data...
2016-07-17 02:42:46 +00:00
*
* @param array $json Partially formatted JSON-LD
* @return false If the param $json is not an array
*/
2016-07-19 19:36:52 +00:00
private function set_data( $json ) {
2016-07-17 02:42:46 +00:00
if ( ! is_array( $json ) ) {
return false;
}
2016-07-20 02:33:07 +00:00
2016-07-19 19:36:52 +00:00
$this->data[] = $json;
2016-07-17 02:42:46 +00:00
}
/**
* Formats and returns the structured data...
*
2016-07-19 19:36:52 +00:00
* @return array If structured data is set, returns the fully formatted JSON-LD, otherwise returns empty array
2016-07-17 02:42:46 +00:00
*/
2016-07-19 19:36:52 +00:00
private function get_data() {
if ( ! $this->data ) {
return array();
2016-07-17 02:42:46 +00:00
}
2016-07-20 02:33:07 +00:00
2016-07-18 21:31:29 +00:00
$product_count = 0;
2016-07-19 19:36:52 +00:00
foreach ( $this->data as $value ) {
2016-07-18 21:31:29 +00:00
$type = isset( $value['@type'] ) ? $value['@type'] : false;
if ( 'Product' === $type || 'SoftwareApplication' === $type || 'MusicAlbum' === $type ) {
$products[] = $value;
$product_count ++;
2016-07-20 02:33:07 +00:00
} elseif ( 'Review' === $type ) {
2016-07-18 21:31:29 +00:00
$reviews[] = $value;
2016-07-17 02:42:46 +00:00
}
}
2016-07-20 02:33:07 +00:00
2016-07-18 21:31:29 +00:00
if ( $product_count === 1 ) {
$structured_data = isset( $reviews ) ? $products[0] + array( 'review' => $reviews ) : $products[0];
2016-07-20 02:33:07 +00:00
} elseif ( $product_count > 1 ) {
2016-07-18 21:31:29 +00:00
$structured_data = array( '@graph' => $products );
}
2016-07-20 02:33:07 +00:00
2016-07-18 21:31:29 +00:00
if ( ! isset( $structured_data ) ) {
2016-07-19 19:36:52 +00:00
return array();
2016-07-17 02:42:46 +00:00
}
2016-07-20 02:33:07 +00:00
2016-07-18 21:31:29 +00:00
$context['@context'] = 'http://schema.org/';
2016-07-19 19:36:52 +00:00
return $context + $structured_data;
2016-07-17 02:42:46 +00:00
}
/**
* Contructor
*/
public function __construct() {
2016-07-19 19:36:52 +00:00
add_action( 'woocommerce_before_shop_loop_item', array( $this, 'generate_product_category_data' ) );
add_action( 'woocommerce_single_product_summary', array( $this, 'generate_product_data' ) );
add_action( 'woocommerce_review_meta', array( $this, 'generate_product_review_data' ) );
add_action( 'wp_footer', array( $this, 'enqueue_data' ) );
2016-07-17 02:42:46 +00:00
}
/**
2016-07-19 19:36:52 +00:00
* Sanitizes, encodes and echoes the structured data into `wp_footer` action hook.
2016-07-17 02:42:46 +00:00
*/
2016-07-19 19:36:52 +00:00
public function enqueue_data() {
if ( $structured_data = $this->get_data() ) {
2016-07-20 02:33:07 +00:00
array_walk_recursive( $structured_data, array( $this, 'sanitize_data' ) );
2016-07-19 19:36:52 +00:00
echo '<script type="application/ld+json">' . wp_json_encode( $structured_data ) . '</script>';
2016-07-17 02:42:46 +00:00
}
}
2016-07-20 02:33:07 +00:00
/**
* Callback function for sanitizing the structured data.
* Can't use anonymous function due to PHP v5.2 incompatibility...
*
* @param ref
*/
private function sanitize_data( &$value ) {
$value = sanitize_text_field( $value );
}
2016-07-17 02:42:46 +00:00
/**
* Generates the product category structured data...
* Hooked into the `woocommerce_before_shop_loop_item` action hook...
*/
2016-07-19 19:36:52 +00:00
public function generate_product_category_data() {
2016-07-17 02:42:46 +00:00
if ( ! is_product_category() ) {
return;
}
2016-07-20 02:33:07 +00:00
2016-07-19 19:36:52 +00:00
$this->generate_product_data();
2016-07-17 02:42:46 +00:00
}
2016-07-18 21:31:29 +00:00
2016-07-17 02:42:46 +00:00
/**
* Generates the product structured data...
* Hooked into the `woocommerce_single_product_summary` action hook...
* Applies the `woocommerce_product_structured_data` filter hook for clean structured data customization...
*/
2016-07-19 19:36:52 +00:00
public function generate_product_data() {
2016-07-17 02:42:46 +00:00
global $product;
2016-07-18 21:31:29 +00:00
if ( $product->is_downloadable() ) {
switch ( $product->download_type ) {
case 'application' :
$type = "SoftwareApplication";
break;
case 'music' :
$type = "MusicAlbum";
break;
default :
$type = "Product";
break;
}
} else {
$type = "Product";
}
2016-07-20 02:33:07 +00:00
2016-07-18 21:31:29 +00:00
$json['@type'] = $type;
$json['@id'] = get_the_permalink();
2016-07-17 02:42:46 +00:00
$json['name'] = get_the_title();
$json['image'] = wp_get_attachment_url( $product->get_image_id() );
$json['description'] = get_the_excerpt();
$json['url'] = get_the_permalink();
$json['sku'] = $product->get_sku();
2016-07-18 21:31:29 +00:00
if ( $brand = $product->get_attribute( __( 'brand', 'woocommerce' ) ) ) {
$json['brand'] = array(
'@type' => 'Thing',
'name' => $brand
);
}
2016-07-20 02:33:07 +00:00
2016-07-17 02:42:46 +00:00
if ( $product->get_rating_count() ) {
$json['aggregateRating'] = array(
'@type' => 'AggregateRating',
'ratingValue' => $product->get_average_rating(),
'ratingCount' => $product->get_rating_count(),
'reviewCount' => $product->get_review_count()
);
}
2016-07-20 02:33:07 +00:00
2016-07-17 02:42:46 +00:00
$json['offers'] = array(
'@type' => 'Offer',
'priceCurrency' => get_woocommerce_currency(),
'price' => $product->get_price(),
2016-07-18 21:31:29 +00:00
'availability' => 'http://schema.org/' . $stock = ( $product->is_in_stock() ? 'InStock' : 'OutOfStock' )
2016-07-17 02:42:46 +00:00
);
2016-07-20 02:33:07 +00:00
$this->set_data( apply_filters( 'woocommerce_product_structured_data', $json, $product ) );
2016-07-17 02:42:46 +00:00
}
/**
* Generates the product review structured data...
* Hooked into the `woocommerce_review_meta` action hook...
* Applies the `woocommerce_product_review_structured_data` filter hook for clean structured data customization...
*/
2016-07-19 19:36:52 +00:00
public function generate_product_review_data() {
2016-07-17 02:42:46 +00:00
global $comment;
$rating = intval( get_comment_meta( $comment->comment_ID, 'rating', true ) );
$json['@type'] = 'Review';
2016-07-18 21:31:29 +00:00
$json['@id'] = '#li-comment-' . get_comment_ID();
2016-07-17 02:42:46 +00:00
$json['datePublished'] = get_comment_date( 'c' );
$json['description'] = get_comment_text();
$json['reviewRating'] = array(
'@type' => 'rating',
'ratingValue' => $rating
);
$json['author'] = array(
'@type' => 'Person',
'name' => get_comment_author()
);
2016-07-20 02:33:07 +00:00
$this->set_data( apply_filters( 'woocommerce_product_review_structured_data', $json, $comment ) );
2016-07-17 02:42:46 +00:00
}
}