XRiRiRi0RixRiRiRiPRiRiRi(RipRiRiRiHRiRiشRi RihRiRiRi@RiRiжRiRi`RiRiRi8RiRiȸRiRiXRiRiRi0RixRiRiRiPRiRiRi(RipRiRiRiHRiRiؽRi RihRiRiRi@RiRiпRiRi`RiRiRi8RiRiRiQydRiRiRi0RixRiRiRiPRiRiRi(RipRiRiRiHRiRiRi RihRiRiRi@RiRiRiRi`RiRiRi8RiRiRi RihRiRiRi@RiRiRiRi`RiRiRi8RiRiRiRiXRiRiRi0RixRiRiRiPRiRiRi(RipRiRiRiHRiRiRi RihRiRiRi@RiRiRiRi`RiRiRi8RiRiRiRiXRiRiRi0RixRiRiRiPRiRiRi(RipRiRiRiHRiRiRi RihRiRiRi@RiRiRiRi`RiRi@Wi`@Wi@Wi@Wi8AWiAWiAWiBWiXBWiBWiBWi0CWixCWiCWiDWiPDWiDWiDWi(EWipEWiEWiFWiHFWiFWiFWi GWihGWiGWiGWi@HWiHWiHWiIWi`IWiIWiIWi8JWiJWiJWiKWiXKWiKWiKWi0LWixLWiLWiMWiPMWiMWiMWi(NWipNWiNWiOWiHOWiOWiOWi PWihPWiPWiPWi@QWiQWiQWiRWi`RWiRWiRWi8SWiSWiSWiTWiXTWiTWiTWi0UWixUWiUWiVWiPVWiVWiVWi(WWipWWiWWiXWiHXWiXWiXWi YWihYWiYWiYWi@ZWiZWiZWi[Wi`[Wi[Wi[Wi8\Wi\Wi\Wi]WiX]Wi]Wi]Wi0^Wix^Wi^Wi_WiP_Wi_Wi_Wi(`Wip`Wi`WiaWiQyoaWi bWihbWibWibWi@cWicWicWidWi`dWidWidWi8eWieWieWifWiXfWifWifWi0gWixgWigWihWiPhWihWihWi(iWipiWiiWijWiHjWijWijWi kWihkWikWikWi@lWilWilWimWi`mWimWimWi8nWinWinWioWiXoWioWioWi0pWixpWipWiqWiPqWiqWiqWi(rWiprWirWi@Ji @QTi  RiRi@`"i @@zi  PRi8Ri@ i @`j  RiRi@0RTi @Ii  RiRi@`Ii @Li  (RiRi@ Li @Ii  pRiXRi@xSi @ Ji  RiRi@ySi @RTi  RiRi@Ki @@Ki  HRi0Ri@Ki @ Ri  RixRi@gSi @IJi  RiRi@` Ji @STi  RiRi@ZHi @GTi  hRiPRi@0\Hi @HTi  RiRi@@HTi @pHTi  RiRi@STi @STi  @Ri(Ri@HTi @hSi  RipRi@Fi @HTi  RiRi 5.0.0 * * @return string The custom canonical URL, if any. */ public static function get_custom_canonical_url_from_query() { if ( Query::is_real_front_page() ) { if ( Query::is_static_front_page() ) { $url = Data\Plugin::get_option( 'homepage_canonical' ) ?: Data\Plugin\Post::get_meta_item( '_genesis_canonical_uri' ); } else { $url = Data\Plugin::get_option( 'homepage_canonical' ); } } elseif ( Query::is_singular() ) { $url = Data\Plugin\Post::get_meta_item( '_genesis_canonical_uri' ); } elseif ( Query::is_editable_term() ) { $url = Data\Plugin\Term::get_meta_item( 'canonical' ); } elseif ( \is_post_type_archive() ) { $url = Data\Plugin\PTA::get_meta_item( 'canonical' ); } if ( empty( $url ) ) return ''; if ( URI\Utils::url_matches_blog_domain( $url ) ) $url = URI\Utils::set_preferred_url_scheme( $url ); return \sanitize_url( $url, [ 'https', 'http' ] ); } /** * Returns the custom canonical URL, based on arguments. * * @since 5.0.0 * * @param array $args The query arguments. Accepts 'id', 'tax', 'pta', and 'uid'. * @return string The custom canonical URL, if any. */ public static function get_custom_canonical_url_from_args( $args ) { normalize_generation_args( $args ); switch ( get_query_type_from_args( $args ) ) { case 'single': if ( Query::is_static_front_page( $args['id'] ) ) { $url = Data\Plugin::get_option( 'homepage_canonical' ) ?: Data\Plugin\Post::get_meta_item( '_genesis_canonical_uri', $args['id'] ); } else { $url = Data\Plugin\Post::get_meta_item( '_genesis_canonical_uri', $args['id'] ); } break; case 'term': $url = Data\Plugin\Term::get_meta_item( 'canonical', $args['id'] ); break; case 'homeblog': $url = Data\Plugin::get_option( 'homepage_canonical' ); break; case 'pta': $url = Data\Plugin\PTA::get_meta_item( 'canonical', $args['pta'] ); } if ( empty( $url ) ) return ''; if ( URI\Utils::url_matches_blog_domain( $url ) ) $url = URI\Utils::set_preferred_url_scheme( $url ); return \sanitize_url( $url, [ 'https', 'http' ] ); } /** * Gets generated canonical URL, based on query. * * @since 5.0.0 * * @return string The generated canonical URL. */ public static function get_generated_url_from_query() { if ( Query::is_real_front_page() ) { $url = self::get_front_page_url(); } elseif ( Query::is_singular() ) { $url = self::get_singular_url(); } elseif ( Query::is_archive() ) { if ( Query::is_editable_term() ) { $url = self::get_term_url(); } elseif ( \is_post_type_archive() ) { $url = self::get_pta_url(); } elseif ( Query::is_author() ) { $url = self::get_author_url(); } elseif ( \is_date() ) { $url = self::get_date_url(); } } elseif ( Query::is_search() ) { $url = self::get_search_url(); } return $url ?? '' ?: ''; } /** * Gets generated permalink, based on args. * * @since 5.0.0 * * @param array $args The query arguments. Accepts 'id', 'tax', 'pta', and 'uid'. * @return string The generated URL. */ public static function get_generated_url_from_args( $args ) { normalize_generation_args( $args ); switch ( get_query_type_from_args( $args ) ) { case 'single': if ( Query::is_static_front_page( $args['id'] ) ) { $url = self::get_bare_front_page_url(); } else { $url = self::get_bare_singular_url( $args['id'] ); } break; case 'term': $url = self::get_bare_term_url( $args['id'], $args['tax'] ); break; case 'homeblog': $url = self::get_bare_front_page_url(); break; case 'pta': $url = self::get_bare_pta_url( $args['pta'] ); break; case 'user': $url = self::get_bare_author_url( $args['uid'] ); } return $url ?: ''; } /** * Returns home canonical URL. * Automatically adds pagination if the ID matches the query. * * @since 5.0.0 * * @return string The home URL. */ public static function get_front_page_url() { $url = URI\Utils::slash_front_page_url( Data\Blog::get_front_page_url() ); if ( empty( $url ) ) return ''; $page = max( Query::paged(), Query::page() ); if ( $page > 1 ) $url = URI\Utils::add_pagination_to_url( $url, $page, true ); return \sanitize_url( URI\Utils::set_preferred_url_scheme( $url ), [ 'https', 'http' ], ); } /** * Returns home URL without query adjustments. * * @since 5.0.0 * * @return string The home URL. */ public static function get_bare_front_page_url() { return umemo( __METHOD__ ) ?? umemo( __METHOD__, \sanitize_url( URI\Utils::slash_front_page_url( URI\Utils::set_preferred_url_scheme( Data\Blog::get_front_page_url(), ) ), [ 'https', 'http' ], ), ); } /** * Returns singular canonical URL. * * @since 5.0.0 * * @param int|null $post_id The page ID. Leave null to autodetermine. * @return string The singular URL. */ public static function get_singular_url( $post_id = null ) { if ( isset( $post_id ) ) return self::get_bare_singular_url( $post_id ); $url = \get_permalink( Query::get_the_real_id() ); if ( empty( $url ) ) return ''; if ( Query::is_singular_archive() ) { // Singular archives, like blog pages and shop pages, use the pagination base with 'paged'. $paged = Query::paged(); if ( $paged > 1 ) $url = URI\Utils::add_pagination_to_url( $url, $paged, true ); } else { $page = Query::page(); if ( $page > 1 ) $url = URI\Utils::add_pagination_to_url( $url, $page, false ); } return \sanitize_url( URI\Utils::set_preferred_url_scheme( $url ), [ 'https', 'http' ], ); } /** * Returns singular permalink without query adjustments. * * @since 5.0.0 * * @param int|null $post_id The post ID to get the URL from. Leave null to autodetermine. * @return string The singular canonical URL without complex optimizations. */ public static function get_bare_singular_url( $post_id = null ) { $url = \get_permalink( $post_id ); if ( empty( $url ) ) return ''; return \sanitize_url( URI\Utils::set_preferred_url_scheme( $url ), [ 'https', 'http' ], ); } /** * Returns taxonomical canonical URL. * Automatically adds pagination if the ID matches the query. * * @since 5.0.0 * * @param int|null $term_id The term ID. Leave null to autodetermine. * @param string $taxonomy The taxonomy. Leave empty to autodetermine. * @return string The taxonomical canonical URL, if any. */ public static function get_term_url( $term_id = null, $taxonomy = '' ) { if ( isset( $term_id ) ) return self::get_bare_term_url( $term_id, $taxonomy ); $url = \get_term_link( Query::get_the_real_id(), $taxonomy ); if ( empty( $url ) || ! \is_string( $url ) ) return ''; return \sanitize_url( URI\Utils::set_preferred_url_scheme( URI\Utils::add_pagination_to_url( $url, Query::paged(), true, ) ), [ 'https', 'http' ], ); } /** * Returns taxonomical permalink without query adjustments. * * @since 5.0.0 * * @param int|null $term_id The term ID. * @param string $taxonomy The taxonomy. Leave empty to autodetermine. * @return string The taxonomical canonical URL, if any. */ public static function get_bare_term_url( $term_id = null, $taxonomy = '' ) { if ( empty( $term_id ) ) { $term_id = Query::get_the_real_id(); $taxonomy = Query::get_current_taxonomy(); } $url = \get_term_link( $term_id, $taxonomy ); // get_term_link() can return WP_Error. if ( empty( $url ) || ! \is_string( $url ) ) return ''; return \sanitize_url( URI\Utils::set_preferred_url_scheme( $url ), [ 'https', 'http' ], ); } /** * Returns post type archive canonical URL. * * @since 5.0.0 * * @param ?string $post_type The post type archive's post type. * Leave null to autodetermine query and allow pagination. * @return string The post type archive canonical URL, if any. */ public static function get_pta_url( $post_type = null ) { if ( isset( $post_type ) ) return self::get_bare_pta_url( $post_type ); $url = \get_post_type_archive_link( $post_type ?? Query::get_current_post_type() ); if ( empty( $url ) ) return ''; return \sanitize_url( URI\Utils::set_preferred_url_scheme( URI\Utils::add_pagination_to_url( $url, Query::paged(), true, ) ), [ 'https', 'http' ], ); } /** * Returns post type archive canonical URL without query adjustments. * * @since 5.0.0 * * @param null|string $post_type The post type archive's post type. * Leave null to autodetermine query and allow pagination. * @return string The post type archive canonical URL, if any. */ public static function get_bare_pta_url( $post_type = null ) { $url = \get_post_type_archive_link( $post_type ?? Query::get_current_post_type() ); if ( empty( $url ) ) return ''; return \sanitize_url( URI\Utils::set_preferred_url_scheme( $url ), [ 'https', 'http' ], ); } /** * Returns author canonical URL. * * @since 5.0.0 * * @param ?int $id The author ID. Leave null to autodetermine. * @return string The author canonical URL, if any. */ public static function get_author_url( $id = null ) { if ( isset( $id ) ) return self::get_bare_author_url( $id ); $url = \get_author_posts_url( Query::get_the_real_id() ); if ( empty( $url ) ) return ''; return \sanitize_url( URI\Utils::set_preferred_url_scheme( URI\Utils::add_pagination_to_url( $url, Query::paged(), true, ) ), [ 'https', 'http' ], ); } /** * Returns author canonical URL without query adjustments. * * @since 5.0.0 * * @param int|null $id The author ID. Leave null to autodetermine. * @return string The author canonical URL, if any. */ public static function get_bare_author_url( $id = null ) { $url = \get_author_posts_url( $id ?? Query::get_the_real_id() ); if ( empty( $url ) ) return ''; return \sanitize_url( URI\Utils::set_preferred_url_scheme( $url ), [ 'https', 'http' ], ); } /** * Returns date canonical URL. * Automatically adds pagination if the date input matches the query. * * @since 3.0.0 * * @param ?int $year The year. Leave null to autodetermine entire query. * @param ?int $month The month. If set, year must also be set. * @param ?int $day The day. If set, month and year must also be set. * @return string The date canonical URL, if any. */ public static function get_date_url( $year = null, $month = null, $day = null ) { if ( isset( $year ) ) return self::get_bare_date_url( $year, $month, $day ); $year = \get_query_var( 'year' ); $month = \get_query_var( 'monthnum' ); $day = \get_query_var( 'day' ); if ( $day ) { $url = \get_day_link( $year, $month, $day ); } elseif ( $month ) { $url = \get_month_link( $year, $month ); } else { $url = \get_year_link( $year ); } if ( empty( $url ) ) return ''; return \sanitize_url( URI\Utils::set_preferred_url_scheme( URI\Utils::add_pagination_to_url( $url, Query::paged(), true, ) ), [ 'https', 'http' ], ); } /** * Returns date canonical URL without query adjustments. * * @since 5.0.0 * * @param int $year The year. * @param ?int $month The month. * @param ?int $day The day. * @return string The date canonical URL, if any. */ public static function get_bare_date_url( $year, $month = null, $day = null ) { if ( $day ) { $url = \get_day_link( $year, $month, $day ); } elseif ( $month ) { $url = \get_month_link( $year, $month ); } else { $url = \get_year_link( $year ); } if ( empty( $url ) ) return ''; return \sanitize_url( URI\Utils::set_preferred_url_scheme( $url ), [ 'https', 'http' ], ); } /** * Returns search canonical URL. * Automatically adds pagination if the input matches the query. * * @since 5.0.0 * * @param string $search_query The search query. Mustn't be escaped. * When left empty, the current query will be used. * @return string The search canonical URL. */ public static function get_search_url( $search_query = null ) { if ( isset( $search_query ) ) return self::get_bare_search_url( $search_query ); $url = \get_search_link(); if ( empty( $url ) ) return ''; return \sanitize_url( URI\Utils::set_preferred_url_scheme( URI\Utils::add_pagination_to_url( $url, Query::paged(), true, ) ), [ 'https', 'http' ], ); } /** * Returns search canonical URL without query adjustments. * * @since 5.0.0 * * @param string $search_query The search query. Mustn't be escaped. * @return string The date canonical URL, if any. */ public static function get_bare_search_url( $search_query ) { $url = \get_search_link( $search_query ); if ( empty( $url ) ) return ''; return \sanitize_url( URI\Utils::set_preferred_url_scheme( $url ), [ 'https', 'http' ], ); } /** * Gets Previous and Next links. * * @since 3.1.0 * @since 3.2.4 1. Now correctly removes the pagination base from singular URLs. * 2. Now returns no URLs when a custom canonical URL is set. * @since 4.1.0 Removed memoization. * @since 4.1.2 1. Added back memoization. * 2. Reduced needless canonical URL generation when it wouldn't be processed anyway. * @since 5.0.0 1. Removed memoization thanks to optimization. * 2. Moved from `\The_SEO_Framework\Load`. * 3. Removed option checks (unintentionally) * @since 5.0.5 Reinstated missing option checks. * @todo make this a getter via $args. * * @return array { * Paginated URLs for the current request. May be empty if settings do not permit generation. * * @type string $prev The previous URL. May be empty if no previous URL is available. * @type string $next The next URL. May be empty if no next URL is available. * } */ public static function get_paged_urls() { if ( Query::is_real_front_page() ) { $get = Data\Plugin::get_option( 'prev_next_frontpage' ); } elseif ( Query::is_singular() || Query::is_singular_archive() ) { $get = Data\Plugin::get_option( 'prev_next_posts' ); } elseif ( Query::is_archive() ) { $get = Data\Plugin::get_option( 'prev_next_archives' ); } else { $get = false; } return $get ? self::get_generated_paged_urls() : [ '', '' ]; } /** * Generates Previous and Next links. * * @since 5.0.5 * * @return array { * Paginated URLs for the current request. * * @type string $prev The previous URL. May be empty if no previous URL is available. * @type string $next The next URL. May be empty if no next URL is available. * } */ public static function get_generated_paged_urls() { $page = max( Query::paged(), Query::page() ); $numpages = Query::numpages(); // If this page is not the last, create a next-URL. if ( ( $page + 1 ) <= $numpages ) { $url = URI\Utils::remove_pagination_from_url( self::get_generated_url() ); if ( $url ) $next = \sanitize_url( URI\Utils::add_pagination_to_url( $url, $page + 1 ), [ 'https', 'http' ], ); } // If this page is not the first, create a prev-URL. if ( $page > 1 ) { $url ??= URI\Utils::remove_pagination_from_url( self::get_generated_url() ); if ( $url ) $prev = \sanitize_url( URI\Utils::add_pagination_to_url( $url, $page - 1 ), [ 'https', 'http' ], ); } return [ $prev ?? '', $next ?? '', ]; } /** * Returns the redirect URL, if any. * * @since 4.1.4 * @since 4.2.0 1. Now supports the `$args['pta']` index. * 2. Now redirects post type archives. * @since 5.0.0 1. Now expects an ID before getting a post meta item. * 2. Moved from `\The_SEO_Framework\Load`. * * @param array|null $args The query arguments. Accepts 'id', 'tax', 'pta', and 'uid'. * Leave null to autodetermine query. * @return string The canonical URL if found, empty string otherwise. */ public static function get_redirect_url( $args = null ) { if ( isset( $args ) ) { normalize_generation_args( $args ); switch ( get_query_type_from_args( $args ) ) { case 'single': if ( Query::is_static_front_page( $args['id'] ) ) { $url = Data\Plugin::get_option( 'homepage_redirect' ) ?: Data\Plugin\Post::get_meta_item( 'redirect', $args['id'] ); } else { $url = Data\Plugin\Post::get_meta_item( 'redirect', $args['id'] ); } break; case 'term': $url = Data\Plugin\Term::get_meta_item( 'redirect', $args['id'] ); break; case 'homeblog': $url = Data\Plugin::get_option( 'homepage_redirect' ); break; case 'pta': $url = Data\Plugin\PTA::get_meta_item( 'redirect', $args['pta'] ); } } else { if ( Query::is_real_front_page() ) { if ( Query::is_static_front_page() ) { $url = Data\Plugin::get_option( 'homepage_redirect' ) ?: Data\Plugin\Post::get_meta_item( 'redirect' ); } else { $url = Data\Plugin::get_option( 'homepage_redirect' ); } } elseif ( Query::is_singular() ) { $url = Data\Plugin\Post::get_meta_item( 'redirect' ); } elseif ( Query::is_editable_term() ) { $url = Data\Plugin\Term::get_meta_item( 'redirect' ); } elseif ( \is_post_type_archive() ) { $url = Data\Plugin\PTA::get_meta_item( 'redirect' ); } } if ( empty( $url ) ) return ''; return \sanitize_url( $url, [ 'https', 'http' ] ); } /** * Generates shortlink URL. * * @since 5.0.0 * @todo make this a getter via $args. * * @return string The shortlink URL. */ public static function get_shortlink_url() { if ( ! Data\Plugin::get_option( 'shortlink_tag' ) || Query::is_real_front_page() ) return ''; return self::get_generated_shortlink_url(); } /** * Generates shortlink URL. * * @since 5.0.0 * @todo Append queries of other plugins for other pages as well? * * @return string The shortlink URL. */ public static function get_generated_shortlink_url() { if ( Query::is_singular() ) { $query = [ 'p' => Query::get_the_real_id() ]; } elseif ( Query::is_archive() ) { if ( Query::is_category() ) { $query = [ 'cat' => Query::get_the_real_id() ]; } elseif ( Query::is_tag() ) { $slug = \get_queried_object()->slug ?? ''; if ( $slug ) $query = [ 'tag' => $slug ]; } elseif ( Query::is_tag() || Query::is_tax() ) { // Generate shortlink for object type and slug. $object = \get_queried_object(); $tax = $object->taxonomy ?? ''; $slug = $object->slug ?? ''; if ( $tax && $slug ) $query = [ $tax => $slug ]; } elseif ( \is_date() && isset( $GLOBALS['wp_query']->query ) ) { // FIXME: Make Trac ticket: WP doesn't accept paged parameters w/ date parameters. It'll lead to the homepage. $_query = $GLOBALS['wp_query']->query; $_date = [ 'y' => $_query['year'] ?? '', 'm' => $_query['monthnum'] ?? '', 'd' => $_query['day'] ?? '', ]; $query = [ 'm' => implode( '', $_date ) ]; } elseif ( Query::is_author() ) { $query = [ 'author' => Query::get_the_real_id() ]; } } elseif ( Query::is_search() ) { $query = [ 's' => \get_search_query( false ) ]; } if ( empty( $query ) ) return ''; $page = Query::page(); $paged = Query::paged(); if ( $page > 1 ) { $query += [ 'page' => $page ]; } elseif ( $paged > 1 ) { $query += [ 'paged' => $paged ]; } $query = http_build_query( $query ); $extra_query = parse_url( self::get_generated_url( null ), \PHP_URL_QUERY ); if ( $extra_query ) $query .= "&$extra_query"; return \sanitize_url( URI\Utils::append_query_to_url( self::get_bare_front_page_url(), $query, ), [ 'https', 'http' ], ); } }