Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
| Total | |
0.00% |
0 / 127 |
|
0.00% |
0 / 6 |
CRAP | |
0.00% |
0 / 1 |
| Jetpack_SEO | |
0.00% |
0 / 127 |
|
0.00% |
0 / 6 |
1806 | |
0.00% |
0 / 1 |
| __construct | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| init | |
0.00% |
0 / 10 |
|
0.00% |
0 / 1 |
12 | |||
| add_custom_field_post_type_meta | |
0.00% |
0 / 13 |
|
0.00% |
0 / 1 |
12 | |||
| get_authors | |
0.00% |
0 / 8 |
|
0.00% |
0 / 1 |
12 | |||
| set_custom_og_tags | |
0.00% |
0 / 14 |
|
0.00% |
0 / 1 |
72 | |||
| meta_tags | |
0.00% |
0 / 81 |
|
0.00% |
0 / 1 |
600 | |||
| 1 | <?php |
| 2 | /** |
| 3 | * Main class file for the SEO Tools module. |
| 4 | * |
| 5 | * @package automattic/jetpack |
| 6 | */ |
| 7 | |
| 8 | /** |
| 9 | * An SEO expert walks into a bar, bars, pub, public house, Irish pub, drinks, beer, wine, liquor, Grey Goose, Cristal... |
| 10 | * |
| 11 | * @phan-constructor-used-for-side-effects |
| 12 | */ |
| 13 | class Jetpack_SEO { |
| 14 | /** |
| 15 | * Constructor. |
| 16 | */ |
| 17 | public function __construct() { |
| 18 | add_action( 'init', array( $this, 'init' ) ); |
| 19 | } |
| 20 | |
| 21 | /** |
| 22 | * Initialization method for Jetpack_SEO. |
| 23 | */ |
| 24 | public function init() { |
| 25 | /** |
| 26 | * Can be used to prevent SEO tools from inserting custom meta tags. |
| 27 | * |
| 28 | * @module seo-tools |
| 29 | * |
| 30 | * @since 4.4.0 |
| 31 | * |
| 32 | * @param bool true Should Jetpack's SEO Meta Tags be enabled. Defaults to true. |
| 33 | */ |
| 34 | if ( apply_filters( 'jetpack_seo_meta_tags_enabled', true ) ) { |
| 35 | add_action( 'wp_head', array( $this, 'meta_tags' ) ); |
| 36 | |
| 37 | // Add support for editing page excerpts in pages, regardless of theme support. |
| 38 | add_post_type_support( 'page', 'excerpt' ); |
| 39 | } |
| 40 | |
| 41 | /** |
| 42 | * Can be used to prevent SEO tools from modifying site titles. |
| 43 | * |
| 44 | * @module seo-tools |
| 45 | * |
| 46 | * @since 4.4.0 |
| 47 | * |
| 48 | * @param bool true Should Jetpack SEO modify site titles. Defaults to true. |
| 49 | */ |
| 50 | if ( apply_filters( 'jetpack_seo_custom_titles', true ) ) { |
| 51 | // Overwrite page title with custom SEO meta title for themes that support title-tag. |
| 52 | add_filter( 'pre_get_document_title', array( 'Jetpack_SEO_Titles', 'get_custom_title' ) ); |
| 53 | |
| 54 | // Add overwrite support for themes that don't support title-tag. |
| 55 | add_filter( 'wp_title', array( 'Jetpack_SEO_Titles', 'get_custom_title' ) ); |
| 56 | } |
| 57 | |
| 58 | add_filter( 'jetpack_open_graph_tags', array( $this, 'set_custom_og_tags' ) ); |
| 59 | Jetpack_SEO_Posts::register_post_meta(); |
| 60 | // Exclude posts with 'jetpack_seo_noindex' set true from the Jetpack sitemap. |
| 61 | add_filter( 'jetpack_sitemap_skip_post', array( 'Jetpack_SEO_Posts', 'exclude_noindex_posts_from_jetpack_sitemap' ), 10, 2 ); |
| 62 | add_action( 'rest_api_init', array( $this, 'add_custom_field_post_type_meta' ) ); |
| 63 | } |
| 64 | |
| 65 | /** |
| 66 | * Add custom field meta to all public post types that don't already have it. |
| 67 | */ |
| 68 | public function add_custom_field_post_type_meta() { |
| 69 | /** |
| 70 | * Filter the list of post types for which custom fields support is added. |
| 71 | * |
| 72 | * This filter allows modification of the post types that will be processed |
| 73 | * to add support for custom fields if they do not already support it. |
| 74 | * |
| 75 | * @since 14.2 |
| 76 | * |
| 77 | * @param array $post_types An array of post type names. |
| 78 | */ |
| 79 | $post_types = apply_filters( |
| 80 | 'jetpack_seo_custom_field_post_types', |
| 81 | get_post_types( |
| 82 | array( |
| 83 | 'public' => true, |
| 84 | 'show_ui' => true, |
| 85 | '_builtin' => false, |
| 86 | ) |
| 87 | ) |
| 88 | ); |
| 89 | |
| 90 | foreach ( $post_types as $post_type ) { |
| 91 | if ( ! post_type_supports( $post_type, 'custom-fields' ) ) { |
| 92 | add_post_type_support( $post_type, 'custom-fields' ); |
| 93 | } |
| 94 | } |
| 95 | } |
| 96 | |
| 97 | /** |
| 98 | * Helper method to fetch authors. |
| 99 | */ |
| 100 | private function get_authors() { |
| 101 | global $wp_query; |
| 102 | |
| 103 | $authors = array(); |
| 104 | |
| 105 | foreach ( $wp_query->posts as $post ) { |
| 106 | if ( ! $post instanceof WP_Post ) { |
| 107 | continue; |
| 108 | } |
| 109 | $authors[] = get_the_author_meta( 'display_name', (int) $post->post_author ); |
| 110 | } |
| 111 | |
| 112 | $authors = array_unique( $authors ); |
| 113 | |
| 114 | return $authors; |
| 115 | } |
| 116 | |
| 117 | /** |
| 118 | * Constructs open graph tag data. |
| 119 | * |
| 120 | * @param array $tags Array of tag data. |
| 121 | * @return array of tag data. |
| 122 | */ |
| 123 | public function set_custom_og_tags( $tags ) { |
| 124 | $custom_title = Jetpack_SEO_Titles::get_custom_title(); |
| 125 | |
| 126 | if ( ! empty( $custom_title ) ) { |
| 127 | $tags['og:title'] = $custom_title; |
| 128 | } |
| 129 | |
| 130 | $post_custom_description = Jetpack_SEO_Posts::get_post_custom_description( get_post() ); |
| 131 | $front_page_meta = Jetpack_SEO_Utils::get_front_page_meta_description(); |
| 132 | |
| 133 | if ( class_exists( 'woocommerce' ) && is_shop() ) { |
| 134 | $shop_page_id = get_option( 'woocommerce_shop_page_id' ); |
| 135 | if ( $shop_page_id ) { |
| 136 | $post_custom_description = Jetpack_SEO_Posts::get_post_custom_description( get_post( $shop_page_id ) ); |
| 137 | } |
| 138 | } |
| 139 | |
| 140 | if ( is_front_page() && ! empty( $front_page_meta ) ) { |
| 141 | $tags['og:description'] = $front_page_meta; |
| 142 | } elseif ( ! empty( $post_custom_description ) ) { |
| 143 | $tags['og:description'] = $post_custom_description; |
| 144 | } |
| 145 | |
| 146 | return $tags; |
| 147 | } |
| 148 | |
| 149 | /** |
| 150 | * Outputs Jetpack's SEO <meta> tags. |
| 151 | */ |
| 152 | public function meta_tags() { |
| 153 | global $wp_query; |
| 154 | |
| 155 | $post_count = is_countable( $wp_query->posts ) ? count( $wp_query->posts ) : 0; |
| 156 | $period = ''; |
| 157 | $template = ''; |
| 158 | $meta = array(); |
| 159 | |
| 160 | /** |
| 161 | * Can be used to specify a list of themes that set their own meta tags. |
| 162 | * |
| 163 | * If current site is using one of the themes listed as conflicting, inserting Jetpack SEO |
| 164 | * meta tags will be prevented. |
| 165 | * |
| 166 | * @module seo-tools |
| 167 | * |
| 168 | * @since 4.4.0 |
| 169 | * |
| 170 | * @param array List of conflicted theme names. Defaults to empty array. |
| 171 | */ |
| 172 | $conflicted_themes = apply_filters( 'jetpack_seo_meta_tags_conflicted_themes', array() ); |
| 173 | |
| 174 | if ( isset( $conflicted_themes[ get_option( 'template' ) ] ) ) { |
| 175 | return; |
| 176 | } |
| 177 | |
| 178 | $front_page_meta = Jetpack_SEO_Utils::get_front_page_meta_description(); |
| 179 | $description = $front_page_meta ? $front_page_meta : get_bloginfo( 'description' ); |
| 180 | $meta['description'] = trim( $description ); |
| 181 | |
| 182 | // Try to target things if we're on a "specific" page of any kind. |
| 183 | if ( is_singular() ) { |
| 184 | if ( ! ( is_front_page() && Jetpack_SEO_Utils::get_front_page_meta_description() ) ) { |
| 185 | $description = Jetpack_SEO_Posts::get_post_description( get_post() ); |
| 186 | |
| 187 | if ( $description ) { |
| 188 | $description = wp_trim_words( |
| 189 | strip_shortcodes( |
| 190 | wp_strip_all_tags( $description, true ) |
| 191 | ) |
| 192 | ); |
| 193 | $meta['description'] = $description; |
| 194 | } |
| 195 | } |
| 196 | } elseif ( is_author() ) { |
| 197 | $obj = get_queried_object(); |
| 198 | |
| 199 | $meta['description'] = sprintf( |
| 200 | /* translators: first property is an user's display name, the second is the site's title. */ |
| 201 | _x( 'Read all of the posts by %1$s on %2$s', 'Read all of the posts by Author Name on Blog Title', 'jetpack' ), |
| 202 | isset( $obj->display_name ) ? $obj->display_name : __( 'the author', 'jetpack' ), |
| 203 | get_bloginfo( 'title' ) |
| 204 | ); |
| 205 | } elseif ( is_tag() || is_category() || is_tax() ) { |
| 206 | $obj = get_queried_object(); |
| 207 | $description = ''; |
| 208 | |
| 209 | if ( isset( $obj->term_id ) && isset( $obj->taxonomy ) ) { |
| 210 | $description = get_term_field( 'description', $obj->term_id, $obj->taxonomy, 'raw' ); |
| 211 | } |
| 212 | |
| 213 | if ( ! is_wp_error( $description ) && $description ) { |
| 214 | $meta['description'] = wp_trim_words( $description ); |
| 215 | } else { |
| 216 | $authors = $this->get_authors(); |
| 217 | |
| 218 | $meta['description'] = wp_sprintf( |
| 219 | /* translators: %1$s: A post category. %2$l: Post authors. */ |
| 220 | _x( 'Posts about %1$s written by %2$l', 'Posts about Category written by John and Bob', 'jetpack' ), |
| 221 | single_term_title( '', false ), |
| 222 | $authors |
| 223 | ); |
| 224 | } |
| 225 | } elseif ( is_date() ) { |
| 226 | if ( is_year() ) { |
| 227 | $period = get_query_var( 'year' ); |
| 228 | |
| 229 | /* translators: %1$s: Number of posts published. %2$l: Post author. %3$s: A year date. */ |
| 230 | $template = _nx( |
| 231 | '%1$s post published by %2$l in the year %3$s', // Singular. |
| 232 | '%1$s posts published by %2$l in the year %3$s', // Plural. |
| 233 | $post_count, // Number. |
| 234 | '10 posts published by John in the year 2012', // Context. |
| 235 | 'jetpack' |
| 236 | ); |
| 237 | } elseif ( is_month() ) { |
| 238 | $period = gmdate( 'F Y', mktime( 0, 0, 0, get_query_var( 'monthnum' ), 1, get_query_var( 'year' ) ) ); |
| 239 | |
| 240 | /* translators: %1$s: Number of posts published. %2$l: Post author. %3$s: A month/year date. */ |
| 241 | $template = _nx( |
| 242 | '%1$s post published by %2$l during %3$s', // Singular. |
| 243 | '%1$s posts published by %2$l during %3$s', // Plural. |
| 244 | $post_count, // Number. |
| 245 | '10 posts publishes by John during May 2012', // Context. |
| 246 | 'jetpack' |
| 247 | ); |
| 248 | } elseif ( is_day() ) { |
| 249 | $period = gmdate( |
| 250 | 'F j, Y', |
| 251 | mktime( 0, 0, 0, get_query_var( 'monthnum' ), get_query_var( 'day' ), get_query_var( 'year' ) ) |
| 252 | ); |
| 253 | |
| 254 | /* translators: %1$s: Number of posts published. %2$l: Post author. %3$s: A month/day/year date. */ |
| 255 | $template = _nx( |
| 256 | '%1$s post published by %2$l on %3$s', // Singular. |
| 257 | '%1$s posts published by %2$l on %3$s', // Plural. |
| 258 | $post_count, // Number. |
| 259 | '10 posts published by John on May 30, 2012', // Context. |
| 260 | 'jetpack' |
| 261 | ); |
| 262 | } |
| 263 | |
| 264 | $authors = $this->get_authors(); |
| 265 | $meta['description'] = wp_sprintf( $template, $post_count, $authors, $period ); |
| 266 | } |
| 267 | |
| 268 | $mark_as_noindex = Jetpack_SEO_Posts::get_post_noindex_setting( get_post() ); |
| 269 | if ( $mark_as_noindex ) { |
| 270 | $meta['robots'] = 'noindex'; |
| 271 | } |
| 272 | |
| 273 | /** |
| 274 | * Can be used to edit the default SEO tools meta tags. |
| 275 | * |
| 276 | * @module seo-tools |
| 277 | * |
| 278 | * @since 4.4.0 |
| 279 | * |
| 280 | * @param array Array that consists of meta name and meta content pairs. |
| 281 | */ |
| 282 | $meta = apply_filters( 'jetpack_seo_meta_tags', $meta ); |
| 283 | |
| 284 | // Output them. |
| 285 | foreach ( $meta as $name => $content ) { |
| 286 | if ( ! empty( $content ) ) { |
| 287 | echo '<meta name="' . esc_attr( $name ) . '" content="' . esc_attr( $content ) . '" />' . "\n"; |
| 288 | } |
| 289 | } |
| 290 | } |
| 291 | } |