| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604 |
- <?php
- /**
- * WPSEO plugin file.
- *
- * @package WPSEO\Frontend
- */
- /**
- * Class WPSEO_OpenGraph_Image
- */
- class WPSEO_OpenGraph_Image {
- /**
- * 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;
- /**
- * Image tags that we output for each image.
- *
- * @var array
- */
- private $image_tags = array(
- 'width' => 'width',
- 'height' => 'height',
- 'alt' => 'alt',
- '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();
- }
- }
- /**
- * 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;
- }
- /**
- * 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;
- }
- $this->add_image_by_url( WPSEO_Options::get( 'og_frontpage_image', '' ) );
- }
- /**
- * 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_queried_object_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_queried_object_id();
- }
- $this->set_image_post_meta( $post_id );
- if ( $this->has_images() ) {
- return;
- }
- $this->set_featured_image( $post_id );
- }
- /**
- * Get default image and call add_image.
- *
- * @return void
- */
- private function maybe_set_default_image() {
- if ( ! $this->has_images() && WPSEO_Options::get( 'og_default_image', '' ) !== '' ) {
- $this->add_image_by_url( WPSEO_Options::get( 'og_default_image' ) );
- }
- }
- /**
- * 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_url = WPSEO_Meta::get_value( 'opengraph-image', $post_id );
- $this->add_image_by_url( $image_url );
- }
- /**
- * 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_queried_object_id();
- if ( wp_attachment_is_image( $post_id ) ) {
- $this->add_image_by_id( $post_id );
- }
- }
- /**
- * Adds the first usable attachment image from the post content.
- *
- * @param object $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;
- }
- foreach ( $images as $image_url ) {
- $attachment_id = WPSEO_Image_Utils::get_attachment_by_url( $image_url );
- // If image is hosted externally, skip it and continue to the next image.
- if ( $attachment_id === 0 ) {
- continue;
- }
- // If locally hosted image meets the requirements, add it as OG image.
- $this->add_image_by_id( $attachment_id );
- // If an image has been added, we're done.
- if ( $this->has_images() ) {
- return;
- }
- }
- }
- /**
- * Adds an image based on a given URL, and attempts to be smart about it.
- *
- * @param string $url The given URL.
- *
- * @return void
- */
- public function add_image_by_url( $url ) {
- if ( empty( $url ) ) {
- return;
- }
- $attachment_id = WPSEO_Image_Utils::get_attachment_by_url( $url );
- if ( $attachment_id > 0 ) {
- $this->add_image_by_id( $attachment_id );
- return;
- }
- $this->add_image( array( 'url' => $url ) );
- }
- /**
- * 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
- */
- private 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 is_singular():
- $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 );
- return in_array( $image_extension, $this->valid_image_extensions, true );
- }
- /**
- * 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 ) {
- $parsed_url = wp_parse_url( $url );
- if ( $parsed_url === false ) {
- return '';
- }
- return $parsed_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 queried object ID.
- *
- * @return int The queried object ID.
- */
- protected function get_queried_object_id() {
- return get_queried_object_id();
- }
- }
|