improved structured data
This commit is contained in:
parent
1d1a5d937c
commit
d74a3408b3
|
@ -0,0 +1,164 @@
|
|||
<?php
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
/**
|
||||
* Structured data's handler and generator using JSON-LD format.
|
||||
*
|
||||
* @class WC_Data_Structurer
|
||||
* @version 2.7.0
|
||||
* @package WooCommerce/Classes
|
||||
* @category Class
|
||||
* @author Clement Cazaud
|
||||
*/
|
||||
class WC_Data_Structurer {
|
||||
/**
|
||||
* @var array Partially formatted structured data
|
||||
*/
|
||||
private $structured_data;
|
||||
|
||||
/**
|
||||
* Checks if the passed $json variable is an array and stores it into $this->structured_data...
|
||||
*
|
||||
* @param array $json Partially formatted JSON-LD
|
||||
* @return false If the param $json is not an array
|
||||
*/
|
||||
public function set_structured_data( $json ) {
|
||||
if ( ! is_array( $json ) ) {
|
||||
return false;
|
||||
}
|
||||
$this->structured_data[] = $json;
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats and returns the structured data...
|
||||
*
|
||||
* @return mixed bool|array If $this->structured_data is set, returns the fully formatted and encoded JSON-LD, otherwise returns false
|
||||
*/
|
||||
public function get_structured_data() {
|
||||
if ( ! $this->structured_data ) {
|
||||
return false;
|
||||
}
|
||||
$context['@context'] = 'http://schema.org/';
|
||||
|
||||
if ( count( $this->structured_data ) > 1 ) {
|
||||
if ( is_product() ) {
|
||||
foreach ( $this->structured_data as $value ) {
|
||||
if ( isset( $value['@type'] ) ) {
|
||||
if ( 'Product' === $value['@type'] ) {
|
||||
$product = $value;
|
||||
}
|
||||
elseif ( 'Review' === $value['@type'] ) {
|
||||
$reviews[] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
$structured_data = isset( $reviews ) ? $product + array( 'review' => $reviews ) : $product;
|
||||
}
|
||||
elseif ( is_product_category() ) {
|
||||
$structured_data = array( '@graph' => $this->structured_data );
|
||||
}
|
||||
}
|
||||
else {
|
||||
$structured_data = $this->structured_data[0];
|
||||
}
|
||||
return wp_json_encode( $context + $structured_data );
|
||||
}
|
||||
|
||||
/**
|
||||
* Contructor
|
||||
*/
|
||||
public function __construct() {
|
||||
add_action( 'woocommerce_before_shop_loop_item', array( $this, 'init_product_category_structured_data' ) );
|
||||
add_action( 'woocommerce_single_product_summary', array( $this, 'init_product_structured_data' ) );
|
||||
add_action( 'woocommerce_review_meta', array( $this, 'init_product_review_structured_data' ) );
|
||||
add_action( 'wp_footer', array( $this, 'enqueue_structured_data' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* If structured data is set, echoes the encoded structured data into the `wp_footer` action hook.
|
||||
*/
|
||||
public function enqueue_structured_data() {
|
||||
if ( $structured_data = $this->get_structured_data() ) {
|
||||
echo '<script type="application/ld+json">' . $structured_data . '</script>';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the product category structured data...
|
||||
* Hooked into the `woocommerce_before_shop_loop_item` action hook...
|
||||
*/
|
||||
public function init_product_category_structured_data() {
|
||||
if ( ! is_product_category() ) {
|
||||
return;
|
||||
}
|
||||
$this->init_product_structured_data();
|
||||
}
|
||||
/**
|
||||
* 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...
|
||||
*/
|
||||
public function init_product_structured_data() {
|
||||
global $product;
|
||||
|
||||
$json['@type'] = 'Product';
|
||||
$json['@id'] = 'product-' . get_the_ID();
|
||||
$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();
|
||||
$json['brand'] = array(
|
||||
'@type' => 'Thing',
|
||||
'name' => $product->get_attribute( __( 'brand', 'woocommerce' ) )
|
||||
);
|
||||
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()
|
||||
);
|
||||
}
|
||||
$json['offers'] = array(
|
||||
'@type' => 'Offer',
|
||||
'priceCurrency' => get_woocommerce_currency(),
|
||||
'price' => $product->get_price(),
|
||||
'itemCondition' => 'http://schema.org/NewCondition',
|
||||
'availability' => 'http://schema.org/' . $stock = ( $product->is_in_stock() ? 'InStock' : 'OutOfStock' ),
|
||||
'seller' => array(
|
||||
'@type' => 'Organization',
|
||||
'name' => get_bloginfo( 'name' )
|
||||
)
|
||||
);
|
||||
$this->set_structured_data( apply_filters( 'woocommerce_product_structured_data', $json ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* 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...
|
||||
*/
|
||||
public function init_product_review_structured_data() {
|
||||
global $comment;
|
||||
|
||||
$rating = intval( get_comment_meta( $comment->comment_ID, 'rating', true ) );
|
||||
|
||||
$json['@type'] = 'Review';
|
||||
$json['@id'] = 'li-comment-' . get_comment_ID();
|
||||
$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()
|
||||
);
|
||||
$this->set_structured_data( apply_filters( 'woocommerce_product_review_structured_data', $json ) );
|
||||
}
|
||||
}
|
|
@ -686,36 +686,6 @@ if ( ! function_exists( 'woocommerce_show_product_loop_sale_flash' ) ) {
|
|||
}
|
||||
}
|
||||
|
||||
if ( ! function_exists( 'woocommerce_get_product_schema' ) ) {
|
||||
|
||||
/**
|
||||
* Get a products Schema.
|
||||
* @return string
|
||||
*/
|
||||
function woocommerce_get_product_schema() {
|
||||
global $product;
|
||||
|
||||
$schema = "Product";
|
||||
|
||||
// Downloadable product schema handling
|
||||
if ( $product->is_downloadable() ) {
|
||||
switch ( $product->download_type ) {
|
||||
case 'application' :
|
||||
$schema = "SoftwareApplication";
|
||||
break;
|
||||
case 'music' :
|
||||
$schema = "MusicAlbum";
|
||||
break;
|
||||
default :
|
||||
$schema = "Product";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 'http://schema.org/' . $schema;
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! function_exists( 'woocommerce_get_product_thumbnail' ) ) {
|
||||
|
||||
/**
|
||||
|
@ -1218,7 +1188,7 @@ if ( ! function_exists( 'woocommerce_review_display_comment_text' ) ) {
|
|||
* Display the review content.
|
||||
*/
|
||||
function woocommerce_review_display_comment_text() {
|
||||
echo '<div itemprop="description" class="description">';
|
||||
echo '<div class="description">';
|
||||
comment_text();
|
||||
echo '</div>';
|
||||
}
|
||||
|
|
|
@ -36,7 +36,7 @@ if ( ! defined( 'ABSPATH' ) ) {
|
|||
}
|
||||
?>
|
||||
|
||||
<div itemscope itemtype="<?php echo woocommerce_get_product_schema(); ?>" id="product-<?php the_ID(); ?>" <?php post_class(); ?>>
|
||||
<div id="product-<?php the_ID(); ?>" <?php post_class(); ?>>
|
||||
|
||||
<?php
|
||||
/**
|
||||
|
@ -78,8 +78,6 @@ if ( ! defined( 'ABSPATH' ) ) {
|
|||
do_action( 'woocommerce_after_single_product_summary' );
|
||||
?>
|
||||
|
||||
<meta itemprop="url" content="<?php the_permalink(); ?>" />
|
||||
|
||||
</div><!-- #product-<?php the_ID(); ?> -->
|
||||
|
||||
<?php do_action( 'woocommerce_after_single_product' ); ?>
|
||||
|
|
|
@ -32,7 +32,7 @@ $tag_count = sizeof( get_the_terms( $post->ID, 'product_tag' ) );
|
|||
|
||||
<?php if ( wc_product_sku_enabled() && ( $product->get_sku() || $product->is_type( 'variable' ) ) ) : ?>
|
||||
|
||||
<span class="sku_wrapper"><?php _e( 'SKU:', 'woocommerce' ); ?> <span class="sku" itemprop="sku"><?php echo ( $sku = $product->get_sku() ) ? $sku : __( 'N/A', 'woocommerce' ); ?></span></span>
|
||||
<span class="sku_wrapper"><?php _e( 'SKU:', 'woocommerce' ); ?> <span class="sku"><?php echo ( $sku = $product->get_sku() ) ? $sku : __( 'N/A', 'woocommerce' ); ?></span></span>
|
||||
|
||||
<?php endif; ?>
|
||||
|
||||
|
|
|
@ -23,12 +23,8 @@ if ( ! defined( 'ABSPATH' ) ) {
|
|||
global $product;
|
||||
|
||||
?>
|
||||
<div itemprop="offers" itemscope itemtype="http://schema.org/Offer">
|
||||
<div>
|
||||
|
||||
<p class="price"><?php echo $product->get_price_html(); ?></p>
|
||||
|
||||
<meta itemprop="price" content="<?php echo esc_attr( $product->get_display_price() ); ?>" />
|
||||
<meta itemprop="priceCurrency" content="<?php echo esc_attr( get_woocommerce_currency() ); ?>" />
|
||||
<link itemprop="availability" href="http://schema.org/<?php echo $product->is_in_stock() ? 'InStock' : 'OutOfStock'; ?>" />
|
||||
|
||||
</div>
|
||||
|
|
|
@ -32,7 +32,7 @@ global $post, $product;
|
|||
'title' => $props['title'],
|
||||
'alt' => $props['alt'],
|
||||
) );
|
||||
echo apply_filters( 'woocommerce_single_product_image_html', sprintf( '<a href="%s" itemprop="image" class="woocommerce-main-image zoom" title="%s" data-rel="prettyPhoto' . $gallery . '">%s</a>', $props['url'], $props['caption'], $image ), $post->ID );
|
||||
echo apply_filters( 'woocommerce_single_product_image_html', sprintf( '<a href="%s" class="woocommerce-main-image zoom" title="%s" data-rel="prettyPhoto' . $gallery . '">%s</a>', $props['url'], $props['caption'], $image ), $post->ID );
|
||||
} else {
|
||||
echo apply_filters( 'woocommerce_single_product_image_html', sprintf( '<img src="%s" alt="%s" />', wc_placeholder_img_src(), __( 'Placeholder', 'woocommerce' ) ), $post->ID );
|
||||
}
|
||||
|
|
|
@ -32,14 +32,14 @@ $average = $product->get_average_rating();
|
|||
|
||||
if ( $rating_count > 0 ) : ?>
|
||||
|
||||
<div class="woocommerce-product-rating" itemprop="aggregateRating" itemscope itemtype="http://schema.org/AggregateRating">
|
||||
<div class="woocommerce-product-rating">
|
||||
<div class="star-rating" title="<?php printf( __( 'Rated %s out of 5', 'woocommerce' ), $average ); ?>">
|
||||
<span style="width:<?php echo ( ( $average / 5 ) * 100 ); ?>%">
|
||||
<strong itemprop="ratingValue" class="rating"><?php echo esc_html( $average ); ?></strong> <?php printf( __( 'out of %s5%s', 'woocommerce' ), '<span itemprop="bestRating">', '</span>' ); ?>
|
||||
<?php printf( _n( 'based on %s customer rating', 'based on %s customer ratings', $rating_count, 'woocommerce' ), '<span itemprop="ratingCount" class="rating">' . $rating_count . '</span>' ); ?>
|
||||
<strong class="rating"><?php echo esc_html( $average ); ?></strong> <?php printf( __( 'out of %s5%s', 'woocommerce' ), '<span>', '</span>' ); ?>
|
||||
<?php printf( _n( 'based on %s customer rating', 'based on %s customer ratings', $rating_count, 'woocommerce' ), '<span class="rating">' . $rating_count . '</span>' ); ?>
|
||||
</span>
|
||||
</div>
|
||||
<?php if ( comments_open() ) : ?><a href="#reviews" class="woocommerce-review-link" rel="nofollow">(<?php printf( _n( '%s customer review', '%s customer reviews', $review_count, 'woocommerce' ), '<span itemprop="reviewCount" class="count">' . $review_count . '</span>' ); ?>)</a><?php endif ?>
|
||||
<?php if ( comments_open() ) : ?><a href="#reviews" class="woocommerce-review-link" rel="nofollow">(<?php printf( _n( '%s customer review', '%s customer reviews', $review_count, 'woocommerce' ), '<span class="count">' . $review_count . '</span>' ); ?>)</a><?php endif ?>
|
||||
</div>
|
||||
|
||||
<?php endif; ?>
|
||||
|
|
|
@ -30,13 +30,13 @@ if ( '0' === $comment->comment_approved ) { ?>
|
|||
<?php } else { ?>
|
||||
|
||||
<p class="meta">
|
||||
<strong itemprop="author"><?php comment_author(); ?></strong> <?php
|
||||
<strong><?php comment_author(); ?></strong> <?php
|
||||
|
||||
if ( 'yes' === get_option( 'woocommerce_review_rating_verification_label' ) && $verified ) {
|
||||
echo '<em class="verified">(' . esc_attr__( 'verified owner', 'woocommerce' ) . ')</em> ';
|
||||
}
|
||||
|
||||
?>– <time itemprop="datePublished" datetime="<?php echo get_comment_date( 'c' ); ?>"><?php echo get_comment_date( wc_date_format() ); ?></time>:
|
||||
?>– <time datetime="<?php echo get_comment_date( 'c' ); ?>"><?php echo get_comment_date( wc_date_format() ); ?></time>:
|
||||
</p>
|
||||
|
||||
<?php }
|
||||
|
|
|
@ -25,8 +25,8 @@ $rating = intval( get_comment_meta( $comment->comment_ID, 'rating', true ) );
|
|||
|
||||
if ( $rating && get_option( 'woocommerce_enable_review_rating' ) === 'yes' ) { ?>
|
||||
|
||||
<div itemprop="reviewRating" itemscope itemtype="http://schema.org/Rating" class="star-rating" title="<?php echo sprintf( esc_attr__( 'Rated %d out of 5', 'woocommerce' ), esc_attr( $rating ) ) ?>">
|
||||
<span style="width:<?php echo ( esc_attr( $rating ) / 5 ) * 100; ?>%"><strong itemprop="ratingValue"><?php echo esc_attr( $rating ); ?></strong> <?php esc_attr_e( 'out of 5', 'woocommerce' ); ?></span>
|
||||
<div class="star-rating" title="<?php echo sprintf( esc_attr__( 'Rated %d out of 5', 'woocommerce' ), esc_attr( $rating ) ) ?>">
|
||||
<span style="width:<?php echo ( esc_attr( $rating ) / 5 ) * 100; ?>%"><strong><?php echo esc_attr( $rating ); ?></strong> <?php esc_attr_e( 'out of 5', 'woocommerce' ); ?></span>
|
||||
</div>
|
||||
|
||||
<?php }
|
||||
|
|
|
@ -22,7 +22,7 @@ if ( ! defined( 'ABSPATH' ) ) {
|
|||
exit; // Exit if accessed directly
|
||||
}
|
||||
?>
|
||||
<li itemprop="review" itemscope itemtype="http://schema.org/Review" <?php comment_class(); ?> id="li-comment-<?php comment_ID() ?>">
|
||||
<li <?php comment_class(); ?> id="li-comment-<?php comment_ID() ?>">
|
||||
|
||||
<div id="comment-<?php comment_ID(); ?>" class="comment_container">
|
||||
|
||||
|
|
|
@ -27,6 +27,6 @@ if ( ! $post->post_excerpt ) {
|
|||
}
|
||||
|
||||
?>
|
||||
<div itemprop="description">
|
||||
<div>
|
||||
<?php echo apply_filters( 'woocommerce_short_description', $post->post_excerpt ) ?>
|
||||
</div>
|
||||
|
|
|
@ -20,4 +20,4 @@ if ( ! defined( 'ABSPATH' ) ) {
|
|||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
||||
the_title( '<h1 itemprop="name" class="product_title entry-title">', '</h1>' );
|
||||
the_title( '<h1 class="product_title entry-title">', '</h1>' );
|
||||
|
|
|
@ -295,6 +295,7 @@ final class WooCommerce {
|
|||
include_once( 'includes/class-wc-customer.php' ); // Customer class
|
||||
include_once( 'includes/class-wc-shortcodes.php' ); // Shortcodes class
|
||||
include_once( 'includes/class-wc-embed.php' ); // Embeds
|
||||
include_once( 'includes/class-wc-data-structurer.php' ); // Data Structurer class
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -328,8 +329,9 @@ final class WooCommerce {
|
|||
|
||||
// Classes/actions loaded for the frontend and for ajax requests.
|
||||
if ( $this->is_request( 'frontend' ) ) {
|
||||
$this->cart = new WC_Cart(); // Cart class, stores the cart contents
|
||||
$this->customer = new WC_Customer(); // Customer class, handles data such as customer location
|
||||
$this->cart = new WC_Cart(); // Cart class, stores the cart contents
|
||||
$this->customer = new WC_Customer(); // Customer class, handles data such as customer location
|
||||
$this->data_structurer = new WC_Data_Structurer(); // Microdata class, generates and encodes a JSON-LD
|
||||
}
|
||||
|
||||
$this->load_webhooks();
|
||||
|
|
Loading…
Reference in New Issue