class-schema-breadcrumb.php 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. <?php
  2. /**
  3. * WPSEO plugin file.
  4. *
  5. * @package WPSEO\Frontend\Schema
  6. */
  7. /**
  8. * Returns schema Breadcrumb data.
  9. *
  10. * @since 10.2
  11. */
  12. class WPSEO_Schema_Breadcrumb implements WPSEO_Graph_Piece {
  13. /**
  14. * A value object with context variables.
  15. *
  16. * @var WPSEO_Schema_Context
  17. */
  18. private $context;
  19. /**
  20. * Current position in the List.
  21. *
  22. * @var int
  23. */
  24. private $index;
  25. /**
  26. * WPSEO_Schema_Breadcrumb constructor.
  27. *
  28. * @param WPSEO_Schema_Context $context A value object with context variables.
  29. */
  30. public function __construct( WPSEO_Schema_Context $context ) {
  31. $this->context = $context;
  32. }
  33. /**
  34. * Determine if we should add a breadcrumb attribute.
  35. *
  36. * @return bool
  37. */
  38. public function is_needed() {
  39. if ( is_404() ) {
  40. return false;
  41. }
  42. if ( is_front_page() ) {
  43. return false;
  44. }
  45. if ( $this->context->breadcrumbs_enabled ) {
  46. return true;
  47. }
  48. return false;
  49. }
  50. /**
  51. * Returns Schema breadcrumb data to allow recognition of page's position in the site hierarchy.
  52. *
  53. * @link https://developers.google.com/search/docs/data-types/breadcrumb
  54. *
  55. * @return bool|array Array on success, false on failure.
  56. */
  57. public function generate() {
  58. $breadcrumbs_instance = WPSEO_Breadcrumbs::get_instance();
  59. $breadcrumbs = $breadcrumbs_instance->get_links();
  60. $broken = false;
  61. $list_elements = [];
  62. foreach ( $breadcrumbs as $index => $breadcrumb ) {
  63. if ( ! empty( $breadcrumb['hide_in_schema'] ) ) {
  64. continue;
  65. }
  66. if ( ! array_key_exists( 'url', $breadcrumb ) || ! array_key_exists( 'text', $breadcrumb ) ) {
  67. $broken = true;
  68. break;
  69. }
  70. $list_elements[] = $this->add_breadcrumb( $index, $breadcrumb );
  71. $this->index = $index;
  72. }
  73. if ( is_paged() ) {
  74. $list_elements[] = $this->add_paginated_state();
  75. }
  76. $data = [
  77. '@type' => 'BreadcrumbList',
  78. '@id' => $this->context->canonical . WPSEO_Schema_IDs::BREADCRUMB_HASH,
  79. 'itemListElement' => $list_elements,
  80. ];
  81. // Only output if JSON is correctly formatted.
  82. if ( ! $broken ) {
  83. return $data;
  84. }
  85. return false;
  86. }
  87. /**
  88. * Returns a breadcrumb array.
  89. *
  90. * @param int $index The position in the list.
  91. * @param array $breadcrumb The breadcrumb array.
  92. *
  93. * @return array A breadcrumb listItem.
  94. */
  95. private function add_breadcrumb( $index, $breadcrumb ) {
  96. if ( empty( $breadcrumb['url'] ) ) {
  97. if ( is_paged() ) {
  98. // Retrieve the un-paginated state of the current page.
  99. $breadcrumb['url'] = WPSEO_Frontend::get_instance()->canonical( false, true );
  100. }
  101. else {
  102. $breadcrumb['url'] = $this->context->canonical;
  103. }
  104. }
  105. if ( empty( $breadcrumb['text'] ) ) {
  106. $breadcrumb['url'] = $this->context->title;
  107. }
  108. return [
  109. '@type' => 'ListItem',
  110. 'position' => ( $index + 1 ),
  111. 'item' => [
  112. '@type' => 'WebPage',
  113. '@id' => $breadcrumb['url'],
  114. 'url' => $breadcrumb['url'], // For future proofing, we're trying to change the standard for this.
  115. 'name' => $breadcrumb['text'],
  116. ],
  117. ];
  118. }
  119. /**
  120. * Adds the paginated state to the breadcrumb array.
  121. *
  122. * @return array A breadcrumb listItem.
  123. */
  124. private function add_paginated_state() {
  125. $this->index++;
  126. return $this->add_breadcrumb(
  127. $this->index,
  128. [
  129. 'url' => $this->context->canonical,
  130. 'text' => $this->context->title,
  131. ]
  132. );
  133. }
  134. }