| 1 |
<?php |
| 2 |
/** |
| 3 |
* UI: Metadata renderer class. |
| 4 |
* |
| 5 |
* @package Parsely |
| 6 |
* @since 3.3.0 |
| 7 |
*/ |
| 8 |
|
| 9 |
declare(strict_types=1); |
| 10 |
|
| 11 |
namespace Parsely\UI; |
| 12 |
|
| 13 |
use Parsely\Metadata; |
| 14 |
use Parsely\Parsely; |
| 15 |
use WP_Post; |
| 16 |
|
| 17 |
/** |
| 18 |
* Renders metadata in the WordPress front-end header. |
| 19 |
* |
| 20 |
* @since 3.3.0 |
| 21 |
*/ |
| 22 |
final class Metadata_Renderer { |
| 23 |
/** |
| 24 |
* Instance of Parsely class. |
| 25 |
* |
| 26 |
* @var Parsely |
| 27 |
*/ |
| 28 |
private $parsely; |
| 29 |
|
| 30 |
/** |
| 31 |
* Constructor. |
| 32 |
* |
| 33 |
* @param Parsely $parsely Instance of Parsely class. |
| 34 |
*/ |
| 35 |
public function __construct( Parsely $parsely ) { |
| 36 |
$this->parsely = $parsely; |
| 37 |
} |
| 38 |
|
| 39 |
/** |
| 40 |
* Registers metadata actions. |
| 41 |
* |
| 42 |
* @since 3.3.0 |
| 43 |
*/ |
| 44 |
public function run(): void { |
| 45 |
/** |
| 46 |
* Filter whether the Parse.ly meta tags should be inserted in the page. |
| 47 |
* |
| 48 |
* By default, the tags are inserted. |
| 49 |
* |
| 50 |
* @since 3.0.0 |
| 51 |
* |
| 52 |
* @param bool $insert_metadata True to insert the metadata, false otherwise. |
| 53 |
*/ |
| 54 |
if ( apply_filters( 'wp_parsely_should_insert_metadata', true ) ) { |
| 55 |
add_action( 'wp_head', array( $this, 'render_metadata_on_head' ) ); |
| 56 |
} |
| 57 |
} |
| 58 |
|
| 59 |
/** |
| 60 |
* Renders metadata on site's head using the format from the site's options. |
| 61 |
* |
| 62 |
* @since 3.3.0 |
| 63 |
*/ |
| 64 |
public function render_metadata_on_head(): void { |
| 65 |
$parsely_options = $this->parsely->get_options(); |
| 66 |
$this->render_metadata( $parsely_options['meta_type'] ); |
| 67 |
} |
| 68 |
|
| 69 |
/** |
| 70 |
* Inserts the code for the meta parameter within the head tag. |
| 71 |
* |
| 72 |
* @since 3.2.0 |
| 73 |
* @since 3.3.0 Moved from `Parsely` class to `Metadata_Header`. |
| 74 |
* |
| 75 |
* @param string $meta_type `json_ld` or `repeated_metas`. |
| 76 |
*/ |
| 77 |
public function render_metadata( string $meta_type ): void { |
| 78 |
$parsely_options = $this->parsely->get_options(); |
| 79 |
|
| 80 |
if ( |
| 81 |
$this->parsely->site_id_is_missing() || |
| 82 |
|
| 83 |
// Chosen not to track logged-in users. |
| 84 |
( ! $parsely_options['track_authenticated_users'] && $this->parsely->is_blog_member_logged_in() ) || |
| 85 |
|
| 86 |
// 404 pages are not tracked. |
| 87 |
is_404() || |
| 88 |
|
| 89 |
// Search pages are not tracked. |
| 90 |
is_search() |
| 91 |
) { |
| 92 |
return; |
| 93 |
} |
| 94 |
|
| 95 |
global $post; |
| 96 |
|
| 97 |
// We can't construct the metadata without a valid post object. |
| 98 |
$parsed_post = get_post( $post ); |
| 99 |
if ( ! $parsed_post instanceof WP_Post ) { |
| 100 |
return; |
| 101 |
} |
| 102 |
|
| 103 |
$metadata = ( new Metadata( $this->parsely ) )->construct_metadata( $parsed_post ); |
| 104 |
|
| 105 |
// Something went wrong - abort. |
| 106 |
if ( ! isset( $metadata['headline'] ) ) { |
| 107 |
return; |
| 108 |
} |
| 109 |
|
| 110 |
// Insert JSON-LD or repeated metas. |
| 111 |
if ( 'json_ld' === $meta_type ) { |
| 112 |
echo '<script type="application/ld+json" class="wp-parsely-metadata">' . wp_json_encode( $metadata ) . '</script>'; |
| 113 |
} else { |
| 114 |
// Assume `meta_type` is `repeated_metas`. |
| 115 |
$parsely_post_type = $this->parsely->convert_jsonld_to_parsely_type( $metadata['@type'] ?? '' ); |
| 116 |
$tags = ''; |
| 117 |
|
| 118 |
// @phpstan-ignore-next-line |
| 119 |
if ( isset( $metadata['keywords'] ) && is_array( $metadata['keywords'] ) ) { |
| 120 |
$tags = implode( ',', $metadata['keywords'] ); |
| 121 |
} |
| 122 |
|
| 123 |
$parsely_metas = array( |
| 124 |
'title' => $metadata['headline'], |
| 125 |
'link' => $metadata['url'] ?? '', |
| 126 |
'type' => $parsely_post_type, |
| 127 |
'image-url' => $metadata['thumbnailUrl'] ?? '', |
| 128 |
'pub-date' => $metadata['datePublished'] ?? '', |
| 129 |
'section' => $metadata['articleSection'] ?? '', |
| 130 |
'tags' => $tags, |
| 131 |
); |
| 132 |
$parsely_metas = array_filter( $parsely_metas, array( $this, 'filter_empty_and_not_string_from_array' ) ); |
| 133 |
|
| 134 |
// Output metas. |
| 135 |
foreach ( $parsely_metas as $parsely_meta_key => $parsely_meta_val ) { |
| 136 |
printf( |
| 137 |
'<meta name="%s" content="%s" />%s', |
| 138 |
esc_attr( 'parsely-' . $parsely_meta_key ), |
| 139 |
esc_attr( $parsely_meta_val ), |
| 140 |
"\n" |
| 141 |
); |
| 142 |
} |
| 143 |
|
| 144 |
// Output author metas (they can be multiple). |
| 145 |
if ( isset( $metadata['author'] ) ) { |
| 146 |
$parsely_page_authors = wp_list_pluck( $metadata['author'], 'name' ); |
| 147 |
$parsely_page_authors = array_filter( $parsely_page_authors, array( $this, 'filter_empty_and_not_string_from_array' ) ); |
| 148 |
|
| 149 |
foreach ( $parsely_page_authors as $parsely_author_name ) { |
| 150 |
printf( |
| 151 |
'<meta name="parsely-author" content="%s" />%s', |
| 152 |
esc_attr( $parsely_author_name ), |
| 153 |
"\n" |
| 154 |
); |
| 155 |
} |
| 156 |
} |
| 157 |
} |
| 158 |
|
| 159 |
// Add any custom metadata. |
| 160 |
if ( isset( $metadata['custom_metadata'] ) ) { |
| 161 |
echo '<meta name="parsely-metadata" content="' . esc_attr( $metadata['custom_metadata'] ) . '" />'; |
| 162 |
} |
| 163 |
} |
| 164 |
|
| 165 |
/** |
| 166 |
* Function to be used in `array_filter` to clean up repeated metas. |
| 167 |
* |
| 168 |
* @since 2.6.0 |
| 169 |
* @since 3.3.0 Moved from `Parsely` class to `Metadata_Header`. |
| 170 |
* |
| 171 |
* @param mixed $value Value to filter from the array. |
| 172 |
* @return bool True if the variable is not empty, and it's a string. |
| 173 |
*/ |
| 174 |
private function filter_empty_and_not_string_from_array( $value ): bool { |
| 175 |
return is_string( $value ) && '' !== $value; |
| 176 |
} |
| 177 |
} |
| 178 |
|