-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
…tegration Improve default integration with Yoast SEO
- Loading branch information
Showing
6 changed files
with
287 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,150 @@ | ||
<?php | ||
/** | ||
* Integrate with Yoast SEO | ||
* | ||
* @package Byline_Manager | ||
*/ | ||
|
||
namespace Byline_Manager; | ||
|
||
use Byline_Manager\Models\Profile; | ||
use Byline_Manager\Models\TextProfile; | ||
use Byline_Manager\Yoast\Profile_Schema; | ||
use Byline_Manager\Yoast\TextProfile_Schema; | ||
use Yoast\WP\SEO\Config\Schema_Types; | ||
use Yoast\WP\SEO\Context\Meta_Tags_Context; | ||
use Yoast\WP\SEO\Generators\Schema\Abstract_Schema_Piece; | ||
use Yoast\WP\SEO\Generators\Schema\Person; | ||
use Yoast\WP\SEO\Presentations\Indexable_Presentation; | ||
|
||
// These filters run early to try to give preference to existing integrations on sites using both plugins. | ||
add_filter( 'wpseo_meta_author', __NAMESPACE__ . '\filter_wpseo_meta_author', 1, 2 ); | ||
add_filter( 'wpseo_enhanced_slack_data', __NAMESPACE__ . '\filter_wpseo_enhanced_slack_data', 1, 2 ); | ||
add_filter( 'wpseo_schema_graph_pieces', __NAMESPACE__ . '\filter_wpseo_schema_graph_pieces', 1, 2 ); | ||
add_filter( 'wpseo_schema_graph', __NAMESPACE__ . '\filter_wpseo_schema_graph', 1, 2 ); | ||
|
||
/** | ||
* Filter the Yoast SEO author meta tag. | ||
* | ||
* @param string $author_name The article author's display name. Return empty to disable the tag. | ||
* @param Indexable_Presentation $presentation The presentation of an indexable. | ||
* @return string Filtered tag. | ||
*/ | ||
function filter_wpseo_meta_author( $author_name, $presentation ): string { | ||
$id = $presentation->context->post->ID; | ||
$type = $presentation->model->object_sub_type; | ||
|
||
if ( $id && $type && Utils::is_post_type_supported( $type ) ) { | ||
$author_name = get_the_byline( $id ); | ||
} | ||
|
||
return $author_name; | ||
} | ||
|
||
/** | ||
* Filter the Yoast SEO enhanced data for sharing on Slack. | ||
* | ||
* @param array $data The enhanced Slack sharing data. | ||
* @param Indexable_Presentation $presentation The presentation of an indexable. | ||
* @return array Filtered data. | ||
*/ | ||
function filter_wpseo_enhanced_slack_data( $data, $presentation ): array { | ||
$id = $presentation->context->post->ID; | ||
$type = $presentation->model->object_sub_type; | ||
|
||
if ( $id && $type && Utils::is_post_type_supported( $type ) ) { | ||
$byline = get_the_byline( $id ); | ||
|
||
if ( $byline ) { | ||
$data['Written by'] = $byline; | ||
} else { | ||
unset( $data['Written by'] ); | ||
} | ||
} | ||
|
||
return $data; | ||
} | ||
|
||
/** | ||
* Remove all 'Person' nodes from the Yoast SEO schema graph before adding ours. | ||
* | ||
* @param Abstract_Schema_Piece[] $schema_pieces The existing graph pieces. | ||
* @param Meta_Tags_Context $context An object with context variables. | ||
* @return Abstract_Schema_Piece[] | ||
*/ | ||
function filter_wpseo_schema_graph_pieces( $schema_pieces, $context ) { | ||
if ( | ||
'post' === $context->indexable->object_type | ||
&& Utils::is_post_type_supported( $context->indexable->object_sub_type ) | ||
) { | ||
$schema_pieces = array_filter( $schema_pieces, fn ( $piece ) => ! $piece instanceof Person ); | ||
} | ||
|
||
return $schema_pieces; | ||
} | ||
|
||
/** | ||
* Filters the Yoast SEO schema graph output. | ||
* | ||
* @param array $graph The graph to filter. | ||
* @param Meta_Tags_Context $context An object with context variables. | ||
* @return array | ||
*/ | ||
function filter_wpseo_schema_graph( $graph, $context ) { | ||
if ( ! class_exists( Schema_Types::class ) || ! function_exists( 'YoastSEO' ) ) { | ||
return $graph; | ||
} | ||
|
||
if ( ! $graph ) { | ||
return $graph; | ||
} | ||
|
||
$schema_pieces = []; | ||
$schema_types = new Schema_Types(); | ||
$helpers = YoastSeo()->helpers; | ||
|
||
/* | ||
* It's easier to create the schema pieces and generate their output here, rather than filtering the schema | ||
* pieces into 'filter_schema_graph_pieces', because Yoast allows only one node of each '@type' in the graph. | ||
*/ | ||
if ( 'post' === $context->indexable->object_type && Utils::is_post_type_supported( $context->indexable->object_sub_type ) ) { | ||
foreach ( Utils::get_byline_entries_for_post( $context->indexable->object_id ) as $entry ) { | ||
if ( $entry instanceof Profile ) { | ||
$schema_pieces[] = new Profile_Schema( $entry, $helpers, $context ); | ||
} | ||
|
||
if ( $entry instanceof TextProfile ) { | ||
$schema_pieces[] = new TextProfile_Schema( $entry, $helpers, $context ); | ||
} | ||
} | ||
} | ||
|
||
$new_schema_nodes = []; | ||
$new_schema_ids = []; | ||
|
||
foreach ( $schema_pieces as $schema_piece ) { | ||
if ( $schema_piece->is_needed() ) { | ||
$generated = $schema_piece->generate(); | ||
$new_schema_nodes[] = $generated; | ||
|
||
if ( isset( $generated['@id'] ) ) { | ||
$new_schema_ids[] = [ '@id' => $generated['@id'] ]; | ||
} | ||
} | ||
} | ||
|
||
array_push( $graph, ...$new_schema_nodes ); | ||
|
||
// Update 'author' property in article nodes to reference the IDs of our new schema objects. | ||
foreach ( $graph as $i => $node ) { | ||
if ( | ||
isset( $node['@type'] ) | ||
&& is_string( $node['@type'] ) | ||
&& isset( $schema_types::ARTICLE_TYPES[ $node['@type'] ] ) | ||
) { | ||
$graph[ $i ]['author'] = $new_schema_ids; | ||
} | ||
} | ||
|
||
return $graph; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
<?php | ||
/** | ||
* Profile_Schema class file | ||
* | ||
* @package Byline_Manager | ||
*/ | ||
|
||
namespace Byline_Manager\Yoast; | ||
|
||
use Byline_Manager\Models\Profile; | ||
use Yoast\WP\SEO\Config\Schema_IDs; | ||
use Yoast\WP\SEO\Context\Meta_Tags_Context; | ||
use Yoast\WP\SEO\Generators\Schema\Author; | ||
use Yoast\WP\SEO\Surfaces\Helpers_Surface; | ||
|
||
/** | ||
* Adds a Byline Manager profile to the Yoast SEO schema graph. | ||
* | ||
* Extend the Author class for its `is_needed()` logic. | ||
*/ | ||
final class Profile_Schema extends Author { | ||
/** | ||
* Constructor. | ||
* | ||
* @param Profile $profile Profile instance. | ||
* @param Helpers_Surface $helpers Helpers surface. | ||
* @param Meta_Tags_Context $context Meta tags context. | ||
*/ | ||
public function __construct( | ||
private readonly Profile $profile, | ||
public $helpers, | ||
public $context, | ||
) {} | ||
|
||
/** | ||
* Generates the schema piece. | ||
* | ||
* @return mixed | ||
*/ | ||
public function generate() { | ||
$post = $this->profile->get_post(); | ||
|
||
$data = [ | ||
'@type' => 'Person', | ||
'@id' => $post->guid, | ||
'name' => $this->helpers->schema->html->smart_strip_tags( $this->profile->display_name ), | ||
'url' => $this->profile->link, | ||
]; | ||
|
||
$excerpt = $this->helpers->schema->html->smart_strip_tags( get_the_excerpt( $post ) ); | ||
|
||
if ( $excerpt ) { | ||
$data['description'] = $excerpt; | ||
} | ||
|
||
if ( has_post_thumbnail( $post ) ) { | ||
$data['image'] = $this->helpers->schema->image->generate_from_attachment_id( | ||
$this->context->site_url . Schema_IDs::PERSON_LOGO_HASH, | ||
get_post_thumbnail_id( $post ), | ||
'' | ||
); | ||
} | ||
|
||
/** | ||
* Filters the Yoast SEO schema graph data for the Byline Manager profile. | ||
* | ||
* @param array $data The schema data for the profile. | ||
* @param Profile $profile The Byline Manager profile. | ||
*/ | ||
return apply_filters( 'byline_manager_yoast_profile_schema', $data, $this->profile ); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
<?php | ||
/** | ||
* TextProfile_Schema class file | ||
* | ||
* @package Byline_Manager | ||
*/ | ||
|
||
namespace Byline_Manager\Yoast; | ||
|
||
use Byline_Manager\Models\TextProfile; | ||
use Yoast\WP\SEO\Config\Schema_IDs; | ||
use Yoast\WP\SEO\Context\Meta_Tags_Context; | ||
use Yoast\WP\SEO\Generators\Schema\Author; | ||
use Yoast\WP\SEO\Surfaces\Helpers_Surface; | ||
|
||
/** | ||
* Adds a Byline Manager text profile to the Yoast SEO schema graph. | ||
* | ||
* Extend Author for its `is_needed()` logic. | ||
*/ | ||
final class TextProfile_Schema extends Author { | ||
/** | ||
* Constructor. | ||
* | ||
* @param TextProfile $profile TextProfile instance. | ||
* @param Helpers_Surface $helpers Helpers surface. | ||
* @param Meta_Tags_Context $context Meta tags context. | ||
*/ | ||
public function __construct( | ||
private readonly TextProfile $profile, | ||
public $helpers, | ||
public $context, | ||
) {} | ||
|
||
/** | ||
* Generates the schema piece. | ||
* | ||
* @return mixed | ||
*/ | ||
public function generate() { | ||
return [ | ||
'@type' => 'Person', | ||
'@id' => $this->context->site_url . Schema_IDs::PERSON_HASH . wp_hash( $this->profile->display_name ), | ||
'name' => $this->helpers->schema->html->smart_strip_tags( $this->profile->display_name ), | ||
]; | ||
} | ||
} |