Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
83.72% covered (warning)
83.72%
36 / 43
0.00% covered (danger)
0.00%
0 / 2
CRAP
0.00% covered (danger)
0.00%
0 / 1
Jetpack_Canonical_Urls_Resolver
83.72% covered (warning)
83.72%
36 / 43
0.00% covered (danger)
0.00%
0 / 2
28.92
0.00% covered (danger)
0.00%
0 / 1
 get_canonical_url
83.33% covered (warning)
83.33%
30 / 36
0.00% covered (danger)
0.00%
0 / 1
24.24
 apply_pagination
85.71% covered (warning)
85.71%
6 / 7
0.00% covered (danger)
0.00%
0 / 1
4.05
1<?php
2/**
3 * URL resolution logic for the Canonical URLs module.
4 *
5 * @package automattic/jetpack
6 */
7
8/**
9 * Resolves canonical URLs for different archive page types.
10 *
11 * URLs are built from scratch using WordPress API functions (get_permalink,
12 * get_term_link, etc.) rather than parsing the current request URL, so they
13 * are inherently clean — no sorting, filtering, or tracking parameters.
14 */
15class Jetpack_Canonical_Urls_Resolver {
16
17    /**
18     * Get the canonical URL for the current page.
19     *
20     * Routes to the correct URL based on the current query conditionals.
21     *
22     * @since 15.6
23     *
24     * @return string The canonical URL, or empty string if none should be output.
25     */
26    public static function get_canonical_url() {
27        $url = '';
28
29        if ( is_front_page() && is_home() ) {
30            // Default homepage (latest posts).
31            $url = home_url( '/' );
32        } elseif ( is_front_page() ) {
33            // Static front page.
34            $url = home_url( '/' );
35        } elseif ( is_home() ) {
36            // Blog page (when a static front page is set).
37            $blog_page_id = (int) get_option( 'page_for_posts' );
38            if ( $blog_page_id ) {
39                $url = get_permalink( $blog_page_id );
40            }
41        } elseif ( function_exists( 'is_shop' ) && is_shop() ) {
42            // WooCommerce shop page.
43            $shop_page_id = (int) get_option( 'woocommerce_shop_page_id' );
44            if ( $shop_page_id ) {
45                $url = get_permalink( $shop_page_id );
46            }
47        } elseif ( is_category() || is_tag() || is_tax() ) {
48            $term = get_queried_object();
49            if ( $term instanceof WP_Term ) {
50                $url = get_term_link( $term );
51                if ( is_wp_error( $url ) ) {
52                    $url = '';
53                }
54            }
55        } elseif ( is_post_type_archive() ) {
56            $url = get_post_type_archive_link( get_query_var( 'post_type' ) );
57            if ( false === $url ) {
58                $url = '';
59            }
60        } elseif ( is_author() ) {
61            $author_id = (int) get_query_var( 'author' );
62            if ( $author_id ) {
63                $url = get_author_posts_url( $author_id );
64            }
65        } elseif ( is_year() ) {
66            $url = get_year_link( get_query_var( 'year' ) );
67        } elseif ( is_month() ) {
68            $url = get_month_link( get_query_var( 'year' ), get_query_var( 'monthnum' ) );
69        } elseif ( is_day() ) {
70            $url = get_day_link( get_query_var( 'year' ), get_query_var( 'monthnum' ), get_query_var( 'day' ) );
71        }
72        // is_search() and is_404() intentionally return empty string (no canonical).
73
74        if ( ! empty( $url ) ) {
75            $url = self::apply_pagination( $url );
76        }
77
78        /**
79         * Filter the canonical URL before output.
80         *
81         * @module canonical-urls
82         *
83         * @since 15.6
84         *
85         * @param string $url The canonical URL for the current page.
86         */
87        return apply_filters( 'jetpack_canonical_url', $url );
88    }
89
90    /**
91     * Append pagination to the canonical URL for paged views.
92     *
93     * @since 15.6
94     *
95     * @param string $url The base canonical URL.
96     * @return string The URL with pagination appended if applicable.
97     */
98    private static function apply_pagination( $url ) {
99        $paged = get_query_var( 'paged', 0 );
100
101        if ( $paged < 2 ) {
102            return $url;
103        }
104
105        global $wp_rewrite;
106
107        if ( $wp_rewrite->using_permalinks() && false === strpos( $url, '?' ) ) {
108            $url = user_trailingslashit( trailingslashit( $url ) . $wp_rewrite->pagination_base . '/' . $paged );
109        } else {
110            $url = add_query_arg( 'paged', $paged, $url );
111        }
112
113        return $url;
114    }
115}