PluginProbe
Yoast SEO – Advanced SEO with real-time guidance and built-in AI / 28.3
Yoast SEO – Advanced SEO with real-time guidance and built-in AI v28.3
28.5 28.4 28.3 28.2 28.1 28.0 27.9 27.8 27.7 27.6 27.5 trunk 18.0 18.1 18.2 18.3 18.4 18.4.1 18.5 18.5.1 18.6 18.7 18.8 18.9 19.0 All 129 releases
wordpress-seo / src / generators / schema / howto.php

howto.php in Yoast SEO – Advanced SEO with real-time guidance and built-in AI 28.3, at src/generators/schema/howto.php

217 lines 5.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace Yoast\WP\SEO\Generators\Schema;
4
5 use Yoast\WP\SEO\Config\Schema_IDs;
6
7 /**
8 * Returns schema HowTo data.
9 */
10 class HowTo extends Abstract_Schema_Piece {
11
12 /**
13 * Determines whether or not a piece should be added to the graph.
14 *
15 * @return bool
16 */
17 public function is_needed() {
18 return ! empty( $this->context->blocks['yoast/how-to-block'] );
19 }
20
21 /**
22 * Renders a list of questions, referencing them by ID.
23 *
24 * @return array Our Schema graph.
25 */
26 public function generate() {
27 $graph = [];
28
29 foreach ( $this->context->blocks['yoast/how-to-block'] as $index => $block ) {
30 $this->add_how_to( $graph, $block, $index );
31 }
32
33 return $graph;
34 }
35
36 /**
37 * Adds the duration of the task to the Schema.
38 *
39 * @param array $data Our How-To schema data.
40 * @param array $attributes The block data attributes.
41 *
42 * @return void
43 */
44 private function add_duration( &$data, $attributes ) {
45 if ( empty( $attributes['hasDuration'] ) ) {
46 return;
47 }
48
49 $days = empty( $attributes['days'] ) ? 0 : $attributes['days'];
50 $hours = empty( $attributes['hours'] ) ? 0 : $attributes['hours'];
51 $minutes = empty( $attributes['minutes'] ) ? 0 : $attributes['minutes'];
52
53 if ( ( $days + $hours + $minutes ) > 0 ) {
54 $data['totalTime'] = \esc_attr( 'P' . $days . 'DT' . $hours . 'H' . $minutes . 'M' );
55 }
56 }
57
58 /**
59 * Adds the steps to our How-To output.
60 *
61 * @param array $data Our How-To schema data.
62 * @param array $steps Our How-To block's steps.
63 *
64 * @return void
65 */
66 private function add_steps( &$data, $steps ) {
67 foreach ( $steps as $step ) {
68 $schema_id = $this->context->canonical . '#' . \esc_attr( $step['id'] );
69 $schema_step = [
70 '@type' => 'HowToStep',
71 'url' => $schema_id,
72 ];
73
74 if ( isset( $step['jsonText'] ) ) {
75 $json_text = $this->helpers->schema->html->sanitize( $step['jsonText'] );
76 }
77
78 if ( isset( $step['jsonName'] ) ) {
79 $json_name = $this->helpers->schema->html->smart_strip_tags( $step['jsonName'] );
80 }
81
82 if ( empty( $json_name ) ) {
83 if ( empty( $step['text'] ) ) {
84 continue;
85 }
86
87 $schema_step['text'] = '';
88
89 $this->add_step_image( $schema_step, $step );
90
91 // If there is no text and no image, don't output the step.
92 if ( empty( $json_text ) && empty( $schema_step['image'] ) ) {
93 continue;
94 }
95
96 if ( ! empty( $json_text ) ) {
97 $schema_step['text'] = $json_text;
98 }
99 }
100
101 elseif ( empty( $json_text ) ) {
102 $schema_step['text'] = $json_name;
103 }
104 else {
105 $schema_step['name'] = $json_name;
106
107 $this->add_step_description( $schema_step, $json_text );
108 $this->add_step_image( $schema_step, $step );
109 }
110
111 $data['step'][] = $schema_step;
112 }
113 }
114
115 /**
116 * Checks if we have a step description, if we do, add it.
117 *
118 * @param array $schema_step Our Schema output for the Step.
119 * @param string $json_text The step text.
120 *
121 * @return void
122 */
123 private function add_step_description( &$schema_step, $json_text ) {
124 // Decode HTML entities.
125 $json_text = \html_entity_decode( $json_text );
126 // Remove the image from the text if it exists. Search and replace the img tag.
127 $json_text = \preg_replace( '/<img[^>]+>/i', '', $json_text );
128 // Strip all HTML tags to ensure plain text for the JSON-LD output.
129 $json_text = \wp_strip_all_tags( $json_text );
130 // Trim whitespace.
131 $json_text = \trim( $json_text );
132
133 $schema_step['itemListElement'] = [
134 [
135 '@type' => 'HowToDirection',
136 'text' => $json_text,
137 ],
138 ];
139 }
140
141 /**
142 * Checks if we have a step image, if we do, add it.
143 *
144 * @param array $schema_step Our Schema output for the Step.
145 * @param array $step The step block data.
146 *
147 * @return void
148 */
149 private function add_step_image( &$schema_step, $step ) {
150 if ( isset( $step['images'] ) && \is_array( $step['images'] ) ) {
151 foreach ( $step['images'] as $image ) {
152 if ( isset( $image['type'] ) && $image['type'] === 'img' ) {
153 $schema_step['image'] = $this->get_image_schema( \esc_url( $image['props']['src'] ) );
154 }
155 }
156 }
157 elseif ( isset( $step['text'] ) && \is_array( $step['text'] ) ) {
158 // Backwards compatibility for older How-To blocks.
159 foreach ( $step['text'] as $line ) {
160 if ( \is_array( $line ) && isset( $line['type'] ) && $line['type'] === 'img' ) {
161 $schema_step['image'] = $this->get_image_schema( \esc_url( $line['props']['src'] ) );
162 }
163 }
164 }
165 }
166
167 /**
168 * Generates the HowTo schema for a block.
169 *
170 * @param array $graph Our Schema data.
171 * @param array $block The How-To block content.
172 * @param int $index The index of the current block.
173 *
174 * @return void
175 */
176 protected function add_how_to( &$graph, $block, $index ) {
177 $data = [
178 '@type' => 'HowTo',
179 '@id' => $this->context->canonical . '#howto-' . ( $index + 1 ),
180 'name' => $this->helpers->schema->html->smart_strip_tags( $this->helpers->post->get_post_title_with_fallback( $this->context->id ) ),
181 'mainEntityOfPage' => [ '@id' => $this->context->main_schema_id ],
182 'description' => '',
183 ];
184
185 if ( $this->context->has_article ) {
186 $data['mainEntityOfPage'] = [ '@id' => $this->context->main_schema_id . Schema_IDs::ARTICLE_HASH ];
187 }
188
189 if ( isset( $block['attrs']['jsonDescription'] ) ) {
190 $data['description'] = $this->helpers->schema->html->sanitize( $block['attrs']['jsonDescription'] );
191 }
192
193 $this->add_duration( $data, $block['attrs'] );
194
195 if ( isset( $block['attrs']['steps'] ) ) {
196 $this->add_steps( $data, $block['attrs']['steps'] );
197 }
198
199 $data = $this->helpers->schema->language->add_piece_language( $data );
200
201 $graph[] = $data;
202 }
203
204 /**
205 * Generates the image schema from the attachment $url.
206 *
207 * @param string $url Attachment url.
208 *
209 * @return array Image schema.
210 */
211 protected function get_image_schema( $url ) {
212 $schema_id = $this->context->canonical . '#schema-image-' . \md5( $url );
213
214 return $this->helpers->schema->image->generate_from_url( $schema_id, $url );
215 }
216 }
217