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 / breadcrumb.php

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

187 lines 5.1 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 Breadcrumb data.
9 */
10 class Breadcrumb extends Abstract_Schema_Piece {
11
12 /**
13 * Determine if we should add a breadcrumb attribute.
14 *
15 * @return bool
16 */
17 public function is_needed() {
18 if ( $this->context->indexable->object_type === 'unknown' ) {
19 return false;
20 }
21
22 if ( $this->context->indexable->object_type === 'system-page' && $this->context->indexable->object_sub_type === '404' ) {
23 return false;
24 }
25
26 return true;
27 }
28
29 /**
30 * Returns Schema breadcrumb data to allow recognition of page's position in the site hierarchy.
31 *
32 * @link https://developers.google.com/search/docs/data-types/breadcrumb
33 *
34 * @return bool|array Array on success, false on failure.
35 */
36 public function generate() {
37 $breadcrumbs = $this->context->presentation->breadcrumbs;
38 $list_elements = [];
39
40 // In case of pagination, replace the last breadcrumb, because it only contains "Page [number]" and has no URL.
41 if (
42 (
43 $this->helpers->current_page->is_paged()
44 || $this->context->indexable->number_of_pages > 1
45 ) && (
46 // Do not replace the last breadcrumb on static post pages.
47 ! $this->helpers->current_page->is_static_posts_page()
48 // Do not remove the last breadcrumb if only one exists (bugfix for custom paginated frontpages).
49 && \count( $breadcrumbs ) > 1
50 )
51 ) {
52 \array_pop( $breadcrumbs );
53 }
54
55 // Only output breadcrumbs that are not hidden.
56 $breadcrumbs = \array_filter( $breadcrumbs, [ $this, 'not_hidden' ] );
57
58 \reset( $breadcrumbs );
59
60 /*
61 * Check whether at least one of the breadcrumbs is broken.
62 * If so, do not output anything.
63 */
64 foreach ( $breadcrumbs as $breadcrumb ) {
65 if ( $this->is_broken( $breadcrumb ) ) {
66 return false;
67 }
68 }
69
70 // Create the last breadcrumb.
71 $last_breadcrumb = \array_pop( $breadcrumbs );
72 $breadcrumbs[] = $this->format_last_breadcrumb( $last_breadcrumb );
73
74 // If this is a static front page, prevent nested pages from creating a trail.
75 if ( $this->helpers->current_page->is_home_static_page() ) {
76
77 // Check if we're dealing with a nested page.
78 if ( \count( $breadcrumbs ) > 1 ) {
79
80 // Store the breadcrumbs home variable before dropping the parent page from the Schema.
81 $breadcrumbs_home = $breadcrumbs[0]['text'];
82 $breadcrumbs = [ \array_pop( $breadcrumbs ) ];
83
84 // Make the child page show the breadcrumbs home variable rather than its own title.
85 $breadcrumbs[0]['text'] = $breadcrumbs_home;
86 }
87 }
88
89 $breadcrumbs = \array_filter( $breadcrumbs, [ $this, 'not_empty_text' ] );
90 $breadcrumbs = \array_values( $breadcrumbs );
91
92 // Create intermediate breadcrumbs.
93 foreach ( $breadcrumbs as $index => $breadcrumb ) {
94 $list_elements[] = $this->create_breadcrumb( $index, $breadcrumb );
95 }
96
97 return [
98 '@type' => 'BreadcrumbList',
99 '@id' => $this->context->canonical . Schema_IDs::BREADCRUMB_HASH,
100 'itemListElement' => $list_elements,
101 ];
102 }
103
104 /**
105 * Returns a breadcrumb array.
106 *
107 * @param int $index The position in the list.
108 * @param array $breadcrumb The position in the list.
109 *
110 * @return array A breadcrumb listItem.
111 */
112 private function create_breadcrumb( $index, $breadcrumb ) {
113 $crumb = [
114 '@type' => 'ListItem',
115 'position' => ( $index + 1 ),
116 'name' => $this->helpers->schema->html->smart_strip_tags( $breadcrumb['text'] ),
117 ];
118
119 if ( ! empty( $breadcrumb['url'] ) ) {
120 $crumb['item'] = $breadcrumb['url'];
121 }
122
123 return $crumb;
124 }
125
126 /**
127 * Creates the last breadcrumb in the breadcrumb list, omitting the URL per Google's spec.
128 *
129 * @link https://developers.google.com/search/docs/data-types/breadcrumb
130 *
131 * @param array $breadcrumb The position in the list.
132 *
133 * @return array The last of the breadcrumbs.
134 */
135 private function format_last_breadcrumb( $breadcrumb ) {
136 unset( $breadcrumb['url'] );
137
138 return $breadcrumb;
139 }
140
141 /**
142 * Tests if the breadcrumb is broken.
143 * A breadcrumb is considered broken:
144 * - when it is not an array.
145 * - when it has no URL or text.
146 *
147 * @param array $breadcrumb The breadcrumb to test.
148 *
149 * @return bool `true` if the breadcrumb is broken.
150 */
151 private function is_broken( $breadcrumb ) {
152 // A breadcrumb is broken if it is not an array.
153 if ( ! \is_array( $breadcrumb ) ) {
154 return true;
155 }
156
157 // A breadcrumb is broken if it does not contain a URL or text.
158 if ( ! \array_key_exists( 'url', $breadcrumb ) || ! \array_key_exists( 'text', $breadcrumb ) ) {
159 return true;
160 }
161
162 return false;
163 }
164
165 /**
166 * Checks whether the breadcrumb is not set to be hidden.
167 *
168 * @param array $breadcrumb The breadcrumb array.
169 *
170 * @return bool If the breadcrumb should not be hidden.
171 */
172 private function not_hidden( $breadcrumb ) {
173 return empty( $breadcrumb['hide_in_schema'] );
174 }
175
176 /**
177 * Checks whether the breadcrumb has a not empty text.
178 *
179 * @param array $breadcrumb The breadcrumb array.
180 *
181 * @return bool If the breadcrumb has a not empty text.
182 */
183 private function not_empty_text( $breadcrumb ) {
184 return ! empty( $breadcrumb['text'] );
185 }
186 }
187