| Current Path : /home/x/b/o/xbodynamge/namtation/wp-content/ |
| Current File : /home/x/b/o/xbodynamge/namtation/wp-content/Schema.tar |
Schema.php 0000666 00000021213 15114625602 0006462 0 ustar 00 <?php
namespace AIOSEO\Plugin\Common\Schema;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
use AIOSEO\Plugin\Common\Integrations\BuddyPress as BuddyPressIntegration;
use AIOSEO\Plugin\Common\Integrations\BbPress as BbPressIntegration;
/**
* Builds our schema.
*
* @since 4.0.0
*/
class Schema {
/**
* The graphs that need to be generated.
*
* @since 4.2.5
*
* @var array
*/
public $graphs = [];
/**
* The context data.
*
* @since 4.0.0
*
* @var array
*/
public $context = [];
/**
* Helpers class instance.
*
* @since 4.2.7
*
* @var Helpers
*/
public $helpers = null;
/**
* The subdirectories that contain graph classes.
*
* @since 4.2.5
*
* @var array
*/
protected $graphSubDirectories = [
'Article',
'KnowledgeGraph',
'WebPage'
];
/**
* All existing WebPage graphs.
*
* @since 4.0.0
*
* @var array
*/
public $webPageGraphs = [
'WebPage',
'AboutPage',
'CheckoutPage',
'CollectionPage',
'ContactPage',
'FAQPage',
'ItemPage',
'MedicalWebPage',
'ProfilePage',
'RealEstateListing',
'SearchResultsPage'
];
/**
* Fields that can be 0 or null, which shouldn't be stripped when cleaning the data.
*
* @since 4.1.2
*
* @var array
*/
public $nullableFields = [
'price', // Needs to be 0 if free for Software Application.
'ratingValue', // Needs to be 0 for 0 star ratings.
'value', // Needs to be 0 if free for product shipping details.
'minValue', // Needs to be 0 for product delivery time.
'maxValue', // Needs to be 0 for product delivery time.
'suggestedMinAge' // Needs to be 0 for PeopleAudience minimum age.
];
/**
* List of mapped parents with properties that are allowed to contain a restricted set of HTML tags.
*
* @since 4.2.3
*
* @var array
*/
public $htmlAllowedFields = [
// FAQPage
'acceptedAnswer' => [
'text'
]
];
/**
* Whether we are generating the validator output.
*
* @since 4.6.3
*
* @var bool
*/
public $generatingValidatorOutput = false;
/**
* Class constructor.
*/
public function __construct() {
// No AJAX check since we need to be able to grab the schema output via the REST API.
if ( wp_doing_cron() ) {
return;
}
$this->helpers = new Helpers();
}
/**
* Returns the JSON schema output.
*
* @since 4.0.0
*
* @return string The JSON schema output.
*/
public function get() {
// First, check if the schema is disabled.
if ( ! $this->helpers->isEnabled() ) {
return '';
}
$this->determineSmartGraphsAndContext();
return $this->generateSchema();
}
/**
* Generates the JSON schema after the graphs/context have been determined.
*
* @since 4.2.5
*
* @return string The JSON schema output.
*/
protected function generateSchema() {
// Now, filter the graphs.
$this->graphs = apply_filters(
'aioseo_schema_graphs',
array_unique( array_filter( array_values( $this->graphs ) ) )
);
if ( ! $this->graphs ) {
return '';
}
// Check if a WebPage graph is included. Otherwise add the default one.
$webPageGraphFound = false;
foreach ( $this->graphs as $graphName ) {
if ( in_array( $graphName, $this->webPageGraphs, true ) ) {
$webPageGraphFound = true;
break;
}
}
if ( ! $webPageGraphFound ) {
$this->graphs[] = 'WebPage';
}
// Now that we've determined the graphs, start generating their data.
$schema = [
'@context' => 'https://schema.org',
'@graph' => []
];
// By determining the length of the array after every iteration, we are able to add additional graphs during runtime.
// e.g. The Article graph may require a Person graph to be output for the author.
$this->graphs = array_values( $this->graphs );
for ( $i = 0; $i < count( $this->graphs ); $i++ ) {
$namespace = $this->getGraphNamespace( $this->graphs[ $i ] );
if ( $namespace ) {
$schema['@graph'][] = ( new $namespace() )->get();
}
}
return aioseo()->schema->helpers->getOutput( $schema );
}
/**
* Gets the relevant namespace for the given graph.
*
* @since 4.2.5
*
* @param string $graphName The graph name.
* @return string The namespace.
*/
protected function getGraphNamespace( $graphName ) {
$namespace = "\AIOSEO\Plugin\Common\Schema\Graphs\\{$graphName}";
if ( class_exists( $namespace ) ) {
return $namespace;
}
// If we can't find it in the root dir, check if we can find it in a sub dir.
foreach ( $this->graphSubDirectories as $dirName ) {
$namespace = "\AIOSEO\Plugin\Common\Schema\Graphs\\{$dirName}\\{$graphName}";
if ( class_exists( $namespace ) ) {
return $namespace;
}
}
return '';
}
/**
* Determines the smart graphs that need to be output by default, as well as the current context for the breadcrumbs.
*
* @since 4.2.5
*
* @return void
*/
protected function determineSmartGraphsAndContext() {
$this->graphs = array_merge( $this->graphs, $this->getDefaultGraphs() );
$contextInstance = new Context();
$this->context = $contextInstance->defaults();
if ( BuddyPressIntegration::isComponentPage() ) {
aioseo()->standalone->buddyPress->component->determineSchemaGraphsAndContext( $contextInstance );
return;
}
if ( BbPressIntegration::isComponentPage() ) {
aioseo()->standalone->bbPress->component->determineSchemaGraphsAndContext();
return;
}
if ( aioseo()->helpers->isDynamicHomePage() ) {
$this->graphs[] = 'CollectionPage';
$this->context = $contextInstance->home();
return;
}
if ( is_home() || aioseo()->helpers->isWooCommerceShopPage() ) {
$this->graphs[] = 'CollectionPage';
$this->context = $contextInstance->post();
return;
}
if ( is_singular() ) {
$this->determineContextSingular( $contextInstance );
if ( is_singular( 'web-story' ) ) {
$this->graphs[] = 'AmpStory';
}
}
if ( is_category() || is_tag() || is_tax() ) {
$this->graphs[] = 'CollectionPage';
$this->context = $contextInstance->term();
return;
}
if ( is_author() ) {
$this->graphs[] = 'ProfilePage';
$this->graphs[] = 'PersonAuthor';
$this->context = $contextInstance->author();
}
if ( is_post_type_archive() ) {
$this->graphs[] = 'CollectionPage';
$this->context = $contextInstance->postArchive();
return;
}
if ( is_date() ) {
$this->graphs[] = 'CollectionPage';
$this->context = $contextInstance->date();
return;
}
if ( is_search() ) {
$this->graphs[] = 'SearchResultsPage';
$this->context = $contextInstance->search();
return;
}
if ( is_404() ) {
$this->context = $contextInstance->notFound();
}
}
/**
* Determines the smart graphs and context for singular pages.
*
* @since 4.2.6
*
* @param Context $contextInstance The Context class instance.
* @return void
*/
protected function determineContextSingular( $contextInstance ) {
// If the current request is for the validator, we can't include the default graph here.
// We need to include the default graph that the validator sent.
// Don't do this if we're in Pro since we then need to get it from the post meta.
if ( ! $this->generatingValidatorOutput ) {
$this->graphs[] = $this->getDefaultPostGraph();
}
$this->context = $contextInstance->post();
}
/**
* Returns the default graph for the post type.
*
* @since 4.2.6
*
* @return string The default graph.
*/
public function getDefaultPostGraph() {
return $this->getDefaultPostTypeGraph();
}
/**
* Returns the default graph for the current post type.
*
* @since 4.2.5
*
* @param \WP_Post $post The post object.
* @return string The default graph.
*/
public function getDefaultPostTypeGraph( $post = null ) {
$post = $post ? $post : aioseo()->helpers->getPost();
if ( ! is_a( $post, 'WP_Post' ) ) {
return '';
}
$dynamicOptions = aioseo()->dynamicOptions->noConflict();
if ( ! $dynamicOptions->searchAppearance->postTypes->has( $post->post_type ) ) {
return '';
}
$defaultType = $dynamicOptions->searchAppearance->postTypes->{$post->post_type}->schemaType;
switch ( $defaultType ) {
case 'Article':
return $dynamicOptions->searchAppearance->postTypes->{$post->post_type}->articleType;
case 'WebPage':
return $dynamicOptions->searchAppearance->postTypes->{$post->post_type}->webPageType;
default:
return $defaultType;
}
}
/**
* Returns the default graphs that should be output on every page, regardless of its type.
*
* @since 4.2.5
*
* @return array The default graphs.
*/
protected function getDefaultGraphs() {
$siteRepresents = ucfirst( aioseo()->options->searchAppearance->global->schema->siteRepresents );
return [
'BreadcrumbList',
'Kg' . $siteRepresents,
'WebSite'
];
}
} Context.php 0000666 00000014327 15114625602 0006716 0 ustar 00 <?php
namespace AIOSEO\Plugin\Common\Schema;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Determines the context.
*
* @since 4.0.0
*/
class Context {
/**
* Breadcrumb class instance.
*
* @since 4.2.7
*
* @var Breadcrumb
*/
public $breadcrumb = null;
/**
* Class constructor.
*
* @since 4.0.0
*/
public function __construct() {
$this->breadcrumb = new Breadcrumb();
}
/**
* Returns the default context data.
*
* @since 4.3.0
*
* @return array The context data.
*/
public function defaults() {
return [
'name' => aioseo()->meta->title->getTitle(),
'description' => aioseo()->meta->description->getDescription(),
'url' => aioseo()->helpers->getUrl(),
'breadcrumb' => []
];
}
/**
* Returns the context data for the homepage.
*
* @since 4.0.0
*
* @return array $context The context data.
*/
public function home() {
$context = [
'url' => aioseo()->helpers->getUrl(),
'breadcrumb' => $this->breadcrumb->home(),
'name' => aioseo()->meta->title->getTitle(),
'description' => aioseo()->meta->description->getDescription()
];
// Homepage set to show latest posts.
if ( 'posts' === get_option( 'show_on_front' ) && is_home() ) {
return $context;
}
// Homepage set to static page.
$post = aioseo()->helpers->getPost();
if ( ! $post ) {
return [
'name' => '',
'description' => '',
'url' => aioseo()->helpers->getUrl(),
'breadcrumb' => [],
];
}
$context['object'] = $post;
return $context;
}
/**
* Returns the context data for the requested post.
*
* @since 4.0.0
*
* @return array The context data.
*/
public function post() {
$post = aioseo()->helpers->getPost();
if ( ! $post ) {
return [
'name' => '',
'description' => '',
'url' => aioseo()->helpers->getUrl(),
'breadcrumb' => [],
];
}
return [
'name' => aioseo()->meta->title->getTitle( $post ),
'description' => aioseo()->meta->description->getDescription( $post ),
'url' => aioseo()->helpers->getUrl(),
'breadcrumb' => $this->breadcrumb->post( $post ),
'object' => $post,
];
}
/**
* Returns the context data for the requested term archive.
*
* @since 4.0.0
*
* @return array The context data.
*/
public function term() {
$term = aioseo()->helpers->getTerm();
if ( ! $term ) {
return [
'name' => '',
'description' => '',
'url' => aioseo()->helpers->getUrl(),
'breadcrumb' => [],
];
}
return [
'name' => aioseo()->meta->title->getTitle(),
'description' => aioseo()->meta->description->getDescription(),
'url' => aioseo()->helpers->getUrl(),
'breadcrumb' => $this->breadcrumb->term( $term )
];
}
/**
* Returns the context data for the requested author archive.
*
* @since 4.0.0
*
* @return array The context data.
*/
public function author() {
$author = get_queried_object();
if ( ! $author ) {
return [
'name' => '',
'description' => '',
'url' => aioseo()->helpers->getUrl(),
'breadcrumb' => [],
];
}
$title = aioseo()->meta->title->getTitle();
$description = aioseo()->meta->description->getDescription();
$url = aioseo()->helpers->getUrl();
if ( ! $description ) {
$description = get_the_author_meta( 'description', $author->ID );
}
return [
'name' => $title,
'description' => $description,
'url' => $url,
'breadcrumb' => $this->breadcrumb->setPositions( [
'name' => get_the_author_meta( 'display_name', $author->ID ),
'description' => $description,
'url' => $url,
'type' => 'CollectionPage'
] )
];
}
/**
* Returns the context data for the requested post archive.
*
* @since 4.0.0
*
* @return array The context data.
*/
public function postArchive() {
$postType = get_queried_object();
if ( ! $postType ) {
return [
'name' => '',
'description' => '',
'url' => aioseo()->helpers->getUrl(),
'breadcrumb' => [],
];
}
$title = aioseo()->meta->title->getTitle();
$description = aioseo()->meta->description->getDescription();
$url = aioseo()->helpers->getUrl();
return [
'name' => $title,
'description' => $description,
'url' => $url,
'breadcrumb' => $this->breadcrumb->setPositions( [
'name' => $postType->label,
'description' => $description,
'url' => $url,
'type' => 'CollectionPage'
] )
];
}
/**
* Returns the context data for the requested data archive.
*
* @since 4.0.0
*
* @return array $context The context data.
*/
public function date() {
$context = [
'name' => aioseo()->meta->title->getTitle(),
'description' => aioseo()->meta->description->getDescription(),
'url' => aioseo()->helpers->getUrl()
];
$context['breadcrumb'] = $this->breadcrumb->date();
return $context;
}
/**
* Returns the context data for the search page.
*
* @since 4.0.0
*
* @return array The context data.
*/
public function search() {
global $s;
$title = aioseo()->meta->title->getTitle();
$description = aioseo()->meta->description->getDescription();
$url = aioseo()->helpers->getUrl();
return [
'name' => $title,
'description' => $description,
'url' => $url,
'breadcrumb' => $this->breadcrumb->setPositions( [
'name' => $s ? $s : $title,
'description' => $description,
'url' => $url,
'type' => 'SearchResultsPage'
] )
];
}
/**
* Returns the context data for the 404 Not Found page.
*
* @since 4.0.0
*
* @return array The context data.
*/
public function notFound() {
$title = aioseo()->meta->title->getTitle();
$description = aioseo()->meta->description->getDescription();
$url = aioseo()->helpers->getUrl();
return [
'name' => $title,
'description' => $description,
'url' => $url,
'breadcrumb' => $this->breadcrumb->setPositions( [
'name' => __( 'Not Found', 'all-in-one-seo-pack' ),
'description' => $description,
'url' => $url
] )
];
}
} Breadcrumb.php 0000666 00000023613 15114625602 0007336 0 ustar 00 <?php
namespace AIOSEO\Plugin\Common\Schema;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Determines the breadcrumb trail.
*
* @since 4.0.0
*/
class Breadcrumb {
/**
* Returns the breadcrumb trail for the homepage.
*
* @since 4.0.0
*
* @return array The breadcrumb trail.
*/
public function home() {
// Since we just need the root breadcrumb (homepage), we can call this immediately without passing any breadcrumbs.
return $this->setPositions();
}
/**
* Returns the breadcrumb trail for the requested post.
*
* @since 4.0.0
*
* @param \WP_Post $post The post object.
* @return array The breadcrumb trail.
*/
public function post( $post ) {
// Check if page is the static homepage.
if ( aioseo()->helpers->isStaticHomePage() ) {
return $this->home();
}
if ( is_post_type_hierarchical( $post->post_type ) ) {
return $this->setPositions( $this->postHierarchical( $post ) );
}
return $this->setPositions( $this->postNonHierarchical( $post ) );
}
/**
* Returns the breadcrumb trail for a hierarchical post.
*
* @since 4.0.0
*
* @param \WP_Post $post The post object.
* @return array The breadcrumb trail.
*/
private function postHierarchical( $post ) {
$breadcrumbs = [];
do {
array_unshift(
$breadcrumbs,
[
'name' => $post->post_title,
'description' => aioseo()->meta->description->getDescription( $post ),
'url' => get_permalink( $post ),
'type' => aioseo()->helpers->isWooCommerceShopPage( $post->ID ) || is_home() ? 'CollectionPage' : $this->getPostWebPageGraph()
]
);
if ( $post->post_parent ) {
$post = get_post( $post->post_parent );
} else {
$post = false;
}
} while ( $post );
return $breadcrumbs;
}
/**
* Returns the breadcrumb trail for a non-hierarchical post.
*
* In this case we need to compare the permalink structure with the permalink of the requested post and loop through all objects we're able to find.
*
* @since 4.0.0
*
* @param \WP_Post $post The post object.
* @return array The breadcrumb trail.
*/
private function postNonHierarchical( $post ) {
global $wp_query; // phpcs:ignore Squiz.NamingConventions.ValidVariableName
$homeUrl = aioseo()->helpers->escapeRegex( home_url() );
$permalink = get_permalink();
$slug = preg_replace( "/$homeUrl/", '', (string) $permalink );
$tags = array_filter( explode( '/', get_option( 'permalink_structure' ) ) ); // Permalink structure exploded into separate tag strings.
$objects = array_filter( explode( '/', $slug ) ); // Permalink slug exploded into separate object slugs.
$postGraph = $this->getPostWebPageGraph();
if ( count( $tags ) !== count( $objects ) ) {
return [
'name' => $post->post_title,
'description' => aioseo()->meta->description->getDescription( $post ),
'url' => $permalink,
'type' => $postGraph
];
}
$pairs = array_reverse( array_combine( $tags, $objects ) );
$breadcrumbs = [];
$dateName = null;
$timestamp = strtotime( $post->post_date );
foreach ( $pairs as $tag => $object ) {
// Escape the delimiter.
$escObject = aioseo()->helpers->escapeRegex( $object );
// Determine the slug for the object.
preg_match( "/.*{$escObject}[\/]/", (string) $permalink, $url );
if ( empty( $url[0] ) ) {
continue;
}
$breadcrumb = [];
switch ( $tag ) {
case '%category%':
$term = aioseo()->standalone->primaryTerm->getPrimaryTerm( $post->ID, 'category' );
if ( ! $term ) {
$term = get_category_by_slug( $object );
}
if ( ! $term ) {
break;
}
// phpcs:disable Squiz.NamingConventions.ValidVariableName
$oldQueriedObject = $wp_query->queried_object;
$wp_query->queried_object = $term;
$wp_query->is_category = true;
$breadcrumb = [
'name' => $term->name,
'description' => aioseo()->meta->description->getDescription(),
'url' => get_term_link( $term ),
'type' => 'CollectionPage'
];
$wp_query->queried_object = $oldQueriedObject;
$wp_query->is_category = false;
// phpcs:enable Squiz.NamingConventions.ValidVariableName
break;
case '%author%':
$breadcrumb = [
'name' => get_the_author_meta( 'display_name', $post->post_author ),
'description' => aioseo()->meta->description->helpers->prepare( aioseo()->options->searchAppearance->archives->author->metaDescription ),
'url' => $url[0],
'type' => 'ProfilePage'
];
break;
case '%postid%':
case '%postname%':
$breadcrumb = [
'name' => $post->post_title,
'description' => aioseo()->meta->description->getDescription( $post ),
'url' => $url[0],
'type' => $postGraph
];
break;
case '%year%':
$dateName = gmdate( 'Y', $timestamp );
case '%monthnum%':
if ( ! $dateName ) {
$dateName = gmdate( 'F', $timestamp );
}
case '%day%':
if ( ! $dateName ) {
$dateName = gmdate( 'j', $timestamp );
}
$breadcrumb = [
'name' => $dateName,
'description' => aioseo()->meta->description->helpers->prepare( aioseo()->options->searchAppearance->archives->date->metaDescription ),
'url' => $url[0],
'type' => 'CollectionPage'
];
$dateName = null;
break;
default:
break;
}
if ( $breadcrumb ) {
array_unshift( $breadcrumbs, $breadcrumb );
}
}
return $breadcrumbs;
}
/**
* Returns the breadcrumb trail for the requested term.
*
* @since 4.0.0
*
* @param \WP_Term $term The term object.
* @return array The breadcrumb trail.
*/
public function term( $term ) {
if ( 'product_attributes' === $term->taxonomy ) {
$term = get_term( $term->term_id );
}
$breadcrumbs = [];
do {
array_unshift(
$breadcrumbs,
[
'name' => $term->name,
'description' => aioseo()->meta->description->getDescription(),
'url' => get_term_link( $term, $term->taxonomy ),
'type' => 'CollectionPage'
]
);
if ( $term->parent ) {
$term = aioseo()->helpers->getTerm( $term->parent, $term->taxonomy );
} else {
$term = false;
}
} while ( $term );
return $this->setPositions( $breadcrumbs );
}
/**
* Returns the breadcrumb trail for the requested date archive.
*
* @since 4.0.0
*
* @return array The breadcrumb trail.
*/
public function date() {
// phpcs:disable Squiz.NamingConventions.ValidVariableName
global $wp_query;
$oldYear = $wp_query->is_year;
$oldMonth = $wp_query->is_month;
$oldDay = $wp_query->is_day;
$wp_query->is_year = true;
$wp_query->is_month = false;
$wp_query->is_day = false;
$breadcrumbs = [
[
'name' => get_the_date( 'Y' ),
'description' => aioseo()->meta->description->getDescription(),
'url' => trailingslashit( get_year_link( $wp_query->query_vars['year'] ) ),
'type' => 'CollectionPage'
]
];
$wp_query->is_year = $oldYear;
// Fall through if data archive is more specific than the year.
if ( is_year() ) {
return $this->setPositions( $breadcrumbs );
}
$wp_query->is_month = true;
$breadcrumbs[] = [
'name' => get_the_date( 'F, Y' ),
'description' => aioseo()->meta->description->getDescription(),
'url' => trailingslashit( get_month_link(
$wp_query->query_vars['year'],
$wp_query->query_vars['monthnum']
) ),
'type' => 'CollectionPage'
];
$wp_query->is_month = $oldMonth;
// Fall through if data archive is more specific than the year & month.
if ( is_month() ) {
return $this->setPositions( $breadcrumbs );
}
$wp_query->is_day = $oldDay;
$breadcrumbs[] = [
'name' => get_the_date(),
'description' => aioseo()->meta->description->getDescription(),
'url' => trailingslashit( get_day_link(
$wp_query->query_vars['year'],
$wp_query->query_vars['monthnum'],
$wp_query->query_vars['day']
) ),
'type' => 'CollectionPage'
];
// phpcs:enable Squiz.NamingConventions.ValidVariableName
return $this->setPositions( $breadcrumbs );
}
/**
* Sets the position for each breadcrumb after adding the root breadcrumb first.
*
* If no breadcrumbs are passed, then we assume we're on the homepage and just need the root breadcrumb.
*
* @since 4.0.0
*
* @param array $breadcrumbs The breadcrumb trail.
* @return array The modified breadcrumb trail.
*/
public function setPositions( $breadcrumbs = [] ) {
// If the array isn't two-dimensional, then we need to wrap it in another array before continuing.
if (
count( $breadcrumbs ) &&
count( $breadcrumbs ) === count( $breadcrumbs, COUNT_RECURSIVE )
) {
$breadcrumbs = [ $breadcrumbs ];
}
// The homepage needs to be root item of all trails.
$homepage = [
// Translators: This refers to the homepage of the site.
'name' => apply_filters( 'aioseo_schema_breadcrumbs_home', __( 'Home', 'all-in-one-seo-pack' ) ),
'description' => aioseo()->meta->description->getHomePageDescription(),
'url' => trailingslashit( home_url() ),
'type' => 'posts' === get_option( 'show_on_front' ) ? 'CollectionPage' : 'WebPage'
];
array_unshift( $breadcrumbs, $homepage );
$breadcrumbs = array_filter( $breadcrumbs );
foreach ( $breadcrumbs as $index => &$breadcrumb ) {
$breadcrumb['position'] = $index + 1;
}
return $breadcrumbs;
}
/**
* Returns the most relevant WebPage graph for the post.
*
* @since 4.2.5
*
* @return string The graph name.
*/
private function getPostWebPageGraph() {
foreach ( aioseo()->schema->graphs as $graphName ) {
if ( in_array( $graphName, aioseo()->schema->webPageGraphs, true ) ) {
return $graphName;
}
}
// Return the default if no WebPage graph was found.
return 'WebPage';
}
} Graphs/WebPage/RealEstateListing.php 0000666 00000001244 15114625602 0013405 0 ustar 00 <?php
namespace AIOSEO\Plugin\Common\Schema\Graphs\WebPage;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* RealEstateListing graph class.
*
* @since 4.0.0
*/
class RealEstateListing extends WebPage {
/**
* The graph type.
*
* @since 4.0.0
*
* @var string
*/
protected $type = 'RealEstateListing';
/**
* Returns the graph data.
*
* @since 4.0.0
*
* @return array $data The graph data.
*/
public function get() {
$data = parent::get();
$post = aioseo()->helpers->getPost();
if ( ! $post ) {
return $data;
}
$data['datePosted'] = mysql2date( DATE_W3C, $post->post_date, false );
return $data;
}
} Graphs/WebPage/FAQPage.php 0000666 00000000476 15114625602 0011234 0 ustar 00 <?php
namespace AIOSEO\Plugin\Common\Schema\Graphs\WebPage;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* FAQPage graph class.
*
* @since 4.0.0
*/
class FAQPage extends WebPage {
/**
* The graph type.
*
* @since 4.0.0
*
* @var string
*/
protected $type = 'FAQPage';
} Graphs/WebPage/MedicalWebPage.php 0000666 00000000650 15114625602 0012613 0 ustar 00 <?php
namespace AIOSEO\Plugin\Common\Schema\Graphs\WebPage;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* MedicalWebPage graph class.
*
* @since 4.6.4
*/
class MedicalWebPage extends WebPage {
/**
* The graph type.
*
* This value can be overridden by WebPage child graphs that are more specific.
*
* @since 4.6.4
*
* @var string
*/
protected $type = 'MedicalWebPage';
} Graphs/WebPage/AboutPage.php 0000666 00000000504 15114625602 0011667 0 ustar 00 <?php
namespace AIOSEO\Plugin\Common\Schema\Graphs\WebPage;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* AboutPage graph class.
*
* @since 4.0.0
*/
class AboutPage extends WebPage {
/**
* The graph type.
*
* @since 4.0.0
*
* @var string
*/
protected $type = 'AboutPage';
} Graphs/WebPage/CollectionPage.php 0000666 00000000523 15114625602 0012711 0 ustar 00 <?php
namespace AIOSEO\Plugin\Common\Schema\Graphs\WebPage;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* CollectionPage graph class.
*
* @since 4.0.0
*/
class CollectionPage extends WebPage {
/**
* The graph type.
*
* @since 4.0.0
*
* @var string
*/
protected $type = 'CollectionPage';
} Graphs/WebPage/WebPage.php 0000666 00000005577 15114625602 0011351 0 ustar 00 <?php
namespace AIOSEO\Plugin\Common\Schema\Graphs\WebPage;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
use AIOSEO\Plugin\Common\Schema\Graphs;
/**
* WebPage graph class.
*
* @since 4.0.0
*/
class WebPage extends Graphs\Graph {
/**
* The graph type.
*
* This value can be overridden by WebPage child graphs that are more specific.
*
* @since 4.0.0
*
* @var string
*/
protected $type = 'WebPage';
/**
* Returns the graph data.
*
* @since 4.0.0
*
* @return array $data The graph data.
*/
public function get() {
$homeUrl = trailingslashit( home_url() );
$data = [
'@type' => $this->type,
'@id' => aioseo()->schema->context['url'] . '#' . strtolower( $this->type ),
'url' => aioseo()->schema->context['url'],
'name' => aioseo()->meta->title->getTitle(),
'description' => aioseo()->schema->context['description'],
'inLanguage' => aioseo()->helpers->currentLanguageCodeBCP47(),
'isPartOf' => [ '@id' => $homeUrl . '#website' ]
];
$breadcrumbs = aioseo()->breadcrumbs->frontend->getBreadcrumbs() ?? '';
if ( ! empty( $breadcrumbs ) ) {
$data['breadcrumb'] = [ '@id' => aioseo()->schema->context['url'] . '#breadcrumblist' ];
}
if ( is_singular() && 'page' !== get_post_type() ) {
$post = aioseo()->helpers->getPost();
if ( is_a( $post, 'WP_Post' ) && post_type_supports( $post->post_type, 'author' ) ) {
$author = get_author_posts_url( $post->post_author );
if ( ! empty( $author ) ) {
if ( ! in_array( 'PersonAuthor', aioseo()->schema->graphs, true ) ) {
aioseo()->schema->graphs[] = 'PersonAuthor';
}
$data['author'] = [ '@id' => $author . '#author' ];
$data['creator'] = [ '@id' => $author . '#author' ];
}
}
}
if ( isset( aioseo()->schema->context['description'] ) && aioseo()->schema->context['description'] ) {
$data['description'] = aioseo()->schema->context['description'];
}
if ( is_singular() ) {
if ( ! isset( aioseo()->schema->context['object'] ) || ! aioseo()->schema->context['object'] ) {
return $this->getAddonData( $data, 'webPage' );
}
$post = aioseo()->schema->context['object'];
if ( has_post_thumbnail( $post ) ) {
$image = $this->image( get_post_thumbnail_id(), 'mainImage' );
if ( $image ) {
$data['image'] = $image;
$data['primaryImageOfPage'] = [
'@id' => aioseo()->schema->context['url'] . '#mainImage'
];
}
}
$data['datePublished'] = mysql2date( DATE_W3C, $post->post_date, false );
$data['dateModified'] = mysql2date( DATE_W3C, $post->post_modified, false );
return $this->getAddonData( $data, 'webPage' );
}
if ( is_front_page() ) {
$data['about'] = [ '@id' => trailingslashit( home_url() ) . '#' . aioseo()->options->searchAppearance->global->schema->siteRepresents ];
}
return $this->getAddonData( $data, 'webPage' );
}
} Graphs/WebPage/CheckoutPage.php 0000666 00000000642 15114625602 0012365 0 ustar 00 <?php
namespace AIOSEO\Plugin\Common\Schema\Graphs\WebPage;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* CheckoutPage graph class.
*
* @since 4.6.4
*/
class CheckoutPage extends WebPage {
/**
* The graph type.
*
* This value can be overridden by WebPage child graphs that are more specific.
*
* @since 4.6.4
*
* @var string
*/
protected $type = 'CheckoutPage';
} Graphs/WebPage/SearchResultsPage.php 0000666 00000000534 15114625602 0013407 0 ustar 00 <?php
namespace AIOSEO\Plugin\Common\Schema\Graphs\WebPage;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* SearchResultsPage graph class.
*
* @since 4.0.0
*/
class SearchResultsPage extends WebPage {
/**
* The graph type.
*
* @since 4.0.0
*
* @var string
*/
protected $type = 'SearchResultsPage';
} Graphs/WebPage/ContactPage.php 0000666 00000000512 15114625602 0012207 0 ustar 00 <?php
namespace AIOSEO\Plugin\Common\Schema\Graphs\WebPage;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* ContactPage graph class.
*
* @since 4.0.0
*/
class ContactPage extends WebPage {
/**
* The graph type.
*
* @since 4.0.0
*
* @var string
*/
protected $type = 'ContactPage';
} Graphs/WebPage/ProfilePage.php 0000666 00000004274 15114625602 0012225 0 ustar 00 <?php
namespace AIOSEO\Plugin\Common\Schema\Graphs\WebPage;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
use AIOSEO\Plugin\Common\Integrations\BuddyPress as BuddyPressIntegration;
/**
* ProfilePage graph class.
*
* @since 4.0.0
*/
class ProfilePage extends WebPage {
/**
* The graph type.
*
* @since 4.5.6
*
* @var string
*/
protected $type = 'ProfilePage';
/**
* Returns the graph data.
*
* @since 4.5.4
*
* @return array The graph data.
*/
public function get() {
$data = parent::get();
$post = aioseo()->helpers->getPost();
$author = get_queried_object();
if (
! is_a( $author, 'WP_User' ) &&
( is_singular() && ! is_a( $post, 'WP_Post' ) )
) {
return [];
}
global $wp_query; // phpcs:ignore Squiz.NamingConventions.ValidVariableName
$articles = [];
$authorId = $author->ID ?? $post->post_author ?? 0;
foreach ( $wp_query->posts as $post ) { // phpcs:ignore Squiz.NamingConventions.ValidVariableName
if ( $post->post_author !== $authorId ) {
continue;
}
$articles[] = [
'@type' => 'Article',
'url' => get_permalink( $post->ID ),
'headline' => $post->post_title,
'datePublished' => mysql2date( DATE_W3C, $post->post_date, false ),
'dateModified' => mysql2date( DATE_W3C, $post->post_modified, false ),
'author' => [
'@id' => get_author_posts_url( $authorId ) . '#author'
]
];
}
$data = array_merge( $data, [
'dateCreated' => mysql2date( DATE_W3C, $author->user_registered, false ),
'mainEntity' => [
'@id' => get_author_posts_url( $authorId ) . '#author'
],
'hasPart' => $articles
] );
if (
BuddyPressIntegration::isComponentPage() &&
'bp-member_single' === aioseo()->standalone->buddyPress->component->templateType
) {
if ( ! isset( $data['mainEntity'] ) ) {
$data['mainEntity'] = [];
}
$data['mainEntity']['@type'] = 'Person';
$data['mainEntity']['name'] = aioseo()->standalone->buddyPress->component->author->display_name;
$data['mainEntity']['url'] = BuddyPressIntegration::getComponentSingleUrl( 'member', aioseo()->standalone->buddyPress->component->author->ID );
}
return $data;
}
} Graphs/WebPage/ItemPage.php 0000666 00000000626 15114625602 0011520 0 ustar 00 <?php
namespace AIOSEO\Plugin\Common\Schema\Graphs\WebPage;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* ItemPage graph class.
*
* @since 4.0.0
*/
class ItemPage extends WebPage {
/**
* The graph type.
*
* This value can be overridden by WebPage child graphs that are more specific.
*
* @since 4.0.0
*
* @var string
*/
protected $type = 'ItemPage';
} Graphs/WebPage/PersonAuthor.php 0000666 00000004016 15114625602 0012453 0 ustar 00 <?php
namespace AIOSEO\Plugin\Common\Schema\Graphs\WebPage;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
use AIOSEO\Plugin\Common\Schema\Graphs;
/**
* Person Author graph class.
* This a secondary Person graph for post authors and BuddyPress profile pages.
*
* @since 4.0.0
*/
class PersonAuthor extends Graphs\Graph {
/**
* Returns the graph data.
*
* @since 4.0.0
*
* @param int $userId The user ID.
* @return array $data The graph data.
*/
public function get( $userId = null ) {
$post = aioseo()->helpers->getPost();
$user = get_queried_object();
$isAuthorPage = is_author() && is_a( $user, 'WP_User' );
if (
(
( ! is_singular() && ! $isAuthorPage ) ||
( is_singular() && ! is_a( $post, 'WP_Post' ) )
) &&
! $userId
) {
return [];
}
// Dynamically determine the User ID.
if ( ! $userId ) {
$userId = $isAuthorPage ? $user->ID : $post->post_author;
if ( function_exists( 'bp_is_user' ) && bp_is_user() ) {
$userId = intval( wp_get_current_user()->ID );
}
}
if ( ! $userId ) {
return [];
}
$authorUrl = get_author_posts_url( $userId );
$data = [
'@type' => 'Person',
'@id' => $authorUrl . '#author',
'url' => $authorUrl,
'name' => get_the_author_meta( 'display_name', $userId )
];
$avatar = $this->avatar( $userId, 'authorImage' );
if ( $avatar ) {
$data['image'] = $avatar;
}
$socialUrls = array_values( $this->getUserProfiles( $userId ) );
if ( $socialUrls ) {
$data['sameAs'] = $socialUrls;
}
if ( is_author() ) {
$data['mainEntityOfPage'] = [
'@id' => aioseo()->schema->context['url'] . '#profilepage'
];
}
// Check if our addons need to modify this graph.
$addonsPersonAuthorData = array_filter( aioseo()->addons->doAddonFunction( 'personAuthor', 'get', [
'userId' => $userId,
'data' => $data
] ) );
foreach ( $addonsPersonAuthorData as $addonPersonAuthorData ) {
$data = array_merge( $data, $addonPersonAuthorData );
}
return $data;
}
} Graphs/Traits/Image.php 0000666 00000005462 15114625602 0011006 0 ustar 00 <?php
namespace AIOSEO\Plugin\Common\Schema\Graphs\Traits;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Trait that handles images for the graphs.
*
* @since 4.2.5
*/
trait Image {
/**
* Builds the graph data for a given image with a given schema ID.
*
* @since 4.0.0
*
* @param int $imageId The image ID.
* @param string $graphId The graph ID (optional).
* @return array $data The image graph data.
*/
protected function image( $imageId, $graphId = '' ) {
$attachmentId = is_string( $imageId ) && ! is_numeric( $imageId ) ? aioseo()->helpers->attachmentUrlToPostId( $imageId ) : $imageId;
$imageUrl = wp_get_attachment_image_url( $attachmentId, 'full' );
$data = [
'@type' => 'ImageObject',
'url' => $imageUrl ? $imageUrl : $imageId,
];
if ( $graphId ) {
$baseUrl = aioseo()->schema->context['url'] ?? aioseo()->helpers->getUrl();
$data['@id'] = trailingslashit( $baseUrl ) . '#' . $graphId;
}
if ( ! $attachmentId ) {
return $data;
}
$metaData = wp_get_attachment_metadata( $attachmentId );
if ( $metaData && ! empty( $metaData['width'] ) && ! empty( $metaData['height'] ) ) {
$data['width'] = (int) $metaData['width'];
$data['height'] = (int) $metaData['height'];
}
$caption = $this->getImageCaption( $attachmentId );
if ( ! empty( $caption ) ) {
$data['caption'] = $caption;
}
return $data;
}
/**
* Get the image caption.
*
* @since 4.1.4
*
* @param int $attachmentId The attachment ID.
* @return string The caption.
*/
private function getImageCaption( $attachmentId ) {
$caption = wp_get_attachment_caption( $attachmentId );
if ( ! empty( $caption ) ) {
return $caption;
}
return get_post_meta( $attachmentId, '_wp_attachment_image_alt', true );
}
/**
* Returns the graph data for the avatar of a given user.
*
* @since 4.0.0
*
* @param int $userId The user ID.
* @param string $graphId The graph ID.
* @return array The graph data.
*/
protected function avatar( $userId, $graphId ) {
if ( ! get_option( 'show_avatars' ) ) {
return [];
}
$avatar = get_avatar_data( $userId );
if ( ! $avatar['found_avatar'] ) {
return [];
}
return array_filter( [
'@type' => 'ImageObject',
'@id' => aioseo()->schema->context['url'] . "#$graphId",
'url' => $avatar['url'],
'width' => $avatar['width'],
'height' => $avatar['height'],
'caption' => get_the_author_meta( 'display_name', $userId )
] );
}
/**
* Returns the graph data for the post's featured image.
*
* @since 4.2.5
*
* @return string The featured image URL.
*/
protected function getFeaturedImage() {
$post = aioseo()->helpers->getPost();
return has_post_thumbnail( $post ) ? $this->image( get_post_thumbnail_id() ) : '';
}
} Graphs/KnowledgeGraph/KgOrganization.php 0000666 00000005336 15114625602 0014345 0 ustar 00 <?php
namespace AIOSEO\Plugin\Common\Schema\Graphs\KnowledgeGraph;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
use \AIOSEO\Plugin\Common\Schema\Graphs;
/**
* Knowledge Graph Organization graph class.
*
* @since 4.0.0
*/
class KgOrganization extends Graphs\Graph {
/**
* Returns the graph data.
*
* @since 4.0.0
*
* @return array $data The graph data.
*/
public function get() {
$homeUrl = trailingslashit( home_url() );
$organizationName = aioseo()->tags->replaceTags( aioseo()->options->searchAppearance->global->schema->organizationName );
$organizationDescription = aioseo()->tags->replaceTags( aioseo()->options->searchAppearance->global->schema->organizationDescription );
$data = [
'@type' => 'Organization',
'@id' => $homeUrl . '#organization',
'name' => $organizationName ? $organizationName : aioseo()->helpers->decodeHtmlEntities( get_bloginfo( 'name' ) ),
'description' => $organizationDescription,
'url' => $homeUrl,
'email' => aioseo()->options->searchAppearance->global->schema->email,
'telephone' => aioseo()->options->searchAppearance->global->schema->phone,
'foundingDate' => aioseo()->options->searchAppearance->global->schema->foundingDate
];
$numberOfEmployeesData = aioseo()->options->searchAppearance->global->schema->numberOfEmployees->all();
if (
$numberOfEmployeesData['isRange'] &&
isset( $numberOfEmployeesData['from'] ) &&
isset( $numberOfEmployeesData['to'] ) &&
0 < $numberOfEmployeesData['to']
) {
$data['numberOfEmployees'] = [
'@type' => 'QuantitativeValue',
'minValue' => $numberOfEmployeesData['from'],
'maxValue' => $numberOfEmployeesData['to']
];
}
if (
! $numberOfEmployeesData['isRange'] &&
! empty( $numberOfEmployeesData['number'] )
) {
$data['numberOfEmployees'] = [
'@type' => 'QuantitativeValue',
'value' => $numberOfEmployeesData['number']
];
}
$logo = $this->logo();
if ( ! empty( $logo ) ) {
$data['logo'] = $logo;
$data['image'] = [ '@id' => $data['logo']['@id'] ];
}
$socialUrls = array_values( $this->getOrganizationProfiles() );
if ( $socialUrls ) {
$data['sameAs'] = $socialUrls;
}
$data = $this->getAddonData( $data, 'kgOrganization' );
return $data;
}
/**
* Returns the logo data.
*
* @since 4.0.0
*
* @return array The logo data.
*/
public function logo() {
$logo = aioseo()->options->searchAppearance->global->schema->organizationLogo;
if ( $logo ) {
return $this->image( $logo, 'organizationLogo' );
}
$imageId = aioseo()->helpers->getSiteLogoId();
if ( $imageId ) {
return $this->image( $imageId, 'organizationLogo' );
}
return [];
}
} Graphs/KnowledgeGraph/KgPerson.php 0000666 00000003457 15114625602 0013151 0 ustar 00 <?php
namespace AIOSEO\Plugin\Common\Schema\Graphs\KnowledgeGraph;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
use \AIOSEO\Plugin\Common\Schema\Graphs;
/**
* Knowledge Graph Person graph class.
* This is the main Person graph that can be set to represent the site.
*
* @since 4.0.0
*/
class KgPerson extends Graphs\Graph {
/**
* Returns the graph data.
*
* @since 4.0.0
*
* @return array $data The graph data.
*/
public function get() {
if ( 'person' !== aioseo()->options->searchAppearance->global->schema->siteRepresents ) {
return [];
}
$person = aioseo()->options->searchAppearance->global->schema->person;
if ( 'manual' === $person ) {
return $this->manual();
}
$person = intval( $person );
if ( empty( $person ) ) {
return [];
}
$data = [
'@type' => 'Person',
'@id' => trailingslashit( home_url() ) . '#person',
'name' => get_the_author_meta( 'display_name', $person )
];
$avatar = $this->avatar( $person, 'personImage' );
if ( $avatar ) {
$data['image'] = $avatar;
}
$socialUrls = array_values( $this->getUserProfiles( $person ) );
if ( $socialUrls ) {
$data['sameAs'] = $socialUrls;
}
return $data;
}
/**
* Returns the data for the person if it is set manually.
*
* @since 4.0.0
*
* @return array $data The graph data.
*/
private function manual() {
$data = [
'@type' => 'Person',
'@id' => trailingslashit( home_url() ) . '#person',
'name' => aioseo()->options->searchAppearance->global->schema->personName
];
$logo = aioseo()->options->searchAppearance->global->schema->personLogo;
if ( $logo ) {
$data['image'] = $logo;
}
$socialUrls = array_values( $this->getOrganizationProfiles() );
if ( $socialUrls ) {
$data['sameAs'] = $socialUrls;
}
return $data;
}
} Graphs/WebSite.php 0000666 00000001747 15114625602 0010062 0 ustar 00 <?php
namespace AIOSEO\Plugin\Common\Schema\Graphs;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* WebSite graph class.
*
* @since 4.0.0
*/
class WebSite extends Graph {
/**
* Returns the graph data.
*
* @since 4.0.0
*
* @return array $data The graph data.
*/
public function get() {
$homeUrl = trailingslashit( home_url() );
$data = [
'@type' => 'WebSite',
'@id' => $homeUrl . '#website',
'url' => $homeUrl,
'name' => aioseo()->helpers->getWebsiteName(),
'alternateName' => aioseo()->tags->replaceTags( aioseo()->options->searchAppearance->global->schema->websiteAlternateName ),
'description' => aioseo()->helpers->decodeHtmlEntities( get_bloginfo( 'description' ) ),
'inLanguage' => aioseo()->helpers->currentLanguageCodeBCP47(),
'publisher' => [ '@id' => $homeUrl . '#' . aioseo()->options->searchAppearance->global->schema->siteRepresents ]
];
return $data;
}
} Graphs/BreadcrumbList.php 0000666 00000004205 15114625602 0011412 0 ustar 00 <?php
namespace AIOSEO\Plugin\Common\Schema\Graphs;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* BreadcrumbList graph class.
*
* @since 4.0.0
*/
class BreadcrumbList extends Graph {
/**
* Returns the graph data.
*
* @since 4.0.0
*
* @return array The graph data.
*/
public function get() {
$breadcrumbs = aioseo()->breadcrumbs->frontend->getBreadcrumbs() ?? '';
if ( ! $breadcrumbs ) {
return [];
}
// Set the position for each breadcrumb.
foreach ( $breadcrumbs as $k => $breadcrumb ) {
if ( ! isset( $breadcrumb['position'] ) ) {
$breadcrumbs[ $k ]['position'] = $k + 1;
}
}
$trailLength = count( $breadcrumbs );
if ( ! $trailLength ) {
return [];
}
$listItems = [];
foreach ( $breadcrumbs as $breadcrumb ) {
if ( empty( $breadcrumb['link'] ) ) {
continue;
}
$listItem = [
'@type' => 'ListItem',
'@id' => $breadcrumb['link'] . '#listItem',
'position' => $breadcrumb['position'],
'name' => $breadcrumb['label'] ?? ''
];
// Don't add "item" prop for last crumb.
if ( $trailLength !== $breadcrumb['position'] ) {
$listItem['item'] = $breadcrumb['link'];
}
if ( 1 === $trailLength ) {
$listItems[] = $listItem;
continue;
}
if ( $trailLength > $breadcrumb['position'] && ! empty( $breadcrumbs[ $breadcrumb['position'] ]['label'] ) ) {
$listItem['nextItem'] = [
'@type' => 'ListItem',
'@id' => $breadcrumbs[ $breadcrumb['position'] ]['link'] . '#listItem',
'name' => $breadcrumbs[ $breadcrumb['position'] ]['label'],
];
}
if ( 1 < $breadcrumb['position'] && ! empty( $breadcrumbs[ $breadcrumb['position'] - 2 ]['label'] ) ) {
$listItem['previousItem'] = [
'@type' => 'ListItem',
'@id' => $breadcrumbs[ $breadcrumb['position'] - 2 ]['link'] . '#listItem',
'name' => $breadcrumbs[ $breadcrumb['position'] - 2 ]['label'],
];
}
$listItems[] = $listItem;
}
$data = [
'@type' => 'BreadcrumbList',
'@id' => aioseo()->schema->context['url'] . '#breadcrumblist',
'itemListElement' => $listItems
];
return $data;
}
} Graphs/Graph.php 0000666 00000004542 15114625602 0007555 0 ustar 00 <?php
namespace AIOSEO\Plugin\Common\Schema\Graphs;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
use AIOSEO\Plugin\Common\Traits as CommonTraits;
/**
* The base graph class.
*
* @since 4.0.0
*/
abstract class Graph {
use Traits\Image;
use CommonTraits\SocialProfiles;
/**
* The graph data to overwrite.
*
* @since 4.7.6
*
* @var array
*/
protected static $overwriteGraphData = [];
/**
* Returns the graph data.
*
* @since 4.0.0
*/
abstract public function get();
/**
* Iterates over a list of functions and sets the results as graph data.
*
* @since 4.0.13
*
* @param array $data The graph data to add to.
* @param array $dataFunctions List of functions to loop over, associated with a graph property.
* @return array $data The graph data with the results added.
*/
protected function getData( $data, $dataFunctions ) {
foreach ( $dataFunctions as $k => $f ) {
if ( ! method_exists( $this, $f ) ) {
continue;
}
$value = $this->$f();
if ( $value || in_array( $k, aioseo()->schema->nullableFields, true ) ) {
$data[ $k ] = $value;
}
}
return $data;
}
/**
* Decodes a multiselect field and returns the values.
*
* @since 4.6.4
*
* @param string $json The JSON encoded multiselect field.
* @return array The decoded values.
*/
protected function extractMultiselectTags( $json ) {
$tags = is_string( $json ) ? json_decode( $json ) : [];
if ( ! $tags ) {
return [];
}
return wp_list_pluck( $tags, 'value' );
}
/**
* Merges in data from our addon plugins.
*
* @since 4.5.6
* @version 4.6.4 Moved to main graph class.
*
* @param array $data The graph data.
* @return array The graph data.
*/
protected function getAddonData( $data, $className, $methodName = 'getAdditionalGraphData' ) {
$addonData = array_filter( aioseo()->addons->doAddonFunction( $className, $methodName, [
'postId' => get_the_ID(),
'data' => $data
] ) );
foreach ( $addonData as $addonGraphData ) {
$data = array_merge( $data, $addonGraphData );
}
return $data;
}
/**
* A way to overwrite the graph data.
*
* @since 4.7.6
*
* @param array $data The data to overwrite.
* @return void
*/
public static function setOverwriteGraphData( $data ) {
self::$overwriteGraphData[ static::class ] = $data;
}
} Graphs/Article/NewsArticle.php 0000666 00000002315 15114625602 0012313 0 ustar 00 <?php
namespace AIOSEO\Plugin\Common\Schema\Graphs\Article;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* News Article graph class.
*
* @since 4.0.0
*/
class NewsArticle extends Article {
/**
* Returns the graph data.
*
* @since 4.0.0
*
* @param object $graphData The graph data.
* @return array The parsed graph data.
*/
public function get( $graphData = null ) {
if ( ! empty( self::$overwriteGraphData[ __CLASS__ ] ) ) {
$graphData = json_decode( wp_json_encode( wp_parse_args( self::$overwriteGraphData[ __CLASS__ ], $graphData ) ) );
}
$data = parent::get( $graphData );
if ( ! $data ) {
return [];
}
$data['@type'] = 'NewsArticle';
$data['@id'] = ! empty( $graphData->id ) ? aioseo()->schema->context['url'] . $graphData->id : aioseo()->schema->context['url'] . '#newsarticle';
$date = ! empty( $graphData->properties->datePublished )
? mysql2date( 'F j, Y', $graphData->properties->datePublished, false )
: get_the_date( 'F j, Y' );
if ( $date ) {
// Translators: 1 - A date (e.g. September 2, 2022).
$data['dateline'] = sprintf( __( 'Published on %1$s.', 'all-in-one-seo-pack' ), $date );
}
return $data;
}
} Graphs/Article/BlogPosting.php 0000666 00000001307 15114625602 0012322 0 ustar 00 <?php
namespace AIOSEO\Plugin\Common\Schema\Graphs\Article;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Blog Posting graph class.
*
* @since 4.0.0
*/
class BlogPosting extends Article {
/**
* Returns the graph data.
*
* @since 4.0.0
*
* @return object $graphData The graph data.
* @return array The parsed graph data.
*/
public function get( $graphData = null ) {
$data = parent::get( $graphData );
if ( ! $data ) {
return [];
}
$data['@type'] = 'BlogPosting';
$data['@id'] = ! empty( $graphData->id ) ? aioseo()->schema->context['url'] . $graphData->id : aioseo()->schema->context['url'] . '#blogposting';
return $data;
}
} Graphs/Article/Article.php 0000666 00000011770 15114625602 0011463 0 ustar 00 <?php
namespace AIOSEO\Plugin\Common\Schema\Graphs\Article;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
use AIOSEO\Plugin\Common\Schema\Graphs;
/**
* Article graph class.
*
* @since 4.0.0
*/
class Article extends Graphs\Graph {
/**
* Returns the graph data.
*
* @since 4.2.5
*
* @param Object $graphData The graph data.
* @return array The parsed graph data.
*/
public function get( $graphData = null ) {
$post = aioseo()->helpers->getPost();
if ( ! is_a( $post, 'WP_Post' ) ) {
return [];
}
$data = [
'@type' => 'Article',
'@id' => ! empty( $graphData->id ) ? aioseo()->schema->context['url'] . $graphData->id : aioseo()->schema->context['url'] . '#article',
'name' => ! empty( $graphData->properties->name ) ? $graphData->properties->name : aioseo()->schema->context['name'],
'headline' => ! empty( $graphData->properties->headline ) ? $graphData->properties->headline : get_the_title(),
'description' => ! empty( $graphData->properties->description ) ? $graphData->properties->description : '',
'author' => [
'@type' => 'Person',
'name' => ! empty( $graphData->properties->author->name ) ? $graphData->properties->author->name : get_the_author_meta( 'display_name' ),
'url' => ! empty( $graphData->properties->author->url ) ? $graphData->properties->author->url : '',
],
'publisher' => [ '@id' => trailingslashit( home_url() ) . '#' . aioseo()->options->searchAppearance->global->schema->siteRepresents ],
'image' => ! empty( $graphData->properties->image ) ? $this->image( $graphData->properties->image ) : $this->postImage( $post ),
'datePublished' => ! empty( $graphData->properties->dates->datePublished )
? mysql2date( DATE_W3C, $graphData->properties->dates->datePublished, false )
: mysql2date( DATE_W3C, $post->post_date, false ),
'dateModified' => ! empty( $graphData->properties->dates->dateModified )
? mysql2date( DATE_W3C, $graphData->properties->dates->dateModified, false )
: mysql2date( DATE_W3C, $post->post_modified, false ),
'inLanguage' => aioseo()->helpers->currentLanguageCodeBCP47(),
'commentCount' => get_comment_count( $post->ID )['approved'],
'mainEntityOfPage' => empty( $graphData ) ? [ '@id' => aioseo()->schema->context['url'] . '#webpage' ] : '',
'isPartOf' => empty( $graphData ) ? [ '@id' => aioseo()->schema->context['url'] . '#webpage' ] : ''
];
if ( empty( $graphData->properties->author->name ) ) {
if ( ! in_array( 'PersonAuthor', aioseo()->schema->graphs, true ) ) {
aioseo()->schema->graphs[] = 'PersonAuthor';
}
$data['author'] = [
'@id' => get_author_posts_url( $post->post_author ) . '#author'
];
}
if ( ! empty( $graphData->properties->keywords ) ) {
$keywords = json_decode( $graphData->properties->keywords, true );
$keywords = array_map( function ( $keywordObject ) {
return $keywordObject['value'];
}, $keywords );
$data['keywords'] = implode( ', ', $keywords );
}
if ( isset( $graphData->properties->dates->include ) && ! $graphData->properties->dates->include ) {
unset( $data['datePublished'] );
unset( $data['dateModified'] );
}
$postTaxonomies = get_post_taxonomies( $post );
$postTerms = [];
foreach ( $postTaxonomies as $taxonomy ) {
$terms = get_the_terms( $post, $taxonomy );
if ( $terms ) {
$postTerms = array_merge( $postTerms, wp_list_pluck( $terms, 'name' ) );
}
}
if ( ! empty( $postTerms ) ) {
$data['articleSection'] = implode( ', ', $postTerms );
}
$pageNumber = aioseo()->helpers->getPageNumber();
if ( 1 < $pageNumber ) {
$data['pagination'] = $pageNumber;
}
return $data;
}
/**
* Returns the graph data for the post image.
*
* @since 4.0.0
*
* @param \WP_Post $post The post object.
* @return array The image graph data.
*/
private function postImage( $post ) {
$featuredImage = $this->getFeaturedImage();
if ( $featuredImage ) {
return $featuredImage;
}
preg_match_all( '#<img[^>]+src="([^">]+)"#', (string) $post->post_content, $matches );
if ( isset( $matches[1] ) && isset( $matches[1][0] ) ) {
$url = aioseo()->helpers->removeImageDimensions( $matches[1][0] );
$imageId = aioseo()->helpers->attachmentUrlToPostId( $url );
if ( $imageId ) {
return $this->image( $imageId, 'articleImage' );
} else {
return $this->image( $url, 'articleImage' );
}
}
if ( 'organization' === aioseo()->options->searchAppearance->global->schema->siteRepresents ) {
$logo = ( new Graphs\KnowledgeGraph\KgOrganization() )->logo();
if ( ! empty( $logo ) ) {
$logo['@id'] = trailingslashit( home_url() ) . '#articleImage';
return $logo;
}
} else {
$avatar = $this->avatar( $post->post_author, 'articleImage' );
if ( $avatar ) {
return $avatar;
}
}
$imageId = aioseo()->helpers->getSiteLogoId();
if ( $imageId ) {
return $this->image( $imageId, 'articleImage' );
}
return [];
}
} Graphs/AmpStory.php 0000666 00000002471 15114625602 0010271 0 ustar 00 <?php
namespace AIOSEO\Plugin\Common\Schema\Graphs;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* AmpStory graph class.
*
* @since 4.7.6
*/
class AmpStory extends Graph {
/**
* Returns the graph data.
*
* @since 4.7.6
*
* @return array The parsed graph data.
*/
public function get() {
$post = aioseo()->helpers->getPost();
if ( ! is_a( $post, 'WP_Post' ) || 'web-story' !== $post->post_type ) {
return [];
}
$data = [
'@type' => 'AmpStory',
'@id' => aioseo()->schema->context['url'] . '#amp-story',
'name' => aioseo()->schema->context['name'],
'headline' => get_the_title(),
'author' => [
'@id' => get_author_posts_url( $post->post_author ) . '#author'
],
'publisher' => [ '@id' => trailingslashit( home_url() ) . '#' . aioseo()->options->searchAppearance->global->schema->siteRepresents ],
'image' => $this->getFeaturedImage(),
'datePublished' => mysql2date( DATE_W3C, $post->post_date, false ),
'dateModified' => mysql2date( DATE_W3C, $post->post_modified, false ),
'inLanguage' => aioseo()->helpers->currentLanguageCodeBCP47()
];
if ( ! in_array( 'PersonAuthor', aioseo()->schema->graphs, true ) ) {
aioseo()->schema->graphs[] = 'PersonAuthor';
}
return $data;
}
} Helpers.php 0000666 00000006776 15114625602 0006705 0 ustar 00 <?php
namespace AIOSEO\Plugin\Common\Schema;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Contains helper methods for our schema classes.
*
* @since 4.2.5
*/
class Helpers {
/**
* Checks whether the schema markup feature is enabled.
*
* @since 4.2.5
*
* @return bool Whether the schema markup feature is enabled or not.
*/
public function isEnabled() {
$isEnabled = ! in_array( 'enableSchemaMarkup', aioseo()->internalOptions->deprecatedOptions, true ) || aioseo()->options->deprecated->searchAppearance->global->schema->enableSchemaMarkup;
return ! apply_filters( 'aioseo_schema_disable', ! $isEnabled );
}
/**
* Strips HTML and removes all blank properties in each of our graphs.
* Also parses properties that might contain smart tags.
*
* @since 4.0.13
* @version 4.2.5
*
* @param array $data The graph data.
* @param string $parentKey The key of the group parent (optional).
* @param bool $replaceTags Whether the smart tags should be replaced.
* @return array The cleaned graph data.
*/
public function cleanAndParseData( $data, $parentKey = '', $replaceTags = true ) {
foreach ( $data as $k => &$v ) {
if ( is_numeric( $v ) || is_bool( $v ) || is_null( $v ) ) {
// Do nothing.
} elseif ( is_array( $v ) ) {
$v = $this->cleanAndParseData( $v, $k, $replaceTags );
} else {
// Check if the prop can contain some HTML tags.
if (
isset( aioseo()->schema->htmlAllowedFields[ $parentKey ] ) &&
in_array( $k, aioseo()->schema->htmlAllowedFields[ $parentKey ], true )
) {
$v = trim( wp_kses_post( $v ) );
} else {
$v = trim( wp_strip_all_tags( $v ) );
}
$v = $replaceTags ? aioseo()->tags->replaceTags( $v, get_the_ID() ) : $v;
}
if ( empty( $v ) && ! in_array( $k, aioseo()->schema->nullableFields, true ) ) {
unset( $data[ $k ] );
} else {
$data[ $k ] = $v;
}
}
return $data;
}
/**
* Sorts the schema data and then returns it as JSON.
* We temporarily change the floating point precision in order to prevent rounding errors.
* Otherwise e.g. 4.9 could be output as 4.90000004.
*
* @since 4.2.7
*
* @param array $schema The schema data.
* @param bool $replaceTags Whether the smart tags should be replaced.
* @return string The schema as JSON.
*/
public function getOutput( $schema, $replaceTags = true ) {
$schema['@graph'] = apply_filters( 'aioseo_schema_output', $schema['@graph'] );
$schema['@graph'] = $this->cleanAndParseData( $schema['@graph'], '', $replaceTags );
// Sort the graphs alphabetically.
usort( $schema['@graph'], function ( $a, $b ) {
$typeA = $a['@type'] ?? null;
$typeB = $b['@type'] ?? null;
if ( is_null( $typeA ) || is_array( $typeA ) ) {
return 1;
}
if ( is_null( $typeB ) || is_array( $typeB ) ) {
return -1;
}
return strcmp( $typeA, $typeB );
} );
// Allow users to control the default json_encode flags.
// Some users report better SEO performance when non-Latin unicode characters are not escaped.
$jsonFlags = apply_filters( 'aioseo_schema_json_flags', 0 );
$json = isset( $_GET['aioseo-dev'] ) || aioseo()->schema->generatingValidatorOutput // phpcs:ignore HM.Security.NonceVerification.Recommended, WordPress.Security.NonceVerification.Recommended
? aioseo()->helpers->wpJsonEncode( $schema, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE )
: aioseo()->helpers->wpJsonEncode( $schema, $jsonFlags );
return $json;
}
}