| @@ -1,8 +1,9 @@ | ||
| 1 | 1 | <?php |
| 2 | 2 | |
| 3 | 3 | namespace Yoast\WP\SEO\Generators\Schema; |
| 4 | 4 | |
| 5 | +use WP_User; | |
| 5 | 6 | use Yoast\WP\SEO\Config\Schema_IDs; |
| 6 | 7 | |
| 7 | 8 | /** |
| 8 | 9 | * Returns schema Article data. |
| @@ -18,13 +19,8 @@ | ||
| 18 | 19 | if ( $this->context->indexable->object_type !== 'post' ) { |
| 19 | 20 | return false; |
| 20 | 21 | } |
| 21 | 22 | |
| 22 | - // If we cannot output a publisher, we shouldn't output an Article. | |
| 23 | - if ( $this->context->site_represents === false ) { | |
| 24 | - return false; | |
| 25 | - } | |
| 26 | - | |
| 27 | 23 | // If we cannot output an author, we shouldn't output an Article. |
| 28 | 24 | if ( ! $this->helpers->schema->article->is_author_supported( $this->context->indexable->object_sub_type ) ) { |
| 29 | 25 | return false; |
| 30 | 26 | } |
| @@ -29,10 +25,9 @@ | ||
| 29 | 25 | return false; |
| 30 | 26 | } |
| 31 | 27 | |
| 32 | 28 | if ( $this->context->schema_article_type !== 'None' ) { |
| 33 | - $this->context->main_schema_id = $this->context->canonical . Schema_IDs::ARTICLE_HASH; | |
| 34 | - | |
| 29 | + $this->context->has_article = true; | |
| 35 | 30 | return true; |
| 36 | 31 | } |
| 37 | 32 | |
| 38 | 33 | return false; |
| @@ -43,20 +38,28 @@ | ||
| 43 | 38 | * |
| 44 | 39 | * @return array Article data. |
| 45 | 40 | */ |
| 46 | 41 | public function generate() { |
| 47 | - $data = [ | |
| 42 | + $author = \get_userdata( $this->context->post->post_author ); | |
| 43 | + $data = [ | |
| 48 | 44 | '@type' => $this->context->schema_article_type, |
| 49 | 45 | '@id' => $this->context->canonical . Schema_IDs::ARTICLE_HASH, |
| 50 | - 'isPartOf' => [ '@id' => $this->context->canonical . Schema_IDs::WEBPAGE_HASH ], | |
| 51 | - 'author' => [ '@id' => $this->helpers->schema->id->get_user_schema_id( $this->context->post->post_author, $this->context ) ], | |
| 46 | + 'isPartOf' => [ '@id' => $this->context->main_schema_id ], | |
| 47 | + 'author' => [ | |
| 48 | + 'name' => ( $author instanceof WP_User ) ? $this->helpers->schema->html->smart_strip_tags( $author->display_name ) : '', | |
| 49 | + '@id' => $this->helpers->schema->id->get_user_schema_id( $this->context->post->post_author, $this->context ), | |
| 50 | + ], | |
| 52 | 51 | 'headline' => $this->helpers->schema->html->smart_strip_tags( $this->helpers->post->get_post_title_with_fallback( $this->context->id ) ), |
| 53 | 52 | 'datePublished' => $this->helpers->date->format( $this->context->post->post_date_gmt ), |
| 54 | - 'dateModified' => $this->helpers->date->format( $this->context->post->post_modified_gmt ), | |
| 55 | - 'mainEntityOfPage' => [ '@id' => $this->context->canonical . Schema_IDs::WEBPAGE_HASH ], | |
| 56 | - 'wordCount' => $this->word_count( $this->context->post->post_content, $this->context->post->post_title ), | |
| 57 | 53 | ]; |
| 58 | 54 | |
| 55 | + if ( \strtotime( $this->context->post->post_modified_gmt ) > \strtotime( $this->context->post->post_date_gmt ) ) { | |
| 56 | + $data['dateModified'] = $this->helpers->date->format( $this->context->post->post_modified_gmt ); | |
| 57 | + } | |
| 58 | + | |
| 59 | + $data['mainEntityOfPage'] = [ '@id' => $this->context->main_schema_id ]; | |
| 60 | + $data['wordCount'] = $this->word_count( $this->context->post->post_content, $this->context->post->post_title ); | |
| 61 | + | |
| 59 | 62 | if ( $this->context->post->comment_status === 'open' ) { |
| 60 | 63 | $data['commentCount'] = \intval( $this->context->post->comment_count, 10 ); |
| 61 | 64 | } |
| 62 | 65 | |
| @@ -86,9 +89,9 @@ | ||
| 86 | 89 | private function add_keywords( $data ) { |
| 87 | 90 | /** |
| 88 | 91 | * Filter: 'wpseo_schema_article_keywords_taxonomy' - Allow changing the taxonomy used to assign keywords to a post type Article data. |
| 89 | 92 | * |
| 90 | - * @api string $taxonomy The chosen taxonomy. | |
| 93 | + * @param string $taxonomy The chosen taxonomy. | |
| 91 | 94 | */ |
| 92 | 95 | $taxonomy = \apply_filters( 'wpseo_schema_article_keywords_taxonomy', 'post_tag' ); |
| 93 | 96 | |
| 94 | 97 | return $this->add_terms( $data, 'keywords', $taxonomy ); |
| @@ -104,9 +107,9 @@ | ||
| 104 | 107 | private function add_sections( $data ) { |
| 105 | 108 | /** |
| 106 | 109 | * Filter: 'wpseo_schema_article_sections_taxonomy' - Allow changing the taxonomy used to assign keywords to a post type Article data. |
| 107 | 110 | * |
| 108 | - * @api string $taxonomy The chosen taxonomy. | |
| 111 | + * @param string $taxonomy The chosen taxonomy. | |
| 109 | 112 | */ |
| 110 | 113 | $taxonomy = \apply_filters( 'wpseo_schema_article_sections_taxonomy', 'category' ); |
| 111 | 114 | |
| 112 | 115 | return $this->add_terms( $data, 'articleSection', $taxonomy ); |
| @@ -127,9 +130,9 @@ | ||
| 127 | 130 | if ( ! \is_array( $terms ) ) { |
| 128 | 131 | return $data; |
| 129 | 132 | } |
| 130 | 133 | |
| 131 | - $callback = static function( $term ) { | |
| 134 | + $callback = static function ( $term ) { | |
| 132 | 135 | // We are using the WordPress internal translation. |
| 133 | 136 | return $term->name !== \__( 'Uncategorized', 'default' ); |
| 134 | 137 | }; |
| 135 | 138 | $terms = \array_filter( $terms, $callback ); |
| @@ -171,9 +174,9 @@ | ||
| 171 | 174 | private function add_potential_action( $data ) { |
| 172 | 175 | /** |
| 173 | 176 | * Filter: 'wpseo_schema_article_potential_action_target' - Allows filtering of the schema Article potentialAction target. |
| 174 | 177 | * |
| 175 | - * @api array $targets The URLs for the Article potentialAction target. | |
| 178 | + * @param array $targets The URLs for the Article potentialAction target. | |
| 176 | 179 | */ |
| 177 | 180 | $targets = \apply_filters( 'wpseo_schema_article_potential_action_target', [ $this->context->canonical . '#respond' ] ); |
| 178 | 181 | |
| 179 | 182 | $data['potentialAction'][] = [ |
| @@ -199,10 +202,32 @@ | ||
| 199 | 202 | |
| 200 | 203 | // Strip pre/code blocks and their content. |
| 201 | 204 | $post_content = \preg_replace( '@<(pre|code)[^>]*?>.*?</\\1>@si', '', $post_content ); |
| 202 | 205 | |
| 206 | + // Add space between tags that don't have it. | |
| 207 | + $post_content = \preg_replace( '@><@', '> <', $post_content ); | |
| 208 | + | |
| 203 | 209 | // Strips all other tags. |
| 204 | 210 | $post_content = \wp_strip_all_tags( $post_content ); |
| 205 | 211 | |
| 206 | - return \str_word_count( $post_content, 0 ); | |
| 212 | + $characters = ''; | |
| 213 | + | |
| 214 | + if ( \preg_match( '@[а-я]@ui', $post_content ) ) { | |
| 215 | + // Correct counting of the number of words in the Russian and Ukrainian languages. | |
| 216 | + $alphabet = [ | |
| 217 | + 'ru' => 'абвгдеёжзийклмнопрстуфхцчшщъыьэюя', | |
| 218 | + 'ua' => 'абвгґдеєжзиіїйклмнопрстуфхцчшщьюя', | |
| 219 | + ]; | |
| 220 | + | |
| 221 | + $characters = \implode( '', $alphabet ); | |
| 222 | + $characters = \preg_split( '//u', $characters, -1, \PREG_SPLIT_NO_EMPTY ); | |
| 223 | + $characters = \array_unique( $characters ); | |
| 224 | + $characters = \implode( '', $characters ); | |
| 225 | + $characters .= \mb_strtoupper( $characters ); | |
| 226 | + } | |
| 227 | + | |
| 228 | + // Remove characters from HTML entities. | |
| 229 | + $post_content = \preg_replace( '@&[a-z0-9]+;@i', ' ', \htmlentities( $post_content ) ); | |
| 230 | + | |
| 231 | + return \str_word_count( $post_content, 0, $characters ); | |
| 207 | 232 | } |
| 208 | 233 | } |