Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
62.50% covered (warning)
62.50%
20 / 32
83.33% covered (warning)
83.33%
5 / 6
CRAP
n/a
0 / 0
wpcomsh_is_staging_site_get_atomic_persistent_data
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
6
wpcomsh_disable_outgoing_pings_in_non_production_envs
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
2
wpcomsh_disable_incoming_pings_in_non_production_envs
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
wpcomsh_force_pingback_flag_off_on_staging
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
wpcomsh_force_ping_status_closed_on_staging
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
wpcomsh_disable_pingback_ui_on_staging
100.00% covered (success)
100.00%
9 / 9
100.00% covered (success)
100.00%
1 / 1
4
1<?php
2/**
3 * Customizations for the staging sites.
4 *
5 * @package wpcomsh
6 */
7
8/**
9 * Returns Atomic persistent data value for wpcom_is_staging_site.
10 *
11 * @param string $wpcom_is_staging_site Value for the preview links option.
12 *
13 * @return string The value of WPCOM_IS_STAGING_SITE if set, otherwise the option value.
14 */
15function wpcomsh_is_staging_site_get_atomic_persistent_data( $wpcom_is_staging_site ) {
16    $persistent_data                       = new Atomic_Persistent_Data();
17    $persistent_data_is_staging_site_value = $persistent_data->WPCOM_IS_STAGING_SITE; // phpcs:ignore WordPress.NamingConventions.ValidVariableName
18
19    if ( $persistent_data_is_staging_site_value !== null ) {
20        return json_decode( $persistent_data_is_staging_site_value );
21    }
22
23    return $wpcom_is_staging_site;
24}
25// need to hook to default_option_* too because if this option doesn't exist, the hook wouldn't run.
26add_filter( 'default_option_wpcom_is_staging_site', 'wpcomsh_is_staging_site_get_atomic_persistent_data' );
27add_filter( 'option_wpcom_is_staging_site', 'wpcomsh_is_staging_site_get_atomic_persistent_data' );
28
29/**
30 * Disables outgoing pingbacks/trackbacks in staging environments.
31 *
32 * Prevents the dispatch of pingbacks when the environment type is 'staging'
33 * by clearing the list of URLs to ping. The `pre_ping` action passes
34 * `$post_links` by reference, so emptying it prevents all outgoing pings.
35 *
36 * This can be removed once WordPress core addresses the issue.
37 *
38 * @see https://core.trac.wordpress.org/ticket/64837
39 *
40 * @param string[] $post_links Array of URLs to ping (passed by reference).
41 */
42function wpcomsh_disable_outgoing_pings_in_non_production_envs( &$post_links ) {
43    if ( 'staging' === wp_get_environment_type() ) {
44        $post_links = array();
45    }
46}
47add_action( 'pre_ping', 'wpcomsh_disable_outgoing_pings_in_non_production_envs' );
48
49/**
50 * Disables incoming pingbacks in staging environments by removing
51 * the 'pingback.ping' XML-RPC method.
52 *
53 * Prevents WordPress from processing incoming pingbacks when the environment
54 * type is 'staging'. This can be removed once WordPress core addresses the issue.
55 *
56 * @see https://core.trac.wordpress.org/ticket/64837
57 *
58 * @param array<string, callable> $methods Associative array of XML-RPC methods.
59 * @return array<string, callable> Modified associative array of XML-RPC methods.
60 */
61function wpcomsh_disable_incoming_pings_in_non_production_envs( $methods ) {
62    if ( 'staging' === wp_get_environment_type() ) {
63        unset( $methods['pingback.ping'] );
64    }
65
66    return $methods;
67}
68add_filter( 'xmlrpc_methods', 'wpcomsh_disable_incoming_pings_in_non_production_envs' );
69
70/**
71 * Forces the default_pingback_flag option to '0' on staging sites so the
72 * Discussion Settings UI reflects that outgoing pingbacks are disabled.
73 *
74 * @return string|false '0' on staging sites, false to allow normal behavior otherwise.
75 */
76function wpcomsh_force_pingback_flag_off_on_staging() {
77    if ( 'staging' === wp_get_environment_type() ) {
78        return '0';
79    }
80
81    return false;
82}
83add_filter( 'pre_option_default_pingback_flag', 'wpcomsh_force_pingback_flag_off_on_staging' );
84
85/**
86 * Forces the default_ping_status option to 'closed' on staging sites so the
87 * Discussion Settings UI reflects that incoming pingbacks are disabled.
88 *
89 * @return string|false 'closed' on staging sites, false to allow normal behavior otherwise.
90 */
91function wpcomsh_force_ping_status_closed_on_staging() {
92    if ( 'staging' === wp_get_environment_type() ) {
93        return 'closed';
94    }
95
96    return false;
97}
98add_filter( 'pre_option_default_ping_status', 'wpcomsh_force_ping_status_closed_on_staging' );
99
100/**
101 * Disables pingback checkboxes and adds an explanation on the Discussion
102 * Settings page for staging sites.
103 */
104function wpcomsh_disable_pingback_ui_on_staging() {
105    if ( 'staging' !== wp_get_environment_type() ) {
106        return;
107    }
108
109    $screen = get_current_screen();
110    if ( ! $screen || 'options-discussion' !== $screen->id ) {
111        return;
112    }
113
114    ?>
115    <script>
116    ( function() {
117        var ids = [ 'default_pingback_flag', 'default_ping_status' ];
118        var message = ' — ' + <?php echo wp_json_encode( __( 'Pingbacks are disabled on staging sites to prevent unintended outbound requests.', 'wpcomsh' ), JSON_UNESCAPED_SLASHES | JSON_HEX_TAG | JSON_HEX_AMP ); ?>;
119        ids.forEach( function( id ) {
120            var checkbox = document.getElementById( id );
121            if ( checkbox ) {
122                checkbox.disabled = true;
123                var note = document.createElement( 'em' );
124                note.textContent = message;
125                checkbox.parentNode.appendChild( note );
126            }
127        } );
128    } )();
129    </script>
130    <?php
131}
132add_action( 'admin_print_footer_scripts', 'wpcomsh_disable_pingback_ui_on_staging' );