resolver = $resolver; $this->settings = $settings; $this->graph = $graph; $this->trail = $trail; } /** * Registers hooks. */ public function register() { add_filter( 'pre_get_document_title', array( $this, 'filter_title' ), 20 ); add_filter( 'wp_robots', array( $this, 'filter_robots' ), 20 ); remove_action( 'wp_head', 'rel_canonical' ); add_action( 'wp_head', array( $this, 'print_tags' ), 1 ); } /** * Supplies the through core's title-tag support. * * @param string $title Title from earlier filters. * @return string Escaped title. */ public function filter_title( $title ) { $data = $this->resolver->for_request(); if ( ! $data || '' === $data['title'] ) { return $title; } // Core does not escape values returned from this filter. return esc_html( $data['title'] ); } /** * Adds noindex/nofollow through core's wp_robots API so there is one robots tag. * * @param array $robots Directives. * @return array */ public function filter_robots( $robots ) { $data = $this->resolver->for_request(); if ( ! $data ) { return $robots; } if ( $data['noindex'] ) { $robots['noindex'] = true; } if ( $data['nofollow'] ) { $robots['nofollow'] = true; } return $robots; } /** * Prints description, canonical, Open Graph and Twitter tags. */ public function print_tags() { $data = $this->resolver->for_request(); if ( ! $data ) { // Unmanaged view (e.g. an attachment page): keep core's canonical. if ( is_singular() ) { rel_canonical(); } return; } echo "\n<!-- Orbitstem SEO -->\n"; foreach ( $this->tags( $data ) as $tag ) { echo $tag . "\n"; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- built from escaped parts in tags(). } if ( $this->settings->get( 'schema_enabled' ) ) { $json = Graph::to_json( $this->graph->build( $data, $this->trail->for_request() ) ); echo '<script type="application/ld+json" class="orbitstem-seo-schema">' . $json . "</script>\n"; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- JSON encoded with JSON_HEX_TAG. } echo "<!-- / Orbitstem SEO -->\n\n"; } /** * Builds escaped tag strings. * * @param array $data Resolved values. * @return string[] */ public function tags( array $data ) { $tags = array(); $canonical = $data['noindex'] ? '' : $data['canonical']; if ( '' !== $data['description'] ) { $tags[] = $this->meta( 'name', 'description', $data['description'] ); } if ( '' !== $canonical ) { $tags[] = '<link rel="canonical" href="' . esc_url( $canonical ) . '" />'; } $title = '' !== $data['title'] ? $data['title'] : wp_strip_all_tags( wp_get_document_title() ); $og_title = ! empty( $data['og_title'] ) ? $data['og_title'] : $title; $og_desc = ! empty( $data['og_desc'] ) ? $data['og_desc'] : $data['description']; $tags[] = $this->meta( 'property', 'og:locale', get_locale() ); $tags[] = $this->meta( 'property', 'og:type', $data['og_type'] ); $tags[] = $this->meta( 'property', 'og:title', $og_title ); if ( '' !== $og_desc ) { $tags[] = $this->meta( 'property', 'og:description', $og_desc ); } if ( '' !== $canonical ) { $tags[] = '<meta property="og:url" content="' . esc_url( $canonical ) . '" />'; } $tags[] = $this->meta( 'property', 'og:site_name', wp_strip_all_tags( get_bloginfo( 'name' ) ) ); if ( '' !== $data['image'] ) { $tags[] = '<meta property="og:image" content="' . esc_url( $data['image'] ) . '" />'; } if ( '' !== $data['published'] ) { $tags[] = $this->meta( 'property', 'article:published_time', $data['published'] ); $tags[] = $this->meta( 'property', 'article:modified_time', $data['modified'] ); } $tags[] = $this->meta( 'name', 'twitter:card', '' !== $data['image'] ? 'summary_large_image' : 'summary' ); $site = (string) $this->settings->get( 'twitter_site' ); if ( '' !== $site ) { $tags[] = $this->meta( 'name', 'twitter:site', '@' . $site ); } /** * Filters the escaped head tags before printing. * * @param string[] $tags Tag strings. * @param array $data Resolved values. */ return apply_filters( 'orbitstem_seo_head_tags', $tags, $data ); } /** * One escaped meta tag. * * @param string $attr 'name' or 'property'. * @param string $key Attribute value. * @param string $value Content. * @return string */ private function meta( $attr, $key, $value ) { return sprintf( '<meta %s="%s" content="%s" />', $attr, esc_attr( $key ), esc_attr( $value ) ); } }