Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 39
0.00% covered (danger)
0.00%
0 / 6
CRAP
0.00% covered (danger)
0.00%
0 / 1
WordAds_Consent_Management_Provider
0.00% covered (danger)
0.00%
0 / 37
0.00% covered (danger)
0.00%
0 / 6
90
0.00% covered (danger)
0.00%
0 / 1
 init
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
2
 init_ajax_actions
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 handle_set_consent_request
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
6
 enqueue_frontend_scripts
0.00% covered (danger)
0.00%
0 / 18
0.00% covered (danger)
0.00%
0 / 1
2
 get_config_url
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
2
 get_cookie_domain
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
12
1<?php
2/**
3 * WordAds Consent Management Provider
4 *
5 * @package automattic/jetpack
6 */
7
8use Automattic\Jetpack\Assets;
9
10if ( ! defined( 'ABSPATH' ) ) {
11    exit( 0 );
12}
13
14/**
15 * Class WordAds_Consent_Management_Provider
16 *
17 * This is an integration with the GDPR Consent Management Provider
18 * to comply with GDPR requirements for privacy and transparency related to advertising.
19 */
20class WordAds_Consent_Management_Provider {
21
22    /**
23     * IAB specified cookie name for storing the consent string.
24     */
25    const COOKIE_NAME = 'euconsent-v2';
26
27    /**
28     * Initializes loading of the frontend framework.
29     */
30    public static function init() {
31        // Prevent Cookies & Consent banner from displaying when the CMP is active.
32        add_filter( 'jetpack_disable_eu_cookie_law_widget', '__return_true' );
33        add_filter( 'jetpack_disable_cookie_consent_block', '__return_true' );
34
35        // Enqueue scripts.
36        add_action( 'wp_enqueue_scripts', array( __CLASS__, 'enqueue_frontend_scripts' ) );
37    }
38
39    /**
40     * AJAX handlers for fetching purposes and vendor data and setting the cookie serverside.
41     *
42     * Serverside cookie used so that the expiration can be longer than one week.
43     * This function is called from: /mu-plugins/wordads-ajax.php to ensure they run on all
44     * requests including admin requests.
45     */
46    public static function init_ajax_actions() {
47        add_action( 'wp_ajax_gdpr_set_consent', array( __CLASS__, 'handle_set_consent_request' ) );
48        add_action( 'wp_ajax_nopriv_gdpr_set_consent', array( __CLASS__, 'handle_set_consent_request' ) );
49    }
50
51    /**
52     * Handler for setting consent cookie AJAX request.
53     */
54    public static function handle_set_consent_request() {
55
56        // phpcs:disable WordPress.Security.NonceVerification.Missing
57        if ( ! isset( $_POST['consent'] ) ) {
58            // @phan-suppress-next-line PhanTypeMismatchArgumentProbablyReal -- It takes null, but its phpdoc only says int.
59            wp_send_json_error( null, null, JSON_UNESCAPED_SLASHES );
60        }
61
62        // TODO: Is there better sanitizing we can do here?
63        $consent = trim( wp_unslash( $_POST['consent'] ) ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
64
65        setcookie( self::COOKIE_NAME, $consent, time() + YEAR_IN_SECONDS, '/', self::get_cookie_domain(), is_ssl(), false ); // phpcs:ignore Jetpack.Functions.SetCookie -- Client side CMP needs to be able to read this value.
66
67        // @phan-suppress-next-line PhanTypeMismatchArgumentProbablyReal -- It takes null, but its phpdoc only says int.
68        wp_send_json_success( true, null, JSON_UNESCAPED_SLASHES );
69
70        // phpcs:enable WordPress.Security.NonceVerification.Missing
71    }
72
73    /**
74     * Enqueues the main frontend Javascript.
75     */
76    public static function enqueue_frontend_scripts() {
77        Assets::register_script(
78            'cmp_script_loader',
79            '_inc/build/wordads/js/cmp-loader.min.js',
80            JETPACK__PLUGIN_FILE,
81            array(
82                'nonmin_path'  => 'modules/wordads/js/cmp-loader.js',
83                'dependencies' => array(),
84                'enqueue'      => true,
85                'version'      => JETPACK__VERSION,
86            )
87        );
88
89        wp_enqueue_script(
90            'cmp_config_script',
91            esc_url( self::get_config_url() ),
92            array( 'cmp_script_loader' ),
93            JETPACK__VERSION,
94            false
95        );
96    }
97
98    /**
99     * Gets the value to be used when an opt-in cookie is set.
100     *
101     * @return string The value to store in the opt-in cookie.
102     */
103    private static function get_config_url() {
104        return sprintf(
105            'https://public-api.wordpress.com/wpcom/v2/sites/%1$d/cmp/configuration/%2$s/?_jsonp=a8c_cmp_callback',
106            (int) Jetpack_Options::get_option( 'id' ),
107            strtolower( get_locale() ) // Defaults to en_US not en.
108        );
109    }
110
111    /**
112     * Gets the domain to be used for the opt-out cookie.
113     * Use the site's custom domain, or if the site has a wordpress.com subdomain, use .wordpress.com to share the cookie.
114     *
115     * @return string The domain to set for the opt-out cookie.
116     */
117    public static function get_cookie_domain() {
118        $host = 'localhost';
119
120        if ( isset( $_SERVER['HTTP_HOST'] ) ) {
121            $host = filter_var( wp_unslash( $_SERVER['HTTP_HOST'] ) );
122        }
123
124        return '.wordpress.com' === substr( $host, -strlen( '.wordpress.com' ) ) ? '.wordpress.com' : '.' . $host;
125    }
126}