PDF rausgenommen
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,70 @@
|
||||
<?php
|
||||
/**
|
||||
* WPSEO plugin file.
|
||||
*
|
||||
* @package WPSEO\Frontend
|
||||
*/
|
||||
|
||||
/**
|
||||
* Represents the classifier for determine the type of the currently opened page.
|
||||
*/
|
||||
class WPSEO_Frontend_Page_Type {
|
||||
|
||||
/**
|
||||
* Checks if the currently opened page is a simple page.
|
||||
*
|
||||
* @return bool Whether the currently opened page is a simple page.
|
||||
*/
|
||||
public function is_simple_page() {
|
||||
return $this->get_simple_page_id() > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the id of the currently opened page.
|
||||
*
|
||||
* @return int The id of the currently opened page.
|
||||
*/
|
||||
public function get_simple_page_id() {
|
||||
if ( is_singular() ) {
|
||||
return get_the_ID();
|
||||
}
|
||||
|
||||
if ( $this->is_posts_page() ) {
|
||||
return get_option( 'page_for_posts' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter: Allow changing the default page id.
|
||||
*
|
||||
* @api int $page_id The default page id.
|
||||
*/
|
||||
return apply_filters( 'wpseo_frontend_page_type_simple_page_id', 0 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether this is the homepage and shows posts.
|
||||
*
|
||||
* @return bool Whether or not the current page is the homepage that displays posts.
|
||||
*/
|
||||
public function is_home_posts_page() {
|
||||
return ( is_home() && get_option( 'show_on_front' ) === 'posts' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether this is the static frontpage.
|
||||
*
|
||||
* @return bool Whether or not the current page is a static frontpage.
|
||||
*/
|
||||
public function is_home_static_page() {
|
||||
return ( is_front_page() && get_option( 'show_on_front' ) === 'page' && is_page( get_option( 'page_on_front' ) ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether this is the statically set posts page, when it's not the frontpage.
|
||||
*
|
||||
* @return bool Whether or not it's a non-frontpage, statically set posts page.
|
||||
*/
|
||||
public function is_posts_page() {
|
||||
return ( is_home() && get_option( 'show_on_front' ) === 'page' );
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,92 @@
|
||||
<?php
|
||||
/**
|
||||
* WPSEO plugin file.
|
||||
*
|
||||
* @package WPSEO\Frontend
|
||||
*/
|
||||
|
||||
/**
|
||||
* Class WPSEO_Handle_404
|
||||
*
|
||||
* Handles intercepting requests.
|
||||
*
|
||||
* @since 9.4
|
||||
*/
|
||||
class WPSEO_Handle_404 implements WPSEO_WordPress_Integration {
|
||||
|
||||
/**
|
||||
* Registers all hooks to WordPress.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register_hooks() {
|
||||
add_filter( 'pre_handle_404', array( $this, 'handle_404' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the 404 status code.
|
||||
*
|
||||
* @param bool $handled Whether we've handled the request.
|
||||
*
|
||||
* @return bool True if it's 404.
|
||||
*/
|
||||
public function handle_404( $handled ) {
|
||||
|
||||
if ( is_feed() ) {
|
||||
return $this->is_feed_404( $handled );
|
||||
}
|
||||
|
||||
return $handled;
|
||||
}
|
||||
|
||||
/**
|
||||
* If there are no posts in a feed, make it 404 instead of sending an empty RSS feed.
|
||||
*
|
||||
* @global WP_Query $wp_query
|
||||
*
|
||||
* @param bool $handled Whether we've handled the request.
|
||||
*
|
||||
* @return bool True if it's 404.
|
||||
*/
|
||||
protected function is_feed_404( $handled ) {
|
||||
global $wp_query;
|
||||
|
||||
// Don't 404 if the query contains post(s) or an object.
|
||||
if ( $wp_query->posts || $wp_query->get_queried_object() ) {
|
||||
return $handled;
|
||||
}
|
||||
|
||||
// Don't 404 if it isn't archive or singular.
|
||||
if ( ! $wp_query->is_archive() && ! $wp_query->is_singular() ) {
|
||||
return $handled;
|
||||
}
|
||||
|
||||
$wp_query->is_feed = false;
|
||||
$this->set_404();
|
||||
|
||||
add_filter( 'old_slug_redirect_url', '__return_false' );
|
||||
add_filter( 'redirect_canonical', '__return_false' );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the 404 status code.
|
||||
*
|
||||
* @global WP_Query $wp_query
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function set_404() {
|
||||
global $wp_query;
|
||||
|
||||
// Overwrite Content-Type header.
|
||||
if ( ! headers_sent() ) {
|
||||
header( 'Content-Type: ' . get_option( 'html_type' ) . '; charset=' . get_option( 'blog_charset' ) );
|
||||
}
|
||||
|
||||
$wp_query->set_404();
|
||||
status_header( 404 );
|
||||
nocache_headers();
|
||||
}
|
||||
}
|
@ -0,0 +1,707 @@
|
||||
<?php
|
||||
/**
|
||||
* WPSEO plugin file.
|
||||
*
|
||||
* @package WPSEO\Frontend
|
||||
*/
|
||||
|
||||
/**
|
||||
* Class WPSEO_OpenGraph_Image.
|
||||
*/
|
||||
class WPSEO_OpenGraph_Image {
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
const EXTERNAL_IMAGE_ID = '-1';
|
||||
|
||||
/**
|
||||
* Holds the images that have been put out as OG image.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $images = array();
|
||||
|
||||
/**
|
||||
* Holds the WPSEO_OpenGraph instance, so we can call og_tag.
|
||||
*
|
||||
* @var WPSEO_OpenGraph
|
||||
*/
|
||||
private $opengraph;
|
||||
|
||||
/**
|
||||
* Holds the WPSEO_Frontend_Page_Type instance.
|
||||
*
|
||||
* @var WPSEO_Frontend_Page_Type
|
||||
*/
|
||||
private $frontend_page_type;
|
||||
|
||||
/**
|
||||
* Image tags that we output for each image.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $image_tags = array(
|
||||
'width' => 'width',
|
||||
'height' => 'height',
|
||||
'mime-type' => 'type',
|
||||
);
|
||||
|
||||
/**
|
||||
* The parameters we have for Facebook images.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $image_params = array(
|
||||
'min_width' => 200,
|
||||
'max_width' => 2000,
|
||||
'min_height' => 200,
|
||||
'max_height' => 2000,
|
||||
);
|
||||
|
||||
/**
|
||||
* Image types that are supported by OpenGraph.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $valid_image_types = array( 'image/jpeg', 'image/gif', 'image/png' );
|
||||
|
||||
/**
|
||||
* Image extensions that are supported by OpenGraph.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $valid_image_extensions = array( 'jpeg', 'jpg', 'gif', 'png' );
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param null|string $image Optional. The Image to use.
|
||||
* @param WPSEO_OpenGraph $opengraph Optional. The OpenGraph object.
|
||||
*/
|
||||
public function __construct( $image = null, WPSEO_OpenGraph $opengraph = null ) {
|
||||
if ( $opengraph === null ) {
|
||||
global $wpseo_og;
|
||||
|
||||
// Use the global if available.
|
||||
if ( empty( $wpseo_og ) ) {
|
||||
$wpseo_og = new WPSEO_OpenGraph();
|
||||
}
|
||||
|
||||
$opengraph = $wpseo_og;
|
||||
}
|
||||
|
||||
$this->opengraph = $opengraph;
|
||||
|
||||
if ( ! empty( $image ) && is_string( $image ) ) {
|
||||
$this->add_image_by_url( $image );
|
||||
}
|
||||
|
||||
if ( ! post_password_required() ) {
|
||||
$this->set_images();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the class for determine the current page type.
|
||||
*
|
||||
* @return WPSEO_Frontend_Page_Type
|
||||
*/
|
||||
protected function get_frontend_page_type() {
|
||||
if ( ! isset( $this->frontend_page_type ) ) {
|
||||
$this->frontend_page_type = new WPSEO_Frontend_Page_Type();
|
||||
}
|
||||
|
||||
return $this->frontend_page_type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs the images.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function show() {
|
||||
foreach ( $this->get_images() as $image => $image_meta ) {
|
||||
$this->og_image_tag( $image );
|
||||
$this->show_image_meta( $image_meta );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Output the image metadata.
|
||||
*
|
||||
* @param array $image_meta Image meta data to output.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function show_image_meta( $image_meta ) {
|
||||
foreach ( $this->image_tags as $key => $value ) {
|
||||
if ( ! empty( $image_meta[ $key ] ) ) {
|
||||
$this->opengraph->og_tag( 'og:image:' . $key, $image_meta[ $key ] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs an image tag based on whether it's https or not.
|
||||
*
|
||||
* @param string $image_url The image URL.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function og_image_tag( $image_url ) {
|
||||
$this->opengraph->og_tag( 'og:image', esc_url( $image_url ) );
|
||||
|
||||
// Add secure URL if detected. Not all services implement this, so the regular one also needs to be rendered.
|
||||
if ( strpos( $image_url, 'https://' ) === 0 ) {
|
||||
$this->opengraph->og_tag( 'og:image:secure_url', esc_url( $image_url ) );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the images array.
|
||||
*
|
||||
* @return array The images.
|
||||
*/
|
||||
public function get_images() {
|
||||
return $this->images;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether we have images or not.
|
||||
*
|
||||
* @return bool True if we have images, false if we don't.
|
||||
*/
|
||||
public function has_images() {
|
||||
return ! empty( $this->images );
|
||||
}
|
||||
|
||||
/**
|
||||
* Display an OpenGraph image tag.
|
||||
*
|
||||
* @param string|array $attachment Attachment array.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function add_image( $attachment ) {
|
||||
// In the past `add_image` accepted an image url, so leave this for backwards compatibility.
|
||||
if ( is_string( $attachment ) ) {
|
||||
$attachment = array( 'url' => $attachment );
|
||||
}
|
||||
|
||||
if ( ! is_array( $attachment ) || empty( $attachment['url'] ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If the URL ends in `.svg`, we need to return.
|
||||
if ( ! $this->is_valid_image_url( $attachment['url'] ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter: 'wpseo_opengraph_image' - Allow changing the OpenGraph image.
|
||||
*
|
||||
* @api string - The URL of the OpenGraph image.
|
||||
*/
|
||||
$image_url = trim( apply_filters( 'wpseo_opengraph_image', $attachment['url'] ) );
|
||||
if ( empty( $image_url ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( WPSEO_Utils::is_url_relative( $image_url ) === true ) {
|
||||
$image_url = WPSEO_Image_Utils::get_relative_path( $image_url );
|
||||
}
|
||||
|
||||
if ( array_key_exists( $image_url, $this->images ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->images[ $image_url ] = $attachment;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an image by ID if possible and by URL if the ID isn't present.
|
||||
*
|
||||
* @param string $image_id The image ID as set in the database.
|
||||
* @param string $image_url The saved URL for the image.
|
||||
* @param callable $on_save_id Function to call to save the ID if it needs to be saved.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function add_image_by_id_or_url( $image_id, $image_url, $on_save_id ) {
|
||||
switch ( $image_id ) {
|
||||
case self::EXTERNAL_IMAGE_ID:
|
||||
// Add image by URL, but skip attachment_to_id call. We already know this is an external image.
|
||||
$this->add_image( array( 'url' => $image_url ) );
|
||||
break;
|
||||
|
||||
case '':
|
||||
// Add image by URL, try to save the ID afterwards. So we can use the ID the next time.
|
||||
$attachment_id = $this->add_image_by_url( $image_url );
|
||||
|
||||
if ( $attachment_id !== null ) {
|
||||
call_user_func( $on_save_id, $attachment_id );
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
// Add the image by ID. This is our ideal scenario.
|
||||
$this->add_image_by_id( $image_id );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the ID to the frontpage Open Graph image ID.
|
||||
*
|
||||
* @param string $attachment_id The ID to save.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function save_frontpage_image_id( $attachment_id ) {
|
||||
WPSEO_Options::set( 'og_frontpage_image_id', $attachment_id );
|
||||
}
|
||||
|
||||
/**
|
||||
* If the frontpage image exists, call add_image.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function set_front_page_image() {
|
||||
if ( get_option( 'show_on_front' ) === 'page' ) {
|
||||
$this->set_user_defined_image();
|
||||
|
||||
// Don't fall back to the frontpage image below, as that's not set for this situation, so we should fall back to the default image.
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
$frontpage_image_url = WPSEO_Options::get( 'og_frontpage_image' );
|
||||
$frontpage_image_id = WPSEO_Options::get( 'og_frontpage_image_id' );
|
||||
|
||||
$this->add_image_by_id_or_url( $frontpage_image_id, $frontpage_image_url, array( $this, 'save_frontpage_image_id' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the images of the posts page.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function set_posts_page_image() {
|
||||
$post_id = get_option( 'page_for_posts' );
|
||||
|
||||
$this->set_image_post_meta( $post_id );
|
||||
|
||||
if ( $this->has_images() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->set_featured_image( $post_id );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the images of the singular post.
|
||||
*
|
||||
* @param null|int $post_id The post id to get the images for.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function set_singular_image( $post_id = null ) {
|
||||
if ( $post_id === null ) {
|
||||
$post_id = $this->get_post_id();
|
||||
}
|
||||
|
||||
$this->set_user_defined_image( $post_id );
|
||||
|
||||
if ( $this->has_images() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->add_first_usable_content_image( get_post( $post_id ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the user-defined image of the post.
|
||||
*
|
||||
* @param null|int $post_id The post id to get the images for.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function set_user_defined_image( $post_id = null ) {
|
||||
if ( $post_id === null ) {
|
||||
$post_id = $this->get_post_id();
|
||||
}
|
||||
|
||||
$this->set_image_post_meta( $post_id );
|
||||
|
||||
if ( $this->has_images() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->set_featured_image( $post_id );
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the default image ID for Open Graph images to the database.
|
||||
*
|
||||
* @param string $attachment_id The ID to save.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function save_default_image_id( $attachment_id ) {
|
||||
WPSEO_Options::set( 'og_default_image_id', $attachment_id );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get default image and call add_image.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function maybe_set_default_image() {
|
||||
if ( $this->has_images() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$default_image_url = WPSEO_Options::get( 'og_default_image', '' );
|
||||
$default_image_id = WPSEO_Options::get( 'og_default_image_id', '' );
|
||||
|
||||
if ( $default_image_url === '' && $default_image_id === '' ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->add_image_by_id_or_url( $default_image_id, $default_image_url, array( $this, 'save_default_image_id' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the Open Graph image meta to the database for the current post.
|
||||
*
|
||||
* @param string $attachment_id The ID to save.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function save_opengraph_image_id_meta( $attachment_id ) {
|
||||
$post_id = $this->get_post_id();
|
||||
|
||||
WPSEO_Meta::set_value( 'opengraph-image-id', (string) $attachment_id, $post_id );
|
||||
}
|
||||
|
||||
/**
|
||||
* If opengraph-image is set, call add_image and return true.
|
||||
*
|
||||
* @param int $post_id Optional post ID to use.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function set_image_post_meta( $post_id = 0 ) {
|
||||
$image_id = WPSEO_Meta::get_value( 'opengraph-image-id', $post_id );
|
||||
$image_url = WPSEO_Meta::get_value( 'opengraph-image', $post_id );
|
||||
|
||||
$this->add_image_by_id_or_url( $image_id, $image_url, array( $this, 'save_opengraph_image_id_meta' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if taxonomy has an image and add this image.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function set_taxonomy_image() {
|
||||
$image_url = WPSEO_Taxonomy_Meta::get_meta_without_term( 'opengraph-image' );
|
||||
$this->add_image_by_url( $image_url );
|
||||
}
|
||||
|
||||
/**
|
||||
* If there is a featured image, check image size. If image size is correct, call add_image and return true.
|
||||
*
|
||||
* @param int $post_id The post ID.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function set_featured_image( $post_id ) {
|
||||
if ( has_post_thumbnail( $post_id ) ) {
|
||||
$attachment_id = get_post_thumbnail_id( $post_id );
|
||||
$this->add_image_by_id( $attachment_id );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If this is an attachment page, call add_image with the attachment.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function set_attachment_page_image() {
|
||||
$post_id = $this->get_post_id();
|
||||
if ( wp_attachment_is_image( $post_id ) ) {
|
||||
$this->add_image_by_id( $post_id );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an image based on a given URL, and attempts to be smart about it.
|
||||
*
|
||||
* @param string $url The given URL.
|
||||
*
|
||||
* @return null|number Returns the found attachment ID if it exists. Otherwise -1.
|
||||
* If the URL is empty we return null.
|
||||
*/
|
||||
public function add_image_by_url( $url ) {
|
||||
if ( empty( $url ) ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$attachment_id = WPSEO_Image_Utils::get_attachment_by_url( $url );
|
||||
|
||||
if ( $attachment_id > 0 ) {
|
||||
$this->add_image_by_id( $attachment_id );
|
||||
return $attachment_id;
|
||||
}
|
||||
|
||||
$this->add_image( array( 'url' => $url ) );
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the overridden image size if it has been overridden.
|
||||
*
|
||||
* @return null|string The overridden image size or null.
|
||||
*/
|
||||
protected function get_overridden_image_size() {
|
||||
/**
|
||||
* Filter: 'wpseo_opengraph_image_size' - Allow overriding the image size used
|
||||
* for OpenGraph sharing. If this filter is used, the defined size will always be
|
||||
* used for the og:image. The image will still be rejected if it is too small.
|
||||
*
|
||||
* Only use this filter if you manually want to determine the best image size
|
||||
* for the `og:image` tag.
|
||||
*
|
||||
* Use the `wpseo_image_sizes` filter if you want to use our logic. That filter
|
||||
* can be used to add an image size that needs to be taken into consideration
|
||||
* within our own logic.
|
||||
*
|
||||
* @api string $size Size string.
|
||||
*/
|
||||
return apply_filters( 'wpseo_opengraph_image_size', null );
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the OpenGraph image size should overridden.
|
||||
*
|
||||
* @return bool Whether the size should be overridden.
|
||||
*/
|
||||
protected function is_size_overridden() {
|
||||
return $this->get_overridden_image_size() !== null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the possibility to short-circuit all the optimal variation logic with
|
||||
* your own size.
|
||||
*
|
||||
* @param int $attachment_id The attachment ID that is used.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function get_overridden_image( $attachment_id ) {
|
||||
$attachment = WPSEO_Image_Utils::get_image( $attachment_id, $this->get_overridden_image_size() );
|
||||
|
||||
if ( $attachment ) {
|
||||
$this->add_image( $attachment );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an image to the list by attachment ID.
|
||||
*
|
||||
* @param int $attachment_id The attachment ID to add.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function add_image_by_id( $attachment_id ) {
|
||||
if ( ! $this->is_valid_attachment( $attachment_id ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( $this->is_size_overridden() ) {
|
||||
$this->get_overridden_image( $attachment_id );
|
||||
return;
|
||||
}
|
||||
|
||||
$variations = WPSEO_Image_Utils::get_variations( $attachment_id );
|
||||
$variations = WPSEO_Image_Utils::filter_usable_dimensions( $this->image_params, $variations );
|
||||
$variations = WPSEO_Image_Utils::filter_usable_file_size( $variations );
|
||||
|
||||
// If we are left without variations, there is no valid variation for this attachment.
|
||||
if ( empty( $variations ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// The variations are ordered so the first variations is by definition the best one.
|
||||
$attachment = $variations[0];
|
||||
|
||||
if ( $attachment ) {
|
||||
$this->add_image( $attachment );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the images based on the page type.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function set_images() {
|
||||
/**
|
||||
* Filter: wpseo_add_opengraph_images - Allow developers to add images to the OpenGraph tags.
|
||||
*
|
||||
* @api WPSEO_OpenGraph_Image The current object.
|
||||
*/
|
||||
do_action( 'wpseo_add_opengraph_images', $this );
|
||||
|
||||
switch ( true ) {
|
||||
case is_front_page():
|
||||
$this->set_front_page_image();
|
||||
break;
|
||||
case is_home():
|
||||
$this->set_posts_page_image();
|
||||
break;
|
||||
case is_attachment():
|
||||
$this->set_attachment_page_image();
|
||||
break;
|
||||
case $this->get_frontend_page_type()->is_simple_page():
|
||||
$this->set_singular_image();
|
||||
break;
|
||||
case is_category():
|
||||
case is_tag():
|
||||
case is_tax():
|
||||
$this->set_taxonomy_image();
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter: wpseo_add_opengraph_additional_images - Allows to add additional images to the OpenGraph tags.
|
||||
*
|
||||
* @api WPSEO_OpenGraph_Image The current object.
|
||||
*/
|
||||
do_action( 'wpseo_add_opengraph_additional_images', $this );
|
||||
|
||||
$this->maybe_set_default_image();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether or not the wanted attachment is considered valid.
|
||||
*
|
||||
* @param int $attachment_id The attachment ID to get the attachment by.
|
||||
*
|
||||
* @return bool Whether or not the attachment is valid.
|
||||
*/
|
||||
protected function is_valid_attachment( $attachment_id ) {
|
||||
$attachment = get_post_mime_type( $attachment_id );
|
||||
|
||||
if ( $attachment === false ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->is_valid_image_type( $attachment );
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the passed mime type is a valid image type.
|
||||
*
|
||||
* @param string $mime_type The detected mime type.
|
||||
*
|
||||
* @return bool Whether or not the attachment is a valid image type.
|
||||
*/
|
||||
protected function is_valid_image_type( $mime_type ) {
|
||||
return in_array( $mime_type, $this->valid_image_types, true );
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the passed URL is considered valid.
|
||||
*
|
||||
* @param string $url The URL to check.
|
||||
*
|
||||
* @return bool Whether or not the URL is a valid image.
|
||||
*/
|
||||
protected function is_valid_image_url( $url ) {
|
||||
if ( ! is_string( $url ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$image_extension = $this->get_extension_from_url( $url );
|
||||
|
||||
$is_valid = in_array( $image_extension, $this->valid_image_extensions, true );
|
||||
|
||||
/**
|
||||
* Filter: 'wpseo_opengraph_is_valid_image_url' - Allows extra validation for an image url.
|
||||
*
|
||||
* @api bool - Current validation result.
|
||||
*
|
||||
* @param string $url The image url to validate.
|
||||
*/
|
||||
return apply_filters( 'wpseo_opengraph_is_valid_image_url', $is_valid, $url );
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the image path from the passed URL.
|
||||
*
|
||||
* @param string $url The URL to get the path from.
|
||||
*
|
||||
* @return string The path of the image URL. Returns an empty string if URL parsing fails.
|
||||
*/
|
||||
protected function get_image_url_path( $url ) {
|
||||
return (string) wp_parse_url( $url, PHP_URL_PATH );
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the file extension of the passed URL.
|
||||
*
|
||||
* @param string $url The URL.
|
||||
*
|
||||
* @return string The extension.
|
||||
*/
|
||||
protected function get_extension_from_url( $url ) {
|
||||
$extension = '';
|
||||
$path = $this->get_image_url_path( $url );
|
||||
|
||||
if ( $path === '' ) {
|
||||
return $extension;
|
||||
}
|
||||
|
||||
$parts = explode( '.', $path );
|
||||
|
||||
if ( ! empty( $parts ) ) {
|
||||
$extension = end( $parts );
|
||||
}
|
||||
|
||||
return $extension;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the post ID.
|
||||
*
|
||||
* @return int The post ID.
|
||||
*/
|
||||
protected function get_post_id() {
|
||||
return $this->get_frontend_page_type()->get_simple_page_id();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the first usable attachment image from the post content.
|
||||
*
|
||||
* @param WP_Post $post The post object.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function add_first_usable_content_image( $post ) {
|
||||
$image_finder = new WPSEO_Content_Images();
|
||||
$images = $image_finder->get_images( $post->ID, $post );
|
||||
|
||||
if ( ! is_array( $images ) || $images === array() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$image_url = reset( $images );
|
||||
if ( ! $image_url ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->add_image( array( 'url' => $image_url ) );
|
||||
}
|
||||
}
|
@ -0,0 +1,72 @@
|
||||
<?php
|
||||
/**
|
||||
* WPSEO plugin file.
|
||||
*
|
||||
* @package WPSEO\Frontend
|
||||
*/
|
||||
|
||||
/**
|
||||
* Class WPSEO_OpenGraph_OEmbed.
|
||||
*/
|
||||
class WPSEO_OpenGraph_OEmbed implements WPSEO_WordPress_Integration {
|
||||
|
||||
/**
|
||||
* Registers the hooks.
|
||||
*/
|
||||
public function register_hooks() {
|
||||
// Check to make sure opengraph is enabled before adding filter.
|
||||
if ( WPSEO_Options::get( 'opengraph' ) ) {
|
||||
add_filter( 'oembed_response_data', array( $this, 'set_oembed_data' ), 10, 2 );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback function to pass to the oEmbed's response data that will enable
|
||||
* support for using the image and title set by the WordPress SEO plugin's fields. This
|
||||
* address the concern where some social channels/subscribed use oEmebed data over OpenGraph data
|
||||
* if both are present.
|
||||
*
|
||||
* @param array $data The oEmbed data.
|
||||
* @param WP_Post $post The current Post object.
|
||||
*
|
||||
* @link https://developer.wordpress.org/reference/hooks/oembed_response_data/ for hook info.
|
||||
*
|
||||
* @return array $filter_data - An array of oEmbed data with modified values where appropriate.
|
||||
*/
|
||||
public function set_oembed_data( $data, $post ) {
|
||||
// Data to be returned.
|
||||
$filter_data = $data;
|
||||
|
||||
// Look for the Yoast meta values (image and title)...
|
||||
$opengraph_title = WPSEO_Meta::get_value( 'opengraph-title', $post->ID );
|
||||
$opengraph_image = WPSEO_Meta::get_value( 'opengraph-image', $post->ID );
|
||||
|
||||
// If yoast has a title set, update oEmbed with Yoast's title.
|
||||
if ( ! empty( $opengraph_title ) ) {
|
||||
$filter_data['title'] = $opengraph_title;
|
||||
}
|
||||
|
||||
// If WPSEO Image was _not_ set, return the `$filter_data` as it currently is.
|
||||
if ( empty( $opengraph_image ) ) {
|
||||
return $filter_data;
|
||||
}
|
||||
|
||||
// Since the a WPSEO Image was set, update the oEmbed data with the Yoast Image's info.
|
||||
// Get the image's ID from a URL.
|
||||
$image_id = WPSEO_Image_Utils::get_attachment_by_url( $opengraph_image );
|
||||
|
||||
// Get the image's info from it's ID.
|
||||
$image_info = wp_get_attachment_metadata( $image_id );
|
||||
|
||||
// Update the oEmbed data.
|
||||
$filter_data['thumbnail_url'] = $opengraph_image;
|
||||
if ( ! empty( $image_info['height'] ) ) {
|
||||
$filter_data['thumbnail_height'] = $image_info['height'];
|
||||
}
|
||||
if ( ! empty( $image_info['width'] ) ) {
|
||||
$filter_data['thumbnail_width'] = $image_info['width'];
|
||||
}
|
||||
|
||||
return $filter_data;
|
||||
}
|
||||
}
|
@ -0,0 +1,806 @@
|
||||
<?php
|
||||
/**
|
||||
* WPSEO plugin file.
|
||||
*
|
||||
* @package WPSEO\Frontend
|
||||
*/
|
||||
|
||||
/**
|
||||
* This code adds the OpenGraph output.
|
||||
*/
|
||||
class WPSEO_OpenGraph {
|
||||
|
||||
/**
|
||||
* @var WPSEO_Frontend_Page_Type
|
||||
*/
|
||||
protected $frontend_page_type;
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
if ( isset( $GLOBALS['fb_ver'] ) || class_exists( 'Facebook_Loader', false ) ) {
|
||||
add_filter( 'fb_meta_tags', array( $this, 'facebook_filter' ), 10, 1 );
|
||||
}
|
||||
else {
|
||||
add_filter( 'language_attributes', array( $this, 'add_opengraph_namespace' ), 15 );
|
||||
|
||||
add_action( 'wpseo_opengraph', array( $this, 'locale' ), 1 );
|
||||
add_action( 'wpseo_opengraph', array( $this, 'type' ), 5 );
|
||||
add_action( 'wpseo_opengraph', array( $this, 'og_title' ), 10 );
|
||||
add_action( 'wpseo_opengraph', array( $this, 'app_id' ), 20 );
|
||||
add_action( 'wpseo_opengraph', array( $this, 'description' ), 11 );
|
||||
add_action( 'wpseo_opengraph', array( $this, 'url' ), 12 );
|
||||
add_action( 'wpseo_opengraph', array( $this, 'site_name' ), 13 );
|
||||
add_action( 'wpseo_opengraph', array( $this, 'website_facebook' ), 14 );
|
||||
if ( is_singular() && ! is_front_page() ) {
|
||||
add_action( 'wpseo_opengraph', array( $this, 'article_author_facebook' ), 15 );
|
||||
add_action( 'wpseo_opengraph', array( $this, 'tags' ), 16 );
|
||||
add_action( 'wpseo_opengraph', array( $this, 'category' ), 17 );
|
||||
add_action( 'wpseo_opengraph', array( $this, 'publish_date' ), 19 );
|
||||
}
|
||||
|
||||
add_action( 'wpseo_opengraph', array( $this, 'image' ), 30 );
|
||||
}
|
||||
add_filter( 'jetpack_enable_open_graph', '__return_false' );
|
||||
add_action( 'wpseo_head', array( $this, 'opengraph' ), 30 );
|
||||
|
||||
// Class for determine the current page type.
|
||||
$this->frontend_page_type = new WPSEO_Frontend_Page_Type();
|
||||
}
|
||||
|
||||
/**
|
||||
* Main OpenGraph output.
|
||||
*/
|
||||
public function opengraph() {
|
||||
wp_reset_query();
|
||||
/**
|
||||
* Action: 'wpseo_opengraph' - Hook to add all Facebook OpenGraph output to so they're close together.
|
||||
*/
|
||||
do_action( 'wpseo_opengraph' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal function to output FB tags. This also adds an output filter to each bit of output based on the property.
|
||||
*
|
||||
* @param string $property Property attribute value.
|
||||
* @param string $content Content attribute value.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function og_tag( $property, $content ) {
|
||||
$og_property = str_replace( ':', '_', $property );
|
||||
/**
|
||||
* Filter: 'wpseo_og_' . $og_property - Allow developers to change the content of specific OG meta tags.
|
||||
*
|
||||
* @api string $content The content of the property.
|
||||
*/
|
||||
$content = apply_filters( 'wpseo_og_' . $og_property, $content );
|
||||
if ( empty( $content ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
echo '<meta property="', esc_attr( $property ), '" content="', esc_attr( $content ), '" />', "\n";
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter the Facebook plugins metadata.
|
||||
*
|
||||
* @param array $meta_tags The array to fix.
|
||||
*
|
||||
* @return array $meta_tags
|
||||
*/
|
||||
public function facebook_filter( $meta_tags ) {
|
||||
$meta_tags['http://ogp.me/ns#type'] = $this->type( false );
|
||||
$meta_tags['http://ogp.me/ns#title'] = $this->og_title( false );
|
||||
|
||||
// Filter the locale too because the Facebook plugin locale code is not as good as ours.
|
||||
$meta_tags['http://ogp.me/ns#locale'] = $this->locale( false );
|
||||
|
||||
$ogdesc = $this->description( false );
|
||||
if ( ! empty( $ogdesc ) ) {
|
||||
$meta_tags['http://ogp.me/ns#description'] = $ogdesc;
|
||||
}
|
||||
|
||||
return $meta_tags;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter for the namespace, adding the OpenGraph namespace.
|
||||
*
|
||||
* @link https://developers.facebook.com/docs/web/tutorials/scrumptious/open-graph-object/
|
||||
*
|
||||
* @param string $input The input namespace string.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function add_opengraph_namespace( $input ) {
|
||||
$namespaces = array(
|
||||
'og: http://ogp.me/ns#',
|
||||
);
|
||||
|
||||
/**
|
||||
* Allow for adding additional namespaces to the <html> prefix attributes.
|
||||
*
|
||||
* @since 3.9.0
|
||||
*
|
||||
* @param array $namespaces Currently registered namespaces which are to be
|
||||
* added to the prefix attribute.
|
||||
* Namespaces are strings and have the following syntax:
|
||||
* ns: http://url.to.namespace/definition
|
||||
*/
|
||||
$namespaces = apply_filters( 'wpseo_html_namespaces', $namespaces );
|
||||
$namespace_string = implode( ' ', array_unique( $namespaces ) );
|
||||
|
||||
if ( strpos( $input, ' prefix=' ) !== false ) {
|
||||
$regex = '`prefix=([\'"])(.+?)\1`';
|
||||
$replace = 'prefix="$2 ' . $namespace_string . '"';
|
||||
$input = preg_replace( $regex, $replace, $input );
|
||||
}
|
||||
else {
|
||||
$input .= ' prefix="' . $namespace_string . '"';
|
||||
}
|
||||
|
||||
return $input;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs the authors FB page.
|
||||
*
|
||||
* @link https://developers.facebook.com/blog/post/2013/06/19/platform-updates--new-open-graph-tags-for-media-publishers-and-more/
|
||||
* @link https://developers.facebook.com/docs/reference/opengraph/object-type/article/
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function article_author_facebook() {
|
||||
if ( ! is_singular() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter: 'wpseo_opengraph_author_facebook' - Allow developers to filter the Yoast SEO post authors facebook profile URL.
|
||||
*
|
||||
* @api bool|string $unsigned The Facebook author URL, return false to disable.
|
||||
*/
|
||||
$facebook = apply_filters( 'wpseo_opengraph_author_facebook', get_the_author_meta( 'facebook', $GLOBALS['post']->post_author ) );
|
||||
|
||||
if ( $facebook && ( is_string( $facebook ) && $facebook !== '' ) ) {
|
||||
$this->og_tag( 'article:author', $facebook );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs the websites FB page.
|
||||
*
|
||||
* @link https://developers.facebook.com/blog/post/2013/06/19/platform-updates--new-open-graph-tags-for-media-publishers-and-more/
|
||||
* @link https://developers.facebook.com/docs/reference/opengraph/object-type/article/
|
||||
* @return boolean
|
||||
*/
|
||||
public function website_facebook() {
|
||||
|
||||
if ( 'article' === $this->type( false ) && WPSEO_Options::get( 'facebook_site', '' ) !== '' ) {
|
||||
$this->og_tag( 'article:publisher', WPSEO_Options::get( 'facebook_site' ) );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs the SEO title as OpenGraph title.
|
||||
*
|
||||
* @link https://developers.facebook.com/docs/reference/opengraph/object-type/article/
|
||||
*
|
||||
* @param bool $echo Whether or not to echo the output.
|
||||
*
|
||||
* @return string|boolean
|
||||
*/
|
||||
public function og_title( $echo = true ) {
|
||||
|
||||
$frontend = WPSEO_Frontend::get_instance();
|
||||
|
||||
if ( $this->frontend_page_type->is_simple_page() ) {
|
||||
$post_id = $this->frontend_page_type->get_simple_page_id();
|
||||
$post = get_post( $post_id );
|
||||
$title = WPSEO_Meta::get_value( 'opengraph-title', $post_id );
|
||||
|
||||
if ( $title === '' ) {
|
||||
$title = $frontend->title( '' );
|
||||
}
|
||||
else {
|
||||
// Replace Yoast SEO Variables.
|
||||
$title = wpseo_replace_vars( $title, $post );
|
||||
}
|
||||
}
|
||||
elseif ( is_front_page() ) {
|
||||
$title = ( WPSEO_Options::get( 'og_frontpage_title', '' ) !== '' ) ? WPSEO_Options::get( 'og_frontpage_title' ) : $frontend->title( '' );
|
||||
}
|
||||
elseif ( is_category() || is_tax() || is_tag() ) {
|
||||
$title = WPSEO_Taxonomy_Meta::get_meta_without_term( 'opengraph-title' );
|
||||
if ( $title === '' ) {
|
||||
$title = $frontend->title( '' );
|
||||
}
|
||||
else {
|
||||
// Replace Yoast SEO Variables.
|
||||
$title = wpseo_replace_vars( $title, $GLOBALS['wp_query']->get_queried_object() );
|
||||
}
|
||||
}
|
||||
else {
|
||||
$title = $frontend->title( '' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter: 'wpseo_opengraph_title' - Allow changing the title specifically for OpenGraph.
|
||||
*
|
||||
* @api string $unsigned The title string.
|
||||
*/
|
||||
$title = trim( apply_filters( 'wpseo_opengraph_title', $title ) );
|
||||
|
||||
if ( is_string( $title ) && $title !== '' ) {
|
||||
if ( $echo !== false ) {
|
||||
$this->og_tag( 'og:title', $title );
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if ( $echo === false ) {
|
||||
return $title;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs the canonical URL as OpenGraph URL, which consolidates likes and shares.
|
||||
*
|
||||
* @link https://developers.facebook.com/docs/reference/opengraph/object-type/article/
|
||||
* @return boolean
|
||||
*/
|
||||
public function url() {
|
||||
$url = WPSEO_Frontend::get_instance()->canonical( false, false );
|
||||
$unpaged_url = WPSEO_Frontend::get_instance()->canonical( false, true );
|
||||
|
||||
/*
|
||||
* If the unpaged URL is the same as the normal URL but just with pagination added, use that.
|
||||
* This makes sure we always use the unpaged URL when we can, but doesn't break for overridden canonicals.
|
||||
*/
|
||||
if ( is_string( $unpaged_url ) && strpos( $url, $unpaged_url ) === 0 ) {
|
||||
$url = $unpaged_url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter: 'wpseo_opengraph_url' - Allow changing the OpenGraph URL.
|
||||
*
|
||||
* @api string $unsigned Canonical URL.
|
||||
*/
|
||||
$url = apply_filters( 'wpseo_opengraph_url', $url );
|
||||
|
||||
if ( is_string( $url ) && $url !== '' ) {
|
||||
$this->og_tag( 'og:url', esc_url( $url ) );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Output the locale, doing some conversions to make sure the proper Facebook locale is outputted.
|
||||
*
|
||||
* Last update/compare with FB list done on 2015-03-16 by Rarst.
|
||||
*
|
||||
* @link http://www.facebook.com/translations/FacebookLocales.xml for the list of supported locales.
|
||||
*
|
||||
* @link https://developers.facebook.com/docs/reference/opengraph/object-type/article/
|
||||
*
|
||||
* @param bool $echo Whether to echo or return the locale.
|
||||
*
|
||||
* @return string $locale
|
||||
*/
|
||||
public function locale( $echo = true ) {
|
||||
/**
|
||||
* Filter: 'wpseo_locale' - Allow changing the locale output.
|
||||
*
|
||||
* @api string $unsigned 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 = array(
|
||||
'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 ] ) ) {
|
||||
$locale = $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 = array(
|
||||
'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 ) ) {
|
||||
$locale = strtolower( substr( $locale, 0, 2 ) ) . '_' . strtoupper( substr( $locale, 0, 2 ) );
|
||||
if ( ! in_array( $locale, $fb_valid_fb_locales, true ) ) {
|
||||
$locale = 'en_US';
|
||||
}
|
||||
}
|
||||
|
||||
if ( $echo !== false ) {
|
||||
$this->og_tag( 'og:locale', $locale );
|
||||
}
|
||||
|
||||
return $locale;
|
||||
}
|
||||
|
||||
/**
|
||||
* Output the OpenGraph type.
|
||||
*
|
||||
* @param boolean $echo Whether to echo or return the type.
|
||||
*
|
||||
* @link https://developers.facebook.com/docs/reference/opengraph/object-type/object/
|
||||
*
|
||||
* @return string $type
|
||||
*/
|
||||
public function type( $echo = true ) {
|
||||
|
||||
if ( is_front_page() || is_home() ) {
|
||||
$type = 'website';
|
||||
}
|
||||
elseif ( is_singular() ) {
|
||||
|
||||
// This'll usually only be changed by plugins right now.
|
||||
$type = WPSEO_Meta::get_value( 'og_type' );
|
||||
|
||||
if ( $type === '' ) {
|
||||
$type = 'article';
|
||||
}
|
||||
}
|
||||
else {
|
||||
// We use "object" for archives etc. as article doesn't apply there.
|
||||
$type = 'object';
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter: 'wpseo_opengraph_type' - Allow changing the OpenGraph type of the page.
|
||||
*
|
||||
* @api string $type The OpenGraph type string.
|
||||
*/
|
||||
$type = apply_filters( 'wpseo_opengraph_type', $type );
|
||||
|
||||
if ( is_string( $type ) && $type !== '' ) {
|
||||
if ( $echo !== false ) {
|
||||
$this->og_tag( 'og:type', $type );
|
||||
}
|
||||
else {
|
||||
return $type;
|
||||
}
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Create new WPSEO_OpenGraph_Image class and get the images to set the og:image.
|
||||
*
|
||||
* @param string|bool $image Optional. Image URL.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function image( $image = false ) {
|
||||
$opengraph_image = new WPSEO_OpenGraph_Image( $image, $this );
|
||||
$opengraph_image->show();
|
||||
}
|
||||
|
||||
/**
|
||||
* Output the OpenGraph description, specific OG description first, if not, grab the meta description.
|
||||
*
|
||||
* @param bool $echo Whether to echo or return the description.
|
||||
*
|
||||
* @return string $ogdesc
|
||||
*/
|
||||
public function description( $echo = true ) {
|
||||
$ogdesc = '';
|
||||
$frontend = WPSEO_Frontend::get_instance();
|
||||
|
||||
if ( is_front_page() ) {
|
||||
if ( WPSEO_Options::get( 'og_frontpage_desc', '' ) !== '' ) {
|
||||
$ogdesc = wpseo_replace_vars( WPSEO_Options::get( 'og_frontpage_desc' ), null );
|
||||
}
|
||||
else {
|
||||
$ogdesc = $frontend->metadesc( false );
|
||||
}
|
||||
}
|
||||
|
||||
if ( $this->frontend_page_type->is_simple_page() ) {
|
||||
$post_id = $this->frontend_page_type->get_simple_page_id();
|
||||
$post = get_post( $post_id );
|
||||
$ogdesc = WPSEO_Meta::get_value( 'opengraph-description', $post_id );
|
||||
|
||||
// Replace Yoast SEO Variables.
|
||||
$ogdesc = wpseo_replace_vars( $ogdesc, $post );
|
||||
|
||||
// Use metadesc if $ogdesc is empty.
|
||||
if ( $ogdesc === '' ) {
|
||||
$ogdesc = $frontend->metadesc( false );
|
||||
}
|
||||
|
||||
// Tag og:description is still blank so grab it from get_the_excerpt().
|
||||
if ( ! is_string( $ogdesc ) || ( is_string( $ogdesc ) && $ogdesc === '' ) ) {
|
||||
$ogdesc = str_replace( '[…]', '…', wp_strip_all_tags( get_the_excerpt() ) );
|
||||
}
|
||||
}
|
||||
|
||||
if ( is_author() ) {
|
||||
$ogdesc = $frontend->metadesc( false );
|
||||
}
|
||||
|
||||
if ( is_category() || is_tag() || is_tax() ) {
|
||||
$ogdesc = WPSEO_Taxonomy_Meta::get_meta_without_term( 'opengraph-description' );
|
||||
if ( $ogdesc === '' ) {
|
||||
$ogdesc = $frontend->metadesc( false );
|
||||
}
|
||||
|
||||
if ( $ogdesc === '' ) {
|
||||
$ogdesc = wp_strip_all_tags( term_description() );
|
||||
}
|
||||
|
||||
if ( $ogdesc === '' ) {
|
||||
$ogdesc = WPSEO_Taxonomy_Meta::get_meta_without_term( 'desc' );
|
||||
}
|
||||
$ogdesc = wpseo_replace_vars( $ogdesc, get_queried_object() );
|
||||
}
|
||||
|
||||
// Strip shortcodes if any.
|
||||
$ogdesc = strip_shortcodes( $ogdesc );
|
||||
|
||||
/**
|
||||
* Filter: 'wpseo_opengraph_desc' - Allow changing the OpenGraph description.
|
||||
*
|
||||
* @api string $ogdesc The description string.
|
||||
*/
|
||||
$ogdesc = trim( apply_filters( 'wpseo_opengraph_desc', $ogdesc ) );
|
||||
|
||||
if ( is_string( $ogdesc ) && $ogdesc !== '' ) {
|
||||
if ( $echo !== false ) {
|
||||
$this->og_tag( 'og:description', $ogdesc );
|
||||
}
|
||||
}
|
||||
|
||||
return $ogdesc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Output the site name straight from the blog info.
|
||||
*/
|
||||
public function site_name() {
|
||||
/**
|
||||
* Filter: 'wpseo_opengraph_site_name' - Allow changing the OpenGraph site name.
|
||||
*
|
||||
* @api string $unsigned Blog name string.
|
||||
*/
|
||||
$name = apply_filters( 'wpseo_opengraph_site_name', get_bloginfo( 'name' ) );
|
||||
if ( is_string( $name ) && $name !== '' ) {
|
||||
$this->og_tag( 'og:site_name', $name );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Output the article tags as article:tag tags.
|
||||
*
|
||||
* @link https://developers.facebook.com/docs/reference/opengraph/object-type/article/
|
||||
* @return boolean
|
||||
*/
|
||||
public function tags() {
|
||||
if ( ! is_singular() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$tags = get_the_tags();
|
||||
if ( ! is_wp_error( $tags ) && ( is_array( $tags ) && $tags !== array() ) ) {
|
||||
|
||||
foreach ( $tags as $tag ) {
|
||||
$this->og_tag( 'article:tag', $tag->name );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Output the article category as an article:section tag.
|
||||
*
|
||||
* @link https://developers.facebook.com/docs/reference/opengraph/object-type/article/
|
||||
* @return boolean;
|
||||
*/
|
||||
public function category() {
|
||||
|
||||
if ( ! is_singular() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$post = get_post();
|
||||
if ( ! $post ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$primary_term = new WPSEO_Primary_Term( 'category', $post->ID );
|
||||
$primary_category = $primary_term->get_primary_term();
|
||||
|
||||
if ( $primary_category ) {
|
||||
// We can only show one section here, so we take the first one.
|
||||
$this->og_tag( 'article:section', get_cat_name( $primary_category ) );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
$terms = get_the_category();
|
||||
|
||||
if ( ! is_wp_error( $terms ) && is_array( $terms ) && ! empty( $terms ) ) {
|
||||
// We can only show one section here, so we take the first one.
|
||||
$term = reset( $terms );
|
||||
$this->og_tag( 'article:section', $term->name );
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Output the article publish and last modification date.
|
||||
*
|
||||
* @link https://developers.facebook.com/docs/reference/opengraph/object-type/article/
|
||||
* @return boolean;
|
||||
*/
|
||||
public function publish_date() {
|
||||
|
||||
if ( ! is_singular( 'post' ) ) {
|
||||
/**
|
||||
* Filter: 'wpseo_opengraph_show_publish_date' - Allow showing publication date for other post types.
|
||||
*
|
||||
* @api bool $unsigned Whether or not to show publish date.
|
||||
*
|
||||
* @param string $post_type The current URL's post type.
|
||||
*/
|
||||
if ( false === apply_filters( 'wpseo_opengraph_show_publish_date', false, get_post_type() ) ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
$post = get_post();
|
||||
|
||||
$pub = mysql2date( DATE_W3C, $post->post_date_gmt, false );
|
||||
$this->og_tag( 'article:published_time', $pub );
|
||||
|
||||
$mod = mysql2date( DATE_W3C, $post->post_modified_gmt, false );
|
||||
if ( $mod !== $pub ) {
|
||||
$this->og_tag( 'article:modified_time', $mod );
|
||||
$this->og_tag( 'og:updated_time', $mod );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs the Facebook app_id.
|
||||
*
|
||||
* @link https://developers.facebook.com/docs/reference/opengraph/object-type/article/
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function app_id() {
|
||||
$app_id = WPSEO_Options::get( 'fbadminapp', '' );
|
||||
if ( $app_id !== '' ) {
|
||||
$this->og_tag( 'fb:app_id', $app_id );
|
||||
}
|
||||
}
|
||||
|
||||
/* ********************* DEPRECATED METHODS ********************* */
|
||||
|
||||
/**
|
||||
* Outputs the site owner.
|
||||
*
|
||||
* @link https://developers.facebook.com/docs/reference/opengraph/object-type/article/
|
||||
* @return void
|
||||
*
|
||||
* @deprecated 7.1
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
public function site_owner() {
|
||||
// As this is a frontend method, we want to make sure it is not displayed for non-logged in users.
|
||||
if ( function_exists( 'wp_get_current_user' ) && current_user_can( 'manage_options' ) ) {
|
||||
_deprecated_function( 'WPSEO_OpenGraph::site_owner', '7.1', null );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fallback method for plugins using image_output.
|
||||
*
|
||||
* @param string|bool $image Image URL.
|
||||
*
|
||||
* @deprecated 7.4
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
public function image_output( $image = false ) {
|
||||
_deprecated_function( 'WPSEO_OpenGraph::image_output', '7.4', 'WPSEO_OpenGraph::image' );
|
||||
|
||||
$this->image( $image );
|
||||
}
|
||||
} /* End of class */
|
@ -0,0 +1,71 @@
|
||||
<?php
|
||||
/**
|
||||
* WPSEO plugin file.
|
||||
*
|
||||
* @package WPSEO\Frontend
|
||||
*/
|
||||
|
||||
/**
|
||||
* Adds customizations to the front end for the primary category.
|
||||
*/
|
||||
class WPSEO_Frontend_Primary_Category implements WPSEO_WordPress_Integration {
|
||||
|
||||
/**
|
||||
* Registers the hooks necessary for correct primary category behaviour.
|
||||
*/
|
||||
public function register_hooks() {
|
||||
add_filter( 'post_link_category', array( $this, 'post_link_category' ), 10, 3 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters post_link_category to change the category to the chosen category by the user.
|
||||
*
|
||||
* @param stdClass $category The category that is now used for the post link.
|
||||
* @param array $categories This parameter is not used.
|
||||
* @param WP_Post $post The post in question.
|
||||
*
|
||||
* @return array|null|object|WP_Error The category we want to use for the post link.
|
||||
*/
|
||||
public function post_link_category( $category, $categories = null, $post = null ) {
|
||||
$post = get_post( $post );
|
||||
$primary_category = $this->get_primary_category( $post );
|
||||
|
||||
if ( false !== $primary_category && $primary_category !== $category->cat_ID ) {
|
||||
$category = $this->get_category( $primary_category );
|
||||
}
|
||||
|
||||
return $category;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the id of the primary category.
|
||||
*
|
||||
* @param WP_Post $post The post in question.
|
||||
*
|
||||
* @return int Primary category id.
|
||||
*/
|
||||
protected function get_primary_category( $post = null ) {
|
||||
$post = get_post( $post );
|
||||
|
||||
if ( $post === null ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$primary_term = new WPSEO_Primary_Term( 'category', $post->ID );
|
||||
|
||||
return $primary_term->get_primary_term();
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper for get category to make mocking easier.
|
||||
*
|
||||
* @param int $primary_category ID of primary category.
|
||||
*
|
||||
* @return array|null|object|WP_Error
|
||||
*/
|
||||
protected function get_category( $primary_category ) {
|
||||
$category = get_category( $primary_category );
|
||||
|
||||
return $category;
|
||||
}
|
||||
}
|
@ -0,0 +1,83 @@
|
||||
<?php
|
||||
/**
|
||||
* WPSEO plugin file.
|
||||
*
|
||||
* @package WPSEO\Frontend
|
||||
*/
|
||||
|
||||
/**
|
||||
* Class WPSEO_Remove_Reply_To_Com.
|
||||
*
|
||||
* @since 7.0
|
||||
*/
|
||||
class WPSEO_Remove_Reply_To_Com implements WPSEO_WordPress_Integration {
|
||||
|
||||
/**
|
||||
* Registers the hooks necessary to handle removing ?replytocom.
|
||||
*
|
||||
* @since 7.0
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register_hooks() {
|
||||
if ( $this->clean_reply_to_com() ) {
|
||||
add_filter( 'comment_reply_link', array( $this, 'remove_reply_to_com' ) );
|
||||
add_action( 'template_redirect', array( $this, 'replytocom_redirect' ), 1 );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the ?replytocom variable from the link, replacing it with a #comment-<number> anchor.
|
||||
*
|
||||
* @todo Should this function also allow for relative urls ?
|
||||
*
|
||||
* @param string $link The comment link as a string.
|
||||
*
|
||||
* @return string The modified link.
|
||||
*/
|
||||
public function remove_reply_to_com( $link ) {
|
||||
return preg_replace( '`href=(["\'])(?:.*(?:\?|&|&)replytocom=(\d+)#respond)`', 'href=$1#comment-$2', $link );
|
||||
}
|
||||
|
||||
/**
|
||||
* Redirects out the ?replytocom variables.
|
||||
*
|
||||
* @since 1.4.13
|
||||
* @return boolean True when redirect has been done.
|
||||
*/
|
||||
public function replytocom_redirect() {
|
||||
if ( isset( $_GET['replytocom'] ) && is_singular() ) {
|
||||
$url = get_permalink( $GLOBALS['post']->ID );
|
||||
$hash = sanitize_text_field( wp_unslash( $_GET['replytocom'] ) );
|
||||
$query_string = '';
|
||||
if ( isset( $_SERVER['QUERY_STRING'] ) ) {
|
||||
$query_string = remove_query_arg( 'replytocom', sanitize_text_field( wp_unslash( $_SERVER['QUERY_STRING'] ) ) );
|
||||
}
|
||||
if ( ! empty( $query_string ) ) {
|
||||
$url .= '?' . $query_string;
|
||||
}
|
||||
$url .= '#comment-' . $hash;
|
||||
|
||||
$front = WPSEO_Frontend::get_instance();
|
||||
$front->redirect( $url, 301 );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether we can allow the feature that removes ?replytocom query parameters.
|
||||
*
|
||||
* @return bool True to remove, false not to remove.
|
||||
*/
|
||||
private function clean_reply_to_com() {
|
||||
/**
|
||||
* Filter: 'wpseo_remove_reply_to_com' - Allow disabling the feature that removes ?replytocom query parameters.
|
||||
*
|
||||
* @param bool $return True to remove, false not to remove.
|
||||
*/
|
||||
return (bool) apply_filters( 'wpseo_remove_reply_to_com', true );
|
||||
}
|
||||
}
|
@ -0,0 +1,688 @@
|
||||
<?php
|
||||
/**
|
||||
* WPSEO plugin file.
|
||||
*
|
||||
* @package WPSEO\Frontend
|
||||
*/
|
||||
|
||||
/**
|
||||
* This class handles the Twitter card functionality.
|
||||
*
|
||||
* @link https://dev.twitter.com/docs/cards
|
||||
*/
|
||||
class WPSEO_Twitter {
|
||||
|
||||
/**
|
||||
* Instance of this class.
|
||||
*
|
||||
* @var object
|
||||
*/
|
||||
public static $instance;
|
||||
|
||||
/**
|
||||
* Images.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $images = array();
|
||||
|
||||
/**
|
||||
* Images.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $shown_images = array();
|
||||
|
||||
/**
|
||||
* @var WPSEO_Frontend_Page_Type
|
||||
*/
|
||||
protected $frontend_page_type;
|
||||
|
||||
/**
|
||||
* Will hold the Twitter card type being created.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $type;
|
||||
|
||||
/**
|
||||
* Card types currently allowed by Twitter.
|
||||
*
|
||||
* @link https://dev.twitter.com/cards/types
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $valid_types = array(
|
||||
'summary',
|
||||
'summary_large_image',
|
||||
'app',
|
||||
'player',
|
||||
);
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
// Class for determine the current page type.
|
||||
$this->frontend_page_type = new WPSEO_Frontend_Page_Type();
|
||||
|
||||
$this->twitter();
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs the Twitter Card code on singular pages.
|
||||
*/
|
||||
public function twitter() {
|
||||
|
||||
/**
|
||||
* Filter: 'wpseo_output_twitter_card' - Allow disabling of the Twitter card.
|
||||
*
|
||||
* @api bool $enabled Enabled/disabled flag
|
||||
*/
|
||||
if ( false === apply_filters( 'wpseo_output_twitter_card', true ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
wp_reset_query();
|
||||
|
||||
$this->type();
|
||||
$this->description();
|
||||
$this->title();
|
||||
$this->site_twitter();
|
||||
|
||||
if ( ! post_password_required() ) {
|
||||
$this->image();
|
||||
}
|
||||
|
||||
if ( is_singular() ) {
|
||||
$this->author();
|
||||
}
|
||||
|
||||
/**
|
||||
* Action: 'wpseo_twitter' - Hook to add all Yoast SEO Twitter output to so they're close together.
|
||||
*/
|
||||
do_action( 'wpseo_twitter' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the Twitter card type.
|
||||
*
|
||||
* This defaults to summary but can be filtered using the <code>wpseo_twitter_card_type</code> filter.
|
||||
*
|
||||
* @link https://dev.twitter.com/docs/cards
|
||||
*/
|
||||
protected function type() {
|
||||
$this->determine_card_type();
|
||||
$this->sanitize_card_type();
|
||||
|
||||
$this->output_metatag( 'card', $this->type );
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the twitter card type for the current page.
|
||||
*/
|
||||
private function determine_card_type() {
|
||||
$this->type = WPSEO_Options::get( 'twitter_card_type' );
|
||||
|
||||
// @todo This should be reworked to use summary_large_image for any fitting image R.
|
||||
if ( is_singular() && has_shortcode( $GLOBALS['post']->post_content, 'gallery' ) ) {
|
||||
|
||||
$this->images = get_post_gallery_images();
|
||||
|
||||
if ( count( $this->images ) > 0 ) {
|
||||
$this->type = 'summary_large_image';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter: 'wpseo_twitter_card_type' - Allow changing the Twitter Card type as output in the Twitter card by Yoast SEO.
|
||||
*
|
||||
* @api string $unsigned The type string.
|
||||
*/
|
||||
$this->type = apply_filters( 'wpseo_twitter_card_type', $this->type );
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the card type is of a type currently allowed by Twitter.
|
||||
*
|
||||
* @link https://dev.twitter.com/cards/types
|
||||
*/
|
||||
private function sanitize_card_type() {
|
||||
if ( ! in_array( $this->type, $this->valid_types, true ) ) {
|
||||
$this->type = 'summary';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Output the metatag.
|
||||
*
|
||||
* @param string $name Tag name string.
|
||||
* @param string $value Tag value string.
|
||||
* @param bool $escaped Force escape flag.
|
||||
*/
|
||||
private function output_metatag( $name, $value, $escaped = false ) {
|
||||
|
||||
// Escape the value if not escaped.
|
||||
if ( false === $escaped ) {
|
||||
$value = esc_attr( $value );
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter: 'wpseo_twitter_metatag_key' - Make the Twitter metatag key filterable.
|
||||
*
|
||||
* @api string $key The Twitter metatag key.
|
||||
*/
|
||||
$metatag_key = apply_filters( 'wpseo_twitter_metatag_key', 'name' );
|
||||
|
||||
// Output meta.
|
||||
echo '<meta ', esc_attr( $metatag_key ), '="twitter:', esc_attr( $name ), '" content="', $value, '" />', "\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the description for Twitter.
|
||||
*
|
||||
* Only used when OpenGraph is inactive.
|
||||
*/
|
||||
protected function description() {
|
||||
if ( $this->frontend_page_type->is_simple_page() ) {
|
||||
$meta_desc = $this->single_description( $this->frontend_page_type->get_simple_page_id() );
|
||||
}
|
||||
elseif ( is_category() || is_tax() || is_tag() ) {
|
||||
$meta_desc = $this->taxonomy_description();
|
||||
}
|
||||
else {
|
||||
$meta_desc = $this->fallback_description();
|
||||
}
|
||||
|
||||
$meta_desc = wpseo_replace_vars( $meta_desc, get_queried_object() );
|
||||
|
||||
/**
|
||||
* Filter: 'wpseo_twitter_description' - Allow changing the Twitter description as output in the Twitter card by Yoast SEO.
|
||||
*
|
||||
* @api string $twitter The description string.
|
||||
*/
|
||||
$meta_desc = apply_filters( 'wpseo_twitter_description', $meta_desc );
|
||||
if ( is_string( $meta_desc ) && $meta_desc !== '' ) {
|
||||
$this->output_metatag( 'description', $meta_desc );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the description for a singular page.
|
||||
*
|
||||
* @param int $post_id Post ID.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function single_description( $post_id = 0 ) {
|
||||
$meta_desc = trim( WPSEO_Meta::get_value( 'twitter-description', $post_id ) );
|
||||
|
||||
if ( is_string( $meta_desc ) && '' !== $meta_desc ) {
|
||||
return $meta_desc;
|
||||
}
|
||||
|
||||
$meta_desc = $this->fallback_description();
|
||||
if ( is_string( $meta_desc ) && '' !== $meta_desc ) {
|
||||
return $meta_desc;
|
||||
}
|
||||
|
||||
return wp_strip_all_tags( get_the_excerpt() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Getting the description for the taxonomy.
|
||||
*
|
||||
* @return bool|mixed|string
|
||||
*/
|
||||
private function taxonomy_description() {
|
||||
$meta_desc = WPSEO_Taxonomy_Meta::get_meta_without_term( 'twitter-description' );
|
||||
|
||||
if ( ! is_string( $meta_desc ) || $meta_desc === '' ) {
|
||||
$meta_desc = $this->fallback_description();
|
||||
}
|
||||
|
||||
if ( is_string( $meta_desc ) && $meta_desc !== '' ) {
|
||||
return $meta_desc;
|
||||
}
|
||||
|
||||
return wp_strip_all_tags( term_description() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a fallback description.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function fallback_description() {
|
||||
return trim( WPSEO_Frontend::get_instance()->metadesc( false ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the title for Twitter.
|
||||
*
|
||||
* Only used when OpenGraph is inactive.
|
||||
*/
|
||||
protected function title() {
|
||||
if ( $this->frontend_page_type->is_simple_page() ) {
|
||||
$title = $this->single_title( $this->frontend_page_type->get_simple_page_id() );
|
||||
}
|
||||
elseif ( is_category() || is_tax() || is_tag() ) {
|
||||
$title = $this->taxonomy_title();
|
||||
}
|
||||
else {
|
||||
$title = $this->fallback_title();
|
||||
}
|
||||
|
||||
$title = wpseo_replace_vars( $title, get_queried_object() );
|
||||
|
||||
/**
|
||||
* Filter: 'wpseo_twitter_title' - Allow changing the Twitter title as output in the Twitter card by Yoast SEO.
|
||||
*
|
||||
* @api string $twitter The title string.
|
||||
*/
|
||||
$title = apply_filters( 'wpseo_twitter_title', $title );
|
||||
if ( is_string( $title ) && $title !== '' ) {
|
||||
$this->output_metatag( 'title', $title );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Twitter title for a single post.
|
||||
*
|
||||
* @param int $post_id Post ID.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function single_title( $post_id = 0 ) {
|
||||
$title = WPSEO_Meta::get_value( 'twitter-title', $post_id );
|
||||
if ( ! is_string( $title ) || $title === '' ) {
|
||||
return $this->fallback_title();
|
||||
}
|
||||
|
||||
return $title;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getting the title for the taxonomy.
|
||||
*
|
||||
* @return bool|mixed|string
|
||||
*/
|
||||
private function taxonomy_title() {
|
||||
$title = WPSEO_Taxonomy_Meta::get_meta_without_term( 'twitter-title' );
|
||||
|
||||
if ( ! is_string( $title ) || $title === '' ) {
|
||||
return $this->fallback_title();
|
||||
}
|
||||
|
||||
return $title;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Twitter title for any page.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function fallback_title() {
|
||||
return WPSEO_Frontend::get_instance()->title( '' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the Twitter account for the site.
|
||||
*/
|
||||
protected function site_twitter() {
|
||||
switch ( WPSEO_Options::get( 'company_or_person', '' ) ) {
|
||||
case 'person':
|
||||
$user_id = (int) WPSEO_Options::get( 'company_or_person_user_id', false );
|
||||
$twitter = get_the_author_meta( 'twitter', $user_id );
|
||||
// For backwards compat reasons, if there is no twitter ID for person, we fall back to site.
|
||||
if ( empty( $twitter ) ) {
|
||||
$twitter = WPSEO_Options::get( 'twitter_site' );
|
||||
}
|
||||
break;
|
||||
case 'company':
|
||||
default:
|
||||
$twitter = WPSEO_Options::get( 'twitter_site' );
|
||||
break;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter: 'wpseo_twitter_site' - Allow changing the Twitter site account as output in the Twitter card by Yoast SEO.
|
||||
*
|
||||
* @api string $unsigned Twitter site account string.
|
||||
*/
|
||||
$site = apply_filters( 'wpseo_twitter_site', $twitter );
|
||||
$site = $this->get_twitter_id( $site );
|
||||
|
||||
if ( is_string( $site ) && $site !== '' ) {
|
||||
$this->output_metatag( 'site', '@' . $site );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given id is actually an id or a url and if url, distills the id from it.
|
||||
*
|
||||
* Solves issues with filters returning urls and theme's/other plugins also adding a user meta
|
||||
* twitter field which expects url rather than an id (which is what we expect).
|
||||
*
|
||||
* @param string $id Twitter ID or url.
|
||||
*
|
||||
* @return string|bool Twitter ID or false if it failed to get a valid Twitter ID.
|
||||
*/
|
||||
private function get_twitter_id( $id ) {
|
||||
if ( preg_match( '`([A-Za-z0-9_]{1,25})$`', $id, $match ) ) {
|
||||
return $match[1];
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the image for Twitter.
|
||||
*
|
||||
* Only used when OpenGraph is inactive or Summary Large Image card is chosen.
|
||||
*/
|
||||
protected function image() {
|
||||
if ( is_category() || is_tax() || is_tag() ) {
|
||||
$this->taxonomy_image_output();
|
||||
}
|
||||
else {
|
||||
$this->single_image_output();
|
||||
}
|
||||
|
||||
if ( count( $this->shown_images ) === 0 && WPSEO_Options::get( 'og_default_image', '' ) !== '' ) {
|
||||
$this->image_output( WPSEO_Options::get( 'og_default_image' ) );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs the first image of a gallery.
|
||||
*/
|
||||
private function gallery_images_output() {
|
||||
|
||||
$this->image_output( reset( $this->images ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
private function taxonomy_image_output() {
|
||||
foreach ( array( 'twitter-image', 'opengraph-image' ) as $tag ) {
|
||||
$img = WPSEO_Taxonomy_Meta::get_meta_without_term( $tag );
|
||||
if ( is_string( $img ) && $img !== '' ) {
|
||||
$this->image_output( $img );
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter: wpseo_twitter_taxonomy_image - Allow developers to set a custom Twitter image for taxonomies.
|
||||
*
|
||||
* @api bool|string $unsigned Return string to supply image to use, false to use no image.
|
||||
*/
|
||||
$img = apply_filters( 'wpseo_twitter_taxonomy_image', false );
|
||||
if ( is_string( $img ) && $img !== '' ) {
|
||||
$this->image_output( $img );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes care of image output when we only need to display a single image.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function single_image_output() {
|
||||
if ( $this->homepage_image_output() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Posts page, which won't be caught by is_singular() below.
|
||||
if ( $this->posts_page_image_output() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( $this->frontend_page_type->is_simple_page() ) {
|
||||
$post_id = $this->frontend_page_type->get_simple_page_id();
|
||||
|
||||
if ( $this->image_from_meta_values_output( $post_id ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( $this->image_of_attachment_page_output( $post_id ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( $this->image_thumbnail_output( $post_id ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( count( $this->images ) > 0 ) {
|
||||
$this->gallery_images_output();
|
||||
return;
|
||||
}
|
||||
|
||||
if ( $this->image_from_content_output( $post_id ) ) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the front page image.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function homepage_image_output() {
|
||||
if ( is_front_page() ) {
|
||||
if ( WPSEO_Options::get( 'og_frontpage_image', '' ) !== '' ) {
|
||||
$this->image_output( WPSEO_Options::get( 'og_frontpage_image' ) );
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the posts page image.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function posts_page_image_output() {
|
||||
|
||||
if ( is_front_page() || ! is_home() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$post_id = get_option( 'page_for_posts' );
|
||||
|
||||
if ( $this->image_from_meta_values_output( $post_id ) ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( $this->image_thumbnail_output( $post_id ) ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs a Twitter image tag for a given image.
|
||||
*
|
||||
* @param string $img The source URL to the image.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function image_output( $img ) {
|
||||
|
||||
/**
|
||||
* Filter: 'wpseo_twitter_image' - Allow changing the Twitter Card image.
|
||||
*
|
||||
* @api string $img Image URL string.
|
||||
*/
|
||||
$img = apply_filters( 'wpseo_twitter_image', $img );
|
||||
|
||||
if ( WPSEO_Utils::is_url_relative( $img ) === true && $img[0] === '/' ) {
|
||||
$parsed_url = wp_parse_url( home_url() );
|
||||
$img = $parsed_url['scheme'] . '://' . $parsed_url['host'] . $img;
|
||||
}
|
||||
|
||||
$escaped_img = esc_url( $img );
|
||||
|
||||
if ( in_array( $escaped_img, $this->shown_images, true ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( is_string( $escaped_img ) && $escaped_img !== '' ) {
|
||||
$this->output_metatag( 'image', $escaped_img, true );
|
||||
array_push( $this->shown_images, $escaped_img );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve images from the post meta values.
|
||||
*
|
||||
* @param int $post_id Optional post ID to use.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function image_from_meta_values_output( $post_id = 0 ) {
|
||||
foreach ( array( 'twitter-image', 'opengraph-image' ) as $tag ) {
|
||||
$img = WPSEO_Meta::get_value( $tag, $post_id );
|
||||
if ( $img !== '' ) {
|
||||
$this->image_output( $img );
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve an attachment page's attachment.
|
||||
*
|
||||
* @param string $attachment_id The ID of the attachment for which to retrieve the image.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function image_of_attachment_page_output( $attachment_id ) {
|
||||
if ( get_post_type( $attachment_id ) === 'attachment' ) {
|
||||
$mime_type = get_post_mime_type( $attachment_id );
|
||||
switch ( $mime_type ) {
|
||||
case 'image/jpeg':
|
||||
case 'image/png':
|
||||
case 'image/gif':
|
||||
$this->image_output( wp_get_attachment_url( $attachment_id ) );
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the featured image.
|
||||
*
|
||||
* @param int $post_id Optional post ID to use.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function image_thumbnail_output( $post_id = 0 ) {
|
||||
|
||||
if ( empty( $post_id ) ) {
|
||||
$post_id = get_the_ID();
|
||||
}
|
||||
|
||||
if ( function_exists( 'has_post_thumbnail' ) && has_post_thumbnail( $post_id ) ) {
|
||||
/**
|
||||
* Filter: 'wpseo_twitter_image_size' - Allow changing the Twitter Card image size.
|
||||
*
|
||||
* @api string $featured_img Image size string.
|
||||
*/
|
||||
$featured_img = wp_get_attachment_image_src( get_post_thumbnail_id( $post_id ), apply_filters( 'wpseo_twitter_image_size', 'full' ) );
|
||||
|
||||
if ( $featured_img ) {
|
||||
$this->image_output( $featured_img[0] );
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the image from the content.
|
||||
*
|
||||
* @param int $post_id The post id to extract the images from.
|
||||
*
|
||||
* @return bool True when images output succeeded.
|
||||
*/
|
||||
private function image_from_content_output( $post_id ) {
|
||||
$image_finder = new WPSEO_Content_Images();
|
||||
$images = $image_finder->get_images( $post_id );
|
||||
|
||||
if ( ! is_array( $images ) || $images === array() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$image_url = reset( $images );
|
||||
if ( ! $image_url ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->image_output( $image_url );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the authors Twitter account.
|
||||
*/
|
||||
protected function author() {
|
||||
$post = get_post();
|
||||
|
||||
$twitter = null;
|
||||
if ( is_object( $post ) ) {
|
||||
$twitter = ltrim( trim( get_the_author_meta( 'twitter', $post->post_author ) ), '@' );
|
||||
}
|
||||
/**
|
||||
* Filter: 'wpseo_twitter_creator_account' - Allow changing the Twitter account as output in the Twitter card by Yoast SEO.
|
||||
*
|
||||
* @api string $twitter The twitter account name string.
|
||||
*/
|
||||
$twitter = apply_filters( 'wpseo_twitter_creator_account', $twitter );
|
||||
$twitter = $this->get_twitter_id( $twitter );
|
||||
|
||||
if ( is_string( $twitter ) && $twitter !== '' ) {
|
||||
$this->output_metatag( 'creator', '@' . $twitter );
|
||||
}
|
||||
elseif ( WPSEO_Options::get( 'twitter_site', '' ) !== '' && is_string( WPSEO_Options::get( 'twitter_site' ) ) ) {
|
||||
$this->output_metatag( 'creator', '@' . WPSEO_Options::get( 'twitter_site' ) );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the singleton instance of this class.
|
||||
*
|
||||
* @return object
|
||||
*/
|
||||
public static function get_instance() {
|
||||
if ( ! ( self::$instance instanceof self ) ) {
|
||||
self::$instance = new self();
|
||||
}
|
||||
|
||||
return self::$instance;
|
||||
}
|
||||
} /* End of class */
|
@ -0,0 +1,96 @@
|
||||
<?php
|
||||
/**
|
||||
* WPSEO plugin file.
|
||||
*
|
||||
* @package WPSEO\Frontend
|
||||
*/
|
||||
|
||||
/**
|
||||
* Represents the logic to determine if the current page is a WooCommerce shop page.
|
||||
*/
|
||||
class WPSEO_WooCommerce_Shop_Page implements WPSEO_WordPress_Integration {
|
||||
|
||||
/**
|
||||
* Holds the shop page id.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected static $shop_page_id;
|
||||
|
||||
/**
|
||||
* True when current page is the shop page.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected static $is_shop_page;
|
||||
|
||||
/**
|
||||
* Registers the hooks.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register_hooks() {
|
||||
if ( ! $this->is_woocommerce_active() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
add_filter( 'wpseo_frontend_page_type_simple_page_id', array( $this, 'get_page_id' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether or not WooCommerce is active.
|
||||
*
|
||||
* @return bool True if woocommerce plugin is active.
|
||||
*/
|
||||
private function is_woocommerce_active() {
|
||||
return WPSEO_Utils::is_woocommerce_active();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ID of the WooCommerce shop page when the currently opened page is the shop page.
|
||||
*
|
||||
* @param int $page_id The page id.
|
||||
*
|
||||
* @return int The Page ID of the shop.
|
||||
*/
|
||||
public function get_page_id( $page_id ) {
|
||||
if ( ! $this->is_shop_page() ) {
|
||||
return $page_id;
|
||||
}
|
||||
|
||||
return $this->get_shop_page_id();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the current page is the shop page.
|
||||
*
|
||||
* @return bool Whether the current page is the WooCommerce shop page.
|
||||
*/
|
||||
public function is_shop_page() {
|
||||
global $wp_query;
|
||||
|
||||
// Prevents too early "caching".
|
||||
if ( ! isset( $wp_query ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ! isset( self::$is_shop_page ) ) {
|
||||
self::$is_shop_page = $this->is_woocommerce_active() && is_shop() && ! is_search();
|
||||
}
|
||||
|
||||
return self::$is_shop_page;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the id of the set WooCommerce shop page.
|
||||
*
|
||||
* @return int The ID of the set page.
|
||||
*/
|
||||
public function get_shop_page_id() {
|
||||
if ( ! isset( self::$shop_page_id ) ) {
|
||||
self::$shop_page_id = function_exists( 'wc_get_page_id' ) ? wc_get_page_id( 'shop' ) : ( -1 );
|
||||
}
|
||||
|
||||
return self::$shop_page_id;
|
||||
}
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
<?php
|
||||
/**
|
||||
* Nothing to see here.
|
||||
*/
|
@ -0,0 +1,183 @@
|
||||
<?php
|
||||
/**
|
||||
* WPSEO plugin file.
|
||||
*
|
||||
* @package WPSEO\Frontend\Schema
|
||||
*/
|
||||
|
||||
/**
|
||||
* Returns schema Article data.
|
||||
*
|
||||
* @since 10.2
|
||||
*/
|
||||
class WPSEO_Schema_Article implements WPSEO_Graph_Piece {
|
||||
/**
|
||||
* A value object with context variables.
|
||||
*
|
||||
* @var WPSEO_Schema_Context
|
||||
*/
|
||||
private $context;
|
||||
|
||||
/**
|
||||
* WPSEO_Schema_Breadcrumb constructor.
|
||||
*
|
||||
* @param WPSEO_Schema_Context $context A value object with context variables.
|
||||
*/
|
||||
public function __construct( WPSEO_Schema_Context $context ) {
|
||||
$this->context = $context;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether or not a piece should be added to the graph.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function is_needed() {
|
||||
/**
|
||||
* Filter: 'wpseo_schema_article_post_types' - Allow changing for which post types we output Article schema.
|
||||
*
|
||||
* @api string[] $post_types The post types for which we output Article.
|
||||
*/
|
||||
$post_types = apply_filters( 'wpseo_schema_article_post_types', array( 'post' ) );
|
||||
|
||||
return is_singular( $post_types );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns Article data.
|
||||
*
|
||||
* @return array $data Article data.
|
||||
*/
|
||||
public function generate() {
|
||||
$post = get_post( $this->context->id );
|
||||
$comment_count = get_comment_count( $this->context->id );
|
||||
$data = array(
|
||||
'@type' => 'Article',
|
||||
'@id' => $this->context->canonical . WPSEO_Schema_IDs::ARTICLE_HASH,
|
||||
'isPartOf' => array( '@id' => $this->context->canonical . WPSEO_Schema_IDs::WEBPAGE_HASH ),
|
||||
'author' => array(
|
||||
'@id' => $this->get_author_url( $post ),
|
||||
'name' => get_the_author_meta( 'display_name', $post->post_author ),
|
||||
),
|
||||
'publisher' => array( '@id' => $this->get_publisher_url() ),
|
||||
'headline' => get_the_title(),
|
||||
'datePublished' => mysql2date( DATE_W3C, $post->post_date_gmt, false ),
|
||||
'dateModified' => mysql2date( DATE_W3C, $post->post_modified_gmt, false ),
|
||||
'commentCount' => $comment_count['approved'],
|
||||
'mainEntityOfPage' => $this->context->canonical . WPSEO_Schema_IDs::WEBPAGE_HASH,
|
||||
);
|
||||
|
||||
$data = $this->add_image( $data );
|
||||
$data = $this->add_keywords( $data );
|
||||
$data = $this->add_sections( $data );
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the proper author URL.
|
||||
*
|
||||
* @param \WP_Post $post Post object.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function get_author_url( $post ) {
|
||||
if ( $this->context->site_represents === 'person' && $this->context->site_user_id === (int) $post->post_author ) {
|
||||
return $this->context->site_url . WPSEO_Schema_IDs::PERSON_HASH;
|
||||
}
|
||||
|
||||
return get_author_posts_url( $post->post_author ) . WPSEO_Schema_IDs::AUTHOR_HASH;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the proper publisher URL.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function get_publisher_url() {
|
||||
if ( $this->context->site_represents === 'person' ) {
|
||||
return $this->context->site_url . WPSEO_Schema_IDs::PERSON_HASH;
|
||||
}
|
||||
|
||||
return $this->context->site_url . WPSEO_Schema_IDs::ORGANIZATION_HASH;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds tags as keywords, if tags are assigned.
|
||||
*
|
||||
* @param array $data Article data.
|
||||
*
|
||||
* @return array $data Article data.
|
||||
*/
|
||||
private function add_keywords( $data ) {
|
||||
/**
|
||||
* Filter: 'wpseo_schema_article_keywords_taxonomy' - Allow changing the taxonomy used to assign keywords to a post type Article data.
|
||||
*
|
||||
* @api string $taxonomy The chosen taxonomy.
|
||||
*/
|
||||
$taxonomy = apply_filters( 'wpseo_schema_article_keywords_taxonomy', 'post_tag' );
|
||||
|
||||
return $this->add_terms( $data, 'keywords', $taxonomy );
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds categories as sections, if categories are assigned.
|
||||
*
|
||||
* @param array $data Article data.
|
||||
*
|
||||
* @return array $data Article data.
|
||||
*/
|
||||
private function add_sections( $data ) {
|
||||
/**
|
||||
* Filter: 'wpseo_schema_article_sections_taxonomy' - Allow changing the taxonomy used to assign keywords to a post type Article data.
|
||||
*
|
||||
* @api string $taxonomy The chosen taxonomy.
|
||||
*/
|
||||
$taxonomy = apply_filters( 'wpseo_schema_article_sections_taxonomy', 'category' );
|
||||
|
||||
return $this->add_terms( $data, 'articleSection', $taxonomy );
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a term or multiple terms, comma separated, to a field.
|
||||
*
|
||||
* @param array $data Article data.
|
||||
* @param string $key The key in data to save the terms in.
|
||||
* @param string $taxonomy The taxonomy to retrieve the terms from.
|
||||
*
|
||||
* @return mixed array $data Article data.
|
||||
*/
|
||||
private function add_terms( $data, $key, $taxonomy ) {
|
||||
$terms = get_the_terms( $this->context->id, $taxonomy );
|
||||
if ( is_array( $terms ) ) {
|
||||
$keywords = array();
|
||||
foreach ( $terms as $term ) {
|
||||
// We are checking against the WordPress internal translation.
|
||||
// @codingStandardsIgnoreLine
|
||||
if ( $term->name !== __( 'Uncategorized' ) ) {
|
||||
$keywords[] = $term->name;
|
||||
}
|
||||
}
|
||||
$data[ $key ] = implode( ',', $keywords );
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an image node if the post has a featured image.
|
||||
*
|
||||
* @param array $data The Article data.
|
||||
*
|
||||
* @return array $data The Article data.
|
||||
*/
|
||||
private function add_image( $data ) {
|
||||
if ( has_post_thumbnail( $this->context->id ) ) {
|
||||
$data['image'] = array(
|
||||
'@id' => $this->context->canonical . WPSEO_Schema_IDs::PRIMARY_IMAGE_HASH,
|
||||
);
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
@ -0,0 +1,131 @@
|
||||
<?php
|
||||
/**
|
||||
* WPSEO plugin file.
|
||||
*
|
||||
* @package WPSEO\Frontend\Schema
|
||||
*/
|
||||
|
||||
/**
|
||||
* Returns schema Person data.
|
||||
*
|
||||
* @since 10.2
|
||||
*
|
||||
* @property WPSEO_Schema_Context $context A value object with context variables.
|
||||
*/
|
||||
class WPSEO_Schema_Author extends WPSEO_Schema_Person implements WPSEO_Graph_Piece {
|
||||
/**
|
||||
* A value object with context variables.
|
||||
*
|
||||
* @var WPSEO_Schema_Context
|
||||
*/
|
||||
private $context;
|
||||
|
||||
/**
|
||||
* WPSEO_Schema_Breadcrumb constructor.
|
||||
*
|
||||
* @param WPSEO_Schema_Context $context A value object with context variables.
|
||||
*/
|
||||
public function __construct( WPSEO_Schema_Context $context ) {
|
||||
parent::__construct( $context );
|
||||
$this->context = $context;
|
||||
$this->logo_hash = WPSEO_Schema_IDs::AUTHOR_LOGO_HASH;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether we should return Person schema.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function is_needed() {
|
||||
if ( is_author() ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( $this->is_post_author() ) {
|
||||
$post = get_post( $this->context->id );
|
||||
// If the author is the user the site represents, no need for an extra author block.
|
||||
if ( (int) $post->post_author === $this->context->site_user_id ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Builds our array of Schema Person data for a given user ID.
|
||||
*
|
||||
* @param int $user_id The user ID to use.
|
||||
*
|
||||
* @return array An array of Schema Person data.
|
||||
*/
|
||||
protected function build_person_data( $user_id ) {
|
||||
$data = parent::build_person_data( $user_id );
|
||||
|
||||
// If this is an author page, the Person object is the main object, so we set it as such here.
|
||||
if ( is_author() ) {
|
||||
$data['mainEntityOfPage'] = array(
|
||||
'@id' => $this->context->canonical . WPSEO_Schema_IDs::WEBPAGE_HASH,
|
||||
);
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the current URL is worthy of Article schema.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function is_post_author() {
|
||||
/**
|
||||
* Filter: 'wpseo_schema_article_post_type' - Allow changing for which post types we output Article schema.
|
||||
*
|
||||
* @api array $post_types The post types for which we output Article.
|
||||
*/
|
||||
$post_types = apply_filters( 'wpseo_schema_article_post_type', array( 'post' ) );
|
||||
if ( is_singular( $post_types ) ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines a User ID for the Person data.
|
||||
*
|
||||
* @return bool|int User ID or false upon return.
|
||||
*/
|
||||
protected function determine_user_id() {
|
||||
switch ( true ) {
|
||||
case is_author():
|
||||
$user_id = get_queried_object_id();
|
||||
break;
|
||||
default:
|
||||
$post = get_post( $this->context->id );
|
||||
$user_id = (int) $post->post_author;
|
||||
break;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter: 'wpseo_schema_person_user_id' - Allows filtering of user ID used for person output.
|
||||
*
|
||||
* @api int|bool $user_id The user ID currently determined.
|
||||
*/
|
||||
return apply_filters( 'wpseo_schema_person_user_id', $user_id );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the string to use in Schema's `@id`.
|
||||
*
|
||||
* @param int $user_id The user ID if we're on a user page.
|
||||
*
|
||||
* @return string The `@id` string value.
|
||||
*/
|
||||
protected function determine_schema_id( $user_id ) {
|
||||
return get_author_posts_url( $user_id ) . WPSEO_Schema_IDs::AUTHOR_HASH;
|
||||
}
|
||||
}
|
@ -0,0 +1,148 @@
|
||||
<?php
|
||||
/**
|
||||
* WPSEO plugin file.
|
||||
*
|
||||
* @package WPSEO\Frontend\Schema
|
||||
*/
|
||||
|
||||
/**
|
||||
* Returns schema Breadcrumb data.
|
||||
*
|
||||
* @since 10.2
|
||||
*/
|
||||
class WPSEO_Schema_Breadcrumb implements WPSEO_Graph_Piece {
|
||||
/**
|
||||
* A value object with context variables.
|
||||
*
|
||||
* @var WPSEO_Schema_Context
|
||||
*/
|
||||
private $context;
|
||||
/**
|
||||
* Current position in the List.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
private $index;
|
||||
|
||||
/**
|
||||
* WPSEO_Schema_Breadcrumb constructor.
|
||||
*
|
||||
* @param WPSEO_Schema_Context $context A value object with context variables.
|
||||
*/
|
||||
public function __construct( WPSEO_Schema_Context $context ) {
|
||||
$this->context = $context;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if we should add a breadcrumb attribute.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function is_needed() {
|
||||
if ( is_404() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( is_front_page() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( $this->context->breadcrumbs_enabled ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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_instance = WPSEO_Breadcrumbs::get_instance();
|
||||
$breadcrumbs = $breadcrumbs_instance->get_links();
|
||||
$broken = false;
|
||||
$list_elements = array();
|
||||
|
||||
foreach ( $breadcrumbs as $index => $breadcrumb ) {
|
||||
if ( ! empty( $breadcrumb['hide_in_schema'] ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( ! array_key_exists( 'url', $breadcrumb ) || ! array_key_exists( 'text', $breadcrumb ) ) {
|
||||
$broken = true;
|
||||
break;
|
||||
}
|
||||
$list_elements[] = $this->add_breadcrumb( $index, $breadcrumb );
|
||||
$this->index = $index;
|
||||
}
|
||||
|
||||
if ( is_paged() ) {
|
||||
$list_elements[] = $this->add_paginated_state();
|
||||
}
|
||||
|
||||
$data = array(
|
||||
'@type' => 'BreadcrumbList',
|
||||
'@id' => $this->context->canonical . WPSEO_Schema_IDs::BREADCRUMB_HASH,
|
||||
'itemListElement' => $list_elements,
|
||||
);
|
||||
|
||||
// Only output if JSON is correctly formatted.
|
||||
if ( ! $broken ) {
|
||||
return $data;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a breadcrumb array.
|
||||
*
|
||||
* @param int $index The position in the list.
|
||||
* @param array $breadcrumb The breadcrumb array.
|
||||
*
|
||||
* @return array A breadcrumb listItem.
|
||||
*/
|
||||
private function add_breadcrumb( $index, $breadcrumb ) {
|
||||
if ( empty( $breadcrumb['url'] ) ) {
|
||||
if ( is_paged() ) {
|
||||
// Retrieve the un-paginated state of the current page.
|
||||
$breadcrumb['url'] = WPSEO_Frontend::get_instance()->canonical( false, true );
|
||||
}
|
||||
else {
|
||||
$breadcrumb['url'] = $this->context->canonical;
|
||||
}
|
||||
}
|
||||
|
||||
if ( empty( $breadcrumb['text'] ) ) {
|
||||
$breadcrumb['url'] = $this->context->title;
|
||||
}
|
||||
|
||||
return array(
|
||||
'@type' => 'ListItem',
|
||||
'position' => ( $index + 1 ),
|
||||
'item' => array(
|
||||
'@type' => 'WebPage',
|
||||
'@id' => $breadcrumb['url'],
|
||||
'url' => $breadcrumb['url'], // For future proofing, we're trying to change the standard for this.
|
||||
'name' => $breadcrumb['text'],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the paginated state to the breadcrumb array.
|
||||
*
|
||||
* @return array A breadcrumb listItem.
|
||||
*/
|
||||
private function add_paginated_state() {
|
||||
$this->index++;
|
||||
return $this->add_breadcrumb( $this->index, array(
|
||||
'url' => $this->context->canonical,
|
||||
'text' => $this->context->title,
|
||||
) );
|
||||
}
|
||||
}
|
@ -0,0 +1,189 @@
|
||||
<?php
|
||||
/**
|
||||
* WPSEO plugin file.
|
||||
*
|
||||
* @package WPSEO\Frontend\Schema
|
||||
*/
|
||||
|
||||
/**
|
||||
* Context variables for Schema generation.
|
||||
*
|
||||
* @property string $canonical The current page's canonical.
|
||||
* @property string $company_name Holds the company name, if the site represents a company.
|
||||
* @property int $id The post ID, if there is one.
|
||||
* @property string $site_name The site's name.
|
||||
* @property string $site_represents Whether this site represents a `company` or a `person`.
|
||||
* @property string $site_url The site's URL.
|
||||
* @property int $site_user_id The site's User ID if a site represents a `person`.
|
||||
* @property string $title Page title.
|
||||
* @property string $description Page description.
|
||||
* @property bool $breadcrumbs_enabled Whether or not this site has breadcrumbs enabled.
|
||||
*
|
||||
* @since 10.2
|
||||
*/
|
||||
class WPSEO_Schema_Context {
|
||||
/**
|
||||
* The current page's canonical.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $canonical;
|
||||
/**
|
||||
* Holds the company name, if the site represents a company.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $company_name;
|
||||
/**
|
||||
* The queried object ID, if there is one.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $id;
|
||||
/**
|
||||
* Whether this site represents a `company` or a `person`.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $site_represents;
|
||||
/**
|
||||
* The site's Name.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $site_name;
|
||||
/**
|
||||
* The site's URL.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $site_url;
|
||||
/**
|
||||
* Page title.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $title;
|
||||
/**
|
||||
* User ID when the site represents a Person.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $site_user_id;
|
||||
/**
|
||||
* Page description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $description;
|
||||
/**
|
||||
* Whether or not this site has breadcrumbs enabled.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $breadcrumbs_enabled;
|
||||
|
||||
/**
|
||||
* Hash used for the Author `@id`.
|
||||
*/
|
||||
const AUTHOR_HASH = '#author';
|
||||
|
||||
/**
|
||||
* Hash used for the Author Logo's `@id`.
|
||||
*/
|
||||
const AUTHOR_LOGO_HASH = '#authorlogo';
|
||||
|
||||
/**
|
||||
* Hash used for the Breadcrumb's `@id`.
|
||||
*/
|
||||
const BREADCRUMB_HASH = '#breadcrumb';
|
||||
|
||||
/**
|
||||
* Hash used for the Person `@id`.
|
||||
*/
|
||||
const PERSON_HASH = '#person';
|
||||
|
||||
/**
|
||||
* Hash used for the Article `@id`.
|
||||
*/
|
||||
const ARTICLE_HASH = '#article';
|
||||
|
||||
/**
|
||||
* Hash used for the Organization `@id`.
|
||||
*/
|
||||
const ORGANIZATION_HASH = '#organization';
|
||||
|
||||
/**
|
||||
* Hash used for the Organization `@id`.
|
||||
*/
|
||||
const ORGANIZATION_LOGO_HASH = '#logo';
|
||||
|
||||
/**
|
||||
* Hash used for the logo `@id`.
|
||||
*/
|
||||
const PERSON_LOGO_HASH = '#personlogo';
|
||||
|
||||
/**
|
||||
* Hash used for an Article's primary image `@id`.
|
||||
*/
|
||||
const PRIMARY_IMAGE_HASH = '#primaryimage';
|
||||
|
||||
/**
|
||||
* Hash used for the WebPage's `@id`.
|
||||
*/
|
||||
const WEBPAGE_HASH = '#webpage';
|
||||
|
||||
/**
|
||||
* Hash used for the Website's `@id`.
|
||||
*/
|
||||
const WEBSITE_HASH = '#website';
|
||||
|
||||
/**
|
||||
* WPSEO_Schema_Context constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
$this->build_data();
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds all the required data for the context object.
|
||||
*/
|
||||
private function build_data() {
|
||||
$this->breadcrumbs_enabled = current_theme_supports( 'yoast-seo-breadcrumbs' );
|
||||
if ( ! $this->breadcrumbs_enabled ) {
|
||||
$this->breadcrumbs_enabled = WPSEO_Options::get( 'breadcrumbs-enable', false );
|
||||
}
|
||||
|
||||
$front = WPSEO_Frontend::get_instance();
|
||||
$this->canonical = $front->canonical( false );
|
||||
$this->title = $front->title( '' );
|
||||
$this->description = $front->metadesc( false );
|
||||
|
||||
$this->site_name = $this->set_site_name();
|
||||
$this->site_represents = WPSEO_Options::get( 'company_or_person', '' );
|
||||
$this->site_url = trailingslashit( WPSEO_Utils::home_url() );
|
||||
|
||||
if ( $this->site_represents === 'company' ) {
|
||||
$this->company_name = WPSEO_Options::get( 'company_name' );
|
||||
}
|
||||
|
||||
if ( $this->site_represents === 'person' ) {
|
||||
$this->site_user_id = WPSEO_Options::get( 'company_or_person_user_id', false );
|
||||
}
|
||||
|
||||
$this->id = get_queried_object_id();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the site's name from settings.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function set_site_name() {
|
||||
if ( '' !== WPSEO_Options::get( 'website_name', '' ) ) {
|
||||
return WPSEO_Options::get( 'website_name' );
|
||||
}
|
||||
|
||||
return get_bloginfo( 'name' );
|
||||
}
|
||||
}
|
@ -0,0 +1,68 @@
|
||||
<?php
|
||||
/**
|
||||
* WPSEO plugin file.
|
||||
*
|
||||
* @package WPSEO\Frontend\Schema
|
||||
*/
|
||||
|
||||
/**
|
||||
* Constants used for @id variables.
|
||||
*
|
||||
* @since 10.2
|
||||
*/
|
||||
class WPSEO_Schema_IDs {
|
||||
/**
|
||||
* Hash used for the Author `@id`.
|
||||
*/
|
||||
const AUTHOR_HASH = '#author';
|
||||
|
||||
/**
|
||||
* Hash used for the Author Logo's `@id`.
|
||||
*/
|
||||
const AUTHOR_LOGO_HASH = '#authorlogo';
|
||||
|
||||
/**
|
||||
* Hash used for the Breadcrumb's `@id`.
|
||||
*/
|
||||
const BREADCRUMB_HASH = '#breadcrumb';
|
||||
|
||||
/**
|
||||
* Hash used for the Person `@id`.
|
||||
*/
|
||||
const PERSON_HASH = '#person';
|
||||
|
||||
/**
|
||||
* Hash used for the Article `@id`.
|
||||
*/
|
||||
const ARTICLE_HASH = '#article';
|
||||
|
||||
/**
|
||||
* Hash used for the Organization `@id`.
|
||||
*/
|
||||
const ORGANIZATION_HASH = '#organization';
|
||||
|
||||
/**
|
||||
* Hash used for the Organization `@id`.
|
||||
*/
|
||||
const ORGANIZATION_LOGO_HASH = '#logo';
|
||||
|
||||
/**
|
||||
* Hash used for the logo `@id`.
|
||||
*/
|
||||
const PERSON_LOGO_HASH = '#personlogo';
|
||||
|
||||
/**
|
||||
* Hash used for an Article's primary image `@id`.
|
||||
*/
|
||||
const PRIMARY_IMAGE_HASH = '#primaryimage';
|
||||
|
||||
/**
|
||||
* Hash used for the WebPage's `@id`.
|
||||
*/
|
||||
const WEBPAGE_HASH = '#webpage';
|
||||
|
||||
/**
|
||||
* Hash used for the Website's `@id`.
|
||||
*/
|
||||
const WEBSITE_HASH = '#website';
|
||||
}
|
@ -0,0 +1,155 @@
|
||||
<?php
|
||||
/**
|
||||
* WPSEO plugin file.
|
||||
*
|
||||
* @package WPSEO\Frontend\Schema
|
||||
*/
|
||||
|
||||
/**
|
||||
* Returns schema image data.
|
||||
*
|
||||
* @since 11.1
|
||||
*
|
||||
* @property string $schema_id The `@id` to use for the returned image.
|
||||
* @property array $data The ImageObject Schema array.
|
||||
* @property int $attachment_id The ID of the attachment used to generate the object.
|
||||
*/
|
||||
class WPSEO_Schema_Image {
|
||||
/**
|
||||
* The `@id` to use for the returned image.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $schema_id;
|
||||
|
||||
/**
|
||||
* The ImageObject Schema array.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $data;
|
||||
|
||||
/**
|
||||
* The ID of the attachment used to generate the object.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
private $attachment_id;
|
||||
|
||||
/**
|
||||
* WPSEO_Schema_Breadcrumb constructor.
|
||||
*
|
||||
* @param string $schema_id The string to use in an image's `@id`.
|
||||
*/
|
||||
public function __construct( $schema_id ) {
|
||||
$this->schema_id = $schema_id;
|
||||
$this->generate_object();
|
||||
}
|
||||
|
||||
/**
|
||||
* Find an image based on its URL and generate a Schema object for it.
|
||||
*
|
||||
* @param string $url The image URL to base our object on.
|
||||
* @param string $caption An optional caption.
|
||||
*
|
||||
* @return array Schema ImageObject array.
|
||||
*/
|
||||
public function generate_from_url( $url, $caption = '' ) {
|
||||
$attachment_id = WPSEO_Image_Utils::get_attachment_by_url( $url );
|
||||
if ( $attachment_id > 0 ) {
|
||||
return $this->generate_from_attachment_id( $attachment_id, $caption );
|
||||
}
|
||||
|
||||
return $this->simple_image_object( $url, $caption );
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve data about an image from the database and use it to generate a Schema object.
|
||||
*
|
||||
* @param int $attachment_id The attachment to retrieve data from.
|
||||
* @param string $caption The caption string, if there is one.
|
||||
*
|
||||
* @return array Schema ImageObject array.
|
||||
*/
|
||||
public function generate_from_attachment_id( $attachment_id, $caption = '' ) {
|
||||
$this->attachment_id = $attachment_id;
|
||||
$this->data['url'] = wp_get_attachment_image_url( $this->attachment_id, 'full' );
|
||||
$this->add_image_size();
|
||||
$this->add_caption( $caption );
|
||||
|
||||
return $this->data;
|
||||
}
|
||||
|
||||
/**
|
||||
* If we can't find $url in our database, we output a simple ImageObject.
|
||||
*
|
||||
* @param string $url The image URL.
|
||||
* @param string $caption A caption, if set.
|
||||
*
|
||||
* @return array $data Schema ImageObject array.
|
||||
*/
|
||||
public function simple_image_object( $url, $caption = '' ) {
|
||||
$this->data['url'] = $url;
|
||||
|
||||
if ( ! empty( $caption ) ) {
|
||||
$this->data['caption'] = $caption;
|
||||
}
|
||||
|
||||
return $this->data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves an image's caption if set, or uses the alt tag if that's set.
|
||||
*
|
||||
* @param string $caption The caption string, if there is one.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function add_caption( $caption = '' ) {
|
||||
if ( ! empty( $caption ) ) {
|
||||
$this->data['caption'] = $caption;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$caption = wp_get_attachment_caption();
|
||||
if ( ! empty( $caption ) ) {
|
||||
$this->data['caption'] = $caption;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$caption = get_post_meta( $this->attachment_id, '_wp_attachment_image_alt', true );
|
||||
if ( ! empty( $caption ) ) {
|
||||
$this->data['caption'] = $caption;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates our bare bone ImageObject.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function generate_object() {
|
||||
$this->data = array(
|
||||
'@type' => 'ImageObject',
|
||||
'@id' => $this->schema_id,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds image's width and height.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function add_image_size() {
|
||||
$image_meta = wp_get_attachment_metadata( $this->attachment_id );
|
||||
if ( empty( $image_meta['width'] ) || empty( $image_meta['height'] ) ) {
|
||||
return;
|
||||
}
|
||||
$this->data['width'] = $image_meta['width'];
|
||||
$this->data['height'] = $image_meta['height'];
|
||||
}
|
||||
}
|
@ -0,0 +1,109 @@
|
||||
<?php
|
||||
/**
|
||||
* WPSEO plugin file.
|
||||
*
|
||||
* @package WPSEO\Frontend\Schema
|
||||
*/
|
||||
|
||||
/**
|
||||
* Returns schema Organization data.
|
||||
*
|
||||
* @since 10.2
|
||||
*/
|
||||
class WPSEO_Schema_Organization implements WPSEO_Graph_Piece {
|
||||
/**
|
||||
* A value object with context variables.
|
||||
*
|
||||
* @var WPSEO_Schema_Context
|
||||
*/
|
||||
private $context;
|
||||
|
||||
/**
|
||||
* WPSEO_Schema_Breadcrumb constructor.
|
||||
*
|
||||
* @param WPSEO_Schema_Context $context A value object with context variables.
|
||||
*/
|
||||
public function __construct( WPSEO_Schema_Context $context ) {
|
||||
$this->context = $context;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 $data The Organization schema.
|
||||
*/
|
||||
public function generate() {
|
||||
$data = array(
|
||||
'@type' => 'Organization',
|
||||
'@id' => $this->context->site_url . WPSEO_Schema_IDs::ORGANIZATION_HASH,
|
||||
'name' => $this->context->company_name,
|
||||
'url' => $this->context->site_url,
|
||||
'sameAs' => $this->fetch_social_profiles(),
|
||||
);
|
||||
$data = $this->add_logo( $data );
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a site's logo.
|
||||
*
|
||||
* @param array $data The Organization schema.
|
||||
*
|
||||
* @return array $data The Organization schema.
|
||||
*/
|
||||
private function add_logo( $data ) {
|
||||
$logo = WPSEO_Options::get( 'company_logo', '' );
|
||||
if ( empty( $logo ) ) {
|
||||
return $data;
|
||||
}
|
||||
$id = $this->context->site_url . WPSEO_Schema_IDs::ORGANIZATION_LOGO_HASH;
|
||||
$schema_image = new WPSEO_Schema_Image( $id );
|
||||
$data['logo'] = $schema_image->generate_from_url( $logo, $this->context->company_name );
|
||||
$data['image'] = array( '@id' => $id );
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the social profiles to display in the organization schema.
|
||||
*
|
||||
* @since 1.8
|
||||
*
|
||||
* @link https://developers.google.com/webmasters/structured-data/customize/social-profiles
|
||||
*
|
||||
* @return array $profiles An array of social profiles.
|
||||
*/
|
||||
private function fetch_social_profiles() {
|
||||
$profiles = array();
|
||||
$social_profiles = array(
|
||||
'facebook_site',
|
||||
'instagram_url',
|
||||
'linkedin_url',
|
||||
'myspace_url',
|
||||
'youtube_url',
|
||||
'pinterest_url',
|
||||
'wikipedia_url',
|
||||
);
|
||||
foreach ( $social_profiles as $profile ) {
|
||||
if ( WPSEO_Options::get( $profile, '' ) !== '' ) {
|
||||
$profiles[] = WPSEO_Options::get( $profile );
|
||||
}
|
||||
}
|
||||
|
||||
if ( WPSEO_Options::get( 'twitter_site', '' ) !== '' ) {
|
||||
$profiles[] = 'https://twitter.com/' . WPSEO_Options::get( 'twitter_site' );
|
||||
}
|
||||
|
||||
return $profiles;
|
||||
}
|
||||
}
|
@ -0,0 +1,197 @@
|
||||
<?php
|
||||
/**
|
||||
* WPSEO plugin file.
|
||||
*
|
||||
* @package WPSEO\Frontend\Schema
|
||||
*/
|
||||
|
||||
/**
|
||||
* Returns schema Person data.
|
||||
*
|
||||
* @since 10.2
|
||||
*/
|
||||
class WPSEO_Schema_Person implements WPSEO_Graph_Piece {
|
||||
/**
|
||||
* A value object with context variables.
|
||||
*
|
||||
* @var WPSEO_Schema_Context
|
||||
*/
|
||||
private $context;
|
||||
|
||||
/**
|
||||
* WPSEO_Schema_Breadcrumb constructor.
|
||||
*
|
||||
* @param WPSEO_Schema_Context $context A value object with context variables.
|
||||
*/
|
||||
public function __construct( WPSEO_Schema_Context $context ) {
|
||||
$this->context = $context;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether we should return Person schema.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function is_needed() {
|
||||
if ( $this->context->site_represents === 'person' || is_author() ) {
|
||||
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 );
|
||||
|
||||
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 = $this->context->site_user_id;
|
||||
|
||||
/**
|
||||
* Filter: 'wpseo_schema_person_user_id' - Allows filtering of user ID used for person output.
|
||||
*
|
||||
* @api int|bool $user_id The user ID currently determined.
|
||||
*/
|
||||
return apply_filters( 'wpseo_schema_person_user_id', $user_id );
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a list of social profile URLs for Person.
|
||||
*
|
||||
* @param int $user_id User ID.
|
||||
*
|
||||
* @return array $output A list of social profiles.
|
||||
*/
|
||||
protected function get_social_profiles( $user_id ) {
|
||||
$social_profiles = array(
|
||||
'facebook',
|
||||
'instagram',
|
||||
'linkedin',
|
||||
'pinterest',
|
||||
'twitter',
|
||||
'myspace',
|
||||
'youtube',
|
||||
'soundcloud',
|
||||
'tumblr',
|
||||
'wikipedia',
|
||||
);
|
||||
$output = array();
|
||||
foreach ( $social_profiles as $profile ) {
|
||||
$social_url = $this->url_social_site( $profile, $user_id );
|
||||
if ( $social_url ) {
|
||||
$output[] = $social_url;
|
||||
}
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds our array of Schema Person data for a given user ID.
|
||||
*
|
||||
* @param int $user_id The user ID to use.
|
||||
*
|
||||
* @return array An array of Schema Person data.
|
||||
*/
|
||||
protected function build_person_data( $user_id ) {
|
||||
$user_data = get_userdata( $user_id );
|
||||
$data = array(
|
||||
'@type' => 'Person',
|
||||
'@id' => $this->determine_schema_id( $user_id ),
|
||||
'name' => $user_data->display_name,
|
||||
);
|
||||
|
||||
$data = $this->add_image( $data, $user_data );
|
||||
|
||||
if ( ! empty( $user_data->description ) ) {
|
||||
$data['description'] = $user_data->description;
|
||||
}
|
||||
|
||||
$social_profiles = $this->get_social_profiles( $user_id );
|
||||
if ( is_array( $social_profiles ) ) {
|
||||
$data['sameAs'] = $social_profiles;
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an ImageObject for the persons avatar.
|
||||
*
|
||||
* @param array $data The Person schema.
|
||||
* @param \WP_User $user_data User data.
|
||||
*
|
||||
* @return array $data The Person schema.
|
||||
*/
|
||||
protected function add_image( $data, $user_data ) {
|
||||
$url = get_avatar_url( $user_data->user_email );
|
||||
if ( empty( $url ) ) {
|
||||
return $data;
|
||||
}
|
||||
|
||||
$id = $this->context->site_url . WPSEO_Schema_IDs::PERSON_LOGO_HASH;
|
||||
$schema_image = new WPSEO_Schema_Image( $id );
|
||||
$data['image'] = $schema_image->simple_image_object( $url, $user_data->display_name );
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the string to use in Schema's `@id`.
|
||||
*
|
||||
* @param int $user_id The user ID if we're on a user page.
|
||||
*
|
||||
* @return string The `@id` string value.
|
||||
*/
|
||||
protected function determine_schema_id( $user_id ) {
|
||||
switch ( true ) {
|
||||
case ( $this->context->site_represents === 'company' ):
|
||||
$url = get_author_posts_url( $user_id );
|
||||
break;
|
||||
default:
|
||||
$url = $this->context->site_url;
|
||||
break;
|
||||
}
|
||||
|
||||
return $url . WPSEO_Schema_IDs::PERSON_HASH;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an author's social site URL.
|
||||
*
|
||||
* @param string $social_site The social site to retrieve the URL for.
|
||||
* @param mixed $user_id The user ID to use function outside of the loop.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function url_social_site( $social_site, $user_id = false ) {
|
||||
$url = get_the_author_meta( $social_site, $user_id );
|
||||
|
||||
if ( ! empty( $url ) ) {
|
||||
switch ( $social_site ) {
|
||||
case 'twitter':
|
||||
$url = 'https://twitter.com/' . $url;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $url;
|
||||
}
|
||||
}
|
@ -0,0 +1,158 @@
|
||||
<?php
|
||||
/**
|
||||
* WPSEO plugin file.
|
||||
*
|
||||
* @package WPSEO\Frontend\Schema
|
||||
*/
|
||||
|
||||
/**
|
||||
* Returns schema WebPage data.
|
||||
*
|
||||
* @since 10.2
|
||||
*/
|
||||
class WPSEO_Schema_WebPage implements WPSEO_Graph_Piece {
|
||||
/**
|
||||
* A value object with context variables.
|
||||
*
|
||||
* @var WPSEO_Schema_Context
|
||||
*/
|
||||
private $context;
|
||||
|
||||
/**
|
||||
* WPSEO_Schema_Breadcrumb constructor.
|
||||
*
|
||||
* @param WPSEO_Schema_Context $context A value object with context variables.
|
||||
*/
|
||||
public function __construct( WPSEO_Schema_Context $context ) {
|
||||
$this->context = $context;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether or not a piece should be added to the graph.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function is_needed() {
|
||||
if ( is_404() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns WebPage schema data.
|
||||
*
|
||||
* @return array WebPage schema data.
|
||||
*/
|
||||
public function generate() {
|
||||
$data = array(
|
||||
'@type' => $this->determine_page_type(),
|
||||
'@id' => $this->context->canonical . WPSEO_Schema_IDs::WEBPAGE_HASH,
|
||||
'url' => $this->context->canonical,
|
||||
'inLanguage' => get_bloginfo( 'language' ),
|
||||
'name' => $this->context->title,
|
||||
'isPartOf' => array(
|
||||
'@id' => $this->context->site_url . WPSEO_Schema_IDs::WEBSITE_HASH,
|
||||
),
|
||||
);
|
||||
|
||||
if ( is_front_page() ) {
|
||||
$about_id = WPSEO_Schema_IDs::ORGANIZATION_HASH;
|
||||
if ( $this->context->site_represents === 'person' ) {
|
||||
$about_id = WPSEO_Schema_IDs::PERSON_HASH;
|
||||
}
|
||||
|
||||
$data['about'] = array(
|
||||
'@id' => $this->context->site_url . $about_id,
|
||||
);
|
||||
}
|
||||
|
||||
if ( is_singular() ) {
|
||||
$data = $this->add_featured_image( $data );
|
||||
|
||||
$post = get_post( $this->context->id );
|
||||
$data['datePublished'] = mysql2date( DATE_W3C, $post->post_date_gmt, false );
|
||||
$data['dateModified'] = mysql2date( DATE_W3C, $post->post_modified_gmt, false );
|
||||
}
|
||||
|
||||
if ( ! empty( $this->context->description ) ) {
|
||||
$data['description'] = $this->context->description;
|
||||
}
|
||||
|
||||
if ( $this->add_breadcrumbs() ) {
|
||||
$data['breadcrumb'] = array(
|
||||
'@id' => $this->context->canonical . WPSEO_Schema_IDs::BREADCRUMB_HASH,
|
||||
);
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if we should add a breadcrumb attribute.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function add_breadcrumbs() {
|
||||
if ( is_front_page() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( $this->context->breadcrumbs_enabled ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the page type for the current page.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function determine_page_type() {
|
||||
switch ( true ) {
|
||||
case is_search():
|
||||
$type = 'SearchResultsPage';
|
||||
break;
|
||||
case is_author():
|
||||
$type = 'ProfilePage';
|
||||
break;
|
||||
case is_archive():
|
||||
$type = 'CollectionPage';
|
||||
break;
|
||||
default:
|
||||
$type = 'WebPage';
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter: 'wpseo_schema_webpage_type' - Allow changing the WebPage type.
|
||||
*
|
||||
* @api string $type The WebPage type.
|
||||
*/
|
||||
return apply_filters( 'wpseo_schema_webpage_type', $type );
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a featured image to the schema if there is one.
|
||||
*
|
||||
* @param array $data WebPage Schema.
|
||||
*
|
||||
* @return array $data WebPage Schema.
|
||||
*/
|
||||
private function add_featured_image( $data ) {
|
||||
if ( ! has_post_thumbnail( $this->context->id ) ) {
|
||||
return $data;
|
||||
}
|
||||
|
||||
$id = $this->context->canonical . WPSEO_Schema_IDs::PRIMARY_IMAGE_HASH;
|
||||
$schema_image = new WPSEO_Schema_Image( $id );
|
||||
$data['image'] = $schema_image->generate_from_attachment_id( get_post_thumbnail_id() );
|
||||
$data['primaryImageOfPage'] = array(
|
||||
'@id' => $id,
|
||||
);
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
@ -0,0 +1,125 @@
|
||||
<?php
|
||||
/**
|
||||
* WPSEO plugin file.
|
||||
*
|
||||
* @package WPSEO\Frontend\Schema
|
||||
*/
|
||||
|
||||
/**
|
||||
* Returns schema Website data.
|
||||
*
|
||||
* @since 10.2
|
||||
*/
|
||||
class WPSEO_Schema_Website implements WPSEO_Graph_Piece {
|
||||
/**
|
||||
* A value object with context variables.
|
||||
*
|
||||
* @var WPSEO_Schema_Context
|
||||
*/
|
||||
private $context;
|
||||
|
||||
/**
|
||||
* WPSEO_Schema_Breadcrumb constructor.
|
||||
*
|
||||
* @param WPSEO_Schema_Context $context A value object with context variables.
|
||||
*/
|
||||
public function __construct( WPSEO_Schema_Context $context ) {
|
||||
$this->context = $context;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether or not a piece should be added to the graph.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function is_needed() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs code to allow recognition of the internal search engine.
|
||||
*
|
||||
* @since 1.5.7
|
||||
*
|
||||
* @link https://developers.google.com/structured-data/site-name
|
||||
*
|
||||
* @return array Website data blob.
|
||||
*/
|
||||
public function generate() {
|
||||
$data = array(
|
||||
'@type' => 'WebSite',
|
||||
'@id' => $this->context->site_url . WPSEO_Schema_IDs::WEBSITE_HASH,
|
||||
'url' => $this->context->site_url,
|
||||
'name' => $this->context->site_name,
|
||||
'publisher' => array(
|
||||
'@id' => $this->get_publisher(),
|
||||
),
|
||||
);
|
||||
|
||||
$data = $this->add_alternate_name( $data );
|
||||
$data = $this->internal_search_section( $data );
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the ID based on Company Or Person settings.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function get_publisher() {
|
||||
if ( $this->context->site_represents === 'person' ) {
|
||||
return $this->context->site_url . WPSEO_Schema_IDs::PERSON_HASH;
|
||||
}
|
||||
|
||||
return $this->context->site_url . WPSEO_Schema_IDs::ORGANIZATION_HASH;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an alternate name if one was specified in the Yoast SEO settings.
|
||||
*
|
||||
* @param array $data The website data array.
|
||||
*
|
||||
* @return array $data
|
||||
*/
|
||||
private function add_alternate_name( $data ) {
|
||||
if ( '' !== WPSEO_Options::get( 'alternate_website_name', '' ) ) {
|
||||
$data['alternateName'] = WPSEO_Options::get( 'alternate_website_name' );
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the internal search JSON LD code to the homepage if it's not disabled.
|
||||
*
|
||||
* @link https://developers.google.com/structured-data/slsb-overview
|
||||
*
|
||||
* @param array $data The website data array.
|
||||
*
|
||||
* @return array $data
|
||||
*/
|
||||
private function internal_search_section( $data ) {
|
||||
/**
|
||||
* Filter: 'disable_wpseo_json_ld_search' - Allow disabling of the json+ld output.
|
||||
*
|
||||
* @api bool $display_search Whether or not to display json+ld search on the frontend.
|
||||
*/
|
||||
if ( ! apply_filters( 'disable_wpseo_json_ld_search', false ) ) {
|
||||
/**
|
||||
* Filter: 'wpseo_json_ld_search_url' - Allows filtering of the search URL for Yoast SEO.
|
||||
*
|
||||
* @api string $search_url The search URL for this site with a `{search_term_string}` variable.
|
||||
*/
|
||||
$search_url = apply_filters( 'wpseo_json_ld_search_url', $this->context->site_url . '?s={search_term_string}' );
|
||||
|
||||
$data['potentialAction'] = array(
|
||||
'@type' => 'SearchAction',
|
||||
'target' => $search_url,
|
||||
'query-input' => 'required name=search_term_string',
|
||||
);
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
@ -0,0 +1,106 @@
|
||||
<?php
|
||||
/**
|
||||
* WPSEO plugin file.
|
||||
*
|
||||
* @package WPSEO\Frontend\Schema
|
||||
*/
|
||||
|
||||
/**
|
||||
* Class WPSEO_Schema
|
||||
*
|
||||
* Outputs schema code specific for Google's JSON LD stuff.
|
||||
*
|
||||
* @since 1.8
|
||||
*/
|
||||
class WPSEO_Schema implements WPSEO_WordPress_Integration {
|
||||
/**
|
||||
* Registers the hooks.
|
||||
*/
|
||||
public function register_hooks() {
|
||||
add_action( 'wpseo_head', array( $this, 'json_ld' ), 91 );
|
||||
add_action( 'wpseo_json_ld', array( $this, 'generate' ), 1 );
|
||||
}
|
||||
|
||||
/**
|
||||
* JSON LD output function that the functions for specific code can hook into.
|
||||
*
|
||||
* @since 1.8
|
||||
*/
|
||||
public function json_ld() {
|
||||
$deprecated_data = array(
|
||||
'_deprecated' => 'Please use the "wpseo_schema_*" filters to extend the Yoast SEO schema data - see the WPSEO_Schema class.',
|
||||
);
|
||||
|
||||
/**
|
||||
* Filter: 'wpseo_json_ld_output' - Allows disabling Yoast's schema output entirely.
|
||||
*
|
||||
* @api mixed If false or an empty array is returned, disable our output.
|
||||
*/
|
||||
$return = apply_filters( 'wpseo_json_ld_output', $deprecated_data, '' );
|
||||
if ( $return === array() || $return === false ) {
|
||||
return;
|
||||
}
|
||||
|
||||
do_action( 'wpseo_json_ld' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs the JSON LD code in a valid JSON+LD wrapper.
|
||||
*
|
||||
* @since 10.2
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function generate() {
|
||||
$graph = array();
|
||||
|
||||
foreach ( $this->get_graph_pieces() as $piece ) {
|
||||
if ( ! $piece->is_needed() ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$graph_piece = $piece->generate();
|
||||
|
||||
/**
|
||||
* Filter: 'wpseo_schema_<class name>' - Allows changing graph piece output.
|
||||
*
|
||||
* @api array $graph_piece The graph piece to filter.
|
||||
*/
|
||||
$class = str_replace( 'wpseo_schema_', '', strtolower( get_class( $piece ) ) );
|
||||
$graph_piece = apply_filters( 'wpseo_schema_' . $class, $graph_piece );
|
||||
if ( is_array( $graph_piece ) ) {
|
||||
$graph[] = $graph_piece;
|
||||
}
|
||||
}
|
||||
|
||||
WPSEO_Utils::schema_output( $graph, 'yoast-schema-graph yoast-schema-graph--main' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all the graph pieces we need.
|
||||
*
|
||||
* @return array A filtered array of graph pieces.
|
||||
*/
|
||||
private function get_graph_pieces() {
|
||||
$context = new WPSEO_Schema_Context();
|
||||
|
||||
$pieces = array(
|
||||
new WPSEO_Schema_Organization( $context ),
|
||||
new WPSEO_Schema_Person( $context ),
|
||||
new WPSEO_Schema_Website( $context ),
|
||||
new WPSEO_Schema_WebPage( $context ),
|
||||
new WPSEO_Schema_Breadcrumb( $context ),
|
||||
new WPSEO_Schema_Article( $context ),
|
||||
new WPSEO_Schema_Author( $context ),
|
||||
);
|
||||
|
||||
/**
|
||||
* Filter: 'wpseo_schema_graph_pieces' - Allows adding pieces to the graph.
|
||||
*
|
||||
* @param WPSEO_Schema_Context $context An object with context variables.
|
||||
*
|
||||
* @api array $pieces The schema pieces.
|
||||
*/
|
||||
return apply_filters( 'wpseo_schema_graph_pieces', $pieces, $context );
|
||||
}
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
<?php
|
||||
/**
|
||||
* WPSEO plugin file.
|
||||
*
|
||||
* @package WPSEO\Frontend\Schema
|
||||
*/
|
||||
|
||||
if ( ! interface_exists( 'WPSEO_Graph_Piece' ) ) {
|
||||
/**
|
||||
* An interface for registering Schema Graph Pieces.
|
||||
*
|
||||
* @since 10.2
|
||||
*/
|
||||
interface WPSEO_Graph_Piece {
|
||||
/**
|
||||
* Add your piece of the graph.
|
||||
*
|
||||
* @return array|bool $graph A graph piece on success, false on failure.
|
||||
*/
|
||||
public function generate();
|
||||
|
||||
/**
|
||||
* Determines whether or not a piece should be added to the graph.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function is_needed();
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user