PluginProbe ʕ •ᴥ•ʔ
WooCommerce / 3.0.3
WooCommerce v3.0.3
10.8.1 10.8.0 10.8.0-rc.1 10.8.0-beta.2 10.8.0-beta.1 7.8.0-beta.1 7.8.0-beta.2 7.8.0-rc.1 7.8.0-rc.2 7.8.1 7.8.2 7.8.3 7.8.4 7.9.0 7.9.0-beta.1 7.9.0-beta.2 7.9.0-rc.2 7.9.0-rc.3 7.9.1 7.9.2 8.0.0 8.0.0-beta.1 8.0.0-beta.2 8.0.0-rc.1 8.0.0-rc.2 8.0.1 8.0.2 8.0.3 8.0.4 8.0.5 8.1.0 8.1.0-beta.1 8.1.0-rc.1 8.1.0-rc.2 8.1.1 8.1.2 8.1.3 8.1.4 8.2.0 8.2.0-beta.1 8.2.0-rc.1 8.2.0-rc.2 8.2.1 8.2.2 8.2.3 8.2.4 8.2.5 8.3.0 8.3.0-beta.1 8.3.0-rc.1 8.3.0-rc.2 8.3.1 8.3.2 8.3.3 8.3.4 8.4.0 8.4.0-beta.1 8.4.0-rc.1 8.4.1 8.4.2 8.4.3 8.5.0 8.5.0-beta.1 8.5.0-rc.1 8.5.1 8.5.2 8.5.3 8.5.4 8.5.5 8.6.0 8.6.0-beta.1 8.6.0-rc.1 8.6.1 8.6.2 8.6.3 8.6.4 8.7.0 8.7.0-beta.1 8.7.0-beta.2 8.7.0-rc.1 8.7.1 8.7.2 8.7.3 8.8.0 8.8.0-beta.1 8.8.0-rc.1 8.8.1 8.8.2 8.8.3 8.8.4 8.8.5 8.8.6 8.8.7 8.9.0 8.9.0-beta.1 8.9.0-rc.1 8.9.1 8.9.2 8.9.3 8.9.4 8.9.5 9.0.0 9.0.0-beta.1 9.0.0-beta.2 9.0.0-rc.1 9.0.1 9.0.2 9.0.3 9.0.4 9.1.0 9.1.0-beta.1 9.1.0-rc.1 9.1.1 9.1.2 9.1.3 9.1.4 9.1.5 9.1.6 9.2.0 9.2.0-beta.1 9.2.0-rc.1 9.2.1 9.2.2 9.2.3 9.2.4 9.2.5 9.3.0 9.3.0-beta.1 9.3.0-rc.1 9.3.1 9.3.2 9.3.3 9.3.4 9.3.5 9.3.6 9.4.0 9.4.0-beta.1 9.4.0-beta.2 9.4.0-rc.1 9.4.0-rc.2 9.4.0-rc.3 9.4.0-rc.4 9.4.1 9.4.2 9.4.3 9.4.4 9.4.5 9.5.0 9.5.0-beta.1 9.5.0-beta.2 9.5.0-rc.1 9.5.1 9.5.2 9.5.3 9.5.4 9.6.0 9.6.0-beta.1 9.6.0-beta.2 9.6.0-rc.1 9.6.1 9.6.2 9.6.3 9.6.4 9.7.0 9.7.0-beta.1 9.7.0-rc.1 9.7.1 9.7.2 9.7.3 9.8.0 9.8.0-beta.1 9.8.0-rc.1 9.8.1 9.8.2 9.8.3 9.8.4 9.8.5 9.8.6 9.8.7 9.9.0 9.9.0-beta.1 9.9.0-rc.1 9.9.1 9.9.2 9.9.3 9.9.4 9.9.5 9.9.6 9.9.7 3.7.3 7.1.2 3.8.0 7.2.0 3.8.0-beta.1 7.2.0-beta.1 3.8.0-rc.1 7.2.0-beta.2 3.8.0-rc.2 7.2.0-rc.1 3.8.1 7.2.0-rc.2 3.8.2 7.2.1 3.8.3 7.2.2 3.9.0 7.2.3 3.9.0-beta.1 7.2.4 3.9.0-beta.2 7.3.0 3.9.0-rc.1 7.3.0-beta.1 3.9.0-rc.2 7.3.0-beta.2 3.9.0-rc.3 7.3.0-rc.1 3.9.0-rc.4 7.3.0-rc.2 3.9.1 7.3.1 3.9.2 7.4.0 3.9.3 7.4.0-beta.1 3.9.4 7.4.0-beta.2 3.9.5 7.4.0-rc.1 4.0.0 7.4.0-rc.2 4.0.0-beta.1 7.4.1 4.0.0-rc.1 7.4.2 4.0.0-rc.2 7.5.0 4.0.1 7.5.0-beta.1 4.0.2 7.5.0-beta.2 4.0.3 7.5.0-rc.1 4.0.4 7.5.1 4.1.0 7.5.2 4.1.0-beta.1 7.6.0 4.1.0-beta.2 7.6.0-beta.1 4.1.0-rc.1 7.6.0-beta.2 4.1.0-rc.2 7.6.0-rc.1 4.1.1 7.6.0-rc.2 4.1.2 7.6.0-rc.3 4.1.3 7.6.1 4.1.4 7.6.2 4.2.0 7.7.0 4.2.0-RC.1 7.7.0-beta.1 4.2.0-RC.2 7.7.0-beta.2 4.2.0-beta.1 7.7.0-rc.1 4.2.1 7.7.1 4.2.2 7.7.2 4.2.3 7.7.3 4.2.4 7.8.0 4.2.5 4.3.0 4.3.0-beta.1 4.3.0-rc.1 4.3.0-rc.2 4.3.0-rc.3 4.3.1 4.3.2 4.3.3 4.3.4 4.3.5 4.3.6 4.4.0 4.4.0-beta.1 4.4.0-rc.1 4.4.1 4.4.2 4.4.3 4.4.4 4.5.0 4.5.0-beta.1 4.5.0-rc.1 4.5.0-rc.3 4.5.1 4.5.2 4.5.3 4.5.4 4.5.5 4.6.0 4.6.0-beta.1 4.6.0-rc.1 4.6.1 4.6.2 4.6.3 4.6.4 4.6.5 4.7.0 4.7.0-beta.1 4.7.0-beta.2 4.7.0-rc.1 4.7.1 4.7.1-beta.1 4.7.2 4.7.3 4.7.4 4.8.0 4.8.0-beta.1 4.8.0-rc.1 4.8.0-rc.2 4.8.1 4.8.2 4.8.3 4.9.0 4.9.0-beta.1 4.9.0-rc.1 4.9.0-rc.2 4.9.1 4.9.2 4.9.3 4.9.4 4.9.5 5.0.0 5.0.0-beta.1 5.0.0-beta.2 5.0.0-rc.1 5.0.0-rc.2 5.0.0-rc.3 5.0.1 5.0.2 5.0.3 5.1.0 5.1.0-beta.1 5.1.0-rc.1 trunk 5.1.1 10.0.0 5.1.2 10.0.0-rc.1 5.1.3 10.0.0-rc.2 5.2.0 10.0.1 5.2.0-beta.1 10.0.2 5.2.0-rc.1 10.0.3 5.2.0-rc.2 10.0.4 5.2.1 10.0.5 5.2.2 10.0.6 5.2.3 10.1.0 5.2.4 10.1.0-rc.1 5.2.5 10.1.0-rc.2 5.3.0 10.1.0-rc.3 5.3.0-beta.1 10.1.0-rc.4 5.3.0-rc.1 10.1.1 5.3.0-rc.2 10.1.2 5.3.1 10.1.3 5.3.2 10.1.4 5.3.3 10.2.0 5.4.0 10.2.0-beta.1 5.4.0-beta.1 10.2.0-beta.2 5.4.0-rc.1 10.2.0-rc.1 5.4.1 10.2.1 5.4.2 10.2.2 5.4.3 10.2.3 5.4.4 10.2.4 5.4.5 10.3.0 5.5.0 10.3.0-beta.1 5.5.0-beta.1 10.3.0-beta.2 5.5.0-rc.1 10.3.0-rc.1 5.5.0-rc.2 10.3.0-rc.2 5.5.1 10.3.1 5.5.2 10.3.2 5.5.3 10.3.3 5.5.4 10.3.4 5.5.5 10.3.5 5.6.0 10.3.6 5.6.0-beta.1 10.3.7 5.6.0-rc.1 10.3.8 5.6.0-rc.2 10.4.0 5.6.1 10.4.0-beta.1 5.6.2 10.4.0-beta.2 5.6.3 10.4.0-rc.1 5.7.0 10.4.1 5.7.0-beta.1 10.4.2 5.7.0-rc.1 10.4.3 5.7.1 10.4.4 5.7.2 10.5.0 5.7.3 10.5.0-beta.1 5.8.0 10.5.0-beta.2 5.8.0-beta.1 10.5.0-rc.1 5.8.0-beta.2 10.5.0-rc.2 5.8.0-rc.1 10.5.0-rc.3 5.8.1 10.5.1 5.8.2 10.5.2 5.9.0 10.5.3 5.9.0-beta.1 10.6.0 5.9.0-rc.1 10.6.0-beta.1 5.9.0-rc.2 10.6.0-beta.2 5.9.1 10.6.0-rc.1 5.9.2 10.6.1 6.0.0 10.6.2 6.0.0-beta.1 10.7.0 6.0.0-rc.1 10.7.0-beta.1 6.0.1 10.7.0-beta.2 6.0.2 10.7.0-rc.1 6.1.0 3.0.0 6.1.0-beta.1 3.0.1 6.1.0-rc.1 3.0.2 6.1.0-rc.2 3.0.3 6.1.1 3.0.4 6.1.2 3.0.5 6.1.3 3.0.6 6.2.0 3.0.7 6.2.0-beta.1 3.0.8 6.2.0-rc.1 3.0.9 6.2.0-rc.2 3.1.0 6.2.1 3.1.1 6.2.2 3.1.2 6.2.3 3.2.0 6.3.0 3.2.1 6.3.0-beta.1 3.2.2 6.3.0-rc.1 3.2.3 6.3.0-rc.2 3.2.4 6.3.1 3.2.5 6.3.2 3.2.6 6.4.0 3.3.0 6.4.0-beta.1 3.3.1 6.4.0-rc.1 3.3.2 6.4.1 3.3.2-rc.1 6.4.2 3.3.3 6.5.0 3.3.4 6.5.0-beta.1 3.3.5 6.5.0-rc.1 3.3.6 6.5.0-rc.2 3.4.0 6.5.1 3.4.0-beta.1 6.5.2 3.4.0-rc.2 6.6.0 3.4.1 6.6.0-beta.1 3.4.2 6.6.0-rc.1 3.4.3 6.6.0-rc.2 3.4.4 6.6.1 3.4.5 6.6.2 3.4.6 6.7.0 3.4.7 6.7.0-beta.1 3.4.8 6.7.0-beta.2 3.5.0 6.7.0-rc.1 3.5.0-beta.1 6.7.1 3.5.0-rc.1 6.8.0 3.5.0-rc.2 6.8.0-beta.1 3.5.1 6.8.0-beta.2 3.5.10 6.8.0-rc.1 3.5.2 6.8.1 3.5.3 6.8.2 3.5.4 6.8.3 3.5.5 6.9.0 3.5.6 6.9.0-beta.1 3.5.7 6.9.0-beta.2 3.5.8 6.9.0-rc.1 3.5.9 6.9.1 3.6.0 6.9.2 3.6.0-beta.1 6.9.3 3.6.0-rc.1 6.9.4 3.6.0-rc.2 6.9.5 3.6.0-rc.3 7.0.0 3.6.1 7.0.0-beta.1 3.6.2 7.0.0-beta.2 3.6.3 7.0.0-beta.3 3.6.4 7.0.0-rc.1 3.6.5 7.0.0-rc.2 3.6.6 7.0.1 3.6.7 7.0.2 3.7.0 7.1.0 3.7.0-beta.1 7.1.0-beta.1 3.7.0-rc.1 7.1.0-beta.2 3.7.0-rc.2 7.1.0-rc.1 3.7.1 7.1.0-rc.2 3.7.2 7.1.1
woocommerce / includes / class-wc-structured-data.php
woocommerce / includes Last commit date
abstracts 9 years ago admin 9 years ago api 9 years ago cli 9 years ago data-stores 9 years ago emails 9 years ago gateways 9 years ago interfaces 9 years ago legacy 9 years ago libraries 9 years ago log-handlers 9 years ago payment-tokens 9 years ago shipping 9 years ago shortcodes 9 years ago theme-support 9 years ago vendor 9 years ago walkers 9 years ago widgets 9 years ago class-wc-ajax.php 9 years ago class-wc-api.php 9 years ago class-wc-auth.php 9 years ago class-wc-autoloader.php 9 years ago class-wc-background-emailer.php 9 years ago class-wc-background-updater.php 9 years ago class-wc-breadcrumb.php 9 years ago class-wc-cache-helper.php 9 years ago class-wc-cart.php 9 years ago class-wc-checkout.php 9 years ago class-wc-cli.php 9 years ago class-wc-comments.php 9 years ago class-wc-countries.php 9 years ago class-wc-coupon.php 9 years ago class-wc-customer-download.php 9 years ago class-wc-customer.php 9 years ago class-wc-data-exception.php 9 years ago class-wc-data-store.php 9 years ago class-wc-datetime.php 9 years ago class-wc-deprecated-action-hooks.php 9 years ago class-wc-deprecated-filter-hooks.php 9 years ago class-wc-download-handler.php 9 years ago class-wc-emails.php 9 years ago class-wc-embed.php 9 years ago class-wc-form-handler.php 9 years ago class-wc-frontend-scripts.php 9 years ago class-wc-geo-ip.php 9 years ago class-wc-geolocation.php 9 years ago class-wc-https.php 9 years ago class-wc-install.php 9 years ago class-wc-integrations.php 9 years ago class-wc-legacy-api.php 9 years ago class-wc-log-levels.php 9 years ago class-wc-logger.php 9 years ago class-wc-order-factory.php 9 years ago class-wc-order-item-coupon.php 9 years ago class-wc-order-item-fee.php 9 years ago class-wc-order-item-meta.php 9 years ago class-wc-order-item-product.php 9 years ago class-wc-order-item-shipping.php 9 years ago class-wc-order-item-tax.php 9 years ago class-wc-order-item.php 9 years ago class-wc-order-refund.php 9 years ago class-wc-order.php 9 years ago class-wc-payment-gateways.php 9 years ago class-wc-payment-tokens.php 9 years ago class-wc-post-data.php 9 years ago class-wc-post-types.php 9 years ago class-wc-product-attribute.php 9 years ago class-wc-product-download.php 9 years ago class-wc-product-external.php 9 years ago class-wc-product-factory.php 9 years ago class-wc-product-grouped.php 9 years ago class-wc-product-simple.php 9 years ago class-wc-product-variable.php 9 years ago class-wc-product-variation.php 9 years ago class-wc-query.php 9 years ago class-wc-register-wp-admin-settings.php 9 years ago class-wc-session-handler.php 9 years ago class-wc-shipping-rate.php 9 years ago class-wc-shipping-zone.php 9 years ago class-wc-shipping-zones.php 9 years ago class-wc-shipping.php 9 years ago class-wc-shortcodes.php 9 years ago class-wc-structured-data.php 9 years ago class-wc-tax.php 9 years ago class-wc-template-loader.php 9 years ago class-wc-tracker.php 9 years ago class-wc-validation.php 9 years ago class-wc-webhook.php 9 years ago wc-account-functions.php 9 years ago wc-attribute-functions.php 9 years ago wc-cart-functions.php 9 years ago wc-conditional-functions.php 9 years ago wc-core-functions.php 9 years ago wc-coupon-functions.php 9 years ago wc-deprecated-functions.php 9 years ago wc-formatting-functions.php 9 years ago wc-notice-functions.php 9 years ago wc-order-functions.php 9 years ago wc-order-item-functions.php 9 years ago wc-page-functions.php 9 years ago wc-product-functions.php 9 years ago wc-rest-functions.php 9 years ago wc-stock-functions.php 9 years ago wc-template-functions.php 9 years ago wc-template-hooks.php 9 years ago wc-term-functions.php 9 years ago wc-update-functions.php 9 years ago wc-user-functions.php 9 years ago wc-webhook-functions.php 9 years ago wc-widget-functions.php 9 years ago
class-wc-structured-data.php
440 lines
1 <?php
2
3 if ( ! defined( 'ABSPATH' ) ) {
4 exit; // Exit if accessed directly.
5 }
6
7 /**
8 * Structured data's handler and generator using JSON-LD format.
9 *
10 * @class WC_Structured_Data
11 * @since 3.0.0
12 * @version 3.0.0
13 * @package WooCommerce/Classes
14 * @author Clément Cazaud <opportus@gmail.com>
15 */
16 class WC_Structured_Data {
17
18 /**
19 * @var array $_data
20 */
21 private $_data = array();
22
23 /**
24 * Constructor.
25 */
26 public function __construct() {
27 // Generate structured data.
28 add_action( 'woocommerce_before_main_content', array( $this, 'generate_website_data' ), 30 );
29 add_action( 'woocommerce_breadcrumb', array( $this, 'generate_breadcrumblist_data' ), 10 );
30 add_action( 'woocommerce_shop_loop', array( $this, 'generate_product_data' ), 10 );
31 add_action( 'woocommerce_single_product_summary', array( $this, 'generate_product_data' ), 60 );
32 add_action( 'woocommerce_review_meta', array( $this, 'generate_review_data' ), 20 );
33 add_action( 'woocommerce_email_order_details', array( $this, 'generate_order_data' ), 20, 3 );
34
35 // Output structured data.
36 add_action( 'woocommerce_email_order_details', array( $this, 'output_email_structured_data' ), 30, 3 );
37 add_action( 'wp_footer', array( $this, 'output_structured_data' ), 10 );
38 }
39
40 /**
41 * Sets data.
42 *
43 * @param array $data Structured data.
44 * @param bool $reset Unset data (default: false).
45 * @return bool
46 */
47 public function set_data( $data, $reset = false ) {
48 if ( ! isset( $data['@type'] ) || ! preg_match( '|^[a-zA-Z]{1,20}$|', $data['@type'] ) ) {
49 return false;
50 }
51
52 if ( $reset && isset( $this->_data ) ) {
53 unset( $this->_data );
54 }
55
56 $this->_data[] = $data;
57
58 return true;
59 }
60
61 /**
62 * Gets data.
63 *
64 * @return array
65 */
66 public function get_data() {
67 return $this->_data;
68 }
69
70 /**
71 * Structures and returns data.
72 *
73 * List of types available by default for specific request:
74 *
75 * 'product',
76 * 'review',
77 * 'breadcrumblist',
78 * 'website',
79 * 'order',
80 *
81 * @param array $types Structured data types.
82 * @return array
83 */
84 public function get_structured_data( $types ) {
85 $data = array();
86
87 // Put together the values of same type of structured data.
88 foreach ( $this->get_data() as $value ) {
89 $data[ strtolower( $value['@type'] ) ][] = $value;
90 }
91
92 // Wrap the multiple values of each type inside a graph... Then add context to each type.
93 foreach ( $data as $type => $value ) {
94 $data[ $type ] = count( $value ) > 1 ? array( '@graph' => $value ) : $value[0];
95 $data[ $type ] = apply_filters( 'woocommerce_structured_data_context', array( '@context' => 'http://schema.org/' ), $data, $type, $value ) + $data[ $type ];
96 }
97
98 // If requested types, pick them up... Finally change the associative array to an indexed one.
99 $data = $types ? array_values( array_intersect_key( $data, array_flip( $types ) ) ) : array_values( $data );
100
101 if ( ! empty( $data ) ) {
102 $data = count( $data ) > 1 ? array( '@graph' => $data ) : $data[0];
103 }
104
105 return $data;
106 }
107
108 /**
109 * Get data types for pages.
110 *
111 * @return array
112 */
113 protected function get_data_type_for_page() {
114 $types = array();
115 $types[] = is_shop() || is_product_category() || is_product() ? 'product' : '';
116 $types[] = is_shop() && is_front_page() ? 'website' : '';
117 $types[] = is_product() ? 'review' : '';
118 $types[] = ! is_shop() ? 'breadcrumblist' : '';
119 $types[] = 'order';
120
121 return array_filter( apply_filters( 'woocommerce_structured_data_type_for_page', $types ) );
122 }
123
124 /**
125 * Makes sure email structured data only outputs on non-plain text versions.
126 *
127 * @param WP_Order $order Order data.
128 * @param bool $sent_to_admin Send to admin (default: false).
129 * @param bool $plain_text Plain text email (default: false).
130 */
131 public function output_email_structured_data( $order, $sent_to_admin = false, $plain_text = false ) {
132 if ( $plain_text ) {
133 return;
134 }
135 echo '<div style="display: none; font-size: 0; max-height: 0; line-height: 0; padding: 0; mso-hide: all;">';
136 $this->output_structured_data();
137 echo '</div>';
138 }
139
140 /**
141 * Sanitizes, encodes and outputs structured data.
142 *
143 * Hooked into `wp_footer` action hook.
144 * Hooked into `woocommerce_email_order_details` action hook.
145 */
146 public function output_structured_data() {
147 $types = $this->get_data_type_for_page();
148
149 if ( $data = wc_clean( $this->get_structured_data( $types ) ) ) {
150 echo '<script type="application/ld+json">' . wp_json_encode( $data ) . '</script>';
151 }
152 }
153
154 /*
155 |--------------------------------------------------------------------------
156 | Generators
157 |--------------------------------------------------------------------------
158 |
159 | Methods for generating specific structured data types:
160 |
161 | - Product
162 | - Review
163 | - BreadcrumbList
164 | - WebSite
165 | - Order
166 |
167 | The generated data is stored into `$this->_data`.
168 | See the methods above for handling `$this->_data`.
169 |
170 */
171
172 /**
173 * Generates Product structured data.
174 *
175 * Hooked into `woocommerce_single_product_summary` action hook.
176 * Hooked into `woocommerce_shop_loop` action hook.
177 *
178 * @param WC_Product $product Product data (default: null).
179 */
180 public function generate_product_data( $product = null ) {
181 if ( ! is_object( $product ) ) {
182 global $product;
183 }
184
185 if ( ! is_a( $product, 'WC_Product' ) ) {
186 return;
187 }
188
189 $shop_name = get_bloginfo( 'name' );
190 $shop_url = home_url();
191 $currency = get_woocommerce_currency();
192 $markup = array();
193 $markup['@type'] = 'Product';
194 $markup['@id'] = get_permalink( $product->get_id() );
195 $markup['url'] = $markup['@id'];
196 $markup['name'] = $product->get_name();
197
198 if ( apply_filters( 'woocommerce_structured_data_product_limit', is_product_taxonomy() || is_shop() ) ) {
199 $this->set_data( apply_filters( 'woocommerce_structured_data_product_limited', $markup, $product ) );
200 return;
201 }
202
203 $markup_offer = array(
204 '@type' => 'Offer',
205 'priceCurrency' => $currency,
206 'availability' => 'http://schema.org/' . $stock = ( $product->is_in_stock() ? 'InStock' : 'OutOfStock' ),
207 'sku' => $product->get_sku(),
208 'image' => wp_get_attachment_url( $product->get_image_id() ),
209 'description' => $product->get_description(),
210 'seller' => array(
211 '@type' => 'Organization',
212 'name' => $shop_name,
213 'url' => $shop_url,
214 ),
215 );
216
217 if ( $product->is_type( 'variable' ) ) {
218 $prices = $product->get_variation_prices();
219
220 $markup_offer['priceSpecification'] = array(
221 'price' => wc_format_decimal( $product->get_price(), wc_get_price_decimals() ),
222 'minPrice' => wc_format_decimal( current( $prices['price'] ), wc_get_price_decimals() ),
223 'maxPrice' => wc_format_decimal( end( $prices['price'] ), wc_get_price_decimals() ),
224 'priceCurrency' => $currency,
225 );
226 } else {
227 $markup_offer['price'] = wc_format_decimal( $product->get_price(), wc_get_price_decimals() );
228 }
229
230 $markup['offers'] = array( apply_filters( 'woocommerce_structured_data_product_offer', $markup_offer, $product ) );
231
232 if ( $product->get_rating_count() ) {
233 $markup['aggregateRating'] = array(
234 '@type' => 'AggregateRating',
235 'ratingValue' => $product->get_average_rating(),
236 'ratingCount' => $product->get_rating_count(),
237 'reviewCount' => $product->get_review_count(),
238 );
239 }
240
241 $this->set_data( apply_filters( 'woocommerce_structured_data_product', $markup, $product ) );
242 }
243
244 /**
245 * Generates Review structured data.
246 *
247 * Hooked into `woocommerce_review_meta` action hook.
248 *
249 * @param WP_Comment $comment Comment data.
250 */
251 public function generate_review_data( $comment ) {
252 $markup = array();
253 $markup['@type'] = 'Review';
254 $markup['@id'] = get_comment_link( $comment->comment_ID );
255 $markup['datePublished'] = get_comment_date( 'c', $comment->comment_ID );
256 $markup['description'] = get_comment_text( $comment->comment_ID );
257 $markup['itemReviewed'] = array(
258 '@type' => 'Product',
259 'name' => get_the_title( $comment->post_ID ),
260 );
261 if ( $rating = get_comment_meta( $comment->comment_ID, 'rating', true ) ) {
262 $markup['reviewRating'] = array(
263 '@type' => 'rating',
264 'ratingValue' => $rating,
265 );
266
267 // Skip replies unless they have a rating.
268 } elseif ( $comment->comment_parent ) {
269 return;
270 }
271
272 $markup['author'] = array(
273 '@type' => 'Person',
274 'name' => get_comment_author( $comment->comment_ID ),
275 );
276
277 $this->set_data( apply_filters( 'woocommerce_structured_data_review', $markup, $comment ) );
278 }
279
280 /**
281 * Generates BreadcrumbList structured data.
282 *
283 * Hooked into `woocommerce_breadcrumb` action hook.
284 *
285 * @param WC_Breadcrumb $breadcrumbs Breadcrumb data.
286 */
287 public function generate_breadcrumblist_data( $breadcrumbs ) {
288 $crumbs = $breadcrumbs->get_breadcrumb();
289
290 $markup = array();
291 $markup['@type'] = 'BreadcrumbList';
292 $markup['itemListElement'] = array();
293
294 foreach ( $crumbs as $key => $crumb ) {
295 $markup['itemListElement'][ $key ] = array(
296 '@type' => 'ListItem',
297 'position' => $key + 1,
298 'item' => array(
299 'name' => $crumb[0],
300 ),
301 );
302
303 if ( ! empty( $crumb[1] ) && sizeof( $crumbs ) !== $key + 1 ) {
304 $markup['itemListElement'][ $key ]['item'] += array( '@id' => $crumb[1] );
305 }
306 }
307
308 $this->set_data( apply_filters( 'woocommerce_structured_data_breadcrumblist', $markup, $breadcrumbs ) );
309 }
310
311 /**
312 * Generates WebSite structured data.
313 *
314 * Hooked into `woocommerce_before_main_content` action hook.
315 */
316 public function generate_website_data() {
317 $markup = array();
318 $markup['@type'] = 'WebSite';
319 $markup['name'] = get_bloginfo( 'name' );
320 $markup['url'] = home_url();
321 $markup['potentialAction'] = array(
322 '@type' => 'SearchAction',
323 'target' => home_url( '?s={search_term_string}&post_type=product' ),
324 'query-input' => 'required name=search_term_string',
325 );
326
327 $this->set_data( apply_filters( 'woocommerce_structured_data_website', $markup ) );
328 }
329
330 /**
331 * Generates Order structured data.
332 *
333 * Hooked into `woocommerce_email_order_details` action hook.
334 *
335 * @param WP_Order $order Order data.
336 * @param bool $sent_to_admin Send to admin (default: false).
337 * @param bool $plain_text Plain text email (default: false).
338 */
339 public function generate_order_data( $order, $sent_to_admin = false, $plain_text = false ) {
340 if ( $plain_text || ! is_a( $order, 'WC_Order' ) ) {
341 return;
342 }
343
344 $shop_name = get_bloginfo( 'name' );
345 $shop_url = home_url();
346 $order_url = $sent_to_admin ? admin_url( 'post.php?post=' . absint( $order->get_id() ) . '&action=edit' ) : $order->get_view_order_url();
347 $order_statuses = array(
348 'pending' => 'http://schema.org/OrderPaymentDue',
349 'processing' => 'http://schema.org/OrderProcessing',
350 'on-hold' => 'http://schema.org/OrderProblem',
351 'completed' => 'http://schema.org/OrderDelivered',
352 'cancelled' => 'http://schema.org/OrderCancelled',
353 'refunded' => 'http://schema.org/OrderReturned',
354 'failed' => 'http://schema.org/OrderProblem',
355 );
356
357 $markup_offers = array();
358 foreach ( $order->get_items() as $item ) {
359 if ( ! apply_filters( 'woocommerce_order_item_visible', true, $item ) ) {
360 continue;
361 }
362
363 $product = apply_filters( 'woocommerce_order_item_product', $order->get_product_from_item( $item ), $item );
364 $product_exists = is_object( $product );
365 $is_visible = $product_exists && $product->is_visible();
366
367 $markup_offers[] = array(
368 '@type' => 'Offer',
369 'price' => $order->get_line_subtotal( $item ),
370 'priceCurrency' => $order->get_currency(),
371 'priceSpecification' => array(
372 'price' => $order->get_line_subtotal( $item ),
373 'priceCurrency' => $order->get_currency(),
374 'eligibleQuantity' => array(
375 '@type' => 'QuantitativeValue',
376 'value' => apply_filters( 'woocommerce_email_order_item_quantity', $item['qty'], $item ),
377 ),
378 ),
379 'itemOffered' => array(
380 '@type' => 'Product',
381 'name' => apply_filters( 'woocommerce_order_item_name', $item['name'], $item, $is_visible ),
382 'sku' => $product_exists ? $product->get_sku() : '',
383 'image' => $product_exists ? wp_get_attachment_image_url( $product->get_image_id() ) : '',
384 'url' => $is_visible ? get_permalink( $product->get_id() ) : get_home_url(),
385 ),
386 'seller' => array(
387 '@type' => 'Organization',
388 'name' => $shop_name,
389 'url' => $shop_url,
390 ),
391 );
392 }
393
394 $markup = array();
395 $markup['@type'] = 'Order';
396 $markup['url'] = $order_url;
397 $markup['orderStatus'] = isset( $order_status[ $order->get_status() ] ) ? $order_status[ $order->get_status() ] : '';
398 $markup['orderNumber'] = $order->get_order_number();
399 $markup['orderDate'] = $order->get_date_created()->format( 'c' );
400 $markup['acceptedOffer'] = $markup_offers;
401 $markup['discount'] = $order->get_total_discount();
402 $markup['discountCurrency'] = $order->get_currency();
403 $markup['price'] = $order->get_total();
404 $markup['priceCurrency'] = $order->get_currency();
405 $markup['priceSpecification'] = array(
406 'price' => $order->get_total(),
407 'priceCurrency' => $order->get_currency(),
408 'valueAddedTaxIncluded' => true,
409 );
410 $markup['billingAddress'] = array(
411 '@type' => 'PostalAddress',
412 'name' => $order->get_formatted_billing_full_name(),
413 'streetAddress' => $order->get_billing_address_1(),
414 'postalCode' => $order->get_billing_postcode(),
415 'addressLocality' => $order->get_billing_city(),
416 'addressRegion' => $order->get_billing_state(),
417 'addressCountry' => $order->get_billing_country(),
418 'email' => $order->get_billing_email(),
419 'telephone' => $order->get_billing_phone(),
420 );
421 $markup['customer'] = array(
422 '@type' => 'Person',
423 'name' => $order->get_formatted_billing_full_name(),
424 );
425 $markup['merchant'] = array(
426 '@type' => 'Organization',
427 'name' => $shop_name,
428 'url' => $shop_url,
429 );
430 $markup['potentialAction'] = array(
431 '@type' => 'ViewAction',
432 'name' => 'View Order',
433 'url' => $order_url,
434 'target' => $order_url,
435 );
436
437 $this->set_data( apply_filters( 'woocommerce_structured_data_order', $markup, $sent_to_admin, $order ), true );
438 }
439 }
440