📁 File Manager Pro
v10.0.3 | PHP: 8.1.34
Server: LiteSpeed
2026-06-28 19:17:24
📂
/ (Root)
/
home
/
apkbfjox
/
y888.online
/
wp-content
/
plugins
/
seo-by-rank-math
/
includes
/
frontend
/
paper
📍 /home/apkbfjox/y888.online/wp-content/plugins/seo-by-rank-math/includes/frontend/paper
🔄 Refresh
✏️
Editing: class-singular.php
Writable
<?php /** * The Singular Class * * @since 1.0.22 * @package RankMath * @subpackage RankMath\Paper * @author Rank Math <support@rankmath.com> */ namespace RankMath\Paper; use RankMath\Post; use RankMath\Helper; use RankMath\Helpers\Security; use RankMath\Helpers\Str; use RankMath\OpenGraph\OpenGraph; defined( 'ABSPATH' ) || exit; /** * Singular class. */ class Singular implements IPaper { /** * Post object. * * @var WP_Post */ private $object; /** * Retrieves the SEO title. * * @return string */ public function title() { return $this->get_post_title( $this->object ); } /** * Retrieves the SEO description. * * @return string */ public function description() { return $this->get_post_description( $this->object ); } /** * Retrieves the robots. * * @return string */ public function robots() { return $this->get_post_robots( $this->object ); } /** * Retrieves the advanced robots. * * @return array */ public function advanced_robots() { return $this->get_post_advanced_robots( $this->object ); } /** * Retrieves the canonical URL. * * @return array */ public function canonical() { $object_id = Post::get_page_id(); $canonical = get_permalink( $object_id ); $canonical_unpaged = $canonical; $canonical_override = Post::get_meta( 'canonical_url', $object_id ); /** * Fix paginated pages canonical, but only if the page is truly paginated. * * @copyright Copyright (C) 2008-2019, Yoast BV * The following code is a derivative work of the code from the Yoast(https://github.com/Yoast/wordpress-seo/), which is licensed under GPL v3. */ if ( is_singular() && get_query_var( 'page' ) > 1 ) { $num_pages = ( substr_count( get_queried_object()->post_content, '<!--nextpage-->' ) + 1 ); if ( $num_pages && get_query_var( 'page' ) <= $num_pages ) { global $wp_rewrite; $canonical = ! $wp_rewrite->using_permalinks() ? Security::add_query_arg_raw( 'page', get_query_var( 'page' ), $canonical ) : user_trailingslashit( trailingslashit( $canonical ) . get_query_var( 'page' ) ); } } return [ 'canonical' => $canonical, 'canonical_unpaged' => $canonical, 'canonical_override' => $canonical_override, ]; } /** * Retrieves meta keywords. * * @return string The focus keywords. */ public function keywords() { return Post::get_meta( 'focus_keyword', $this->object->ID ); } /** * Set post object. * * @param WP_Post $post Current post object. */ public function set_object( $post ) { $this->object = $post; } /** * Get all SEO metadata for a post as a structured array. * * Uses existing Singular and Opengraph methods to ensure frontend fallback logic is applied consistently. * * @since 1.0.272 * * @param int $post_id Post ID. * @return array */ public function get_seo_meta( int $post_id ): array { $post = get_post( $post_id ); if ( ! $post ) { return [ 'error' => esc_html__( 'Post not found.', 'seo-by-rank-math' ) ]; } $this->set_object( $post ); // Set post context so template variables and query-dependent functions resolve correctly. $prev_post = isset( $GLOBALS['post'] ) ? $GLOBALS['post'] : null; $GLOBALS['post'] = $post; // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited setup_postdata( $post ); rank_math()->variables->setup(); $seo_title = $this->title(); $seo_description = $this->description(); // Derive canonical from $post_id directly — canonical() depends on the active WP query // and may return get_permalink(0) outside a real frontend request. $canonical_override = Post::get_meta( 'canonical_url', $post_id ); $canonical = ! empty( $canonical_override ) ? $canonical_override : get_permalink( $post_id ); // Use OpenGraph directly to avoid extra hooks registered by Facebook/Twitter constructors. $facebook = new OpenGraph(); $facebook->network = 'facebook'; $facebook->prefix = 'facebook'; $twitter = new OpenGraph(); $twitter->network = 'twitter'; $twitter->prefix = Helper::get_post_meta( 'twitter_use_facebook', $post_id, true ) ? 'facebook' : 'twitter'; $og_title = $facebook->get_title( $post_id ); $og_description = $facebook->get_description( $post_id ); $tw_title = $twitter->get_title( $post_id ); $tw_description = $twitter->get_description( $post_id ); $result = [ 'post_id' => $post_id, 'title' => $seo_title, 'description' => $seo_description, 'focus_keyword' => $this->keywords(), 'robots' => array_values( $this->get_effective_robots() ), 'canonical' => (string) $canonical, 'og_title' => $og_title ? $og_title : $seo_title, 'og_description' => $og_description ? $og_description : $seo_description, 'twitter_title' => $tw_title ? $tw_title : $seo_title, 'twitter_description' => $tw_description ? $tw_description : $seo_description, 'seo_score' => (int) Post::get_meta( 'seo_score', $post_id ), ]; wp_reset_postdata(); $GLOBALS['post'] = $prev_post; // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited return $result; } /** * Get the SEO title set in the post metabox. * * @param object|null $post Post object to retrieve the title for. * * @return string */ protected function get_post_title( $post = null ) { if ( ! is_object( $post ) ) { return Paper::get_from_options( '404_title', [], esc_html__( 'Page not found', 'seo-by-rank-math' ) ); } $title = Post::get_meta( 'title', $post->ID ); if ( '' !== $title ) { return $title; } $post_type = isset( $post->post_type ) ? $post->post_type : $post->query_var; return Paper::get_from_options( "pt_{$post_type}_title", $post, '%title% %sep% %sitename%' ); } /** * Retrieves the SEO description set in the post metabox. * * Retrieve in this order: * 1. Custom meta description set for the post in SERP field * 2. Excerpt * 3. Description template set in the Titles & Meta * 4. Paragraph with the focus keyword * 5. The First paragraph of the content * * @param object|null $post Object to retrieve the description from. * * @return string The SEO description for the specified object, or queried object if not supplied. */ protected function get_post_description( $post = null ) { if ( ! is_object( $post ) ) { return ''; } // 1. Custom meta description set for the post in SERP field. $description = Post::get_meta( 'description', $post->ID ); if ( '' !== $description ) { return $description; } // 2. Excerpt if ( ! empty( $post->post_excerpt ) ) { return $post->post_excerpt; } // 3. Description template set in the Titles & Meta. $post_type = isset( $post->post_type ) ? $post->post_type : $post->query_var; return Str::truncate( Paper::get_from_options( "pt_{$post_type}_description", $post ), 160 ); } /** * Retrieves the robots set in the post metabox. * * @param object|null $post Object to retrieve the robots data from. * * @return string The robots for the specified object, or queried object if not supplied. */ protected function get_post_robots( $post = null ) { if ( ! is_object( $post ) ) { return []; } $post_type = $post->post_type; $robots = Paper::robots_combine( Post::get_meta( 'robots', $post->ID ) ); if ( empty( $robots ) && Helper::get_settings( "titles.pt_{$post_type}_custom_robots" ) ) { $robots = Paper::robots_combine( Helper::get_settings( "titles.pt_{$post_type}_robots" ), true ); } // `noindex` these conditions. $noindex_private = 'private' === $post->post_status; $no_index_subpages = is_paged() && Helper::get_settings( 'titles.noindex_paginated_pages' ); $noindex_password_protected = ! empty( $post->post_password ) && Helper::get_settings( 'titles.noindex_password_protected' ); if ( $noindex_private || $noindex_password_protected || $no_index_subpages ) { $robots['index'] = 'noindex'; } return $robots; } /** * Retrieves the advanced robots set in the post metabox. * * @param object|null $post Object to retrieve the robots data from. * * @return string The robots for the specified object, or queried object if not supplied. */ protected function get_post_advanced_robots( $post = null ) { if ( ! is_object( $this->object ) ) { return []; } $post_type = $this->object->post_type; $robots = Paper::advanced_robots_combine( Post::get_meta( 'advanced_robots', $this->object->ID ) ); if ( ! is_array( $robots ) && Helper::get_settings( "titles.pt_{$post_type}_custom_robots" ) ) { $robots = Paper::advanced_robots_combine( Helper::get_settings( "titles.pt_{$post_type}_advanced_robots" ), true ); } return $robots; } /** * Resolve the effective robots directives for the current post. * * Applies the same fallback and validation logic as Paper::get_robots(). * * @return array */ private function get_effective_robots(): array { $robots = $this->robots(); if ( empty( $robots ) ) { $robots = Paper::robots_combine( Helper::get_settings( 'titles.robots_global' ) ); } if ( empty( $robots ) || ! is_array( $robots ) ) { return [ 'index' => 'index', 'follow' => 'follow', ]; } if ( ! isset( $robots['index'] ) ) { $robots = [ 'index' => 'index' ] + $robots; } if ( ! isset( $robots['follow'] ) ) { $robots = [ 'follow' => 'follow' ] + $robots; } // Force noindex if the blog is not public. if ( 0 === absint( get_option( 'blog_public' ) ) ) { $robots['index'] = 'noindex'; $robots['follow'] = 'nofollow'; } $allowed = [ 'index' => '', 'follow' => '', 'noarchive' => '', 'noimageindex' => '', 'nosnippet' => '', ]; return array_unique( array_intersect_key( $robots, $allowed ) ); } }
💾 Save Changes
❌ Cancel