• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Yoast / wordpress-seo / 7004843404

27 Nov 2023 11:48AM UTC coverage: 49.206% (-0.03%) from 49.232%
7004843404

push

github

web-flow
Merge pull request #20858 from Yoast/improve-copy-in-the-ftc-57

15305 of 31104 relevant lines covered (49.21%)

4.03 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

93.1
/src/generators/schema/breadcrumb.php
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() {
4✔
18
                if ( $this->context->indexable->object_type === 'unknown' ) {
4✔
19
                        return false;
×
20
                }
21

22
                if ( $this->context->indexable->object_type === 'system-page' && $this->context->indexable->object_sub_type === '404' ) {
4✔
23
                        return false;
2✔
24
                }
25

26
                return true;
2✔
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() {
20✔
37
                $breadcrumbs   = $this->context->presentation->breadcrumbs;
20✔
38
                $list_elements = [];
20✔
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()
20✔
44
                                || $this->context->indexable->number_of_pages > 1
20✔
45
                        ) && (
46
                                // Do not replace the last breadcrumb on static post pages.
47
                                ! $this->helpers->current_page->is_static_posts_page()
13✔
48
                                // Do not remove the last breadcrumb if only one exists (bugfix for custom paginated frontpages).
10✔
49
                                && \count( $breadcrumbs ) > 1
20✔
50
                        )
51
                ) {
52
                        \array_pop( $breadcrumbs );
4✔
53
                }
54

55
                // Only output breadcrumbs that are not hidden.
56
                $breadcrumbs = \array_filter( $breadcrumbs, [ $this, 'not_hidden' ] );
20✔
57

58
                \reset( $breadcrumbs );
20✔
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 ) {
20✔
65
                        if ( $this->is_broken( $breadcrumb ) ) {
20✔
66
                                return false;
4✔
67
                        }
68
                }
69

70
                // Create the last breadcrumb.
71
                $last_breadcrumb = \array_pop( $breadcrumbs );
16✔
72
                $breadcrumbs[]   = $this->format_last_breadcrumb( $last_breadcrumb );
16✔
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() ) {
16✔
76

77
                        // Check if we're dealing with a nested page.
78
                        if ( \count( $breadcrumbs ) > 1 ) {
4✔
79

80
                                // Store the breadcrumbs home variable before dropping the parent page from the Schema.
81
                                $breadcrumbs_home = $breadcrumbs[0]['text'];
2✔
82
                                $breadcrumbs      = [ \array_pop( $breadcrumbs ) ];
2✔
83

84
                                // Make the child page show the breadcrumbs home variable rather than its own title.
85
                                $breadcrumbs[0]['text'] = $breadcrumbs_home;
2✔
86
                        }
87
                }
88

89
                $breadcrumbs = \array_filter( $breadcrumbs, [ $this, 'not_empty_text' ] );
16✔
90
                $breadcrumbs = \array_values( $breadcrumbs );
16✔
91

92
                // Create intermediate breadcrumbs.
93
                foreach ( $breadcrumbs as $index => $breadcrumb ) {
16✔
94
                        $list_elements[] = $this->create_breadcrumb( $index, $breadcrumb );
16✔
95
                }
96

97
                return [
8✔
98
                        '@type'           => 'BreadcrumbList',
16✔
99
                        '@id'             => $this->context->canonical . Schema_IDs::BREADCRUMB_HASH,
16✔
100
                        'itemListElement' => $list_elements,
16✔
101
                ];
8✔
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 ) {
16✔
113
                $crumb = [
8✔
114
                        '@type'    => 'ListItem',
16✔
115
                        'position' => ( $index + 1 ),
16✔
116
                        'name'     => $this->helpers->schema->html->smart_strip_tags( $breadcrumb['text'] ),
16✔
117
                ];
8✔
118

119
                if ( ! empty( $breadcrumb['url'] ) ) {
16✔
120
                        $crumb['item'] = $breadcrumb['url'];
10✔
121
                }
122

123
                return $crumb;
16✔
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 ) {
16✔
136
                unset( $breadcrumb['url'] );
16✔
137

138
                return $breadcrumb;
16✔
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 ) {
20✔
152
                // A breadcrumb is broken if it is not an array.
153
                if ( ! \is_array( $breadcrumb ) ) {
20✔
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 ) ) {
20✔
159
                        return true;
4✔
160
                }
161

162
                return false;
20✔
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 ) {
18✔
173
                return empty( $breadcrumb['hide_in_schema'] );
18✔
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
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc