����JFIF���������
__ __ __ __ _____ _ _ _____ _ _ _ | \/ | \ \ / / | __ \ (_) | | / ____| | | | | | \ / |_ __\ V / | |__) | __ ___ ____ _| |_ ___ | (___ | |__ ___| | | | |\/| | '__|> < | ___/ '__| \ \ / / _` | __/ _ \ \___ \| '_ \ / _ \ | | | | | | |_ / . \ | | | | | |\ V / (_| | || __/ ____) | | | | __/ | | |_| |_|_(_)_/ \_\ |_| |_| |_| \_/ \__,_|\__\___| |_____/|_| |_|\___V 2.1 if you need WebShell for Seo everyday contact me on Telegram Telegram Address : @jackleetFor_More_Tools:
schema/abstract-schema-piece.php 0000666 00000001432 15221073171 0012644 0 ustar 00 <?php
namespace Yoast\WP\SEO\Generators\Schema;
use Yoast\WP\SEO\Context\Meta_Tags_Context;
use Yoast\WP\SEO\Surfaces\Helpers_Surface;
/**
* Class Abstract_Schema_Piece.
*/
abstract class Abstract_Schema_Piece {
/**
* The meta tags context.
*
* @var Meta_Tags_Context
*/
public $context;
/**
* The helpers surface
*
* @var Helpers_Surface
*/
public $helpers;
/**
* Optional identifier for this schema piece.
*
* Used in the `Schema_Generator::filter_graph_pieces_to_generate()` method.
*
* @var string
*/
public $identifier;
/**
* Generates the schema piece.
*
* @return mixed
*/
abstract public function generate();
/**
* Determines whether the schema piece is needed.
*
* @return bool
*/
abstract public function is_needed();
}
schema/organization.php 0000666 00000005145 15221073171 0011231 0 ustar 00 <?php
namespace Yoast\WP\SEO\Generators\Schema;
use Yoast\WP\SEO\Config\Schema_IDs;
/**
* Returns schema Organization data.
*/
class Organization extends Abstract_Schema_Piece {
/**
* Determines whether an Organization graph piece should be added.
*
* @return bool
*/
public function is_needed() {
return $this->context->site_represents === 'company';
}
/**
* Returns the Organization Schema data.
*
* @return array The Organization schema.
*/
public function generate() {
$logo_schema_id = $this->context->site_url . Schema_IDs::ORGANIZATION_LOGO_HASH;
if ( $this->context->company_logo_meta ) {
$logo = $this->helpers->schema->image->generate_from_attachment_meta( $logo_schema_id, $this->context->company_logo_meta, $this->context->company_name );
}
else {
$logo = $this->helpers->schema->image->generate_from_attachment_id( $logo_schema_id, $this->context->company_logo_id, $this->context->company_name );
}
$organization = [
'@type' => 'Organization',
'@id' => $this->context->site_url . Schema_IDs::ORGANIZATION_HASH,
'name' => $this->helpers->schema->html->smart_strip_tags( $this->context->company_name ),
];
if ( ! empty( $this->context->company_alternate_name ) ) {
$organization['alternateName'] = $this->context->company_alternate_name;
}
$organization['url'] = $this->context->site_url;
$organization['logo'] = $logo;
$organization['image'] = [ '@id' => $logo['@id'] ];
$same_as = \array_values( \array_unique( \array_filter( $this->fetch_social_profiles() ) ) );
if ( ! empty( $same_as ) ) {
$organization['sameAs'] = $same_as;
}
if ( \is_array( $this->context->schema_page_type ) && \in_array( 'ProfilePage', $this->context->schema_page_type, true ) ) {
$organization['mainEntityOfPage'] = [
'@id' => $this->context->main_schema_id,
];
}
return $organization;
}
/**
* Retrieve the social profiles to display in the organization schema.
*
* @return array An array of social profiles.
*/
private function fetch_social_profiles() {
$profiles = $this->helpers->social_profiles->get_organization_social_profiles();
if ( isset( $profiles['other_social_urls'] ) ) {
$other_social_urls = $profiles['other_social_urls'];
unset( $profiles['other_social_urls'] );
$profiles = \array_merge( $profiles, $other_social_urls );
}
/**
* Filter: 'wpseo_schema_organization_social_profiles' - Allows filtering social profiles for the
* represented organization.
*
* @param string[] $profiles
*/
$profiles = \apply_filters( 'wpseo_schema_organization_social_profiles', $profiles );
return $profiles;
}
}
schema/author.php 0000666 00000005736 15221073171 0010035 0 ustar 00 <?php
namespace Yoast\WP\SEO\Generators\Schema;
/**
* Returns schema Author data.
*/
class Author extends Person {
/**
* Determine whether we should return Person schema.
*
* @return bool
*/
public function is_needed() {
if ( $this->context->indexable->object_type === 'user' ) {
return true;
}
if (
$this->context->indexable->object_type === 'post'
&& $this->helpers->schema->article->is_author_supported( $this->context->indexable->object_sub_type )
&& $this->context->schema_article_type !== 'None'
) {
return true;
}
return false;
}
/**
* Returns Person Schema data.
*
* @return bool|array Person data on success, false on failure.
*/
public function generate() {
$user_id = $this->determine_user_id();
if ( ! $user_id ) {
return false;
}
$data = $this->build_person_data( $user_id );
if ( $this->site_represents_current_author() === false ) {
$data['@type'] = [ 'Person' ];
unset( $data['logo'] );
}
// If this is an author page, the Person object is the main object, so we set it as such here.
if ( $this->context->indexable->object_type === 'user' ) {
$data['mainEntityOfPage'] = [
'@id' => $this->context->main_schema_id,
];
}
// If this is a post and the author archives are enabled, set the author archive url as the author url.
if ( $this->context->indexable->object_type === 'post' ) {
if ( $this->helpers->options->get( 'disable-author' ) !== true ) {
$data['url'] = $this->helpers->user->get_the_author_posts_url( $user_id );
}
}
return $data;
}
/**
* Determines a User ID for the Person data.
*
* @return bool|int User ID or false upon return.
*/
protected function determine_user_id() {
$user_id = 0;
if ( $this->context->indexable->object_type === 'post' ) {
$user_id = (int) $this->context->post->post_author;
}
if ( $this->context->indexable->object_type === 'user' ) {
$user_id = $this->context->indexable->object_id;
}
/**
* Filter: 'wpseo_schema_person_user_id' - Allows filtering of user ID used for person output.
*
* @param int|bool $user_id The user ID currently determined.
*/
$user_id = \apply_filters( 'wpseo_schema_person_user_id', $user_id );
if ( \is_int( $user_id ) && $user_id > 0 ) {
return $user_id;
}
return false;
}
/**
* An author should not have an image from options, this only applies to persons.
*
* @param array $data The Person schema.
* @param string $schema_id The string used in the `@id` for the schema.
* @param bool $add_hash Whether or not the person's image url hash should be added to the image id.
* @param WP_User|null $user_data User data.
*
* @return array The Person schema.
*/
protected function set_image_from_options( $data, $schema_id, $add_hash = false, $user_data = null ) {
if ( $this->site_represents_current_author( $user_data ) ) {
return parent::set_image_from_options( $data, $schema_id, $add_hash, $user_data );
}
return $data;
}
}
schema/breadcrumb.php 0000666 00000012070 15221073171 0010626 0 ustar 00 <?php
namespace Yoast\WP\SEO\Generators\Schema;
use Yoast\WP\SEO\Config\Schema_IDs;
/**
* Returns schema Breadcrumb data.
*/
class Breadcrumb extends Abstract_Schema_Piece {
/**
* Determine if we should add a breadcrumb attribute.
*
* @return bool
*/
public function is_needed() {
if ( $this->context->indexable->object_type === 'unknown' ) {
return false;
}
if ( $this->context->indexable->object_type === 'system-page' && $this->context->indexable->object_sub_type === '404' ) {
return false;
}
return true;
}
/**
* Returns Schema breadcrumb data to allow recognition of page's position in the site hierarchy.
*
* @link https://developers.google.com/search/docs/data-types/breadcrumb
*
* @return bool|array Array on success, false on failure.
*/
public function generate() {
$breadcrumbs = $this->context->presentation->breadcrumbs;
$list_elements = [];
// In case of pagination, replace the last breadcrumb, because it only contains "Page [number]" and has no URL.
if (
(
$this->helpers->current_page->is_paged()
|| $this->context->indexable->number_of_pages > 1
) && (
// Do not replace the last breadcrumb on static post pages.
! $this->helpers->current_page->is_static_posts_page()
// Do not remove the last breadcrumb if only one exists (bugfix for custom paginated frontpages).
&& \count( $breadcrumbs ) > 1
)
) {
\array_pop( $breadcrumbs );
}
// Only output breadcrumbs that are not hidden.
$breadcrumbs = \array_filter( $breadcrumbs, [ $this, 'not_hidden' ] );
\reset( $breadcrumbs );
/*
* Check whether at least one of the breadcrumbs is broken.
* If so, do not output anything.
*/
foreach ( $breadcrumbs as $breadcrumb ) {
if ( $this->is_broken( $breadcrumb ) ) {
return false;
}
}
// Create the last breadcrumb.
$last_breadcrumb = \array_pop( $breadcrumbs );
$breadcrumbs[] = $this->format_last_breadcrumb( $last_breadcrumb );
// If this is a static front page, prevent nested pages from creating a trail.
if ( $this->helpers->current_page->is_home_static_page() ) {
// Check if we're dealing with a nested page.
if ( \count( $breadcrumbs ) > 1 ) {
// Store the breadcrumbs home variable before dropping the parent page from the Schema.
$breadcrumbs_home = $breadcrumbs[0]['text'];
$breadcrumbs = [ \array_pop( $breadcrumbs ) ];
// Make the child page show the breadcrumbs home variable rather than its own title.
$breadcrumbs[0]['text'] = $breadcrumbs_home;
}
}
$breadcrumbs = \array_filter( $breadcrumbs, [ $this, 'not_empty_text' ] );
$breadcrumbs = \array_values( $breadcrumbs );
// Create intermediate breadcrumbs.
foreach ( $breadcrumbs as $index => $breadcrumb ) {
$list_elements[] = $this->create_breadcrumb( $index, $breadcrumb );
}
return [
'@type' => 'BreadcrumbList',
'@id' => $this->context->canonical . Schema_IDs::BREADCRUMB_HASH,
'itemListElement' => $list_elements,
];
}
/**
* Returns a breadcrumb array.
*
* @param int $index The position in the list.
* @param array $breadcrumb The position in the list.
*
* @return array A breadcrumb listItem.
*/
private function create_breadcrumb( $index, $breadcrumb ) {
$crumb = [
'@type' => 'ListItem',
'position' => ( $index + 1 ),
'name' => $this->helpers->schema->html->smart_strip_tags( $breadcrumb['text'] ),
];
if ( ! empty( $breadcrumb['url'] ) ) {
$crumb['item'] = $breadcrumb['url'];
}
return $crumb;
}
/**
* Creates the last breadcrumb in the breadcrumb list, omitting the URL per Google's spec.
*
* @link https://developers.google.com/search/docs/data-types/breadcrumb
*
* @param array $breadcrumb The position in the list.
*
* @return array The last of the breadcrumbs.
*/
private function format_last_breadcrumb( $breadcrumb ) {
unset( $breadcrumb['url'] );
return $breadcrumb;
}
/**
* Tests if the breadcrumb is broken.
* A breadcrumb is considered broken:
* - when it is not an array.
* - when it has no URL or text.
*
* @param array $breadcrumb The breadcrumb to test.
*
* @return bool `true` if the breadcrumb is broken.
*/
private function is_broken( $breadcrumb ) {
// A breadcrumb is broken if it is not an array.
if ( ! \is_array( $breadcrumb ) ) {
return true;
}
// A breadcrumb is broken if it does not contain a URL or text.
if ( ! \array_key_exists( 'url', $breadcrumb ) || ! \array_key_exists( 'text', $breadcrumb ) ) {
return true;
}
return false;
}
/**
* Checks whether the breadcrumb is not set to be hidden.
*
* @param array $breadcrumb The breadcrumb array.
*
* @return bool If the breadcrumb should not be hidden.
*/
private function not_hidden( $breadcrumb ) {
return empty( $breadcrumb['hide_in_schema'] );
}
/**
* Checks whether the breadcrumb has a not empty text.
*
* @param array $breadcrumb The breadcrumb array.
*
* @return bool If the breadcrumb has a not empty text.
*/
private function not_empty_text( $breadcrumb ) {
return ! empty( $breadcrumb['text'] );
}
}
open-graph-image-generator.php 0000666 00000014114 15221073171 0012365 0 ustar 00 <?php
namespace Yoast\WP\SEO\Generators;
use Error;
use Yoast\WP\SEO\Context\Meta_Tags_Context;
use Yoast\WP\SEO\Helpers\Image_Helper;
use Yoast\WP\SEO\Helpers\Open_Graph\Image_Helper as Open_Graph_Image_Helper;
use Yoast\WP\SEO\Helpers\Options_Helper;
use Yoast\WP\SEO\Helpers\Url_Helper;
use Yoast\WP\SEO\Models\Indexable;
use Yoast\WP\SEO\Values\Open_Graph\Images;
/**
* Represents the generator class for the Open Graph images.
*/
class Open_Graph_Image_Generator implements Generator_Interface {
/**
* The Open Graph image helper.
*
* @var Open_Graph_Image_Helper
*/
protected $open_graph_image;
/**
* The image helper.
*
* @var Image_Helper
*/
protected $image;
/**
* The URL helper.
*
* @var Url_Helper
*/
protected $url;
/**
* The options helper.
*
* @var Options_Helper
*/
private $options;
/**
* Images constructor.
*
* @codeCoverageIgnore
*
* @param Open_Graph_Image_Helper $open_graph_image Image helper for Open Graph.
* @param Image_Helper $image The image helper.
* @param Options_Helper $options The options helper.
* @param Url_Helper $url The url helper.
*/
public function __construct(
Open_Graph_Image_Helper $open_graph_image,
Image_Helper $image,
Options_Helper $options,
Url_Helper $url
) {
$this->open_graph_image = $open_graph_image;
$this->image = $image;
$this->options = $options;
$this->url = $url;
}
/**
* Retrieves the images for an indexable.
*
* For legacy reasons some plugins might expect we filter a WPSEO_Opengraph_Image object. That might cause
* type errors. This is why we try/catch our filters.
*
* @param Meta_Tags_Context $context The context.
*
* @return array The images.
*/
public function generate( Meta_Tags_Context $context ) {
$image_container = $this->get_image_container();
$backup_image_container = $this->get_image_container();
try {
/**
* Filter: wpseo_add_opengraph_images - Allow developers to add images to the Open Graph tags.
*
* @param Yoast\WP\SEO\Values\Open_Graph\Images $image_container The current object.
*/
\apply_filters( 'wpseo_add_opengraph_images', $image_container );
} catch ( Error $error ) {
$image_container = $backup_image_container;
}
$this->add_from_indexable( $context->indexable, $image_container );
$backup_image_container = $image_container;
try {
/**
* Filter: wpseo_add_opengraph_additional_images - Allows to add additional images to the Open Graph tags.
*
* @param Yoast\WP\SEO\Values\Open_Graph\Images $image_container The current object.
*/
\apply_filters( 'wpseo_add_opengraph_additional_images', $image_container );
} catch ( Error $error ) {
$image_container = $backup_image_container;
}
$this->add_from_templates( $context, $image_container );
$this->add_from_default( $image_container );
return $image_container->get_images();
}
/**
* Retrieves the images for an author archive indexable.
*
* This is a custom method to address the case of Author Archives, since they always have an Open Graph image
* set in the indexable (even if it is an empty default Gravatar).
*
* @param Meta_Tags_Context $context The context.
*
* @return array The images.
*/
public function generate_for_author_archive( Meta_Tags_Context $context ) {
$image_container = $this->get_image_container();
$this->add_from_templates( $context, $image_container );
if ( $image_container->has_images() ) {
return $image_container->get_images();
}
return $this->generate( $context );
}
/**
* Adds an image based on the given indexable.
*
* @param Indexable $indexable The indexable.
* @param Images $image_container The image container.
*
* @return void
*/
protected function add_from_indexable( Indexable $indexable, Images $image_container ) {
if ( $indexable->open_graph_image_meta ) {
$image_container->add_image_by_meta( $indexable->open_graph_image_meta );
return;
}
if ( $indexable->open_graph_image_id ) {
$image_container->add_image_by_id( $indexable->open_graph_image_id );
return;
}
if ( $indexable->open_graph_image ) {
$meta_data = [];
if ( $indexable->open_graph_image_meta && \is_string( $indexable->open_graph_image_meta ) ) {
$meta_data = \json_decode( $indexable->open_graph_image_meta, true );
}
$image_container->add_image(
\array_merge(
(array) $meta_data,
[
'url' => $indexable->open_graph_image,
]
)
);
}
}
/**
* Retrieves the default Open Graph image.
*
* @param Images $image_container The image container.
*
* @return void
*/
protected function add_from_default( Images $image_container ) {
if ( $image_container->has_images() ) {
return;
}
$default_image_id = $this->options->get( 'og_default_image_id', '' );
if ( $default_image_id ) {
$image_container->add_image_by_id( $default_image_id );
return;
}
$default_image_url = $this->options->get( 'og_default_image', '' );
if ( $default_image_url ) {
$image_container->add_image_by_url( $default_image_url );
}
}
/**
* Retrieves the default Open Graph image.
*
* @param Meta_Tags_Context $context The context.
* @param Images $image_container The image container.
*
* @return void
*/
protected function add_from_templates( Meta_Tags_Context $context, Images $image_container ) {
if ( $image_container->has_images() ) {
return;
}
if ( $context->presentation->open_graph_image_id ) {
$image_container->add_image_by_id( $context->presentation->open_graph_image_id );
return;
}
if ( $context->presentation->open_graph_image ) {
$image_container->add_image_by_url( $context->presentation->open_graph_image );
}
}
/**
* Retrieves an instance of the image container.
*
* @codeCoverageIgnore
*
* @return Images The image container.
*/
protected function get_image_container() {
$image_container = new Images( $this->image, $this->url );
$image_container->set_helpers( $this->open_graph_image );
return $image_container;
}
}
breadcrumbs-generator.php 0000666 00000031167 15221073171 0011545 0 ustar 00 <?php
namespace Yoast\WP\SEO\Generators;
use Yoast\WP\SEO\Context\Meta_Tags_Context;
use Yoast\WP\SEO\Helpers\Current_Page_Helper;
use Yoast\WP\SEO\Helpers\Options_Helper;
use Yoast\WP\SEO\Helpers\Pagination_Helper;
use Yoast\WP\SEO\Helpers\Post_Type_Helper;
use Yoast\WP\SEO\Helpers\Url_Helper;
use Yoast\WP\SEO\Models\Indexable;
use Yoast\WP\SEO\Repositories\Indexable_Repository;
/**
* Represents the generator class for the breadcrumbs.
*/
class Breadcrumbs_Generator implements Generator_Interface {
/**
* The indexable repository.
*
* @var Indexable_Repository
*/
private $repository;
/**
* The options helper.
*
* @var Options_Helper
*/
private $options;
/**
* The current page helper.
*
* @var Current_Page_Helper
*/
private $current_page_helper;
/**
* The post type helper.
*
* @var Post_Type_Helper
*/
private $post_type_helper;
/**
* The URL helper.
*
* @var Url_Helper
*/
private $url_helper;
/**
* The pagination helper.
*
* @var Pagination_Helper
*/
private $pagination_helper;
/**
* Breadcrumbs_Generator constructor.
*
* @param Indexable_Repository $repository The repository.
* @param Options_Helper $options The options helper.
* @param Current_Page_Helper $current_page_helper The current page helper.
* @param Post_Type_Helper $post_type_helper The post type helper.
* @param Url_Helper $url_helper The URL helper.
* @param Pagination_Helper $pagination_helper The pagination helper.
*/
public function __construct(
Indexable_Repository $repository,
Options_Helper $options,
Current_Page_Helper $current_page_helper,
Post_Type_Helper $post_type_helper,
Url_Helper $url_helper,
Pagination_Helper $pagination_helper
) {
$this->repository = $repository;
$this->options = $options;
$this->current_page_helper = $current_page_helper;
$this->post_type_helper = $post_type_helper;
$this->url_helper = $url_helper;
$this->pagination_helper = $pagination_helper;
}
/**
* Generates the breadcrumbs.
*
* @param Meta_Tags_Context $context The meta tags context.
*
* @return array<array<int, string>> An array of associative arrays that each have a 'text' and a 'url'.
*/
public function generate( Meta_Tags_Context $context ) {
$static_ancestors = [];
$breadcrumbs_home = $this->options->get( 'breadcrumbs-home' );
if ( $breadcrumbs_home !== '' && ! \in_array( $this->current_page_helper->get_page_type(), [ 'Home_Page', 'Static_Home_Page' ], true ) ) {
$front_page_id = $this->current_page_helper->get_front_page_id();
if ( $front_page_id === 0 ) {
$home_page_ancestor = $this->repository->find_for_home_page();
if ( \is_a( $home_page_ancestor, Indexable::class ) ) {
$static_ancestors[] = $home_page_ancestor;
}
}
else {
$static_ancestor = $this->repository->find_by_id_and_type( $front_page_id, 'post' );
if ( \is_a( $static_ancestor, Indexable::class ) && $static_ancestor->post_status !== 'unindexed' ) {
$static_ancestors[] = $static_ancestor;
}
}
}
$page_for_posts = \get_option( 'page_for_posts' );
if ( $this->should_have_blog_crumb( $page_for_posts, $context ) ) {
$static_ancestor = $this->repository->find_by_id_and_type( $page_for_posts, 'post' );
if ( \is_a( $static_ancestor, Indexable::class ) && $static_ancestor->post_status !== 'unindexed' ) {
$static_ancestors[] = $static_ancestor;
}
}
if (
$context->indexable->object_type === 'post'
&& $context->indexable->object_sub_type !== 'post'
&& $context->indexable->object_sub_type !== 'page'
&& $this->post_type_helper->has_archive( $context->indexable->object_sub_type )
) {
$static_ancestor = $this->repository->find_for_post_type_archive( $context->indexable->object_sub_type );
if ( \is_a( $static_ancestor, Indexable::class ) ) {
$static_ancestors[] = $static_ancestor;
}
}
if ( $context->indexable->object_type === 'term' ) {
$parent = $this->get_taxonomy_post_type_parent( $context->indexable->object_sub_type );
if ( $parent && $parent !== 'post' && $this->post_type_helper->has_archive( $parent ) ) {
$static_ancestor = $this->repository->find_for_post_type_archive( $parent );
if ( \is_a( $static_ancestor, Indexable::class ) ) {
$static_ancestors[] = $static_ancestor;
}
}
}
$indexables = [];
if ( ! \in_array( $this->current_page_helper->get_page_type(), [ 'Home_Page', 'Static_Home_Page' ], true ) ) {
// Get all ancestors of the indexable and append itself to get all indexables in the full crumb.
$indexables = $this->repository->get_ancestors( $context->indexable );
}
$indexables[] = $context->indexable;
if ( ! empty( $static_ancestors ) ) {
\array_unshift( $indexables, ...$static_ancestors );
}
$indexables = \apply_filters( 'wpseo_breadcrumb_indexables', $indexables, $context );
$indexables = \is_array( $indexables ) ? $indexables : [];
$indexables = \array_filter(
$indexables,
static function ( $indexable ) {
return \is_a( $indexable, Indexable::class );
}
);
$crumbs = \array_map( [ $this, 'get_post_type_crumb' ], $indexables );
if ( $breadcrumbs_home !== '' ) {
$crumbs[0]['text'] = $breadcrumbs_home;
}
$crumbs = $this->add_paged_crumb( $crumbs, $context->indexable );
/**
* Filter: 'wpseo_breadcrumb_links' - Allow the developer to filter the Yoast SEO breadcrumb links, add to them, change order, etc.
*
* @param array $crumbs The crumbs array.
*/
$filtered_crumbs = \apply_filters( 'wpseo_breadcrumb_links', $crumbs );
// Basic check to make sure the filtered crumbs are in an array.
if ( ! \is_array( $filtered_crumbs ) ) {
\_doing_it_wrong(
'Filter: \'wpseo_breadcrumb_links\'',
'The `wpseo_breadcrumb_links` filter should return a multi-dimensional array.',
'YoastSEO v20.0'
);
}
else {
$crumbs = $filtered_crumbs;
}
$filter_callback = static function ( $link_info, $index ) use ( $crumbs ) {
/**
* Filter: 'wpseo_breadcrumb_single_link_info' - Allow developers to filter the Yoast SEO Breadcrumb link information.
*
* @param array $link_info The breadcrumb link information.
* @param int $index The index of the breadcrumb in the list.
* @param array $crumbs The complete list of breadcrumbs.
*/
return \apply_filters( 'wpseo_breadcrumb_single_link_info', $link_info, $index, $crumbs );
};
return \array_map( $filter_callback, $crumbs, \array_keys( $crumbs ) );
}
/**
* Returns the modified post crumb.
*
* @param string[] $crumb The crumb.
* @param Indexable $ancestor The indexable.
*
* @return array<int, string> The crumb.
*/
private function get_post_crumb( $crumb, $ancestor ) {
$crumb['id'] = $ancestor->object_id;
return $crumb;
}
/**
* Adds the correct ID to the crumb array based on the ancestor provided.
*
* @param Indexable $ancestor The ancestor indexable.
*
* @return string[]
*/
private function get_post_type_crumb( Indexable $ancestor ) {
$crumb = [
'url' => $ancestor->permalink,
'text' => $ancestor->breadcrumb_title,
];
switch ( $ancestor->object_type ) {
case 'post':
$crumb = $this->get_post_crumb( $crumb, $ancestor );
break;
case 'post-type-archive':
$crumb = $this->get_post_type_archive_crumb( $crumb, $ancestor );
break;
case 'term':
$crumb = $this->get_term_crumb( $crumb, $ancestor );
break;
case 'system-page':
$crumb = $this->get_system_page_crumb( $crumb, $ancestor );
break;
case 'user':
$crumb = $this->get_user_crumb( $crumb, $ancestor );
break;
case 'date-archive':
$crumb = $this->get_date_archive_crumb( $crumb );
break;
default:
// Handle unknown object types (optional).
break;
}
return $crumb;
}
/**
* Returns the modified post type crumb.
*
* @param string[] $crumb The crumb.
* @param Indexable $ancestor The indexable.
*
* @return string[] The crumb.
*/
private function get_post_type_archive_crumb( $crumb, $ancestor ) {
$crumb['ptarchive'] = $ancestor->object_sub_type;
return $crumb;
}
/**
* Returns the modified term crumb.
*
* @param string[] $crumb The crumb.
* @param Indexable $ancestor The indexable.
*
* @return array<int, string> The crumb.
*/
private function get_term_crumb( $crumb, $ancestor ) {
$crumb['term_id'] = $ancestor->object_id;
$crumb['taxonomy'] = $ancestor->object_sub_type;
return $crumb;
}
/**
* Returns the modified system page crumb.
*
* @param string[] $crumb The crumb.
* @param Indexable $ancestor The indexable.
*
* @return string[] The crumb.
*/
private function get_system_page_crumb( $crumb, $ancestor ) {
if ( $ancestor->object_sub_type === 'search-result' ) {
$crumb['text'] = $this->options->get( 'breadcrumbs-searchprefix' ) . ' ' . \esc_html( \get_search_query() );
$crumb['url'] = \get_search_link();
}
elseif ( $ancestor->object_sub_type === '404' ) {
$crumb['text'] = $this->options->get( 'breadcrumbs-404crumb' );
}
return $crumb;
}
/**
* Returns the modified user crumb.
*
* @param string[] $crumb The crumb.
* @param Indexable $ancestor The indexable.
*
* @return string[] The crumb.
*/
private function get_user_crumb( $crumb, $ancestor ) {
$display_name = \get_the_author_meta( 'display_name', $ancestor->object_id );
$crumb['text'] = $this->options->get( 'breadcrumbs-archiveprefix' ) . ' ' . $display_name;
return $crumb;
}
/**
* Returns the modified date archive crumb.
*
* @param string[] $crumb The crumb.
*
* @return string[] The crumb.
*/
protected function get_date_archive_crumb( $crumb ) {
$home_url = $this->url_helper->home();
$prefix = $this->options->get( 'breadcrumbs-archiveprefix' );
if ( \is_day() ) {
$day = \esc_html( \get_the_date() );
$crumb['url'] = $home_url . \get_the_date( 'Y/m/d' ) . '/';
$crumb['text'] = $prefix . ' ' . $day;
}
elseif ( \is_month() ) {
$month = \esc_html( \trim( \single_month_title( ' ', false ) ) );
$crumb['url'] = $home_url . \get_the_date( 'Y/m' ) . '/';
$crumb['text'] = $prefix . ' ' . $month;
}
elseif ( \is_year() ) {
$year = \get_the_date( 'Y' );
$crumb['url'] = $home_url . $year . '/';
$crumb['text'] = $prefix . ' ' . $year;
}
return $crumb;
}
/**
* Returns whether or not a blog crumb should be added.
*
* @param int $page_for_posts The page for posts ID.
* @param Meta_Tags_Context $context The meta tags context.
*
* @return bool Whether or not a blog crumb should be added.
*/
protected function should_have_blog_crumb( $page_for_posts, $context ) {
// When there is no page configured as blog page.
if ( \get_option( 'show_on_front' ) !== 'page' || ! $page_for_posts ) {
return false;
}
if ( $context->indexable->object_type === 'term' ) {
$parent = $this->get_taxonomy_post_type_parent( $context->indexable->object_sub_type );
return $parent === 'post';
}
if ( $this->options->get( 'breadcrumbs-display-blog-page' ) !== true ) {
return false;
}
// When the current page is the home page, searchpage or isn't a singular post.
if ( \is_home() || \is_search() || ! \is_singular( 'post' ) ) {
return false;
}
return true;
}
/**
* Returns the post type parent of a given taxonomy.
*
* @param string $taxonomy The taxonomy.
*
* @return string|false The parent if it exists, false otherwise.
*/
protected function get_taxonomy_post_type_parent( $taxonomy ) {
$parent = $this->options->get( 'taxonomy-' . $taxonomy . '-ptparent' );
if ( empty( $parent ) || (string) $parent === '0' ) {
return false;
}
return $parent;
}
/**
* Adds a crumb for the current page, if we're on an archive page or paginated post.
*
* @param string[] $crumbs The array of breadcrumbs.
* @param Indexable $current_indexable The current indexable.
*
* @return string[] The breadcrumbs.
*/
protected function add_paged_crumb( array $crumbs, $current_indexable ) {
$is_simple_page = $this->current_page_helper->is_simple_page();
// If we're not on a paged page do nothing.
if ( ! $is_simple_page && ! $this->current_page_helper->is_paged() ) {
return $crumbs;
}
// If we're not on a paginated post do nothing.
if ( $is_simple_page && $current_indexable->number_of_pages === null ) {
return $crumbs;
}
$current_page_number = $this->pagination_helper->get_current_page_number();
if ( $current_page_number <= 1 ) {
return $crumbs;
}
$crumbs[] = [
'text' => \sprintf(
/* translators: %s expands to the current page number */
\__( 'Page %s', 'wordpress-seo' ),
$current_page_number
),
];
return $crumbs;
}
}
generator-interface.php 0000666 00000000544 15221073171 0011207 0 ustar 00 <?php
namespace Yoast\WP\SEO\Generators;
use Yoast\WP\SEO\Context\Meta_Tags_Context;
interface Generator_Interface {
/**
* Returns a string, or other Thing that the associated presenter can handle.
*
* @param Meta_Tags_Context $context The meta tags context.
*
* @return mixed
*/
public function generate( Meta_Tags_Context $context );
}
open-graph-locale-generator.php 0000666 00000012767 15221073171 0012556 0 ustar 00 <?php
namespace Yoast\WP\SEO\Generators;
use Yoast\WP\SEO\Context\Meta_Tags_Context;
/**
* Class Open_Graph_Locale_Generator.
*/
class Open_Graph_Locale_Generator implements Generator_Interface {
/**
* Generates the OG Locale.
*
* @param Meta_Tags_Context $context The context.
*
* @return string The OG locale.
*/
public function generate( Meta_Tags_Context $context ) {
/**
* Filter: 'wpseo_locale' - Allow changing the locale output.
*
* Note that this filter is different from `wpseo_og_locale`, which is run _after_ the OG specific filtering.
*
* @param string $locale Locale string.
*/
$locale = \apply_filters( 'wpseo_locale', \get_locale() );
// Catch some weird locales served out by WP that are not easily doubled up.
$fix_locales = [
'ca' => 'ca_ES',
'en' => 'en_US',
'el' => 'el_GR',
'et' => 'et_EE',
'ja' => 'ja_JP',
'sq' => 'sq_AL',
'uk' => 'uk_UA',
'vi' => 'vi_VN',
'zh' => 'zh_CN',
];
if ( isset( $fix_locales[ $locale ] ) ) {
return $fix_locales[ $locale ];
}
// Convert locales like "es" to "es_ES", in case that works for the given locale (sometimes it does).
if ( \strlen( $locale ) === 2 ) {
$locale = \strtolower( $locale ) . '_' . \strtoupper( $locale );
}
// These are the locales FB supports.
$fb_valid_fb_locales = [
'af_ZA', // Afrikaans.
'ak_GH', // Akan.
'am_ET', // Amharic.
'ar_AR', // Arabic.
'as_IN', // Assamese.
'ay_BO', // Aymara.
'az_AZ', // Azerbaijani.
'be_BY', // Belarusian.
'bg_BG', // Bulgarian.
'bp_IN', // Bhojpuri.
'bn_IN', // Bengali.
'br_FR', // Breton.
'bs_BA', // Bosnian.
'ca_ES', // Catalan.
'cb_IQ', // Sorani Kurdish.
'ck_US', // Cherokee.
'co_FR', // Corsican.
'cs_CZ', // Czech.
'cx_PH', // Cebuano.
'cy_GB', // Welsh.
'da_DK', // Danish.
'de_DE', // German.
'el_GR', // Greek.
'en_GB', // English (UK).
'en_PI', // English (Pirate).
'en_UD', // English (Upside Down).
'en_US', // English (US).
'em_ZM',
'eo_EO', // Esperanto.
'es_ES', // Spanish (Spain).
'es_LA', // Spanish.
'es_MX', // Spanish (Mexico).
'et_EE', // Estonian.
'eu_ES', // Basque.
'fa_IR', // Persian.
'fb_LT', // Leet Speak.
'ff_NG', // Fulah.
'fi_FI', // Finnish.
'fo_FO', // Faroese.
'fr_CA', // French (Canada).
'fr_FR', // French (France).
'fy_NL', // Frisian.
'ga_IE', // Irish.
'gl_ES', // Galician.
'gn_PY', // Guarani.
'gu_IN', // Gujarati.
'gx_GR', // Classical Greek.
'ha_NG', // Hausa.
'he_IL', // Hebrew.
'hi_IN', // Hindi.
'hr_HR', // Croatian.
'hu_HU', // Hungarian.
'ht_HT', // Haitian Creole.
'hy_AM', // Armenian.
'id_ID', // Indonesian.
'ig_NG', // Igbo.
'is_IS', // Icelandic.
'it_IT', // Italian.
'ik_US',
'iu_CA',
'ja_JP', // Japanese.
'ja_KS', // Japanese (Kansai).
'jv_ID', // Javanese.
'ka_GE', // Georgian.
'kk_KZ', // Kazakh.
'km_KH', // Khmer.
'kn_IN', // Kannada.
'ko_KR', // Korean.
'ks_IN', // Kashmiri.
'ku_TR', // Kurdish (Kurmanji).
'ky_KG', // Kyrgyz.
'la_VA', // Latin.
'lg_UG', // Ganda.
'li_NL', // Limburgish.
'ln_CD', // Lingala.
'lo_LA', // Lao.
'lt_LT', // Lithuanian.
'lv_LV', // Latvian.
'mg_MG', // Malagasy.
'mi_NZ', // Maori.
'mk_MK', // Macedonian.
'ml_IN', // Malayalam.
'mn_MN', // Mongolian.
'mr_IN', // Marathi.
'ms_MY', // Malay.
'mt_MT', // Maltese.
'my_MM', // Burmese.
'nb_NO', // Norwegian (bokmal).
'nd_ZW', // Ndebele.
'ne_NP', // Nepali.
'nl_BE', // Dutch (Belgie).
'nl_NL', // Dutch.
'nn_NO', // Norwegian (nynorsk).
'nr_ZA', // Southern Ndebele.
'ns_ZA', // Northern Sotho.
'ny_MW', // Chewa.
'om_ET', // Oromo.
'or_IN', // Oriya.
'pa_IN', // Punjabi.
'pl_PL', // Polish.
'ps_AF', // Pashto.
'pt_BR', // Portuguese (Brazil).
'pt_PT', // Portuguese (Portugal).
'qc_GT', // Quiché.
'qu_PE', // Quechua.
'qr_GR',
'qz_MM', // Burmese (Zawgyi).
'rm_CH', // Romansh.
'ro_RO', // Romanian.
'ru_RU', // Russian.
'rw_RW', // Kinyarwanda.
'sa_IN', // Sanskrit.
'sc_IT', // Sardinian.
'se_NO', // Northern Sami.
'si_LK', // Sinhala.
'su_ID', // Sundanese.
'sk_SK', // Slovak.
'sl_SI', // Slovenian.
'sn_ZW', // Shona.
'so_SO', // Somali.
'sq_AL', // Albanian.
'sr_RS', // Serbian.
'ss_SZ', // Swazi.
'st_ZA', // Southern Sotho.
'sv_SE', // Swedish.
'sw_KE', // Swahili.
'sy_SY', // Syriac.
'sz_PL', // Silesian.
'ta_IN', // Tamil.
'te_IN', // Telugu.
'tg_TJ', // Tajik.
'th_TH', // Thai.
'tk_TM', // Turkmen.
'tl_PH', // Filipino.
'tl_ST', // Klingon.
'tn_BW', // Tswana.
'tr_TR', // Turkish.
'ts_ZA', // Tsonga.
'tt_RU', // Tatar.
'tz_MA', // Tamazight.
'uk_UA', // Ukrainian.
'ur_PK', // Urdu.
'uz_UZ', // Uzbek.
've_ZA', // Venda.
'vi_VN', // Vietnamese.
'wo_SN', // Wolof.
'xh_ZA', // Xhosa.
'yi_DE', // Yiddish.
'yo_NG', // Yoruba.
'zh_CN', // Simplified Chinese (China).
'zh_HK', // Traditional Chinese (Hong Kong).
'zh_TW', // Traditional Chinese (Taiwan).
'zu_ZA', // Zulu.
'zz_TR', // Zazaki.
];
// Check to see if the locale is a valid FB one, if not, use en_US as a fallback.
if ( \in_array( $locale, $fb_valid_fb_locales, true ) ) {
return $locale;
}
$locale = \strtolower( \substr( $locale, 0, 2 ) ) . '_' . \strtoupper( \substr( $locale, 0, 2 ) );
if ( ! \in_array( $locale, $fb_valid_fb_locales, true ) ) {
return 'en_US';
}
return $locale;
}
}