user The user helper. * @param Permalink_Helper $permalink_helper The permalink helper. * @param Indexable_Helper $indexable_helper The indexable helper. * @param Indexable_Repository $indexable_repository The indexable repository. */ public function __construct( Options_Helper $options, Url_Helper $url, Image_Helper $image, ID_Helper $id_helper, WPSEO_Replace_Vars $replace_vars, Site_Helper $site, User_Helper $user, Permalink_Helper $permalink_helper, Indexable_Helper $indexable_helper, Indexable_Repository $indexable_repository ) { $this->options = $options; $this->url = $url; $this->image = $image; $this->id_helper = $id_helper; $this->replace_vars = $replace_vars; $this->site = $site; $this->user = $user; $this->permalink_helper = $permalink_helper; $this->indexable_helper = $indexable_helper; $this->indexable_repository = $indexable_repository; } /** * Generates the title. * * @return string the title */ public function generate_title() { return $this->replace_vars->replace( $this->presentation->title, $this->presentation->source ); } /** * Generates the description. * * @return string the description */ public function generate_description() { return $this->replace_vars->replace( $this->presentation->meta_description, $this->presentation->source ); } /** * Generates the canonical. * * @return string the canonical */ public function generate_canonical() { return $this->presentation->canonical; } /** * Generates the permalink. * * @return string */ public function generate_permalink() { if ( ! \is_search() ) { return $this->presentation->permalink; } return \add_query_arg( 's', \rawurlencode( \get_search_query() ), \trailingslashit( $this->site_url ) ); } /** * Generates the id. * * @return string the id */ public function generate_id() { return $this->indexable->object_id; } /** * Generates the site name. * * @return string The site name. */ public function generate_site_name() { $site_name = $this->options->get( 'website_name', '' ); if ( $site_name !== '' ) { return $site_name; } return \get_bloginfo( 'name' ); } /** * Generates the alternate site name. * * @return string The alternate site name. */ public function generate_alternate_site_name() { return (string) $this->options->get( 'alternate_website_name', '' ); } /** * Generates the site name from the WordPress options. * * @return string The site name from the WordPress options. */ public function generate_wordpress_site_name() { return $this->site->get_site_name(); } /** * Generates the site url. * * @return string The site url. */ public function generate_site_url() { $home_page_indexable = $this->indexable_repository->find_for_home_page(); if ( $this->indexable_helper->dynamic_permalinks_enabled() ) { return \trailingslashit( $this->permalink_helper->get_permalink_for_indexable( $home_page_indexable ) ); } return \trailingslashit( $home_page_indexable->permalink ); } /** * Generates the company name. * * @return string The company name. */ public function generate_company_name() { /** * Filter: 'wpseo_schema_company_name' - Allows filtering company name * * @param string $company_name. */ $company_name = \apply_filters( 'wpseo_schema_company_name', $this->options->get( 'company_name' ) ); if ( empty( $company_name ) ) { $company_name = $this->site_name; } return $company_name; } /** * Generates the alternate company name. * * @return string */ public function generate_company_alternate_name() { return (string) $this->options->get( 'company_alternate_name' ); } /** * Generates the person logo id. * * @return int|bool The company logo id. */ public function generate_person_logo_id() { $person_logo_id = $this->image->get_attachment_id_from_settings( 'person_logo' ); if ( empty( $person_logo_id ) ) { $person_logo_id = $this->fallback_to_site_logo(); } /** * Filter: 'wpseo_schema_person_logo_id' - Allows filtering person logo id. * * @param int $person_logo_id. */ return \apply_filters( 'wpseo_schema_person_logo_id', $person_logo_id ); } /** * Retrieve the person logo meta. * * @return array>|bool */ public function generate_person_logo_meta() { $person_logo_meta = $this->image->get_attachment_meta_from_settings( 'person_logo' ); if ( empty( $person_logo_meta ) ) { $person_logo_id = $this->fallback_to_site_logo(); $person_logo_meta = $this->image->get_best_attachment_variation( $person_logo_id ); } /** * Filter: 'wpseo_schema_person_logo_meta' - Allows filtering person logo meta. * * @param string $person_logo_meta. */ return \apply_filters( 'wpseo_schema_person_logo_meta', $person_logo_meta ); } /** * Generates the company logo id. * * @return int|bool The company logo id. */ public function generate_company_logo_id() { $company_logo_id = $this->image->get_attachment_id_from_settings( 'company_logo' ); if ( empty( $company_logo_id ) ) { $company_logo_id = $this->fallback_to_site_logo(); } /** * Filter: 'wpseo_schema_company_logo_id' - Allows filtering company logo id. * * @param int $company_logo_id. */ return \apply_filters( 'wpseo_schema_company_logo_id', $company_logo_id ); } /** * Retrieve the company logo meta. * * @return array>|bool */ public function generate_company_logo_meta() { $company_logo_meta = $this->image->get_attachment_meta_from_settings( 'company_logo' ); /** * Filter: 'wpseo_schema_company_logo_meta' - Allows filtering company logo meta. * * @param string $company_logo_meta. */ return \apply_filters( 'wpseo_schema_company_logo_meta', $company_logo_meta ); } /** * Generates the site user id. * * @return int The site user id. */ public function generate_site_user_id() { return (int) $this->options->get( 'company_or_person_user_id', false ); } /** * Determines what our site represents, and grabs their values. * * @return string|false Person or company. False if invalid value. */ public function generate_site_represents() { switch ( $this->options->get( 'company_or_person', false ) ) { case 'company': // Do not use a non-named company. if ( empty( $this->company_name ) ) { return false; } /* * Do not use a company without a logo. * The logic check is on `< 1` instead of `false` due to how `get_attachment_id_from_settings` works. */ if ( $this->company_logo_id < 1 ) { return false; } return 'company'; case 'person': // Do not use a non-existing user. if ( $this->site_user_id !== false && \get_user_by( 'id', $this->site_user_id ) === false ) { return false; } return 'person'; } return false; } /** * Returns the site represents reference. * * @return array|bool The site represents reference. False if none. */ public function generate_site_represents_reference() { if ( $this->site_represents === 'person' ) { return [ '@id' => $this->id_helper->get_user_schema_id( $this->site_user_id, $this ) ]; } if ( $this->site_represents === 'company' ) { return [ '@id' => $this->site_url . Schema_IDs::ORGANIZATION_HASH ]; } return false; } /** * Returns whether or not open graph is enabled. * * @return bool Whether or not open graph is enabled. */ public function generate_open_graph_enabled() { return $this->options->get( 'opengraph' ) === true; } /** * Returns the open graph publisher. * * @return string The open graph publisher. */ public function generate_open_graph_publisher() { if ( $this->site_represents === 'company' ) { return $this->options->get( 'facebook_site', '' ); } if ( $this->site_represents === 'person' ) { return $this->user->get_the_author_meta( 'facebook', $this->site_user_id ); } return $this->options->get( 'facebook_site', '' ); } /** * Returns the twitter card type. * * @return string The twitter card type. */ public function generate_twitter_card() { return 'summary_large_image'; } /** * Returns the schema page type. * * @return string|array The schema page type. */ public function generate_schema_page_type() { switch ( $this->indexable->object_type ) { case 'system-page': switch ( $this->indexable->object_sub_type ) { case 'search-result': $type = [ 'CollectionPage', 'SearchResultsPage' ]; break; default: $type = 'WebPage'; } break; case 'user': $type = 'ProfilePage'; break; case 'home-page': case 'date-archive': case 'term': case 'post-type-archive': $type = 'CollectionPage'; break; default: $additional_type = $this->indexable->schema_page_type; if ( $additional_type === null ) { $additional_type = $this->options->get( 'schema-page-type-' . $this->indexable->object_sub_type ); } $type = [ 'WebPage', $additional_type ]; // Is this indexable set as a page for posts, e.g. in the WordPress reading settings as a static homepage? if ( (int) \get_option( 'page_for_posts' ) === $this->indexable->object_id ) { $type[] = 'CollectionPage'; } // Ensure we get only unique values, and remove any null values and the index. $type = \array_filter( \array_values( \array_unique( $type ) ) ); } /** * Filter: 'wpseo_schema_webpage_type' - Allow changing the WebPage type. * * @param string|array $type The WebPage type. */ return \apply_filters( 'wpseo_schema_webpage_type', $type ); } /** * Returns the schema article type. * * @return string|array The schema article type. */ public function generate_schema_article_type() { $additional_type = $this->indexable->schema_article_type; if ( $additional_type === null ) { $additional_type = $this->options->get( 'schema-article-type-' . $this->indexable->object_sub_type ); } /** This filter is documented in inc/options/class-wpseo-option-titles.php */ $allowed_article_types = \apply_filters( 'wpseo_schema_article_types', Schema_Types::ARTICLE_TYPES ); if ( ! \array_key_exists( $additional_type, $allowed_article_types ) ) { $additional_type = $this->options->get_title_default( 'schema-article-type-' . $this->indexable->object_sub_type ); } // If the additional type is a subtype of Article, we're fine, and we can bail here. if ( \stripos( $additional_type, 'Article' ) !== false ) { /** * Filter: 'wpseo_schema_article_type' - Allow changing the Article type. * * @param string|string[] $type The Article type. * @param Indexable $indexable The indexable. */ return \apply_filters( 'wpseo_schema_article_type', $additional_type, $this->indexable ); } $type = 'Article'; /* * If `None` is set (either on the indexable or as a default), set type to 'None'. * This simplifies is_needed checks downstream. */ if ( $additional_type === 'None' ) { $type = $additional_type; } if ( $additional_type !== $type ) { $type = [ $type, $additional_type ]; } // Filter documented on line 499 above. return \apply_filters( 'wpseo_schema_article_type', $type, $this->indexable ); } /** * Returns the main schema id. * * The main schema id. * * @return string */ public function generate_main_schema_id() { return $this->permalink; } /** * Retrieves the main image URL. This is the featured image by default. * * @return string|null The main image URL. */ public function generate_main_image_url() { if ( $this->main_image_id !== null ) { return $this->image->get_attachment_image_url( $this->main_image_id, 'full' ); } if ( \wp_is_serving_rest_request() ) { return $this->get_main_image_url_for_rest_request(); } if ( ! \is_singular() ) { return null; } $url = $this->image->get_post_content_image( $this->id ); if ( $url === '' ) { return null; } return $url; } /** * Generates the main image ID. * * @return int|null The main image ID. */ public function generate_main_image_id() { if ( \wp_is_serving_rest_request() ) { return $this->get_main_image_id_for_rest_request(); } $image_id = null; switch ( true ) { case \is_singular(): $image_id = $this->get_singular_post_image( $this->id ); break; case \is_author(): case \is_tax(): case \is_tag(): case \is_category(): case \is_search(): case \is_date(): case \is_post_type_archive(): if ( ! empty( $GLOBALS['wp_query']->posts ) ) { if ( $GLOBALS['wp_query']->get( 'fields', 'all' ) === 'ids' ) { $image_id = $this->get_singular_post_image( $GLOBALS['wp_query']->posts[0] ); break; } $image_id = $this->get_singular_post_image( $GLOBALS['wp_query']->posts[0]->ID ); } break; } /** * Filter: 'wpseo_schema_main_image_id' - Allow changing the main image ID. * * @param int|array $image_id The image ID. */ return \apply_filters( 'wpseo_schema_main_image_id', $image_id ); } /** * Determines whether the current indexable has an image. * * @return bool Whether the current indexable has an image. */ public function generate_has_image() { return $this->main_image_url !== null; } /** * Strips all nested dependencies from the debug info. * * @return array */ public function __debugInfo() { return [ 'indexable' => $this->indexable, 'presentation' => $this->presentation, ]; } /** * Retrieve the site logo ID from WordPress settings. * * @return int|false */ public function fallback_to_site_logo() { $logo_id = \get_option( 'site_logo' ); if ( ! $logo_id ) { $logo_id = \get_theme_mod( 'custom_logo', false ); } return $logo_id; } /** * Get the ID for a post's featured image. * * @param int $id Post ID. * * @return int|null */ private function get_singular_post_image( $id ) { if ( \has_post_thumbnail( $id ) ) { $thumbnail_id = \get_post_thumbnail_id( $id ); // Prevent returning something else than an int or null. if ( \is_int( $thumbnail_id ) && $thumbnail_id > 0 ) { return $thumbnail_id; } } if ( \is_singular( 'attachment' ) ) { return \get_query_var( 'attachment_id' ); } return null; } /** * Gets the main image ID for REST requests. * * @return int|null The main image ID. */ private function get_main_image_id_for_rest_request() { switch ( $this->page_type ) { case 'Post_Type': if ( $this->post instanceof WP_Post ) { return $this->get_singular_post_image( $this->post->ID ); } return null; default: return null; } } /** * Gets the main image URL for REST requests. * * @return string|null The main image URL. */ private function get_main_image_url_for_rest_request() { switch ( $this->page_type ) { case 'Post_Type': if ( $this->post instanceof WP_Post ) { $url = $this->image->get_post_content_image( $this->post->ID ); if ( $url === '' ) { return null; } return $url; } return null; default: return null; } } } \class_alias( Meta_Tags_Context::class, 'WPSEO_Schema_Context' ); user The user helper. * @param Permalink_Helper $permalink_helper The permalink helper. * @param Indexable_Helper $indexable_helper The indexable helper. * @param Indexable_Repository $indexable_repository The indexable repository. */ public function __construct( Options_Helper $options, Url_Helper $url, Image_Helper $image, ID_Helper $id_helper, WPSEO_Replace_Vars $replace_vars, Site_Helper $site, User_Helper $user, Permalink_Helper $permalink_helper, Indexable_Helper $indexable_helper, Indexable_Repository $indexable_repository ) { $this->options = $options; $this->url = $url; $this->image = $image; $this->id_helper = $id_helper; $this->replace_vars = $replace_vars; $this->site = $site; $this->user = $user; $this->permalink_helper = $permalink_helper; $this->indexable_helper = $indexable_helper; $this->indexable_repository = $indexable_repository; } /** * Generates the title. * * @return string the title */ public function generate_title() { return $this->replace_vars->replace( $this->presentation->title, $this->presentation->source ); } /** * Generates the description. * * @return string the description */ public function generate_description() { return $this->replace_vars->replace( $this->presentation->meta_description, $this->presentation->source ); } /** * Generates the canonical. * * @return string the canonical */ public function generate_canonical() { return $this->presentation->canonical; } /** * Generates the permalink. * * @return string */ public function generate_permalink() { if ( ! \is_search() ) { return $this->presentation->permalink; } return \add_query_arg( 's', \rawurlencode( \get_search_query() ), \trailingslashit( $this->site_url ) ); } /** * Generates the id. * * @return string the id */ public function generate_id() { return $this->indexable->object_id; } /** * Generates the site name. * * @return string The site name. */ public function generate_site_name() { $site_name = $this->options->get( 'website_name', '' ); if ( $site_name !== '' ) { return $site_name; } return \get_bloginfo( 'name' ); } /** * Generates the alternate site name. * * @return string The alternate site name. */ public function generate_alternate_site_name() { return (string) $this->options->get( 'alternate_website_name', '' ); } /** * Generates the site name from the WordPress options. * * @return string The site name from the WordPress options. */ public function generate_wordpress_site_name() { return $this->site->get_site_name(); } /** * Generates the site url. * * @return string The site url. */ public function generate_site_url() { $home_page_indexable = $this->indexable_repository->find_for_home_page(); if ( $this->indexable_helper->dynamic_permalinks_enabled() ) { return \trailingslashit( $this->permalink_helper->get_permalink_for_indexable( $home_page_indexable ) ); } return \trailingslashit( $home_page_indexable->permalink ); } /** * Generates the company name. * * @return string The company name. */ public function generate_company_name() { /** * Filter: 'wpseo_schema_company_name' - Allows filtering company name * * @param string $company_name. */ $company_name = \apply_filters( 'wpseo_schema_company_name', $this->options->get( 'company_name' ) ); if ( empty( $company_name ) ) { $company_name = $this->site_name; } return $company_name; } /** * Generates the alternate company name. * * @return string */ public function generate_company_alternate_name() { return (string) $this->options->get( 'company_alternate_name' ); } /** * Generates the person logo id. * * @return int|bool The company logo id. */ public function generate_person_logo_id() { $person_logo_id = $this->image->get_attachment_id_from_settings( 'person_logo' ); if ( empty( $person_logo_id ) ) { $person_logo_id = $this->fallback_to_site_logo(); } /** * Filter: 'wpseo_schema_person_logo_id' - Allows filtering person logo id. * * @param int $person_logo_id. */ return \apply_filters( 'wpseo_schema_person_logo_id', $person_logo_id ); } /** * Retrieve the person logo meta. * * @return array>|bool */ public function generate_person_logo_meta() { $person_logo_meta = $this->image->get_attachment_meta_from_settings( 'person_logo' ); if ( empty( $person_logo_meta ) ) { $person_logo_id = $this->fallback_to_site_logo(); $person_logo_meta = $this->image->get_best_attachment_variation( $person_logo_id ); } /** * Filter: 'wpseo_schema_person_logo_meta' - Allows filtering person logo meta. * * @param string $person_logo_meta. */ return \apply_filters( 'wpseo_schema_person_logo_meta', $person_logo_meta ); } /** * Generates the company logo id. * * @return int|bool The company logo id. */ public function generate_company_logo_id() { $company_logo_id = $this->image->get_attachment_id_from_settings( 'company_logo' ); if ( empty( $company_logo_id ) ) { $company_logo_id = $this->fallback_to_site_logo(); } /** * Filter: 'wpseo_schema_company_logo_id' - Allows filtering company logo id. * * @param int $company_logo_id. */ return \apply_filters( 'wpseo_schema_company_logo_id', $company_logo_id ); } /** * Retrieve the company logo meta. * * @return array>|bool */ public function generate_company_logo_meta() { $company_logo_meta = $this->image->get_attachment_meta_from_settings( 'company_logo' ); /** * Filter: 'wpseo_schema_company_logo_meta' - Allows filtering company logo meta. * * @param string $company_logo_meta. */ return \apply_filters( 'wpseo_schema_company_logo_meta', $company_logo_meta ); } /** * Generates the site user id. * * @return int The site user id. */ public function generate_site_user_id() { return (int) $this->options->get( 'company_or_person_user_id', false ); } /** * Determines what our site represents, and grabs their values. * * @return string|false Person or company. False if invalid value. */ public function generate_site_represents() { switch ( $this->options->get( 'company_or_person', false ) ) { case 'company': // Do not use a non-named company. if ( empty( $this->company_name ) ) { return false; } /* * Do not use a company without a logo. * The logic check is on `< 1` instead of `false` due to how `get_attachment_id_from_settings` works. */ if ( $this->company_logo_id < 1 ) { return false; } return 'company'; case 'person': // Do not use a non-existing user. if ( $this->site_user_id !== false && \get_user_by( 'id', $this->site_user_id ) === false ) { return false; } return 'person'; } return false; } /** * Returns the site represents reference. * * @return array|bool The site represents reference. False if none. */ public function generate_site_represents_reference() { if ( $this->site_represents === 'person' ) { return [ '@id' => $this->id_helper->get_user_schema_id( $this->site_user_id, $this ) ]; } if ( $this->site_represents === 'company' ) { return [ '@id' => $this->site_url . Schema_IDs::ORGANIZATION_HASH ]; } return false; } /** * Returns whether or not open graph is enabled. * * @return bool Whether or not open graph is enabled. */ public function generate_open_graph_enabled() { return $this->options->get( 'opengraph' ) === true; } /** * Returns the open graph publisher. * * @return string The open graph publisher. */ public function generate_open_graph_publisher() { if ( $this->site_represents === 'company' ) { return $this->options->get( 'facebook_site', '' ); } if ( $this->site_represents === 'person' ) { return $this->user->get_the_author_meta( 'facebook', $this->site_user_id ); } return $this->options->get( 'facebook_site', '' ); } /** * Returns the twitter card type. * * @return string The twitter card type. */ public function generate_twitter_card() { return 'summary_large_image'; } /** * Returns the schema page type. * * @return string|array The schema page type. */ public function generate_schema_page_type() { switch ( $this->indexable->object_type ) { case 'system-page': switch ( $this->indexable->object_sub_type ) { case 'search-result': $type = [ 'CollectionPage', 'SearchResultsPage' ]; break; default: $type = 'WebPage'; } break; case 'user': $type = 'ProfilePage'; break; case 'home-page': case 'date-archive': case 'term': case 'post-type-archive': $type = 'CollectionPage'; break; default: $additional_type = $this->indexable->schema_page_type; if ( $additional_type === null ) { $additional_type = $this->options->get( 'schema-page-type-' . $this->indexable->object_sub_type ); } $type = [ 'WebPage', $additional_type ]; // Is this indexable set as a page for posts, e.g. in the WordPress reading settings as a static homepage? if ( (int) \get_option( 'page_for_posts' ) === $this->indexable->object_id ) { $type[] = 'CollectionPage'; } // Ensure we get only unique values, and remove any null values and the index. $type = \array_filter( \array_values( \array_unique( $type ) ) ); } /** * Filter: 'wpseo_schema_webpage_type' - Allow changing the WebPage type. * * @param string|array $type The WebPage type. */ return \apply_filters( 'wpseo_schema_webpage_type', $type ); } /** * Returns the schema article type. * * @return string|array The schema article type. */ public function generate_schema_article_type() { $additional_type = $this->indexable->schema_article_type; if ( $additional_type === null ) { $additional_type = $this->options->get( 'schema-article-type-' . $this->indexable->object_sub_type ); } /** This filter is documented in inc/options/class-wpseo-option-titles.php */ $allowed_article_types = \apply_filters( 'wpseo_schema_article_types', Schema_Types::ARTICLE_TYPES ); if ( ! \array_key_exists( $additional_type, $allowed_article_types ) ) { $additional_type = $this->options->get_title_default( 'schema-article-type-' . $this->indexable->object_sub_type ); } // If the additional type is a subtype of Article, we're fine, and we can bail here. if ( \stripos( $additional_type, 'Article' ) !== false ) { /** * Filter: 'wpseo_schema_article_type' - Allow changing the Article type. * * @param string|string[] $type The Article type. * @param Indexable $indexable The indexable. */ return \apply_filters( 'wpseo_schema_article_type', $additional_type, $this->indexable ); } $type = 'Article'; /* * If `None` is set (either on the indexable or as a default), set type to 'None'. * This simplifies is_needed checks downstream. */ if ( $additional_type === 'None' ) { $type = $additional_type; } if ( $additional_type !== $type ) { $type = [ $type, $additional_type ]; } // Filter documented on line 499 above. return \apply_filters( 'wpseo_schema_article_type', $type, $this->indexable ); } /** * Returns the main schema id. * * The main schema id. * * @return string */ public function generate_main_schema_id() { return $this->permalink; } /** * Retrieves the main image URL. This is the featured image by default. * * @return string|null The main image URL. */ public function generate_main_image_url() { if ( $this->main_image_id !== null ) { return $this->image->get_attachment_image_url( $this->main_image_id, 'full' ); } if ( \wp_is_serving_rest_request() ) { return $this->get_main_image_url_for_rest_request(); } if ( ! \is_singular() ) { return null; } $url = $this->image->get_post_content_image( $this->id ); if ( $url === '' ) { return null; } return $url; } /** * Generates the main image ID. * * @return int|null The main image ID. */ public function generate_main_image_id() { if ( \wp_is_serving_rest_request() ) { return $this->get_main_image_id_for_rest_request(); } $image_id = null; switch ( true ) { case \is_singular(): $image_id = $this->get_singular_post_image( $this->id ); break; case \is_author(): case \is_tax(): case \is_tag(): case \is_category(): case \is_search(): case \is_date(): case \is_post_type_archive(): if ( ! empty( $GLOBALS['wp_query']->posts ) ) { if ( $GLOBALS['wp_query']->get( 'fields', 'all' ) === 'ids' ) { $image_id = $this->get_singular_post_image( $GLOBALS['wp_query']->posts[0] ); break; } $image_id = $this->get_singular_post_image( $GLOBALS['wp_query']->posts[0]->ID ); } break; } /** * Filter: 'wpseo_schema_main_image_id' - Allow changing the main image ID. * * @param int|array $image_id The image ID. */ return \apply_filters( 'wpseo_schema_main_image_id', $image_id ); } /** * Determines whether the current indexable has an image. * * @return bool Whether the current indexable has an image. */ public function generate_has_image() { return $this->main_image_url !== null; } /** * Strips all nested dependencies from the debug info. * * @return array */ public function __debugInfo() { return [ 'indexable' => $this->indexable, 'presentation' => $this->presentation, ]; } /** * Retrieve the site logo ID from WordPress settings. * * @return int|false */ public function fallback_to_site_logo() { $logo_id = \get_option( 'site_logo' ); if ( ! $logo_id ) { $logo_id = \get_theme_mod( 'custom_logo', false ); } return $logo_id; } /** * Get the ID for a post's featured image. * * @param int $id Post ID. * * @return int|null */ private function get_singular_post_image( $id ) { if ( \has_post_thumbnail( $id ) ) { $thumbnail_id = \get_post_thumbnail_id( $id ); // Prevent returning something else than an int or null. if ( \is_int( $thumbnail_id ) && $thumbnail_id > 0 ) { return $thumbnail_id; } } if ( \is_singular( 'attachment' ) ) { return \get_query_var( 'attachment_id' ); } return null; } /** * Gets the main image ID for REST requests. * * @return int|null The main image ID. */ private function get_main_image_id_for_rest_request() { switch ( $this->page_type ) { case 'Post_Type': if ( $this->post instanceof WP_Post ) { return $this->get_singular_post_image( $this->post->ID ); } return null; default: return null; } } /** * Gets the main image URL for REST requests. * * @return string|null The main image URL. */ private function get_main_image_url_for_rest_request() { switch ( $this->page_type ) { case 'Post_Type': if ( $this->post instanceof WP_Post ) { $url = $this->image->get_post_content_image( $this->post->ID ); if ( $url === '' ) { return null; } return $url; } return null; default: return null; } } } \class_alias( Meta_Tags_Context::class, 'WPSEO_Schema_Context' ); user The user helper. * @param Permalink_Helper $permalink_helper The permalink helper. * @param Indexable_Helper $indexable_helper The indexable helper. * @param Indexable_Repository $indexable_repository The indexable repository. */ public function __construct( Options_Helper $options, Url_Helper $url, Image_Helper $image, ID_Helper $id_helper, WPSEO_Replace_Vars $replace_vars, Site_Helper $site, User_Helper $user, Permalink_Helper $permalink_helper, Indexable_Helper $indexable_helper, Indexable_Repository $indexable_repository ) { $this->options = $options; $this->url = $url; $this->image = $image; $this->id_helper = $id_helper; $this->replace_vars = $replace_vars; $this->site = $site; $this->user = $user; $this->permalink_helper = $permalink_helper; $this->indexable_helper = $indexable_helper; $this->indexable_repository = $indexable_repository; } /** * Generates the title. * * @return string the title */ public function generate_title() { return $this->replace_vars->replace( $this->presentation->title, $this->presentation->source ); } /** * Generates the description. * * @return string the description */ public function generate_description() { return $this->replace_vars->replace( $this->presentation->meta_description, $this->presentation->source ); } /** * Generates the canonical. * * @return string the canonical */ public function generate_canonical() { return $this->presentation->canonical; } /** * Generates the permalink. * * @return string */ public function generate_permalink() { if ( ! \is_search() ) { return $this->presentation->permalink; } return \add_query_arg( 's', \rawurlencode( \get_search_query() ), \trailingslashit( $this->site_url ) ); } /** * Generates the id. * * @return string the id */ public function generate_id() { return $this->indexable->object_id; } /** * Generates the site name. * * @return string The site name. */ public function generate_site_name() { $site_name = $this->options->get( 'website_name', '' ); if ( $site_name !== '' ) { return $site_name; } return \get_bloginfo( 'name' ); } /** * Generates the alternate site name. * * @return string The alternate site name. */ public function generate_alternate_site_name() { return (string) $this->options->get( 'alternate_website_name', '' ); } /** * Generates the site name from the WordPress options. * * @return string The site name from the WordPress options. */ public function generate_wordpress_site_name() { return $this->site->get_site_name(); } /** * Generates the site url. * * @return string The site url. */ public function generate_site_url() { $home_page_indexable = $this->indexable_repository->find_for_home_page(); if ( $this->indexable_helper->dynamic_permalinks_enabled() ) { return \trailingslashit( $this->permalink_helper->get_permalink_for_indexable( $home_page_indexable ) ); } return \trailingslashit( $home_page_indexable->permalink ); } /** * Generates the company name. * * @return string The company name. */ public function generate_company_name() { /** * Filter: 'wpseo_schema_company_name' - Allows filtering company name * * @param string $company_name. */ $company_name = \apply_filters( 'wpseo_schema_company_name', $this->options->get( 'company_name' ) ); if ( empty( $company_name ) ) { $company_name = $this->site_name; } return $company_name; } /** * Generates the alternate company name. * * @return string */ public function generate_company_alternate_name() { return (string) $this->options->get( 'company_alternate_name' ); } /** * Generates the person logo id. * * @return int|bool The company logo id. */ public function generate_person_logo_id() { $person_logo_id = $this->image->get_attachment_id_from_settings( 'person_logo' ); if ( empty( $person_logo_id ) ) { $person_logo_id = $this->fallback_to_site_logo(); } /** * Filter: 'wpseo_schema_person_logo_id' - Allows filtering person logo id. * * @param int $person_logo_id. */ return \apply_filters( 'wpseo_schema_person_logo_id', $person_logo_id ); } /** * Retrieve the person logo meta. * * @return array>|bool */ public function generate_person_logo_meta() { $person_logo_meta = $this->image->get_attachment_meta_from_settings( 'person_logo' ); if ( empty( $person_logo_meta ) ) { $person_logo_id = $this->fallback_to_site_logo(); $person_logo_meta = $this->image->get_best_attachment_variation( $person_logo_id ); } /** * Filter: 'wpseo_schema_person_logo_meta' - Allows filtering person logo meta. * * @param string $person_logo_meta. */ return \apply_filters( 'wpseo_schema_person_logo_meta', $person_logo_meta ); } /** * Generates the company logo id. * * @return int|bool The company logo id. */ public function generate_company_logo_id() { $company_logo_id = $this->image->get_attachment_id_from_settings( 'company_logo' ); if ( empty( $company_logo_id ) ) { $company_logo_id = $this->fallback_to_site_logo(); } /** * Filter: 'wpseo_schema_company_logo_id' - Allows filtering company logo id. * * @param int $company_logo_id. */ return \apply_filters( 'wpseo_schema_company_logo_id', $company_logo_id ); } /** * Retrieve the company logo meta. * * @return array>|bool */ public function generate_company_logo_meta() { $company_logo_meta = $this->image->get_attachment_meta_from_settings( 'company_logo' ); /** * Filter: 'wpseo_schema_company_logo_meta' - Allows filtering company logo meta. * * @param string $company_logo_meta. */ return \apply_filters( 'wpseo_schema_company_logo_meta', $company_logo_meta ); } /** * Generates the site user id. * * @return int The site user id. */ public function generate_site_user_id() { return (int) $this->options->get( 'company_or_person_user_id', false ); } /** * Determines what our site represents, and grabs their values. * * @return string|false Person or company. False if invalid value. */ public function generate_site_represents() { switch ( $this->options->get( 'company_or_person', false ) ) { case 'company': // Do not use a non-named company. if ( empty( $this->company_name ) ) { return false; } /* * Do not use a company without a logo. * The logic check is on `< 1` instead of `false` due to how `get_attachment_id_from_settings` works. */ if ( $this->company_logo_id < 1 ) { return false; } return 'company'; case 'person': // Do not use a non-existing user. if ( $this->site_user_id !== false && \get_user_by( 'id', $this->site_user_id ) === false ) { return false; } return 'person'; } return false; } /** * Returns the site represents reference. * * @return array|bool The site represents reference. False if none. */ public function generate_site_represents_reference() { if ( $this->site_represents === 'person' ) { return [ '@id' => $this->id_helper->get_user_schema_id( $this->site_user_id, $this ) ]; } if ( $this->site_represents === 'company' ) { return [ '@id' => $this->site_url . Schema_IDs::ORGANIZATION_HASH ]; } return false; } /** * Returns whether or not open graph is enabled. * * @return bool Whether or not open graph is enabled. */ public function generate_open_graph_enabled() { return $this->options->get( 'opengraph' ) === true; } /** * Returns the open graph publisher. * * @return string The open graph publisher. */ public function generate_open_graph_publisher() { if ( $this->site_represents === 'company' ) { return $this->options->get( 'facebook_site', '' ); } if ( $this->site_represents === 'person' ) { return $this->user->get_the_author_meta( 'facebook', $this->site_user_id ); } return $this->options->get( 'facebook_site', '' ); } /** * Returns the twitter card type. * * @return string The twitter card type. */ public function generate_twitter_card() { return 'summary_large_image'; } /** * Returns the schema page type. * * @return string|array The schema page type. */ public function generate_schema_page_type() { switch ( $this->indexable->object_type ) { case 'system-page': switch ( $this->indexable->object_sub_type ) { case 'search-result': $type = [ 'CollectionPage', 'SearchResultsPage' ]; break; default: $type = 'WebPage'; } break; case 'user': $type = 'ProfilePage'; break; case 'home-page': case 'date-archive': case 'term': case 'post-type-archive': $type = 'CollectionPage'; break; default: $additional_type = $this->indexable->schema_page_type; if ( $additional_type === null ) { $additional_type = $this->options->get( 'schema-page-type-' . $this->indexable->object_sub_type ); } $type = [ 'WebPage', $additional_type ]; // Is this indexable set as a page for posts, e.g. in the WordPress reading settings as a static homepage? if ( (int) \get_option( 'page_for_posts' ) === $this->indexable->object_id ) { $type[] = 'CollectionPage'; } // Ensure we get only unique values, and remove any null values and the index. $type = \array_filter( \array_values( \array_unique( $type ) ) ); } /** * Filter: 'wpseo_schema_webpage_type' - Allow changing the WebPage type. * * @param string|array $type The WebPage type. */ return \apply_filters( 'wpseo_schema_webpage_type', $type ); } /** * Returns the schema article type. * * @return string|array The schema article type. */ public function generate_schema_article_type() { $additional_type = $this->indexable->schema_article_type; if ( $additional_type === null ) { $additional_type = $this->options->get( 'schema-article-type-' . $this->indexable->object_sub_type ); } /** This filter is documented in inc/options/class-wpseo-option-titles.php */ $allowed_article_types = \apply_filters( 'wpseo_schema_article_types', Schema_Types::ARTICLE_TYPES ); if ( ! \array_key_exists( $additional_type, $allowed_article_types ) ) { $additional_type = $this->options->get_title_default( 'schema-article-type-' . $this->indexable->object_sub_type ); } // If the additional type is a subtype of Article, we're fine, and we can bail here. if ( \stripos( $additional_type, 'Article' ) !== false ) { /** * Filter: 'wpseo_schema_article_type' - Allow changing the Article type. * * @param string|string[] $type The Article type. * @param Indexable $indexable The indexable. */ return \apply_filters( 'wpseo_schema_article_type', $additional_type, $this->indexable ); } $type = 'Article'; /* * If `None` is set (either on the indexable or as a default), set type to 'None'. * This simplifies is_needed checks downstream. */ if ( $additional_type === 'None' ) { $type = $additional_type; } if ( $additional_type !== $type ) { $type = [ $type, $additional_type ]; } // Filter documented on line 499 above. return \apply_filters( 'wpseo_schema_article_type', $type, $this->indexable ); } /** * Returns the main schema id. * * The main schema id. * * @return string */ public function generate_main_schema_id() { return $this->permalink; } /** * Retrieves the main image URL. This is the featured image by default. * * @return string|null The main image URL. */ public function generate_main_image_url() { if ( $this->main_image_id !== null ) { return $this->image->get_attachment_image_url( $this->main_image_id, 'full' ); } if ( \wp_is_serving_rest_request() ) { return $this->get_main_image_url_for_rest_request(); } if ( ! \is_singular() ) { return null; } $url = $this->image->get_post_content_image( $this->id ); if ( $url === '' ) { return null; } return $url; } /** * Generates the main image ID. * * @return int|null The main image ID. */ public function generate_main_image_id() { if ( \wp_is_serving_rest_request() ) { return $this->get_main_image_id_for_rest_request(); } $image_id = null; switch ( true ) { case \is_singular(): $image_id = $this->get_singular_post_image( $this->id ); break; case \is_author(): case \is_tax(): case \is_tag(): case \is_category(): case \is_search(): case \is_date(): case \is_post_type_archive(): if ( ! empty( $GLOBALS['wp_query']->posts ) ) { if ( $GLOBALS['wp_query']->get( 'fields', 'all' ) === 'ids' ) { $image_id = $this->get_singular_post_image( $GLOBALS['wp_query']->posts[0] ); break; } $image_id = $this->get_singular_post_image( $GLOBALS['wp_query']->posts[0]->ID ); } break; } /** * Filter: 'wpseo_schema_main_image_id' - Allow changing the main image ID. * * @param int|array $image_id The image ID. */ return \apply_filters( 'wpseo_schema_main_image_id', $image_id ); } /** * Determines whether the current indexable has an image. * * @return bool Whether the current indexable has an image. */ public function generate_has_image() { return $this->main_image_url !== null; } /** * Strips all nested dependencies from the debug info. * * @return array */ public function __debugInfo() { return [ 'indexable' => $this->indexable, 'presentation' => $this->presentation, ]; } /** * Retrieve the site logo ID from WordPress settings. * * @return int|false */ public function fallback_to_site_logo() { $logo_id = \get_option( 'site_logo' ); if ( ! $logo_id ) { $logo_id = \get_theme_mod( 'custom_logo', false ); } return $logo_id; } /** * Get the ID for a post's featured image. * * @param int $id Post ID. * * @return int|null */ private function get_singular_post_image( $id ) { if ( \has_post_thumbnail( $id ) ) { $thumbnail_id = \get_post_thumbnail_id( $id ); // Prevent returning something else than an int or null. if ( \is_int( $thumbnail_id ) && $thumbnail_id > 0 ) { return $thumbnail_id; } } if ( \is_singular( 'attachment' ) ) { return \get_query_var( 'attachment_id' ); } return null; } /** * Gets the main image ID for REST requests. * * @return int|null The main image ID. */ private function get_main_image_id_for_rest_request() { switch ( $this->page_type ) { case 'Post_Type': if ( $this->post instanceof WP_Post ) { return $this->get_singular_post_image( $this->post->ID ); } return null; default: return null; } } /** * Gets the main image URL for REST requests. * * @return string|null The main image URL. */ private function get_main_image_url_for_rest_request() { switch ( $this->page_type ) { case 'Post_Type': if ( $this->post instanceof WP_Post ) { $url = $this->image->get_post_content_image( $this->post->ID ); if ( $url === '' ) { return null; } return $url; } return null; default: return null; } } } \class_alias( Meta_Tags_Context::class, 'WPSEO_Schema_Context' ); user The user helper. * @param Permalink_Helper $permalink_helper The permalink helper. * @param Indexable_Helper $indexable_helper The indexable helper. * @param Indexable_Repository $indexable_repository The indexable repository. */ public function __construct( Options_Helper $options, Url_Helper $url, Image_Helper $image, ID_Helper $id_helper, WPSEO_Replace_Vars $replace_vars, Site_Helper $site, User_Helper $user, Permalink_Helper $permalink_helper, Indexable_Helper $indexable_helper, Indexable_Repository $indexable_repository ) { $this->options = $options; $this->url = $url; $this->image = $image; $this->id_helper = $id_helper; $this->replace_vars = $replace_vars; $this->site = $site; $this->user = $user; $this->permalink_helper = $permalink_helper; $this->indexable_helper = $indexable_helper; $this->indexable_repository = $indexable_repository; } /** * Generates the title. * * @return string the title */ public function generate_title() { return $this->replace_vars->replace( $this->presentation->title, $this->presentation->source ); } /** * Generates the description. * * @return string the description */ public function generate_description() { return $this->replace_vars->replace( $this->presentation->meta_description, $this->presentation->source ); } /** * Generates the canonical. * * @return string the canonical */ public function generate_canonical() { return $this->presentation->canonical; } /** * Generates the permalink. * * @return string */ public function generate_permalink() { if ( ! \is_search() ) { return $this->presentation->permalink; } return \add_query_arg( 's', \rawurlencode( \get_search_query() ), \trailingslashit( $this->site_url ) ); } /** * Generates the id. * * @return string the id */ public function generate_id() { return $this->indexable->object_id; } /** * Generates the site name. * * @return string The site name. */ public function generate_site_name() { $site_name = $this->options->get( 'website_name', '' ); if ( $site_name !== '' ) { return $site_name; } return \get_bloginfo( 'name' ); } /** * Generates the alternate site name. * * @return string The alternate site name. */ public function generate_alternate_site_name() { return (string) $this->options->get( 'alternate_website_name', '' ); } /** * Generates the site name from the WordPress options. * * @return string The site name from the WordPress options. */ public function generate_wordpress_site_name() { return $this->site->get_site_name(); } /** * Generates the site url. * * @return string The site url. */ public function generate_site_url() { $home_page_indexable = $this->indexable_repository->find_for_home_page(); if ( $this->indexable_helper->dynamic_permalinks_enabled() ) { return \trailingslashit( $this->permalink_helper->get_permalink_for_indexable( $home_page_indexable ) ); } return \trailingslashit( $home_page_indexable->permalink ); } /** * Generates the company name. * * @return string The company name. */ public function generate_company_name() { /** * Filter: 'wpseo_schema_company_name' - Allows filtering company name * * @param string $company_name. */ $company_name = \apply_filters( 'wpseo_schema_company_name', $this->options->get( 'company_name' ) ); if ( empty( $company_name ) ) { $company_name = $this->site_name; } return $company_name; } /** * Generates the alternate company name. * * @return string */ public function generate_company_alternate_name() { return (string) $this->options->get( 'company_alternate_name' ); } /** * Generates the person logo id. * * @return int|bool The company logo id. */ public function generate_person_logo_id() { $person_logo_id = $this->image->get_attachment_id_from_settings( 'person_logo' ); if ( empty( $person_logo_id ) ) { $person_logo_id = $this->fallback_to_site_logo(); } /** * Filter: 'wpseo_schema_person_logo_id' - Allows filtering person logo id. * * @param int $person_logo_id. */ return \apply_filters( 'wpseo_schema_person_logo_id', $person_logo_id ); } /** * Retrieve the person logo meta. * * @return array>|bool */ public function generate_person_logo_meta() { $person_logo_meta = $this->image->get_attachment_meta_from_settings( 'person_logo' ); if ( empty( $person_logo_meta ) ) { $person_logo_id = $this->fallback_to_site_logo(); $person_logo_meta = $this->image->get_best_attachment_variation( $person_logo_id ); } /** * Filter: 'wpseo_schema_person_logo_meta' - Allows filtering person logo meta. * * @param string $person_logo_meta. */ return \apply_filters( 'wpseo_schema_person_logo_meta', $person_logo_meta ); } /** * Generates the company logo id. * * @return int|bool The company logo id. */ public function generate_company_logo_id() { $company_logo_id = $this->image->get_attachment_id_from_settings( 'company_logo' ); if ( empty( $company_logo_id ) ) { $company_logo_id = $this->fallback_to_site_logo(); } /** * Filter: 'wpseo_schema_company_logo_id' - Allows filtering company logo id. * * @param int $company_logo_id. */ return \apply_filters( 'wpseo_schema_company_logo_id', $company_logo_id ); } /** * Retrieve the company logo meta. * * @return array>|bool */ public function generate_company_logo_meta() { $company_logo_meta = $this->image->get_attachment_meta_from_settings( 'company_logo' ); /** * Filter: 'wpseo_schema_company_logo_meta' - Allows filtering company logo meta. * * @param string $company_logo_meta. */ return \apply_filters( 'wpseo_schema_company_logo_meta', $company_logo_meta ); } /** * Generates the site user id. * * @return int The site user id. */ public function generate_site_user_id() { return (int) $this->options->get( 'company_or_person_user_id', false ); } /** * Determines what our site represents, and grabs their values. * * @return string|false Person or company. False if invalid value. */ public function generate_site_represents() { switch ( $this->options->get( 'company_or_person', false ) ) { case 'company': // Do not use a non-named company. if ( empty( $this->company_name ) ) { return false; } /* * Do not use a company without a logo. * The logic check is on `< 1` instead of `false` due to how `get_attachment_id_from_settings` works. */ if ( $this->company_logo_id < 1 ) { return false; } return 'company'; case 'person': // Do not use a non-existing user. if ( $this->site_user_id !== false && \get_user_by( 'id', $this->site_user_id ) === false ) { return false; } return 'person'; } return false; } /** * Returns the site represents reference. * * @return array|bool The site represents reference. False if none. */ public function generate_site_represents_reference() { if ( $this->site_represents === 'person' ) { return [ '@id' => $this->id_helper->get_user_schema_id( $this->site_user_id, $this ) ]; } if ( $this->site_represents === 'company' ) { return [ '@id' => $this->site_url . Schema_IDs::ORGANIZATION_HASH ]; } return false; } /** * Returns whether or not open graph is enabled. * * @return bool Whether or not open graph is enabled. */ public function generate_open_graph_enabled() { return $this->options->get( 'opengraph' ) === true; } /** * Returns the open graph publisher. * * @return string The open graph publisher. */ public function generate_open_graph_publisher() { if ( $this->site_represents === 'company' ) { return $this->options->get( 'facebook_site', '' ); } if ( $this->site_represents === 'person' ) { return $this->user->get_the_author_meta( 'facebook', $this->site_user_id ); } return $this->options->get( 'facebook_site', '' ); } /** * Returns the twitter card type. * * @return string The twitter card type. */ public function generate_twitter_card() { return 'summary_large_image'; } /** * Returns the schema page type. * * @return string|array The schema page type. */ public function generate_schema_page_type() { switch ( $this->indexable->object_type ) { case 'system-page': switch ( $this->indexable->object_sub_type ) { case 'search-result': $type = [ 'CollectionPage', 'SearchResultsPage' ]; break; default: $type = 'WebPage'; } break; case 'user': $type = 'ProfilePage'; break; case 'home-page': case 'date-archive': case 'term': case 'post-type-archive': $type = 'CollectionPage'; break; default: $additional_type = $this->indexable->schema_page_type; if ( $additional_type === null ) { $additional_type = $this->options->get( 'schema-page-type-' . $this->indexable->object_sub_type ); } $type = [ 'WebPage', $additional_type ]; // Is this indexable set as a page for posts, e.g. in the WordPress reading settings as a static homepage? if ( (int) \get_option( 'page_for_posts' ) === $this->indexable->object_id ) { $type[] = 'CollectionPage'; } // Ensure we get only unique values, and remove any null values and the index. $type = \array_filter( \array_values( \array_unique( $type ) ) ); } /** * Filter: 'wpseo_schema_webpage_type' - Allow changing the WebPage type. * * @param string|array $type The WebPage type. */ return \apply_filters( 'wpseo_schema_webpage_type', $type ); } /** * Returns the schema article type. * * @return string|array The schema article type. */ public function generate_schema_article_type() { $additional_type = $this->indexable->schema_article_type; if ( $additional_type === null ) { $additional_type = $this->options->get( 'schema-article-type-' . $this->indexable->object_sub_type ); } /** This filter is documented in inc/options/class-wpseo-option-titles.php */ $allowed_article_types = \apply_filters( 'wpseo_schema_article_types', Schema_Types::ARTICLE_TYPES ); if ( ! \array_key_exists( $additional_type, $allowed_article_types ) ) { $additional_type = $this->options->get_title_default( 'schema-article-type-' . $this->indexable->object_sub_type ); } // If the additional type is a subtype of Article, we're fine, and we can bail here. if ( \stripos( $additional_type, 'Article' ) !== false ) { /** * Filter: 'wpseo_schema_article_type' - Allow changing the Article type. * * @param string|string[] $type The Article type. * @param Indexable $indexable The indexable. */ return \apply_filters( 'wpseo_schema_article_type', $additional_type, $this->indexable ); } $type = 'Article'; /* * If `None` is set (either on the indexable or as a default), set type to 'None'. * This simplifies is_needed checks downstream. */ if ( $additional_type === 'None' ) { $type = $additional_type; } if ( $additional_type !== $type ) { $type = [ $type, $additional_type ]; } // Filter documented on line 499 above. return \apply_filters( 'wpseo_schema_article_type', $type, $this->indexable ); } /** * Returns the main schema id. * * The main schema id. * * @return string */ public function generate_main_schema_id() { return $this->permalink; } /** * Retrieves the main image URL. This is the featured image by default. * * @return string|null The main image URL. */ public function generate_main_image_url() { if ( $this->main_image_id !== null ) { return $this->image->get_attachment_image_url( $this->main_image_id, 'full' ); } if ( \wp_is_serving_rest_request() ) { return $this->get_main_image_url_for_rest_request(); } if ( ! \is_singular() ) { return null; } $url = $this->image->get_post_content_image( $this->id ); if ( $url === '' ) { return null; } return $url; } /** * Generates the main image ID. * * @return int|null The main image ID. */ public function generate_main_image_id() { if ( \wp_is_serving_rest_request() ) { return $this->get_main_image_id_for_rest_request(); } $image_id = null; switch ( true ) { case \is_singular(): $image_id = $this->get_singular_post_image( $this->id ); break; case \is_author(): case \is_tax(): case \is_tag(): case \is_category(): case \is_search(): case \is_date(): case \is_post_type_archive(): if ( ! empty( $GLOBALS['wp_query']->posts ) ) { if ( $GLOBALS['wp_query']->get( 'fields', 'all' ) === 'ids' ) { $image_id = $this->get_singular_post_image( $GLOBALS['wp_query']->posts[0] ); break; } $image_id = $this->get_singular_post_image( $GLOBALS['wp_query']->posts[0]->ID ); } break; } /** * Filter: 'wpseo_schema_main_image_id' - Allow changing the main image ID. * * @param int|array $image_id The image ID. */ return \apply_filters( 'wpseo_schema_main_image_id', $image_id ); } /** * Determines whether the current indexable has an image. * * @return bool Whether the current indexable has an image. */ public function generate_has_image() { return $this->main_image_url !== null; } /** * Strips all nested dependencies from the debug info. * * @return array */ public function __debugInfo() { return [ 'indexable' => $this->indexable, 'presentation' => $this->presentation, ]; } /** * Retrieve the site logo ID from WordPress settings. * * @return int|false */ public function fallback_to_site_logo() { $logo_id = \get_option( 'site_logo' ); if ( ! $logo_id ) { $logo_id = \get_theme_mod( 'custom_logo', false ); } return $logo_id; } /** * Get the ID for a post's featured image. * * @param int $id Post ID. * * @return int|null */ private function get_singular_post_image( $id ) { if ( \has_post_thumbnail( $id ) ) { $thumbnail_id = \get_post_thumbnail_id( $id ); // Prevent returning something else than an int or null. if ( \is_int( $thumbnail_id ) && $thumbnail_id > 0 ) { return $thumbnail_id; } } if ( \is_singular( 'attachment' ) ) { return \get_query_var( 'attachment_id' ); } return null; } /** * Gets the main image ID for REST requests. * * @return int|null The main image ID. */ private function get_main_image_id_for_rest_request() { switch ( $this->page_type ) { case 'Post_Type': if ( $this->post instanceof WP_Post ) { return $this->get_singular_post_image( $this->post->ID ); } return null; default: return null; } } /** * Gets the main image URL for REST requests. * * @return string|null The main image URL. */ private function get_main_image_url_for_rest_request() { switch ( $this->page_type ) { case 'Post_Type': if ( $this->post instanceof WP_Post ) { $url = $this->image->get_post_content_image( $this->post->ID ); if ( $url === '' ) { return null; } return $url; } return null; default: return null; } } } \class_alias( Meta_Tags_Context::class, 'WPSEO_Schema_Context' ); user The user helper. * @param Permalink_Helper $permalink_helper The permalink helper. * @param Indexable_Helper $indexable_helper The indexable helper. * @param Indexable_Repository $indexable_repository The indexable repository. */ public function __construct( Options_Helper $options, Url_Helper $url, Image_Helper $image, ID_Helper $id_helper, WPSEO_Replace_Vars $replace_vars, Site_Helper $site, User_Helper $user, Permalink_Helper $permalink_helper, Indexable_Helper $indexable_helper, Indexable_Repository $indexable_repository ) { $this->options = $options; $this->url = $url; $this->image = $image; $this->id_helper = $id_helper; $this->replace_vars = $replace_vars; $this->site = $site; $this->user = $user; $this->permalink_helper = $permalink_helper; $this->indexable_helper = $indexable_helper; $this->indexable_repository = $indexable_repository; } /** * Generates the title. * * @return string the title */ public function generate_title() { return $this->replace_vars->replace( $this->presentation->title, $this->presentation->source ); } /** * Generates the description. * * @return string the description */ public function generate_description() { return $this->replace_vars->replace( $this->presentation->meta_description, $this->presentation->source ); } /** * Generates the canonical. * * @return string the canonical */ public function generate_canonical() { return $this->presentation->canonical; } /** * Generates the permalink. * * @return string */ public function generate_permalink() { if ( ! \is_search() ) { return $this->presentation->permalink; } return \add_query_arg( 's', \rawurlencode( \get_search_query() ), \trailingslashit( $this->site_url ) ); } /** * Generates the id. * * @return string the id */ public function generate_id() { return $this->indexable->object_id; } /** * Generates the site name. * * @return string The site name. */ public function generate_site_name() { $site_name = $this->options->get( 'website_name', '' ); if ( $site_name !== '' ) { return $site_name; } return \get_bloginfo( 'name' ); } /** * Generates the alternate site name. * * @return string The alternate site name. */ public function generate_alternate_site_name() { return (string) $this->options->get( 'alternate_website_name', '' ); } /** * Generates the site name from the WordPress options. * * @return string The site name from the WordPress options. */ public function generate_wordpress_site_name() { return $this->site->get_site_name(); } /** * Generates the site url. * * @return string The site url. */ public function generate_site_url() { $home_page_indexable = $this->indexable_repository->find_for_home_page(); if ( $this->indexable_helper->dynamic_permalinks_enabled() ) { return \trailingslashit( $this->permalink_helper->get_permalink_for_indexable( $home_page_indexable ) ); } return \trailingslashit( $home_page_indexable->permalink ); } /** * Generates the company name. * * @return string The company name. */ public function generate_company_name() { /** * Filter: 'wpseo_schema_company_name' - Allows filtering company name * * @param string $company_name. */ $company_name = \apply_filters( 'wpseo_schema_company_name', $this->options->get( 'company_name' ) ); if ( empty( $company_name ) ) { $company_name = $this->site_name; } return $company_name; } /** * Generates the alternate company name. * * @return string */ public function generate_company_alternate_name() { return (string) $this->options->get( 'company_alternate_name' ); } /** * Generates the person logo id. * * @return int|bool The company logo id. */ public function generate_person_logo_id() { $person_logo_id = $this->image->get_attachment_id_from_settings( 'person_logo' ); if ( empty( $person_logo_id ) ) { $person_logo_id = $this->fallback_to_site_logo(); } /** * Filter: 'wpseo_schema_person_logo_id' - Allows filtering person logo id. * * @param int $person_logo_id. */ return \apply_filters( 'wpseo_schema_person_logo_id', $person_logo_id ); } /** * Retrieve the person logo meta. * * @return array>|bool */ public function generate_person_logo_meta() { $person_logo_meta = $this->image->get_attachment_meta_from_settings( 'person_logo' ); if ( empty( $person_logo_meta ) ) { $person_logo_id = $this->fallback_to_site_logo(); $person_logo_meta = $this->image->get_best_attachment_variation( $person_logo_id ); } /** * Filter: 'wpseo_schema_person_logo_meta' - Allows filtering person logo meta. * * @param string $person_logo_meta. */ return \apply_filters( 'wpseo_schema_person_logo_meta', $person_logo_meta ); } /** * Generates the company logo id. * * @return int|bool The company logo id. */ public function generate_company_logo_id() { $company_logo_id = $this->image->get_attachment_id_from_settings( 'company_logo' ); if ( empty( $company_logo_id ) ) { $company_logo_id = $this->fallback_to_site_logo(); } /** * Filter: 'wpseo_schema_company_logo_id' - Allows filtering company logo id. * * @param int $company_logo_id. */ return \apply_filters( 'wpseo_schema_company_logo_id', $company_logo_id ); } /** * Retrieve the company logo meta. * * @return array>|bool */ public function generate_company_logo_meta() { $company_logo_meta = $this->image->get_attachment_meta_from_settings( 'company_logo' ); /** * Filter: 'wpseo_schema_company_logo_meta' - Allows filtering company logo meta. * * @param string $company_logo_meta. */ return \apply_filters( 'wpseo_schema_company_logo_meta', $company_logo_meta ); } /** * Generates the site user id. * * @return int The site user id. */ public function generate_site_user_id() { return (int) $this->options->get( 'company_or_person_user_id', false ); } /** * Determines what our site represents, and grabs their values. * * @return string|false Person or company. False if invalid value. */ public function generate_site_represents() { switch ( $this->options->get( 'company_or_person', false ) ) { case 'company': // Do not use a non-named company. if ( empty( $this->company_name ) ) { return false; } /* * Do not use a company without a logo. * The logic check is on `< 1` instead of `false` due to how `get_attachment_id_from_settings` works. */ if ( $this->company_logo_id < 1 ) { return false; } return 'company'; case 'person': // Do not use a non-existing user. if ( $this->site_user_id !== false && \get_user_by( 'id', $this->site_user_id ) === false ) { return false; } return 'person'; } return false; } /** * Returns the site represents reference. * * @return array|bool The site represents reference. False if none. */ public function generate_site_represents_reference() { if ( $this->site_represents === 'person' ) { return [ '@id' => $this->id_helper->get_user_schema_id( $this->site_user_id, $this ) ]; } if ( $this->site_represents === 'company' ) { return [ '@id' => $this->site_url . Schema_IDs::ORGANIZATION_HASH ]; } return false; } /** * Returns whether or not open graph is enabled. * * @return bool Whether or not open graph is enabled. */ public function generate_open_graph_enabled() { return $this->options->get( 'opengraph' ) === true; } /** * Returns the open graph publisher. * * @return string The open graph publisher. */ public function generate_open_graph_publisher() { if ( $this->site_represents === 'company' ) { return $this->options->get( 'facebook_site', '' ); } if ( $this->site_represents === 'person' ) { return $this->user->get_the_author_meta( 'facebook', $this->site_user_id ); } return $this->options->get( 'facebook_site', '' ); } /** * Returns the twitter card type. * * @return string The twitter card type. */ public function generate_twitter_card() { return 'summary_large_image'; } /** * Returns the schema page type. * * @return string|array The schema page type. */ public function generate_schema_page_type() { switch ( $this->indexable->object_type ) { case 'system-page': switch ( $this->indexable->object_sub_type ) { case 'search-result': $type = [ 'CollectionPage', 'SearchResultsPage' ]; break; default: $type = 'WebPage'; } break; case 'user': $type = 'ProfilePage'; break; case 'home-page': case 'date-archive': case 'term': case 'post-type-archive': $type = 'CollectionPage'; break; default: $additional_type = $this->indexable->schema_page_type; if ( $additional_type === null ) { $additional_type = $this->options->get( 'schema-page-type-' . $this->indexable->object_sub_type ); } $type = [ 'WebPage', $additional_type ]; // Is this indexable set as a page for posts, e.g. in the WordPress reading settings as a static homepage? if ( (int) \get_option( 'page_for_posts' ) === $this->indexable->object_id ) { $type[] = 'CollectionPage'; } // Ensure we get only unique values, and remove any null values and the index. $type = \array_filter( \array_values( \array_unique( $type ) ) ); } /** * Filter: 'wpseo_schema_webpage_type' - Allow changing the WebPage type. * * @param string|array $type The WebPage type. */ return \apply_filters( 'wpseo_schema_webpage_type', $type ); } /** * Returns the schema article type. * * @return string|array The schema article type. */ public function generate_schema_article_type() { $additional_type = $this->indexable->schema_article_type; if ( $additional_type === null ) { $additional_type = $this->options->get( 'schema-article-type-' . $this->indexable->object_sub_type ); } /** This filter is documented in inc/options/class-wpseo-option-titles.php */ $allowed_article_types = \apply_filters( 'wpseo_schema_article_types', Schema_Types::ARTICLE_TYPES ); if ( ! \array_key_exists( $additional_type, $allowed_article_types ) ) { $additional_type = $this->options->get_title_default( 'schema-article-type-' . $this->indexable->object_sub_type ); } // If the additional type is a subtype of Article, we're fine, and we can bail here. if ( \stripos( $additional_type, 'Article' ) !== false ) { /** * Filter: 'wpseo_schema_article_type' - Allow changing the Article type. * * @param string|string[] $type The Article type. * @param Indexable $indexable The indexable. */ return \apply_filters( 'wpseo_schema_article_type', $additional_type, $this->indexable ); } $type = 'Article'; /* * If `None` is set (either on the indexable or as a default), set type to 'None'. * This simplifies is_needed checks downstream. */ if ( $additional_type === 'None' ) { $type = $additional_type; } if ( $additional_type !== $type ) { $type = [ $type, $additional_type ]; } // Filter documented on line 499 above. return \apply_filters( 'wpseo_schema_article_type', $type, $this->indexable ); } /** * Returns the main schema id. * * The main schema id. * * @return string */ public function generate_main_schema_id() { return $this->permalink; } /** * Retrieves the main image URL. This is the featured image by default. * * @return string|null The main image URL. */ public function generate_main_image_url() { if ( $this->main_image_id !== null ) { return $this->image->get_attachment_image_url( $this->main_image_id, 'full' ); } if ( \wp_is_serving_rest_request() ) { return $this->get_main_image_url_for_rest_request(); } if ( ! \is_singular() ) { return null; } $url = $this->image->get_post_content_image( $this->id ); if ( $url === '' ) { return null; } return $url; } /** * Generates the main image ID. * * @return int|null The main image ID. */ public function generate_main_image_id() { if ( \wp_is_serving_rest_request() ) { return $this->get_main_image_id_for_rest_request(); } $image_id = null; switch ( true ) { case \is_singular(): $image_id = $this->get_singular_post_image( $this->id ); break; case \is_author(): case \is_tax(): case \is_tag(): case \is_category(): case \is_search(): case \is_date(): case \is_post_type_archive(): if ( ! empty( $GLOBALS['wp_query']->posts ) ) { if ( $GLOBALS['wp_query']->get( 'fields', 'all' ) === 'ids' ) { $image_id = $this->get_singular_post_image( $GLOBALS['wp_query']->posts[0] ); break; } $image_id = $this->get_singular_post_image( $GLOBALS['wp_query']->posts[0]->ID ); } break; } /** * Filter: 'wpseo_schema_main_image_id' - Allow changing the main image ID. * * @param int|array $image_id The image ID. */ return \apply_filters( 'wpseo_schema_main_image_id', $image_id ); } /** * Determines whether the current indexable has an image. * * @return bool Whether the current indexable has an image. */ public function generate_has_image() { return $this->main_image_url !== null; } /** * Strips all nested dependencies from the debug info. * * @return array */ public function __debugInfo() { return [ 'indexable' => $this->indexable, 'presentation' => $this->presentation, ]; } /** * Retrieve the site logo ID from WordPress settings. * * @return int|false */ public function fallback_to_site_logo() { $logo_id = \get_option( 'site_logo' ); if ( ! $logo_id ) { $logo_id = \get_theme_mod( 'custom_logo', false ); } return $logo_id; } /** * Get the ID for a post's featured image. * * @param int $id Post ID. * * @return int|null */ private function get_singular_post_image( $id ) { if ( \has_post_thumbnail( $id ) ) { $thumbnail_id = \get_post_thumbnail_id( $id ); // Prevent returning something else than an int or null. if ( \is_int( $thumbnail_id ) && $thumbnail_id > 0 ) { return $thumbnail_id; } } if ( \is_singular( 'attachment' ) ) { return \get_query_var( 'attachment_id' ); } return null; } /** * Gets the main image ID for REST requests. * * @return int|null The main image ID. */ private function get_main_image_id_for_rest_request() { switch ( $this->page_type ) { case 'Post_Type': if ( $this->post instanceof WP_Post ) { return $this->get_singular_post_image( $this->post->ID ); } return null; default: return null; } } /** * Gets the main image URL for REST requests. * * @return string|null The main image URL. */ private function get_main_image_url_for_rest_request() { switch ( $this->page_type ) { case 'Post_Type': if ( $this->post instanceof WP_Post ) { $url = $this->image->get_post_content_image( $this->post->ID ); if ( $url === '' ) { return null; } return $url; } return null; default: return null; } } } \class_alias( Meta_Tags_Context::class, 'WPSEO_Schema_Context' ); user The user helper. * @param Permalink_Helper $permalink_helper The permalink helper. * @param Indexable_Helper $indexable_helper The indexable helper. * @param Indexable_Repository $indexable_repository The indexable repository. */ public function __construct( Options_Helper $options, Url_Helper $url, Image_Helper $image, ID_Helper $id_helper, WPSEO_Replace_Vars $replace_vars, Site_Helper $site, User_Helper $user, Permalink_Helper $permalink_helper, Indexable_Helper $indexable_helper, Indexable_Repository $indexable_repository ) { $this->options = $options; $this->url = $url; $this->image = $image; $this->id_helper = $id_helper; $this->replace_vars = $replace_vars; $this->site = $site; $this->user = $user; $this->permalink_helper = $permalink_helper; $this->indexable_helper = $indexable_helper; $this->indexable_repository = $indexable_repository; } /** * Generates the title. * * @return string the title */ public function generate_title() { return $this->replace_vars->replace( $this->presentation->title, $this->presentation->source ); } /** * Generates the description. * * @return string the description */ public function generate_description() { return $this->replace_vars->replace( $this->presentation->meta_description, $this->presentation->source ); } /** * Generates the canonical. * * @return string the canonical */ public function generate_canonical() { return $this->presentation->canonical; } /** * Generates the permalink. * * @return string */ public function generate_permalink() { if ( ! \is_search() ) { return $this->presentation->permalink; } return \add_query_arg( 's', \rawurlencode( \get_search_query() ), \trailingslashit( $this->site_url ) ); } /** * Generates the id. * * @return string the id */ public function generate_id() { return $this->indexable->object_id; } /** * Generates the site name. * * @return string The site name. */ public function generate_site_name() { $site_name = $this->options->get( 'website_name', '' ); if ( $site_name !== '' ) { return $site_name; } return \get_bloginfo( 'name' ); } /** * Generates the alternate site name. * * @return string The alternate site name. */ public function generate_alternate_site_name() { return (string) $this->options->get( 'alternate_website_name', '' ); } /** * Generates the site name from the WordPress options. * * @return string The site name from the WordPress options. */ public function generate_wordpress_site_name() { return $this->site->get_site_name(); } /** * Generates the site url. * * @return string The site url. */ public function generate_site_url() { $home_page_indexable = $this->indexable_repository->find_for_home_page(); if ( $this->indexable_helper->dynamic_permalinks_enabled() ) { return \trailingslashit( $this->permalink_helper->get_permalink_for_indexable( $home_page_indexable ) ); } return \trailingslashit( $home_page_indexable->permalink ); } /** * Generates the company name. * * @return string The company name. */ public function generate_company_name() { /** * Filter: 'wpseo_schema_company_name' - Allows filtering company name * * @param string $company_name. */ $company_name = \apply_filters( 'wpseo_schema_company_name', $this->options->get( 'company_name' ) ); if ( empty( $company_name ) ) { $company_name = $this->site_name; } return $company_name; } /** * Generates the alternate company name. * * @return string */ public function generate_company_alternate_name() { return (string) $this->options->get( 'company_alternate_name' ); } /** * Generates the person logo id. * * @return int|bool The company logo id. */ public function generate_person_logo_id() { $person_logo_id = $this->image->get_attachment_id_from_settings( 'person_logo' ); if ( empty( $person_logo_id ) ) { $person_logo_id = $this->fallback_to_site_logo(); } /** * Filter: 'wpseo_schema_person_logo_id' - Allows filtering person logo id. * * @param int $person_logo_id. */ return \apply_filters( 'wpseo_schema_person_logo_id', $person_logo_id ); } /** * Retrieve the person logo meta. * * @return array>|bool */ public function generate_person_logo_meta() { $person_logo_meta = $this->image->get_attachment_meta_from_settings( 'person_logo' ); if ( empty( $person_logo_meta ) ) { $person_logo_id = $this->fallback_to_site_logo(); $person_logo_meta = $this->image->get_best_attachment_variation( $person_logo_id ); } /** * Filter: 'wpseo_schema_person_logo_meta' - Allows filtering person logo meta. * * @param string $person_logo_meta. */ return \apply_filters( 'wpseo_schema_person_logo_meta', $person_logo_meta ); } /** * Generates the company logo id. * * @return int|bool The company logo id. */ public function generate_company_logo_id() { $company_logo_id = $this->image->get_attachment_id_from_settings( 'company_logo' ); if ( empty( $company_logo_id ) ) { $company_logo_id = $this->fallback_to_site_logo(); } /** * Filter: 'wpseo_schema_company_logo_id' - Allows filtering company logo id. * * @param int $company_logo_id. */ return \apply_filters( 'wpseo_schema_company_logo_id', $company_logo_id ); } /** * Retrieve the company logo meta. * * @return array>|bool */ public function generate_company_logo_meta() { $company_logo_meta = $this->image->get_attachment_meta_from_settings( 'company_logo' ); /** * Filter: 'wpseo_schema_company_logo_meta' - Allows filtering company logo meta. * * @param string $company_logo_meta. */ return \apply_filters( 'wpseo_schema_company_logo_meta', $company_logo_meta ); } /** * Generates the site user id. * * @return int The site user id. */ public function generate_site_user_id() { return (int) $this->options->get( 'company_or_person_user_id', false ); } /** * Determines what our site represents, and grabs their values. * * @return string|false Person or company. False if invalid value. */ public function generate_site_represents() { switch ( $this->options->get( 'company_or_person', false ) ) { case 'company': // Do not use a non-named company. if ( empty( $this->company_name ) ) { return false; } /* * Do not use a company without a logo. * The logic check is on `< 1` instead of `false` due to how `get_attachment_id_from_settings` works. */ if ( $this->company_logo_id < 1 ) { return false; } return 'company'; case 'person': // Do not use a non-existing user. if ( $this->site_user_id !== false && \get_user_by( 'id', $this->site_user_id ) === false ) { return false; } return 'person'; } return false; } /** * Returns the site represents reference. * * @return array|bool The site represents reference. False if none. */ public function generate_site_represents_reference() { if ( $this->site_represents === 'person' ) { return [ '@id' => $this->id_helper->get_user_schema_id( $this->site_user_id, $this ) ]; } if ( $this->site_represents === 'company' ) { return [ '@id' => $this->site_url . Schema_IDs::ORGANIZATION_HASH ]; } return false; } /** * Returns whether or not open graph is enabled. * * @return bool Whether or not open graph is enabled. */ public function generate_open_graph_enabled() { return $this->options->get( 'opengraph' ) === true; } /** * Returns the open graph publisher. * * @return string The open graph publisher. */ public function generate_open_graph_publisher() { if ( $this->site_represents === 'company' ) { return $this->options->get( 'facebook_site', '' ); } if ( $this->site_represents === 'person' ) { return $this->user->get_the_author_meta( 'facebook', $this->site_user_id ); } return $this->options->get( 'facebook_site', '' ); } /** * Returns the twitter card type. * * @return string The twitter card type. */ public function generate_twitter_card() { return 'summary_large_image'; } /** * Returns the schema page type. * * @return string|array The schema page type. */ public function generate_schema_page_type() { switch ( $this->indexable->object_type ) { case 'system-page': switch ( $this->indexable->object_sub_type ) { case 'search-result': $type = [ 'CollectionPage', 'SearchResultsPage' ]; break; default: $type = 'WebPage'; } break; case 'user': $type = 'ProfilePage'; break; case 'home-page': case 'date-archive': case 'term': case 'post-type-archive': $type = 'CollectionPage'; break; default: $additional_type = $this->indexable->schema_page_type; if ( $additional_type === null ) { $additional_type = $this->options->get( 'schema-page-type-' . $this->indexable->object_sub_type ); } $type = [ 'WebPage', $additional_type ]; // Is this indexable set as a page for posts, e.g. in the WordPress reading settings as a static homepage? if ( (int) \get_option( 'page_for_posts' ) === $this->indexable->object_id ) { $type[] = 'CollectionPage'; } // Ensure we get only unique values, and remove any null values and the index. $type = \array_filter( \array_values( \array_unique( $type ) ) ); } /** * Filter: 'wpseo_schema_webpage_type' - Allow changing the WebPage type. * * @param string|array $type The WebPage type. */ return \apply_filters( 'wpseo_schema_webpage_type', $type ); } /** * Returns the schema article type. * * @return string|array The schema article type. */ public function generate_schema_article_type() { $additional_type = $this->indexable->schema_article_type; if ( $additional_type === null ) { $additional_type = $this->options->get( 'schema-article-type-' . $this->indexable->object_sub_type ); } /** This filter is documented in inc/options/class-wpseo-option-titles.php */ $allowed_article_types = \apply_filters( 'wpseo_schema_article_types', Schema_Types::ARTICLE_TYPES ); if ( ! \array_key_exists( $additional_type, $allowed_article_types ) ) { $additional_type = $this->options->get_title_default( 'schema-article-type-' . $this->indexable->object_sub_type ); } // If the additional type is a subtype of Article, we're fine, and we can bail here. if ( \stripos( $additional_type, 'Article' ) !== false ) { /** * Filter: 'wpseo_schema_article_type' - Allow changing the Article type. * * @param string|string[] $type The Article type. * @param Indexable $indexable The indexable. */ return \apply_filters( 'wpseo_schema_article_type', $additional_type, $this->indexable ); } $type = 'Article'; /* * If `None` is set (either on the indexable or as a default), set type to 'None'. * This simplifies is_needed checks downstream. */ if ( $additional_type === 'None' ) { $type = $additional_type; } if ( $additional_type !== $type ) { $type = [ $type, $additional_type ]; } // Filter documented on line 499 above. return \apply_filters( 'wpseo_schema_article_type', $type, $this->indexable ); } /** * Returns the main schema id. * * The main schema id. * * @return string */ public function generate_main_schema_id() { return $this->permalink; } /** * Retrieves the main image URL. This is the featured image by default. * * @return string|null The main image URL. */ public function generate_main_image_url() { if ( $this->main_image_id !== null ) { return $this->image->get_attachment_image_url( $this->main_image_id, 'full' ); } if ( \wp_is_serving_rest_request() ) { return $this->get_main_image_url_for_rest_request(); } if ( ! \is_singular() ) { return null; } $url = $this->image->get_post_content_image( $this->id ); if ( $url === '' ) { return null; } return $url; } /** * Generates the main image ID. * * @return int|null The main image ID. */ public function generate_main_image_id() { if ( \wp_is_serving_rest_request() ) { return $this->get_main_image_id_for_rest_request(); } $image_id = null; switch ( true ) { case \is_singular(): $image_id = $this->get_singular_post_image( $this->id ); break; case \is_author(): case \is_tax(): case \is_tag(): case \is_category(): case \is_search(): case \is_date(): case \is_post_type_archive(): if ( ! empty( $GLOBALS['wp_query']->posts ) ) { if ( $GLOBALS['wp_query']->get( 'fields', 'all' ) === 'ids' ) { $image_id = $this->get_singular_post_image( $GLOBALS['wp_query']->posts[0] ); break; } $image_id = $this->get_singular_post_image( $GLOBALS['wp_query']->posts[0]->ID ); } break; } /** * Filter: 'wpseo_schema_main_image_id' - Allow changing the main image ID. * * @param int|array $image_id The image ID. */ return \apply_filters( 'wpseo_schema_main_image_id', $image_id ); } /** * Determines whether the current indexable has an image. * * @return bool Whether the current indexable has an image. */ public function generate_has_image() { return $this->main_image_url !== null; } /** * Strips all nested dependencies from the debug info. * * @return array */ public function __debugInfo() { return [ 'indexable' => $this->indexable, 'presentation' => $this->presentation, ]; } /** * Retrieve the site logo ID from WordPress settings. * * @return int|false */ public function fallback_to_site_logo() { $logo_id = \get_option( 'site_logo' ); if ( ! $logo_id ) { $logo_id = \get_theme_mod( 'custom_logo', false ); } return $logo_id; } /** * Get the ID for a post's featured image. * * @param int $id Post ID. * * @return int|null */ private function get_singular_post_image( $id ) { if ( \has_post_thumbnail( $id ) ) { $thumbnail_id = \get_post_thumbnail_id( $id ); // Prevent returning something else than an int or null. if ( \is_int( $thumbnail_id ) && $thumbnail_id > 0 ) { return $thumbnail_id; } } if ( \is_singular( 'attachment' ) ) { return \get_query_var( 'attachment_id' ); } return null; } /** * Gets the main image ID for REST requests. * * @return int|null The main image ID. */ private function get_main_image_id_for_rest_request() { switch ( $this->page_type ) { case 'Post_Type': if ( $this->post instanceof WP_Post ) { return $this->get_singular_post_image( $this->post->ID ); } return null; default: return null; } } /** * Gets the main image URL for REST requests. * * @return string|null The main image URL. */ private function get_main_image_url_for_rest_request() { switch ( $this->page_type ) { case 'Post_Type': if ( $this->post instanceof WP_Post ) { $url = $this->image->get_post_content_image( $this->post->ID ); if ( $url === '' ) { return null; } return $url; } return null; default: return null; } } } \class_alias( Meta_Tags_Context::class, 'WPSEO_Schema_Context' ); user The user helper. * @param Permalink_Helper $permalink_helper The permalink helper. * @param Indexable_Helper $indexable_helper The indexable helper. * @param Indexable_Repository $indexable_repository The indexable repository. */ public function __construct( Options_Helper $options, Url_Helper $url, Image_Helper $image, ID_Helper $id_helper, WPSEO_Replace_Vars $replace_vars, Site_Helper $site, User_Helper $user, Permalink_Helper $permalink_helper, Indexable_Helper $indexable_helper, Indexable_Repository $indexable_repository ) { $this->options = $options; $this->url = $url; $this->image = $image; $this->id_helper = $id_helper; $this->replace_vars = $replace_vars; $this->site = $site; $this->user = $user; $this->permalink_helper = $permalink_helper; $this->indexable_helper = $indexable_helper; $this->indexable_repository = $indexable_repository; } /** * Generates the title. * * @return string the title */ public function generate_title() { return $this->replace_vars->replace( $this->presentation->title, $this->presentation->source ); } /** * Generates the description. * * @return string the description */ public function generate_description() { return $this->replace_vars->replace( $this->presentation->meta_description, $this->presentation->source ); } /** * Generates the canonical. * * @return string the canonical */ public function generate_canonical() { return $this->presentation->canonical; } /** * Generates the permalink. * * @return string */ public function generate_permalink() { if ( ! \is_search() ) { return $this->presentation->permalink; } return \add_query_arg( 's', \rawurlencode( \get_search_query() ), \trailingslashit( $this->site_url ) ); } /** * Generates the id. * * @return string the id */ public function generate_id() { return $this->indexable->object_id; } /** * Generates the site name. * * @return string The site name. */ public function generate_site_name() { $site_name = $this->options->get( 'website_name', '' ); if ( $site_name !== '' ) { return $site_name; } return \get_bloginfo( 'name' ); } /** * Generates the alternate site name. * * @return string The alternate site name. */ public function generate_alternate_site_name() { return (string) $this->options->get( 'alternate_website_name', '' ); } /** * Generates the site name from the WordPress options. * * @return string The site name from the WordPress options. */ public function generate_wordpress_site_name() { return $this->site->get_site_name(); } /** * Generates the site url. * * @return string The site url. */ public function generate_site_url() { $home_page_indexable = $this->indexable_repository->find_for_home_page(); if ( $this->indexable_helper->dynamic_permalinks_enabled() ) { return \trailingslashit( $this->permalink_helper->get_permalink_for_indexable( $home_page_indexable ) ); } return \trailingslashit( $home_page_indexable->permalink ); } /** * Generates the company name. * * @return string The company name. */ public function generate_company_name() { /** * Filter: 'wpseo_schema_company_name' - Allows filtering company name * * @param string $company_name. */ $company_name = \apply_filters( 'wpseo_schema_company_name', $this->options->get( 'company_name' ) ); if ( empty( $company_name ) ) { $company_name = $this->site_name; } return $company_name; } /** * Generates the alternate company name. * * @return string */ public function generate_company_alternate_name() { return (string) $this->options->get( 'company_alternate_name' ); } /** * Generates the person logo id. * * @return int|bool The company logo id. */ public function generate_person_logo_id() { $person_logo_id = $this->image->get_attachment_id_from_settings( 'person_logo' ); if ( empty( $person_logo_id ) ) { $person_logo_id = $this->fallback_to_site_logo(); } /** * Filter: 'wpseo_schema_person_logo_id' - Allows filtering person logo id. * * @param int $person_logo_id. */ return \apply_filters( 'wpseo_schema_person_logo_id', $person_logo_id ); } /** * Retrieve the person logo meta. * * @return array>|bool */ public function generate_person_logo_meta() { $person_logo_meta = $this->image->get_attachment_meta_from_settings( 'person_logo' ); if ( empty( $person_logo_meta ) ) { $person_logo_id = $this->fallback_to_site_logo(); $person_logo_meta = $this->image->get_best_attachment_variation( $person_logo_id ); } /** * Filter: 'wpseo_schema_person_logo_meta' - Allows filtering person logo meta. * * @param string $person_logo_meta. */ return \apply_filters( 'wpseo_schema_person_logo_meta', $person_logo_meta ); } /** * Generates the company logo id. * * @return int|bool The company logo id. */ public function generate_company_logo_id() { $company_logo_id = $this->image->get_attachment_id_from_settings( 'company_logo' ); if ( empty( $company_logo_id ) ) { $company_logo_id = $this->fallback_to_site_logo(); } /** * Filter: 'wpseo_schema_company_logo_id' - Allows filtering company logo id. * * @param int $company_logo_id. */ return \apply_filters( 'wpseo_schema_company_logo_id', $company_logo_id ); } /** * Retrieve the company logo meta. * * @return array>|bool */ public function generate_company_logo_meta() { $company_logo_meta = $this->image->get_attachment_meta_from_settings( 'company_logo' ); /** * Filter: 'wpseo_schema_company_logo_meta' - Allows filtering company logo meta. * * @param string $company_logo_meta. */ return \apply_filters( 'wpseo_schema_company_logo_meta', $company_logo_meta ); } /** * Generates the site user id. * * @return int The site user id. */ public function generate_site_user_id() { return (int) $this->options->get( 'company_or_person_user_id', false ); } /** * Determines what our site represents, and grabs their values. * * @return string|false Person or company. False if invalid value. */ public function generate_site_represents() { switch ( $this->options->get( 'company_or_person', false ) ) { case 'company': // Do not use a non-named company. if ( empty( $this->company_name ) ) { return false; } /* * Do not use a company without a logo. * The logic check is on `< 1` instead of `false` due to how `get_attachment_id_from_settings` works. */ if ( $this->company_logo_id < 1 ) { return false; } return 'company'; case 'person': // Do not use a non-existing user. if ( $this->site_user_id !== false && \get_user_by( 'id', $this->site_user_id ) === false ) { return false; } return 'person'; } return false; } /** * Returns the site represents reference. * * @return array|bool The site represents reference. False if none. */ public function generate_site_represents_reference() { if ( $this->site_represents === 'person' ) { return [ '@id' => $this->id_helper->get_user_schema_id( $this->site_user_id, $this ) ]; } if ( $this->site_represents === 'company' ) { return [ '@id' => $this->site_url . Schema_IDs::ORGANIZATION_HASH ]; } return false; } /** * Returns whether or not open graph is enabled. * * @return bool Whether or not open graph is enabled. */ public function generate_open_graph_enabled() { return $this->options->get( 'opengraph' ) === true; } /** * Returns the open graph publisher. * * @return string The open graph publisher. */ public function generate_open_graph_publisher() { if ( $this->site_represents === 'company' ) { return $this->options->get( 'facebook_site', '' ); } if ( $this->site_represents === 'person' ) { return $this->user->get_the_author_meta( 'facebook', $this->site_user_id ); } return $this->options->get( 'facebook_site', '' ); } /** * Returns the twitter card type. * * @return string The twitter card type. */ public function generate_twitter_card() { return 'summary_large_image'; } /** * Returns the schema page type. * * @return string|array The schema page type. */ public function generate_schema_page_type() { switch ( $this->indexable->object_type ) { case 'system-page': switch ( $this->indexable->object_sub_type ) { case 'search-result': $type = [ 'CollectionPage', 'SearchResultsPage' ]; break; default: $type = 'WebPage'; } break; case 'user': $type = 'ProfilePage'; break; case 'home-page': case 'date-archive': case 'term': case 'post-type-archive': $type = 'CollectionPage'; break; default: $additional_type = $this->indexable->schema_page_type; if ( $additional_type === null ) { $additional_type = $this->options->get( 'schema-page-type-' . $this->indexable->object_sub_type ); } $type = [ 'WebPage', $additional_type ]; // Is this indexable set as a page for posts, e.g. in the WordPress reading settings as a static homepage? if ( (int) \get_option( 'page_for_posts' ) === $this->indexable->object_id ) { $type[] = 'CollectionPage'; } // Ensure we get only unique values, and remove any null values and the index. $type = \array_filter( \array_values( \array_unique( $type ) ) ); } /** * Filter: 'wpseo_schema_webpage_type' - Allow changing the WebPage type. * * @param string|array $type The WebPage type. */ return \apply_filters( 'wpseo_schema_webpage_type', $type ); } /** * Returns the schema article type. * * @return string|array The schema article type. */ public function generate_schema_article_type() { $additional_type = $this->indexable->schema_article_type; if ( $additional_type === null ) { $additional_type = $this->options->get( 'schema-article-type-' . $this->indexable->object_sub_type ); } /** This filter is documented in inc/options/class-wpseo-option-titles.php */ $allowed_article_types = \apply_filters( 'wpseo_schema_article_types', Schema_Types::ARTICLE_TYPES ); if ( ! \array_key_exists( $additional_type, $allowed_article_types ) ) { $additional_type = $this->options->get_title_default( 'schema-article-type-' . $this->indexable->object_sub_type ); } // If the additional type is a subtype of Article, we're fine, and we can bail here. if ( \stripos( $additional_type, 'Article' ) !== false ) { /** * Filter: 'wpseo_schema_article_type' - Allow changing the Article type. * * @param string|string[] $type The Article type. * @param Indexable $indexable The indexable. */ return \apply_filters( 'wpseo_schema_article_type', $additional_type, $this->indexable ); } $type = 'Article'; /* * If `None` is set (either on the indexable or as a default), set type to 'None'. * This simplifies is_needed checks downstream. */ if ( $additional_type === 'None' ) { $type = $additional_type; } if ( $additional_type !== $type ) { $type = [ $type, $additional_type ]; } // Filter documented on line 499 above. return \apply_filters( 'wpseo_schema_article_type', $type, $this->indexable ); } /** * Returns the main schema id. * * The main schema id. * * @return string */ public function generate_main_schema_id() { return $this->permalink; } /** * Retrieves the main image URL. This is the featured image by default. * * @return string|null The main image URL. */ public function generate_main_image_url() { if ( $this->main_image_id !== null ) { return $this->image->get_attachment_image_url( $this->main_image_id, 'full' ); } if ( \wp_is_serving_rest_request() ) { return $this->get_main_image_url_for_rest_request(); } if ( ! \is_singular() ) { return null; } $url = $this->image->get_post_content_image( $this->id ); if ( $url === '' ) { return null; } return $url; } /** * Generates the main image ID. * * @return int|null The main image ID. */ public function generate_main_image_id() { if ( \wp_is_serving_rest_request() ) { return $this->get_main_image_id_for_rest_request(); } $image_id = null; switch ( true ) { case \is_singular(): $image_id = $this->get_singular_post_image( $this->id ); break; case \is_author(): case \is_tax(): case \is_tag(): case \is_category(): case \is_search(): case \is_date(): case \is_post_type_archive(): if ( ! empty( $GLOBALS['wp_query']->posts ) ) { if ( $GLOBALS['wp_query']->get( 'fields', 'all' ) === 'ids' ) { $image_id = $this->get_singular_post_image( $GLOBALS['wp_query']->posts[0] ); break; } $image_id = $this->get_singular_post_image( $GLOBALS['wp_query']->posts[0]->ID ); } break; } /** * Filter: 'wpseo_schema_main_image_id' - Allow changing the main image ID. * * @param int|array $image_id The image ID. */ return \apply_filters( 'wpseo_schema_main_image_id', $image_id ); } /** * Determines whether the current indexable has an image. * * @return bool Whether the current indexable has an image. */ public function generate_has_image() { return $this->main_image_url !== null; } /** * Strips all nested dependencies from the debug info. * * @return array */ public function __debugInfo() { return [ 'indexable' => $this->indexable, 'presentation' => $this->presentation, ]; } /** * Retrieve the site logo ID from WordPress settings. * * @return int|false */ public function fallback_to_site_logo() { $logo_id = \get_option( 'site_logo' ); if ( ! $logo_id ) { $logo_id = \get_theme_mod( 'custom_logo', false ); } return $logo_id; } /** * Get the ID for a post's featured image. * * @param int $id Post ID. * * @return int|null */ private function get_singular_post_image( $id ) { if ( \has_post_thumbnail( $id ) ) { $thumbnail_id = \get_post_thumbnail_id( $id ); // Prevent returning something else than an int or null. if ( \is_int( $thumbnail_id ) && $thumbnail_id > 0 ) { return $thumbnail_id; } } if ( \is_singular( 'attachment' ) ) { return \get_query_var( 'attachment_id' ); } return null; } /** * Gets the main image ID for REST requests. * * @return int|null The main image ID. */ private function get_main_image_id_for_rest_request() { switch ( $this->page_type ) { case 'Post_Type': if ( $this->post instanceof WP_Post ) { return $this->get_singular_post_image( $this->post->ID ); } return null; default: return null; } } /** * Gets the main image URL for REST requests. * * @return string|null The main image URL. */ private function get_main_image_url_for_rest_request() { switch ( $this->page_type ) { case 'Post_Type': if ( $this->post instanceof WP_Post ) { $url = $this->image->get_post_content_image( $this->post->ID ); if ( $url === '' ) { return null; } return $url; } return null; default: return null; } } } \class_alias( Meta_Tags_Context::class, 'WPSEO_Schema_Context' ); user The user helper. * @param Permalink_Helper $permalink_helper The permalink helper. * @param Indexable_Helper $indexable_helper The indexable helper. * @param Indexable_Repository $indexable_repository The indexable repository. */ public function __construct( Options_Helper $options, Url_Helper $url, Image_Helper $image, ID_Helper $id_helper, WPSEO_Replace_Vars $replace_vars, Site_Helper $site, User_Helper $user, Permalink_Helper $permalink_helper, Indexable_Helper $indexable_helper, Indexable_Repository $indexable_repository ) { $this->options = $options; $this->url = $url; $this->image = $image; $this->id_helper = $id_helper; $this->replace_vars = $replace_vars; $this->site = $site; $this->user = $user; $this->permalink_helper = $permalink_helper; $this->indexable_helper = $indexable_helper; $this->indexable_repository = $indexable_repository; } /** * Generates the title. * * @return string the title */ public function generate_title() { return $this->replace_vars->replace( $this->presentation->title, $this->presentation->source ); } /** * Generates the description. * * @return string the description */ public function generate_description() { return $this->replace_vars->replace( $this->presentation->meta_description, $this->presentation->source ); } /** * Generates the canonical. * * @return string the canonical */ public function generate_canonical() { return $this->presentation->canonical; } /** * Generates the permalink. * * @return string */ public function generate_permalink() { if ( ! \is_search() ) { return $this->presentation->permalink; } return \add_query_arg( 's', \rawurlencode( \get_search_query() ), \trailingslashit( $this->site_url ) ); } /** * Generates the id. * * @return string the id */ public function generate_id() { return $this->indexable->object_id; } /** * Generates the site name. * * @return string The site name. */ public function generate_site_name() { $site_name = $this->options->get( 'website_name', '' ); if ( $site_name !== '' ) { return $site_name; } return \get_bloginfo( 'name' ); } /** * Generates the alternate site name. * * @return string The alternate site name. */ public function generate_alternate_site_name() { return (string) $this->options->get( 'alternate_website_name', '' ); } /** * Generates the site name from the WordPress options. * * @return string The site name from the WordPress options. */ public function generate_wordpress_site_name() { return $this->site->get_site_name(); } /** * Generates the site url. * * @return string The site url. */ public function generate_site_url() { $home_page_indexable = $this->indexable_repository->find_for_home_page(); if ( $this->indexable_helper->dynamic_permalinks_enabled() ) { return \trailingslashit( $this->permalink_helper->get_permalink_for_indexable( $home_page_indexable ) ); } return \trailingslashit( $home_page_indexable->permalink ); } /** * Generates the company name. * * @return string The company name. */ public function generate_company_name() { /** * Filter: 'wpseo_schema_company_name' - Allows filtering company name * * @param string $company_name. */ $company_name = \apply_filters( 'wpseo_schema_company_name', $this->options->get( 'company_name' ) ); if ( empty( $company_name ) ) { $company_name = $this->site_name; } return $company_name; } /** * Generates the alternate company name. * * @return string */ public function generate_company_alternate_name() { return (string) $this->options->get( 'company_alternate_name' ); } /** * Generates the person logo id. * * @return int|bool The company logo id. */ public function generate_person_logo_id() { $person_logo_id = $this->image->get_attachment_id_from_settings( 'person_logo' ); if ( empty( $person_logo_id ) ) { $person_logo_id = $this->fallback_to_site_logo(); } /** * Filter: 'wpseo_schema_person_logo_id' - Allows filtering person logo id. * * @param int $person_logo_id. */ return \apply_filters( 'wpseo_schema_person_logo_id', $person_logo_id ); } /** * Retrieve the person logo meta. * * @return array>|bool */ public function generate_person_logo_meta() { $person_logo_meta = $this->image->get_attachment_meta_from_settings( 'person_logo' ); if ( empty( $person_logo_meta ) ) { $person_logo_id = $this->fallback_to_site_logo(); $person_logo_meta = $this->image->get_best_attachment_variation( $person_logo_id ); } /** * Filter: 'wpseo_schema_person_logo_meta' - Allows filtering person logo meta. * * @param string $person_logo_meta. */ return \apply_filters( 'wpseo_schema_person_logo_meta', $person_logo_meta ); } /** * Generates the company logo id. * * @return int|bool The company logo id. */ public function generate_company_logo_id() { $company_logo_id = $this->image->get_attachment_id_from_settings( 'company_logo' ); if ( empty( $company_logo_id ) ) { $company_logo_id = $this->fallback_to_site_logo(); } /** * Filter: 'wpseo_schema_company_logo_id' - Allows filtering company logo id. * * @param int $company_logo_id. */ return \apply_filters( 'wpseo_schema_company_logo_id', $company_logo_id ); } /** * Retrieve the company logo meta. * * @return array>|bool */ public function generate_company_logo_meta() { $company_logo_meta = $this->image->get_attachment_meta_from_settings( 'company_logo' ); /** * Filter: 'wpseo_schema_company_logo_meta' - Allows filtering company logo meta. * * @param string $company_logo_meta. */ return \apply_filters( 'wpseo_schema_company_logo_meta', $company_logo_meta ); } /** * Generates the site user id. * * @return int The site user id. */ public function generate_site_user_id() { return (int) $this->options->get( 'company_or_person_user_id', false ); } /** * Determines what our site represents, and grabs their values. * * @return string|false Person or company. False if invalid value. */ public function generate_site_represents() { switch ( $this->options->get( 'company_or_person', false ) ) { case 'company': // Do not use a non-named company. if ( empty( $this->company_name ) ) { return false; } /* * Do not use a company without a logo. * The logic check is on `< 1` instead of `false` due to how `get_attachment_id_from_settings` works. */ if ( $this->company_logo_id < 1 ) { return false; } return 'company'; case 'person': // Do not use a non-existing user. if ( $this->site_user_id !== false && \get_user_by( 'id', $this->site_user_id ) === false ) { return false; } return 'person'; } return false; } /** * Returns the site represents reference. * * @return array|bool The site represents reference. False if none. */ public function generate_site_represents_reference() { if ( $this->site_represents === 'person' ) { return [ '@id' => $this->id_helper->get_user_schema_id( $this->site_user_id, $this ) ]; } if ( $this->site_represents === 'company' ) { return [ '@id' => $this->site_url . Schema_IDs::ORGANIZATION_HASH ]; } return false; } /** * Returns whether or not open graph is enabled. * * @return bool Whether or not open graph is enabled. */ public function generate_open_graph_enabled() { return $this->options->get( 'opengraph' ) === true; } /** * Returns the open graph publisher. * * @return string The open graph publisher. */ public function generate_open_graph_publisher() { if ( $this->site_represents === 'company' ) { return $this->options->get( 'facebook_site', '' ); } if ( $this->site_represents === 'person' ) { return $this->user->get_the_author_meta( 'facebook', $this->site_user_id ); } return $this->options->get( 'facebook_site', '' ); } /** * Returns the twitter card type. * * @return string The twitter card type. */ public function generate_twitter_card() { return 'summary_large_image'; } /** * Returns the schema page type. * * @return string|array The schema page type. */ public function generate_schema_page_type() { switch ( $this->indexable->object_type ) { case 'system-page': switch ( $this->indexable->object_sub_type ) { case 'search-result': $type = [ 'CollectionPage', 'SearchResultsPage' ]; break; default: $type = 'WebPage'; } break; case 'user': $type = 'ProfilePage'; break; case 'home-page': case 'date-archive': case 'term': case 'post-type-archive': $type = 'CollectionPage'; break; default: $additional_type = $this->indexable->schema_page_type; if ( $additional_type === null ) { $additional_type = $this->options->get( 'schema-page-type-' . $this->indexable->object_sub_type ); } $type = [ 'WebPage', $additional_type ]; // Is this indexable set as a page for posts, e.g. in the WordPress reading settings as a static homepage? if ( (int) \get_option( 'page_for_posts' ) === $this->indexable->object_id ) { $type[] = 'CollectionPage'; } // Ensure we get only unique values, and remove any null values and the index. $type = \array_filter( \array_values( \array_unique( $type ) ) ); } /** * Filter: 'wpseo_schema_webpage_type' - Allow changing the WebPage type. * * @param string|array $type The WebPage type. */ return \apply_filters( 'wpseo_schema_webpage_type', $type ); } /** * Returns the schema article type. * * @return string|array The schema article type. */ public function generate_schema_article_type() { $additional_type = $this->indexable->schema_article_type; if ( $additional_type === null ) { $additional_type = $this->options->get( 'schema-article-type-' . $this->indexable->object_sub_type ); } /** This filter is documented in inc/options/class-wpseo-option-titles.php */ $allowed_article_types = \apply_filters( 'wpseo_schema_article_types', Schema_Types::ARTICLE_TYPES ); if ( ! \array_key_exists( $additional_type, $allowed_article_types ) ) { $additional_type = $this->options->get_title_default( 'schema-article-type-' . $this->indexable->object_sub_type ); } // If the additional type is a subtype of Article, we're fine, and we can bail here. if ( \stripos( $additional_type, 'Article' ) !== false ) { /** * Filter: 'wpseo_schema_article_type' - Allow changing the Article type. * * @param string|string[] $type The Article type. * @param Indexable $indexable The indexable. */ return \apply_filters( 'wpseo_schema_article_type', $additional_type, $this->indexable ); } $type = 'Article'; /* * If `None` is set (either on the indexable or as a default), set type to 'None'. * This simplifies is_needed checks downstream. */ if ( $additional_type === 'None' ) { $type = $additional_type; } if ( $additional_type !== $type ) { $type = [ $type, $additional_type ]; } // Filter documented on line 499 above. return \apply_filters( 'wpseo_schema_article_type', $type, $this->indexable ); } /** * Returns the main schema id. * * The main schema id. * * @return string */ public function generate_main_schema_id() { return $this->permalink; } /** * Retrieves the main image URL. This is the featured image by default. * * @return string|null The main image URL. */ public function generate_main_image_url() { if ( $this->main_image_id !== null ) { return $this->image->get_attachment_image_url( $this->main_image_id, 'full' ); } if ( \wp_is_serving_rest_request() ) { return $this->get_main_image_url_for_rest_request(); } if ( ! \is_singular() ) { return null; } $url = $this->image->get_post_content_image( $this->id ); if ( $url === '' ) { return null; } return $url; } /** * Generates the main image ID. * * @return int|null The main image ID. */ public function generate_main_image_id() { if ( \wp_is_serving_rest_request() ) { return $this->get_main_image_id_for_rest_request(); } $image_id = null; switch ( true ) { case \is_singular(): $image_id = $this->get_singular_post_image( $this->id ); break; case \is_author(): case \is_tax(): case \is_tag(): case \is_category(): case \is_search(): case \is_date(): case \is_post_type_archive(): if ( ! empty( $GLOBALS['wp_query']->posts ) ) { if ( $GLOBALS['wp_query']->get( 'fields', 'all' ) === 'ids' ) { $image_id = $this->get_singular_post_image( $GLOBALS['wp_query']->posts[0] ); break; } $image_id = $this->get_singular_post_image( $GLOBALS['wp_query']->posts[0]->ID ); } break; } /** * Filter: 'wpseo_schema_main_image_id' - Allow changing the main image ID. * * @param int|array $image_id The image ID. */ return \apply_filters( 'wpseo_schema_main_image_id', $image_id ); } /** * Determines whether the current indexable has an image. * * @return bool Whether the current indexable has an image. */ public function generate_has_image() { return $this->main_image_url !== null; } /** * Strips all nested dependencies from the debug info. * * @return array */ public function __debugInfo() { return [ 'indexable' => $this->indexable, 'presentation' => $this->presentation, ]; } /** * Retrieve the site logo ID from WordPress settings. * * @return int|false */ public function fallback_to_site_logo() { $logo_id = \get_option( 'site_logo' ); if ( ! $logo_id ) { $logo_id = \get_theme_mod( 'custom_logo', false ); } return $logo_id; } /** * Get the ID for a post's featured image. * * @param int $id Post ID. * * @return int|null */ private function get_singular_post_image( $id ) { if ( \has_post_thumbnail( $id ) ) { $thumbnail_id = \get_post_thumbnail_id( $id ); // Prevent returning something else than an int or null. if ( \is_int( $thumbnail_id ) && $thumbnail_id > 0 ) { return $thumbnail_id; } } if ( \is_singular( 'attachment' ) ) { return \get_query_var( 'attachment_id' ); } return null; } /** * Gets the main image ID for REST requests. * * @return int|null The main image ID. */ private function get_main_image_id_for_rest_request() { switch ( $this->page_type ) { case 'Post_Type': if ( $this->post instanceof WP_Post ) { return $this->get_singular_post_image( $this->post->ID ); } return null; default: return null; } } /** * Gets the main image URL for REST requests. * * @return string|null The main image URL. */ private function get_main_image_url_for_rest_request() { switch ( $this->page_type ) { case 'Post_Type': if ( $this->post instanceof WP_Post ) { $url = $this->image->get_post_content_image( $this->post->ID ); if ( $url === '' ) { return null; } return $url; } return null; default: return null; } } } \class_alias( Meta_Tags_Context::class, 'WPSEO_Schema_Context' ); user The user helper. * @param Permalink_Helper $permalink_helper The permalink helper. * @param Indexable_Helper $indexable_helper The indexable helper. * @param Indexable_Repository $indexable_repository The indexable repository. */ public function __construct( Options_Helper $options, Url_Helper $url, Image_Helper $image, ID_Helper $id_helper, WPSEO_Replace_Vars $replace_vars, Site_Helper $site, User_Helper $user, Permalink_Helper $permalink_helper, Indexable_Helper $indexable_helper, Indexable_Repository $indexable_repository ) { $this->options = $options; $this->url = $url; $this->image = $image; $this->id_helper = $id_helper; $this->replace_vars = $replace_vars; $this->site = $site; $this->user = $user; $this->permalink_helper = $permalink_helper; $this->indexable_helper = $indexable_helper; $this->indexable_repository = $indexable_repository; } /** * Generates the title. * * @return string the title */ public function generate_title() { return $this->replace_vars->replace( $this->presentation->title, $this->presentation->source ); } /** * Generates the description. * * @return string the description */ public function generate_description() { return $this->replace_vars->replace( $this->presentation->meta_description, $this->presentation->source ); } /** * Generates the canonical. * * @return string the canonical */ public function generate_canonical() { return $this->presentation->canonical; } /** * Generates the permalink. * * @return string */ public function generate_permalink() { if ( ! \is_search() ) { return $this->presentation->permalink; } return \add_query_arg( 's', \rawurlencode( \get_search_query() ), \trailingslashit( $this->site_url ) ); } /** * Generates the id. * * @return string the id */ public function generate_id() { return $this->indexable->object_id; } /** * Generates the site name. * * @return string The site name. */ public function generate_site_name() { $site_name = $this->options->get( 'website_name', '' ); if ( $site_name !== '' ) { return $site_name; } return \get_bloginfo( 'name' ); } /** * Generates the alternate site name. * * @return string The alternate site name. */ public function generate_alternate_site_name() { return (string) $this->options->get( 'alternate_website_name', '' ); } /** * Generates the site name from the WordPress options. * * @return string The site name from the WordPress options. */ public function generate_wordpress_site_name() { return $this->site->get_site_name(); } /** * Generates the site url. * * @return string The site url. */ public function generate_site_url() { $home_page_indexable = $this->indexable_repository->find_for_home_page(); if ( $this->indexable_helper->dynamic_permalinks_enabled() ) { return \trailingslashit( $this->permalink_helper->get_permalink_for_indexable( $home_page_indexable ) ); } return \trailingslashit( $home_page_indexable->permalink ); } /** * Generates the company name. * * @return string The company name. */ public function generate_company_name() { /** * Filter: 'wpseo_schema_company_name' - Allows filtering company name * * @param string $company_name. */ $company_name = \apply_filters( 'wpseo_schema_company_name', $this->options->get( 'company_name' ) ); if ( empty( $company_name ) ) { $company_name = $this->site_name; } return $company_name; } /** * Generates the alternate company name. * * @return string */ public function generate_company_alternate_name() { return (string) $this->options->get( 'company_alternate_name' ); } /** * Generates the person logo id. * * @return int|bool The company logo id. */ public function generate_person_logo_id() { $person_logo_id = $this->image->get_attachment_id_from_settings( 'person_logo' ); if ( empty( $person_logo_id ) ) { $person_logo_id = $this->fallback_to_site_logo(); } /** * Filter: 'wpseo_schema_person_logo_id' - Allows filtering person logo id. * * @param int $person_logo_id. */ return \apply_filters( 'wpseo_schema_person_logo_id', $person_logo_id ); } /** * Retrieve the person logo meta. * * @return array>|bool */ public function generate_person_logo_meta() { $person_logo_meta = $this->image->get_attachment_meta_from_settings( 'person_logo' ); if ( empty( $person_logo_meta ) ) { $person_logo_id = $this->fallback_to_site_logo(); $person_logo_meta = $this->image->get_best_attachment_variation( $person_logo_id ); } /** * Filter: 'wpseo_schema_person_logo_meta' - Allows filtering person logo meta. * * @param string $person_logo_meta. */ return \apply_filters( 'wpseo_schema_person_logo_meta', $person_logo_meta ); } /** * Generates the company logo id. * * @return int|bool The company logo id. */ public function generate_company_logo_id() { $company_logo_id = $this->image->get_attachment_id_from_settings( 'company_logo' ); if ( empty( $company_logo_id ) ) { $company_logo_id = $this->fallback_to_site_logo(); } /** * Filter: 'wpseo_schema_company_logo_id' - Allows filtering company logo id. * * @param int $company_logo_id. */ return \apply_filters( 'wpseo_schema_company_logo_id', $company_logo_id ); } /** * Retrieve the company logo meta. * * @return array>|bool */ public function generate_company_logo_meta() { $company_logo_meta = $this->image->get_attachment_meta_from_settings( 'company_logo' ); /** * Filter: 'wpseo_schema_company_logo_meta' - Allows filtering company logo meta. * * @param string $company_logo_meta. */ return \apply_filters( 'wpseo_schema_company_logo_meta', $company_logo_meta ); } /** * Generates the site user id. * * @return int The site user id. */ public function generate_site_user_id() { return (int) $this->options->get( 'company_or_person_user_id', false ); } /** * Determines what our site represents, and grabs their values. * * @return string|false Person or company. False if invalid value. */ public function generate_site_represents() { switch ( $this->options->get( 'company_or_person', false ) ) { case 'company': // Do not use a non-named company. if ( empty( $this->company_name ) ) { return false; } /* * Do not use a company without a logo. * The logic check is on `< 1` instead of `false` due to how `get_attachment_id_from_settings` works. */ if ( $this->company_logo_id < 1 ) { return false; } return 'company'; case 'person': // Do not use a non-existing user. if ( $this->site_user_id !== false && \get_user_by( 'id', $this->site_user_id ) === false ) { return false; } return 'person'; } return false; } /** * Returns the site represents reference. * * @return array|bool The site represents reference. False if none. */ public function generate_site_represents_reference() { if ( $this->site_represents === 'person' ) { return [ '@id' => $this->id_helper->get_user_schema_id( $this->site_user_id, $this ) ]; } if ( $this->site_represents === 'company' ) { return [ '@id' => $this->site_url . Schema_IDs::ORGANIZATION_HASH ]; } return false; } /** * Returns whether or not open graph is enabled. * * @return bool Whether or not open graph is enabled. */ public function generate_open_graph_enabled() { return $this->options->get( 'opengraph' ) === true; } /** * Returns the open graph publisher. * * @return string The open graph publisher. */ public function generate_open_graph_publisher() { if ( $this->site_represents === 'company' ) { return $this->options->get( 'facebook_site', '' ); } if ( $this->site_represents === 'person' ) { return $this->user->get_the_author_meta( 'facebook', $this->site_user_id ); } return $this->options->get( 'facebook_site', '' ); } /** * Returns the twitter card type. * * @return string The twitter card type. */ public function generate_twitter_card() { return 'summary_large_image'; } /** * Returns the schema page type. * * @return string|array The schema page type. */ public function generate_schema_page_type() { switch ( $this->indexable->object_type ) { case 'system-page': switch ( $this->indexable->object_sub_type ) { case 'search-result': $type = [ 'CollectionPage', 'SearchResultsPage' ]; break; default: $type = 'WebPage'; } break; case 'user': $type = 'ProfilePage'; break; case 'home-page': case 'date-archive': case 'term': case 'post-type-archive': $type = 'CollectionPage'; break; default: $additional_type = $this->indexable->schema_page_type; if ( $additional_type === null ) { $additional_type = $this->options->get( 'schema-page-type-' . $this->indexable->object_sub_type ); } $type = [ 'WebPage', $additional_type ]; // Is this indexable set as a page for posts, e.g. in the WordPress reading settings as a static homepage? if ( (int) \get_option( 'page_for_posts' ) === $this->indexable->object_id ) { $type[] = 'CollectionPage'; } // Ensure we get only unique values, and remove any null values and the index. $type = \array_filter( \array_values( \array_unique( $type ) ) ); } /** * Filter: 'wpseo_schema_webpage_type' - Allow changing the WebPage type. * * @param string|array $type The WebPage type. */ return \apply_filters( 'wpseo_schema_webpage_type', $type ); } /** * Returns the schema article type. * * @return string|array The schema article type. */ public function generate_schema_article_type() { $additional_type = $this->indexable->schema_article_type; if ( $additional_type === null ) { $additional_type = $this->options->get( 'schema-article-type-' . $this->indexable->object_sub_type ); } /** This filter is documented in inc/options/class-wpseo-option-titles.php */ $allowed_article_types = \apply_filters( 'wpseo_schema_article_types', Schema_Types::ARTICLE_TYPES ); if ( ! \array_key_exists( $additional_type, $allowed_article_types ) ) { $additional_type = $this->options->get_title_default( 'schema-article-type-' . $this->indexable->object_sub_type ); } // If the additional type is a subtype of Article, we're fine, and we can bail here. if ( \stripos( $additional_type, 'Article' ) !== false ) { /** * Filter: 'wpseo_schema_article_type' - Allow changing the Article type. * * @param string|string[] $type The Article type. * @param Indexable $indexable The indexable. */ return \apply_filters( 'wpseo_schema_article_type', $additional_type, $this->indexable ); } $type = 'Article'; /* * If `None` is set (either on the indexable or as a default), set type to 'None'. * This simplifies is_needed checks downstream. */ if ( $additional_type === 'None' ) { $type = $additional_type; } if ( $additional_type !== $type ) { $type = [ $type, $additional_type ]; } // Filter documented on line 499 above. return \apply_filters( 'wpseo_schema_article_type', $type, $this->indexable ); } /** * Returns the main schema id. * * The main schema id. * * @return string */ public function generate_main_schema_id() { return $this->permalink; } /** * Retrieves the main image URL. This is the featured image by default. * * @return string|null The main image URL. */ public function generate_main_image_url() { if ( $this->main_image_id !== null ) { return $this->image->get_attachment_image_url( $this->main_image_id, 'full' ); } if ( \wp_is_serving_rest_request() ) { return $this->get_main_image_url_for_rest_request(); } if ( ! \is_singular() ) { return null; } $url = $this->image->get_post_content_image( $this->id ); if ( $url === '' ) { return null; } return $url; } /** * Generates the main image ID. * * @return int|null The main image ID. */ public function generate_main_image_id() { if ( \wp_is_serving_rest_request() ) { return $this->get_main_image_id_for_rest_request(); } $image_id = null; switch ( true ) { case \is_singular(): $image_id = $this->get_singular_post_image( $this->id ); break; case \is_author(): case \is_tax(): case \is_tag(): case \is_category(): case \is_search(): case \is_date(): case \is_post_type_archive(): if ( ! empty( $GLOBALS['wp_query']->posts ) ) { if ( $GLOBALS['wp_query']->get( 'fields', 'all' ) === 'ids' ) { $image_id = $this->get_singular_post_image( $GLOBALS['wp_query']->posts[0] ); break; } $image_id = $this->get_singular_post_image( $GLOBALS['wp_query']->posts[0]->ID ); } break; } /** * Filter: 'wpseo_schema_main_image_id' - Allow changing the main image ID. * * @param int|array $image_id The image ID. */ return \apply_filters( 'wpseo_schema_main_image_id', $image_id ); } /** * Determines whether the current indexable has an image. * * @return bool Whether the current indexable has an image. */ public function generate_has_image() { return $this->main_image_url !== null; } /** * Strips all nested dependencies from the debug info. * * @return array */ public function __debugInfo() { return [ 'indexable' => $this->indexable, 'presentation' => $this->presentation, ]; } /** * Retrieve the site logo ID from WordPress settings. * * @return int|false */ public function fallback_to_site_logo() { $logo_id = \get_option( 'site_logo' ); if ( ! $logo_id ) { $logo_id = \get_theme_mod( 'custom_logo', false ); } return $logo_id; } /** * Get the ID for a post's featured image. * * @param int $id Post ID. * * @return int|null */ private function get_singular_post_image( $id ) { if ( \has_post_thumbnail( $id ) ) { $thumbnail_id = \get_post_thumbnail_id( $id ); // Prevent returning something else than an int or null. if ( \is_int( $thumbnail_id ) && $thumbnail_id > 0 ) { return $thumbnail_id; } } if ( \is_singular( 'attachment' ) ) { return \get_query_var( 'attachment_id' ); } return null; } /** * Gets the main image ID for REST requests. * * @return int|null The main image ID. */ private function get_main_image_id_for_rest_request() { switch ( $this->page_type ) { case 'Post_Type': if ( $this->post instanceof WP_Post ) { return $this->get_singular_post_image( $this->post->ID ); } return null; default: return null; } } /** * Gets the main image URL for REST requests. * * @return string|null The main image URL. */ private function get_main_image_url_for_rest_request() { switch ( $this->page_type ) { case 'Post_Type': if ( $this->post instanceof WP_Post ) { $url = $this->image->get_post_content_image( $this->post->ID ); if ( $url === '' ) { return null; } return $url; } return null; default: return null; } } } \class_alias( Meta_Tags_Context::class, 'WPSEO_Schema_Context' ); Maximizing Casinolab Reload Bonuses and Cashback Deals for Frequent Players – Loïs Kedochim
loader image
Livraison gratuite dans le monde, sans surcoût à la réception.
Livraison prévue début décembre.
Livraison gratuite dans le monde, sans surcoût à la réception.
Livraison prévue début décembre.

For avid online casino players, understanding how to effectively leverage reload bonuses and cashback deals can significantly enhance gaming experiences and profitability. These promotional tools are not just marketing gimmicks; when used strategically, they serve as powerful mechanisms to maximize your bankroll, reduce risks, and extend playtime. In this article, we explore proven methods to identify the most rewarding offers, optimize their utilization, and employ advanced strategies to sustain long-term gains, all grounded in practical insights and data-driven approaches.

How to Identify the Most Rewarding Reload Bonus Offers at Casinolab

When aiming to maximize benefits from reload bonuses, the first step is to analyze the specific terms associated with each offer. Not all bonuses are created equal; some may seem attractive but carry restrictive wagering requirements or limited applicability. By scrutinizing the fine print, players can prioritize offers that provide genuine value.

Analyzing Bonus Terms and Wagering Requirements

Wagering requirements specify how much you need to bet before you can withdraw bonus funds or winnings derived from them. For example, a bonus with a 30x wagering requirement on a $50 bonus means you must wager $1,500 before withdrawal. Lower requirements (e.g., 20x or less) are generally more favorable, as they require less betting volume and reduce the risk of losing bonus funds without payout.

Additionally, examine the eligible games. Slots often contribute 100% toward wagering, while table games like blackjack or roulette may contribute less or be restricted entirely. Understanding these nuances helps in selecting bonuses aligned with your preferred game types, enabling faster fulfillment of wagering conditions.

Timing Your Deposits for Maximum Bonus Value

Strategic timing can enhance bonus value. For instance, many casinos offer reload bonuses during specific promotional periods or on certain days. Planning deposits during these windows ensures access to higher bonus percentages or exclusive offers. Moreover, aligning deposits with periods of lower competition or higher game availability can increase your chances of meeting wagering requirements efficiently.

Matching Bonuses with Popular Game Types for Better Returns

Matching bonuses are most beneficial when used on games with high return-to-player (RTP) percentages, such as slot titles with RTPs above 96%, or on games where your skill can influence outcomes, like poker or blackjack. This strategic pairing maximizes the potential for profitable play and quicker fulfillment of bonus conditions.

For example, if a reload bonus applies to slots with an RTP of 97%, your expected return per bet is higher, making it easier to meet wagering requirements while maintaining favorable odds. casinolab provides a comprehensive list of eligible games and current promotions to help players make informed choices.

Strategies to Optimize Cashback Deal Utilization for Consistent Gains

Cashback deals are designed to return a percentage of losses over a specified period, providing a safety net that can stabilize bankroll fluctuations. To maximize their benefits, players should adopt disciplined tracking and strategic activation of offers.

Tracking Cashback Offers and Activation Windows

Most cashback deals have specific timeframes during which they are active. Keeping detailed records of your play sessions, losses, and cashback deadlines ensures timely activation and claim processes. Using personal tracking tools or casino dashboards helps prevent missing out on accrued cashback, especially during busy gaming periods.

Balancing Cashback and Bonus Incentives to Minimize Risks

While cashback offers provide a cushion, overreliance on them without a strategic plan can lead to complacency. Combining cashback deals with ongoing bonuses allows for a layered approach: bonuses can fund higher-risk, higher-reward bets, while cashback mitigates losses. Maintaining this balance reduces the risk of depleting your bankroll prematurely.

Integrating Cashback with Player Loyalty Tiers for Enhanced Benefits

Many online casinos reward loyal players with tiered cashback percentages or exclusive deals. Progressing through loyalty tiers often unlocks higher cashback rates and personalized promotions. Consistently engaging with the platform and fulfilling loyalty criteria can therefore lead to compounded benefits, further boosting your earning potential.

Leveraging Advanced Tips to Enhance Bonus and Cashback Effectiveness

Beyond basic strategies, seasoned players employ sophisticated techniques to meet wagering conditions efficiently and maximize promotional benefits.

Using Betting Patterns to Meet Bonus Wagering Conditions Efficiently

Designing a betting pattern that aligns with bonus terms can accelerate wagering fulfillment. For example, placing smaller, consistent bets on high-contribution games reduces variance and ensures steady progress. Tracking your play and adjusting bet sizes based on remaining wagering requirements can prevent unnecessary risks and optimize bonus clearing times.

Combining Multiple Promotions for Compound Advantages

Stacking promotions—such as using a reload bonus on top of cashback deals—can lead to a cumulative boost in overall profitability. Careful planning involves selecting offers with compatible terms and avoiding conflicting restrictions. For example, initiating a reload bonus on a game where cashback applies can extend playtime and reduce the impact of losses, leveraging the strengths of both promotions.

Employing Bankroll Management to Sustain Long-Term Rewards

Effective bankroll management is critical for sustaining long-term benefits. Setting strict limits on bets and withdrawals prevents overexposure and ensures that promotional advantages are maximized without risking financial stability. For instance, allocating a fixed percentage of your bankroll for bonus play, and adjusting bets accordingly, helps maintain a balanced approach that adapts to fluctuations and preserves capital for future opportunities.

“The key to long-term success in online casino promotions lies in disciplined management, strategic pairing of offers, and continuous monitoring of your play and the evolving promotional landscape.”

In conclusion, mastering the art of utilizing reload bonuses and cashback deals involves a combination of thorough analysis, strategic timing, and disciplined play. By understanding the nuances of bonus terms, tracking cashback opportunities, and employing advanced betting techniques, players can turn these promotional tools into consistent sources of value. For those seeking a comprehensive platform that offers a range of such benefits, exploring resources like casinolab can provide valuable insights and current offers to support your gaming strategy.

Notre but ultime est d’inspirer le plus grand nombre à vivre conformément à leur nature pour qu’ils réalisent leurs rêves.

Panier