Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
94.29% covered (success)
94.29%
33 / 35
33.33% covered (danger)
33.33%
1 / 3
CRAP
0.00% covered (danger)
0.00%
0 / 1
Expiry_Domain
94.12% covered (success)
94.12%
32 / 34
33.33% covered (danger)
33.33%
1 / 3
23.11
0.00% covered (danger)
0.00%
0 / 1
 get_revert_domain
91.67% covered (success)
91.67%
11 / 12
0.00% covered (danger)
0.00%
0 / 1
6.02
 simple_revert_domain
87.50% covered (warning)
87.50%
7 / 8
0.00% covered (danger)
0.00%
0 / 1
6.07
 pick_revert_domain
100.00% covered (success)
100.00%
14 / 14
100.00% covered (success)
100.00%
1 / 1
11
1<?php
2/**
3 * Expiry_Domain: the WordPress.com address a reverted site falls back to.
4 *
5 * @package automattic/jetpack-mu-wpcom
6 */
7
8declare( strict_types = 1 );
9
10namespace Automattic\Jetpack\Jetpack_Mu_Wpcom\Expiry_Notices;
11
12use Automattic\Jetpack\Constants;
13
14require_once __DIR__ . '/class-expiry-wpcom.php';
15
16/**
17 * Resolves the domain the expiry modal names, or null when it should say nothing.
18 */
19class Expiry_Domain {
20
21    const CACHE_KEY = 'wpcom_expiry_notices_revert_domain';
22
23    /**
24     * The WordPress.com address this site would fall back to, or null when the
25     * modal should leave the domain out.
26     *
27     * Null covers both a domain that survives the revert and a lookup that
28     * failed: naming the wrong one is worse than naming none.
29     */
30    public static function get_revert_domain(): ?string {
31        // A reverted site is back on Simple, where the blogs table already
32        // holds the unmapped address and no blog token could ask for it.
33        if ( Constants::is_true( 'IS_WPCOM' ) ) {
34            return self::simple_revert_domain();
35        }
36
37        // A resolved "nothing to say" is remembered as '' so the common case,
38        // a site keeping its custom domain, isn't re-asked every pageview.
39        $domain = Expiry_Wpcom::remember(
40            self::CACHE_KEY,
41            static function (): ?string {
42                $body = Expiry_Wpcom::get_as_blog( '/sites/%d/domains' );
43                if ( ! is_object( $body ) || ! isset( $body->domains ) || ! is_array( $body->domains ) ) {
44                    return null;
45                }
46                return self::pick_revert_domain( $body->domains ) ?? '';
47            }
48        );
49
50        return '' === $domain ? null : $domain;
51    }
52
53    /**
54     * The address a reverted Simple site is now on, or null if it kept its own.
55     *
56     * `wp_blogs.domain` is the unmapped address, so serving from it means the
57     * switch has happened; a custom domain means it never did.
58     */
59    private static function simple_revert_domain(): ?string {
60        if ( ! function_exists( 'get_blog_details' ) ) {
61            return null;
62        }
63
64        $details  = get_blog_details( get_current_blog_id() );
65        $unmapped = ( is_object( $details ) && ! empty( $details->domain ) ) ? (string) $details->domain : '';
66        if ( '' === $unmapped ) {
67            return null;
68        }
69
70        $serving = (string) wp_parse_url( home_url(), PHP_URL_HOST );
71        return $serving === $unmapped ? $unmapped : null;
72    }
73
74    /**
75     * The fallback address out of a site's domain list, or null when the
76     * primary domain survives the revert.
77     *
78     * @param array<int,object> $domains Domain objects from /sites/{id}/domains.
79     */
80    public static function pick_revert_domain( array $domains ): ?string {
81        $wpcom_domain              = null;
82        $primary                   = null;
83        $primary_is_wpcom_provided = false;
84
85        foreach ( $domains as $domain ) {
86            if ( empty( $domain->domain ) || ! is_string( $domain->domain ) ) {
87                continue;
88            }
89
90            // `*.wpcomstaging.com` is an Atomic hosting artifact whose mapping
91            // the revert deletes, so it is never what the site ends up called.
92            if ( ! empty( $domain->wpcom_domain ) && empty( $domain->is_wpcom_staging_domain ) ) {
93                $wpcom_domain = $domain->domain;
94            }
95
96            if ( ! empty( $domain->primary_domain ) ) {
97                $primary                   = $domain->domain;
98                $primary_is_wpcom_provided = ! empty( $domain->wpcom_domain ) || ! empty( $domain->is_wpcom_staging_domain );
99            }
100        }
101
102        if ( null === $wpcom_domain || null === $primary ) {
103            return null;
104        }
105
106        return $primary_is_wpcom_provided ? $wpcom_domain : null;
107    }
108}