fV(0 6[Vѿ' R`V0  0 7V0 ' 8PV PA`V<V` MLV` pp NVp  V' 'qVp ' QƝV 6V ' 7Vp& Q`V 7V & 7Vp& QV 8PV PA`V<pV`*fV` pV* V%%qfV&0 6[Vg% R`V0  0 7V0 % 8PV PA`V<uV`%=PVP%PAPV`uPV %pA`V< Vp {\Vp + V$$qDVP'V$ 5PV PA`V< V`$> FVP$͞V ;V \V `+ V#$q V <V V  MLV N0\V#pPgVd@V `# ]V PPgVd`bV # ^V `PgVd@V " ]V pPgVd@V p"0 ]V0 `V<pV *fV @Vt!0p`؞V`PB VP <VP `Vp 0-Vp Vp  tV !@E[V|30! HRP֚V ! @V Pt`؞V`B V pt`V<0\V `p tV pE`؞VPB V `t V <V P2 V <V  tV xE[V RP֚V @V Pt`؞V`B Vpt`V< tVE`؞VPB V <V  tV0E tV@E`؞VPB`V@ @V@ `t VP <VP P2 V` <V` Vp \V ` +hV`@ s;V ``V .V` QV  eV 4\V +V  MLV p NV Vp0 QPV  QtV {\V `+V0 pV@*is changed. * * @param int $old_post_id The old post id. * @param int $new_post_id The new post id. */ public function disable_timestamp_for_previous_legal_page( $old_post_id, $new_post_id ) { if ( $old_post_id !== $new_post_id ) { \delete_post_meta( $old_post_id, '_yoast_wpseo_wordproof_timestamp' ); } } /** * Return the Yoast post meta key for the SDK to determine if the post should be timestamped. * * @param array $meta_keys The array containing meta keys that should be used. * @return array */ public function add_post_meta_key( $meta_keys ) { return [ $this->post_meta_key ]; } /** * Return an empty array to disable automatically timestamping selected post types. * * @param array $post_types The array containing post types that should be automatically timestamped. * @return array */ public function wordproof_timestamp_post_types( $post_types ) { return []; } /** * This filters hides the certificate if the Yoast post meta key is not set to true. * * @param bool $value If the certificate should be shown. * @param WP_Post $post The post object of the post for which to determine the certificate should be shown. * @return bool|null */ public function show_certificate( $value, $post ) { if ( ! $value ) { return $value; } if ( ! $this->wordproof->integration_is_active() ) { return false; } return \boolval( PostMetaHelper::get( $post->ID, $this->post_meta_key ) ); } /** * Adds the WordProof integration toggle to the array. * * @param array $fields The currently registered meta fields. * * @return array A new array with meta fields. */ public function add_meta_field( $fields ) { $fields['advanced']['wordproof_timestamp'] = [ 'type' => 'hidden', 'title' => '', 'default_value' => '', 'description' => '0', ]; return $fields; } /** * Enqueue the uikit script. * * @return void */ public function enqueue_assets() { if ( CertificateHelper::show() ) { $flat_version = $this->asset_manager->flatten_version( \WPSEO_VERSION ); /** * We are using the Admin asset manager to register and enqueue a file served for all visitors, * authenticated and unauthenticated users. */ $script = new WPSEO_Admin_Asset( [ 'name' => 'wordproof-uikit', 'src' => 'wordproof-uikit.js', 'version' => $flat_version, ] ); $this->asset_manager->register_script( $script ); $this->asset_manager->enqueue_script( 'wordproof-uikit' ); } } /** * Adds async to the wordproof-uikit script. * * @param string $tag The script tag for the enqueued script. * @param string $handle The script's registered handle. * @param string $src The script's source URL. * * @return string The script's tag. * * @phpcs:disable WordPress.WP.EnqueuedResources.NonEnqueuedScript */ public function add_async_to_script( $tag, $handle, $src ) { if ( $handle !== WPSEO_Admin_Asset_Manager::PREFIX . 'wordproof-uikit' ) { return $tag; } return ""; } } ߏhߏ>%@xߏxߏߏȏߏJlߏpߏߏ>1; @Mx ߏP/`ߏxߏߏ>FWߏeߏ vۏP5&|ߏߏߏߏ>`n 6xߏ),|ߏߏvۏ @5ߏߏ>wzvyߏ6ߏ`ߏwߏߏߏ>7xߏwߏߏ`ߏNХߏߏ>7xߏ Pߏ@8ߏ0{ߏߏߏ>vyߏ {ߏߏuߏ .h ߏߏ>xߏm0ߏߏXwߏȪߏߏ>8xߏwߏ ߏ uߏ:ߏЪߏH>xߏ@Ǐߏnߏ pyߏ ߏتߏ8ߏ> 9xߏ `yߏPߏפߏwߏߏજߏP?'wߏwߏ@ߏ`gߏ 0@ॐߏ誜ߏP?5G C`ߏ@ߏ ߏߏߏP?[]QߏP؊ߏ1ߏ5pxOߏPߏP?hxߏvuߏ=JߏP?yߏ was returned. if ( $graph_pieces !== false && \array_key_exists( '@type', $graph_pieces ) ) { $graph_pieces = [ $graph_pieces ]; } if ( ! \is_array( $graph_pieces ) ) { continue; } foreach ( $graph_pieces as $graph_piece ) { /** * Filter: 'wpseo_schema_' - Allows changing graph piece output. * This filter can be called with either an identifier or a block type (see `add_schema_blocks_graph_pieces()`). * * @api array $graph_piece The graph piece to filter. * * @param Meta_Tags_Context $context A value object with context variables. * @param Abstract_Schema_Piece $graph_piece_generator A value object with context variables. * @param Abstract_Schema_Piece[] $graph_piece_generators A value object with context variables. */ $graph_piece = \apply_filters( 'wpseo_schema_' . $identifier, $graph_piece, $context, $graph_piece_generator, $graph_piece_generators ); $graph_piece = $this->type_filter( $graph_piece, $identifier, $context, $graph_piece_generator, $graph_piece_generators ); $graph_piece = $this->validate_type( $graph_piece ); if ( \is_array( $graph_piece ) ) { $graph[] = $graph_piece; } } } /** * Filter: 'wpseo_schema_graph' - Allows changing graph output. * * @api array $graph The graph to filter. * * @param Meta_Tags_Context $context A value object with context variables. */ $graph = \apply_filters( 'wpseo_schema_graph', $graph, $context ); return $graph; } /** * Adds schema graph pieces from Gutenberg blocks on the current page to * the given schema graph. * * Think of blocks like the Yoast FAQ block or the How To block. * * @param array $graph The current schema graph. * @param Meta_Tags_Context $context The meta tags context. * * @return array The graph with the schema blocks graph pieces added. */ protected function add_schema_blocks_graph_pieces( $graph, $context ) { foreach ( $context->blocks as $block_type => $blocks ) { foreach ( $blocks as $block ) { $block_type = \strtolower( $block['blockName'] ); /** * Filter: 'wpseo_schema_block_'. * This filter is documented in the `generate_graph()` function in this class. */ $graph = \apply_filters( 'wpseo_schema_block_' . $block_type, $graph, $block, $context ); if ( isset( $block['attrs']['yoast-schema'] ) ) { $graph[] = $this->schema_replace_vars_helper->replace( $block['attrs']['yoast-schema'], $context->presentation ); } } } return $graph; } /** * Finalizes the schema graph after all filtering is done. * * @param array $graph The current schema graph. * @param Meta_Tags_Context $context The meta tags context. * * @return array The schema graph. */ protected function finalize_graph( $graph, $context ) { $graph = $this->remove_empty_breadcrumb( $graph, $context ); return $graph; } /** * Removes the breadcrumb schema if empty. * * @param array $graph The current schema graph. * @param Meta_Tags_Context $context The meta tags context. * * @return array The schema graph with empty breadcrumbs taken out. */ protected function remove_empty_breadcrumb( $graph, $context ) { if ( $this->helpers->current_page->is_home_static_page() || $this->helpers->current_page->is_home_posts_page() ) { return $graph; } // Remove the breadcrumb piece, if it's empty. $index_to_remove = 0; foreach ( $graph as $key => $piece ) { if ( \in_array( 'BreadcrumbList', $this->get_type_from_piece( $piece ), true ) ) { if ( isset( $piece['itemListElement'] ) && \is_array( $piece['itemListElement'] ) && \count( $piece['itemListElement'] ) === 1 ) { $index_to_remove = $key; break; } } } // If the breadcrumb piece has been removed, we should remove its reference from the WebPage node. if ( $index_to_remove !== 0 ) { \array_splice( $graph, $index_to_remove, 1 ); // Get the type of the WebPage node. $webpage_types = \is_array( $context->schema_page_type ) ? $context->schema_page_type : [ $context->schema_page_type ]; foreach ( $graph as $key => $piece ) { if ( ! empty( \array_intersect( $webpage_types, $this->get_type_from_piece( $piece ) ) ) && isset( $piece['breadcrumb'] ) ) { unset( $piece['breadcrumb'] ); $graph[ $key ] = $piece; } } } return $graph; } /** * Adapts the WebPage graph piece for password-protected posts. * * It should only have certain whitelisted properties. * The type should always be WebPage. * * @param array $graph_piece The WebPage graph piece that should be adapted for password-protected posts. * * @return array The WebPage graph piece that has been adapted for password-protected posts. */ public function protected_webpage_schema( $graph_piece ) { $properties_to_show = \array_flip( [ '@type', '@id', 'url', 'name', 'isPartOf', 'inLanguage', 'datePublished', 'dateModified', 'breadcrumb', ] ); $graph_piece = \array_intersect_key( $graph_piece, $properties_to_show ); $graph_piece['@type'] = 'WebPage'; return $graph_piece; } /** * Gets all the graph pieces we need. * * @param Meta_Tags_Context $context The meta tags context. * * @return Abstract_Schema_Piece[] A filtered array of graph pieces. */ protected function get_graph_pieces( $context ) { if ( $context->indexable->object_type === 'post' && \post_password_required( $context->post ) ) { $schema_pieces = [ new Schema\WebPage(), new Schema\Website(), new Schema\Organization(), ]; \add_filter( 'wpseo_schema_webpage', [ $this, 'protected_webpage_schema' ], 1 ); } else { $schema_pieces = [ new Schema\Article(), new Schema\WebPage(), new Schema\Main_Image(), new Schema\Breadcrumb(), new Schema\Website(), new Schema\Organization(), new Schema\Person(), new Schema\Author(), new Schema\FAQ(), new Schema\HowTo(), ]; } /** * Filter: 'wpseo_schema_graph_pieces' - Allows adding pieces to the graph. * * @param Meta_Tags_Context $context An object with context variables. * * @api array $pieces The schema pieces. */ return \apply_filters( 'wpseo_schema_graph_pieces', $schema_pieces, $context ); } /** * Allows filtering the graph piece by its schema type. * * Note: We removed the Abstract_Schema_Piece type-hint from the $graph_piece_generator argument, because * it caused conflicts with old code, Yoast SEO Video specifically. * * @param array $graph_piece The graph piece we're filtering. * @param string $identifier The identifier of the graph piece that is being filtered. * @param Meta_Tags_Context $context The meta tags context. * @param Abstract_Schema_Piece $graph_piece_generator A value object with context variables. * @param Abstract_Schema_Piece[] $graph_piece_generators A value object with context variables. * * @return array The filtered graph piece. */ private function type_filter( $graph_piece, $identifier, Meta_Tags_Context $context, $graph_piece_generator, array $graph_piece_generators ) { $types = $this->get_type_from_piece( $graph_piece ); foreach ( $types as $type ) { $type = \strtolower( $type ); // Prevent running the same filter twice. This makes sure we run f/i. for 'author' and for 'person'. if ( $type && $type !== $identifier ) { /** * Filter: 'wpseo_schema_' - Allows changing graph piece output by @type. * * @api array $graph_piece The graph piece to filter. * * @param Meta_Tags_Context $context A value object with context variables. * @param Abstract_Schema_Piece $graph_piece_generator A value object with context variables. * @param Abstract_Schema_Piece[] $graph_piece_generators A value object with context variables. */ $graph_piece = \apply_filters( 'wpseo_schema_' . $type, $graph_piece, $context, $graph_piece_generator, $graph_piece_generators ); } } return $graph_piece; } /** * Retrieves the type from a graph piece. * * @param array $piece The graph piece. * * @return array An array of the piece's types. */ private function get_type_from_piece( $piece ) { if ( isset( $piece['@type'] ) ) { if ( \is_array( $piece['@type'] ) ) { // Return as-is, but remove unusable values, like sub-arrays, objects, null. return \array_filter( $piece['@type'], 'is_string' ); } return [ $piece['@type'] ]; } return []; } /** * Validates a graph piece's type. * * When the type is an array: * - Ensure the values are unique. * - Only 1 value? Use that value without the array wrapping. * * @param array $piece The graph piece. * * @return array The graph piece. */ private function validate_type( $piece ) { if ( ! isset( $piece['@type'] ) ) { // No type to validate. return $piece; } // If it is not an array, we can return immediately. if ( ! \is_array( $piece['@type'] ) ) { return $piece; } /* * Ensure the types are unique. * Use array_values to reset the indices (e.g. no 0, 2 because 1 was a duplicate). */ $piece['@type'] = \array_values( \array_unique( $piece['@type'] ) ); // Use the first value if there is only 1 type. if ( \count( $piece['@type'] ) === 1 ) { $piece['@type'] = \reset( $piece['@type'] ); } return $piece; } }