Completed
Push — renovate/wp-coding-standards-w... ( 227465...8587d4 )
by
unknown
35:46 queued 27:50
created

WordAds_California_Privacy::enqueue_scripts()   A

Complexity

Conditions 2
Paths 1

Size

Total Lines 27

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
nc 1
nop 0
dl 0
loc 27
rs 9.488
c 0
b 0
f 0
1
<?php
2
3
use Automattic\Jetpack\Assets;
4
5
/**
6
 * Class WordAds_California_Privacy
7
 *
8
 * Implementation of [California Consumer Privacy Act] (https://leginfo.legislature.ca.gov/faces/codes_displayText.xhtml?lawCode=CIV&division=3.&title=1.81.5.&part=4.&chapter=&article=) as applicable to WordAds.
9
 * Includes:
10
 * - Do Not Sell My Personal Information shortcode and widget.
11
 * - Modal notice to toggle opt-in/opt-out.
12
 * - Cookie handling. Implements IAB usprivacy cookie specifications.
13
 * - Client side geo-detection of California visitors by IP address. Avoids issues with page caching.
14
 */
15
class WordAds_California_Privacy {
16
17
	/**
18
	 * Initializes required scripts and shortcode.
19
	 */
20
	public static function init() {
21
		// Initialize shortcode.
22
		add_shortcode( 'ccpa-do-not-sell-link', array( __CLASS__, 'do_not_sell_link_shortcode' ) );
23
	}
24
25
	/**
26
	 * Enqueue required CCPA JavaScript on the frontend.
27
	 */
28
	public static function enqueue_scripts() {
29
		wp_enqueue_script(
30
			'wordads_ccpa',
31
			Assets::get_file_url_for_environment(
32
				'_inc/build/wordads/js/wordads-ccpa.min.js',
33
				'modules/wordads/js/wordads-ccpa.js'
34
			),
35
			array(),
36
			JETPACK__VERSION,
37
			true
38
		);
39
40
		wp_localize_script(
41
			'wordads_ccpa',
42
			'ccpaSettings',
43
			array(
44
				'defaultOptinCookieString' => esc_html( self::get_optin_cookie_string() ),
45
				'ccpaCssUrl'               => esc_url( Assets::get_file_url_for_environment( '/css/wordads-ccpa.min.css', '/css/wordads-ccpa.css' ) . '?ver=' . JETPACK__VERSION ),
46
				'ajaxUrl'                  => esc_url( admin_url( 'admin-ajax.php' ) ),
47
				'ajaxNonce'                => wp_create_nonce( 'ccpa_optout' ),
48
				'forceApplies'             => wp_json_encode( is_user_logged_in() && current_user_can( 'manage_options' ) ),
49
				'strings'                  => array(
50
					'pleaseWait' => esc_html__( 'Please Wait', 'jetpack' ),
51
				),
52
			)
53
		);
54
	}
55
56
	/**
57
	 * Initializes handlers for admin AJAX.
58
	 */
59
	public static function init_ajax_actions() {
60
		add_action( 'wp_ajax_privacy_optout', array( __CLASS__, 'handle_optout_request' ) );
61
		add_action( 'wp_ajax_nopriv_privacy_optout', array( __CLASS__, 'handle_optout_request' ) );
62
63
		add_action( 'wp_ajax_privacy_optout_markup', array( __CLASS__, 'handle_optout_markup' ) );
64
		add_action( 'wp_ajax_nopriv_privacy_optout_markup', array( __CLASS__, 'handle_optout_markup' ) );
65
	}
66
67
	/**
68
	 * Outputs [ccpa-do-not-sell-link] shortcode markup.
69
	 *
70
	 * @param array  $attributes The shortcode attributes.
71
	 * @param string $content The shortcode content.
72
	 *
73
	 * @return string The generated shortcode markup.
74
	 */
75
	public static function do_not_sell_link_shortcode( $attributes, $content ) {
76
77
		// If in the customizer always display the link.
78
		if ( is_customize_preview() ) {
79
			return '<a href="#" class="ccpa-do-not-sell">' . self::get_optout_link_text() . '</a>';
80
		}
81
82
		// Load required scripts if the shortcode/widget is loaded on the page.
83
		self::enqueue_scripts();
84
85
		return '<a href="#" class="ccpa-do-not-sell" style="display: none;">' . self::get_optout_link_text() . '</a>';
86
	}
87
88
89
	/**
90
	 * Gets the text used to link to the opt-out page. By law must read 'Do Not Sell My Personal Information'.
91
	 *
92
	 * @return mixed|string|void The text of the opt-out link.
93
	 */
94
	private static function get_optout_link_text() {
95
		return __( 'Do Not Sell My Personal Information', 'jetpack' );
96
	}
97
98
	/**
99
	 * Builds the value of the opt-out cookie.
100
	 * Format matches spec of [IAB U.S. Privacy String](https://github.com/InteractiveAdvertisingBureau/USPrivacy/blob/master/CCPA/US%20Privacy%20String.md).
101
	 *
102
	 * @param bool $optout True if setting an opt-out cookie.
103
	 *
104
	 * @return string The value to be stored in the opt-out cookie.
105
	 */
106
	private static function build_iab_privacy_string( $optout ) {
107
		$values = array(
108
			'1', // Specification version.
109
			'Y', // Explicit notice to opt-out provided.
110
			$optout ? 'Y' : 'N', // Opt-out of data sale.
111
			'N', // Signatory to IAB Limited Service Provider Agreement.
112
		);
113
114
		return join( $values );
115
	}
116
117
	/**
118
	 * Gets the name to be used for the opt-out cookie.
119
	 * Name matches spec of [IAB U.S. Privacy String](https://github.com/InteractiveAdvertisingBureau/USPrivacy/blob/master/CCPA/US%20Privacy%20String.md).
120
	 *
121
	 * @return string The name of the opt-out cookie.
122
	 */
123
	private static function get_cookie_name() {
124
		return 'usprivacy';
125
	}
126
127
	/**
128
	 * Gets the domain to be used for the opt-out cookie.
129
	 * Use the site's custom domain, or if the site has a wordpress.com subdomain, use .wordpress.com to share the cookie.
130
	 *
131
	 * @return string The domain to set for the opt-out cookie.
132
	 */
133
	public static function get_cookie_domain() {
134
		$host = 'localhost';
135
136
		if ( isset( $_SERVER['HTTP_HOST'] ) ) {
137
			$host = $_SERVER['HTTP_HOST'];
138
		}
139
140
		return '.wordpress.com' === substr( $host, -strlen( '.wordpress.com' ) ) ? '.wordpress.com' : '.' . $host;
141
	}
142
143
	/**
144
	 * Gets the value to be used when an opt-out cookie is set.
145
	 *
146
	 * @return string The value to store in the opt-out cookie.
147
	 */
148
	private static function get_optout_cookie_string() {
149
		return self::build_iab_privacy_string( true );
150
	}
151
152
	/**
153
	 * Gets the value to be used when an opt-in cookie is set.
154
	 *
155
	 * @return string The value to store in the opt-in cookie.
156
	 */
157
	private static function get_optin_cookie_string() {
158
		return self::build_iab_privacy_string( false );
159
	}
160
161
	/**
162
	 * Sets a cookie in the HTTP response to opt-out visitors from data sales.
163
	 *
164
	 * @return bool True if the cookie could be set.
165
	 */
166
	private static function set_optout_cookie() {
167
		return setcookie( self::get_cookie_name(), self::get_optout_cookie_string(), time() + ( 5 * YEAR_IN_SECONDS ), '/', self::get_cookie_domain() );
168
	}
169
170
	/**
171
	 * Sets a cookie in the HTTP response to opt-in visitors from data sales.
172
	 *
173
	 * @return bool True if the cookie could be set.
174
	 */
175
	private static function set_optin_cookie() {
176
		return setcookie( self::get_cookie_name(), self::get_optin_cookie_string(), time() + YEAR_IN_SECONDS, '/', self::get_cookie_domain() );
177
	}
178
179
	/**
180
	 * Handler for opt-in/opt-out AJAX request.
181
	 */
182
	public static function handle_optout_request() {
183
		check_ajax_referer( 'ccpa_optout', 'security' );
184
185
		$optout = 'true' === $_POST['optout'];
186
		$optout ? self::set_optout_cookie() : self::set_optin_cookie();
187
188
		wp_send_json_success( $optout );
189
	}
190
191
	/**
192
	 * Handler for modal popup notice markup.
193
	 */
194
	public static function handle_optout_markup() {
195
		check_ajax_referer( 'ccpa_optout', 'security' );
196
197
		header( 'Content-Type: text/html; charset=utf-8' );
198
		$policy_url = get_option( 'wordads_ccpa_privacy_policy_url' );
199
200
		$default_disclosure = sprintf(
201
			'<p>%s</p>
202
			<p>%s</p>
203
			<p><strong>%s</strong></p>
204
			<p>%s</p>
205
			<p>%s</p>
206
			<p>%s</p>',
207
			esc_html__( 'If you are a California resident, you have the right to opt out of the "sale" of your "personal information" under the California Consumer Privacy Act ("CCPA")', 'jetpack' ),
208
			esc_html__( 'This site operates an ads program in partnership with third-party vendors who help place ads. Advertising cookies enable these ads partners to serve ads, to personalize those ads based on information like visits to this site and other sites on the internet, and to understand how users engage with those ads. Cookies collect certain information as part of the ads program, and we provide the following categories of information to third-party advertising partners: online identifiers and internet or other network or device activity (such as unique identifiers, cookie information, and IP address), and geolocation data (approximate location information from your IP address). This type of sharing with ads partners may be considered a "sale" of personal information under the CCPA.', 'jetpack' ),
209
			esc_html__( 'We never share information that identifies you personally, like your name or email address, as part of the advertising program.', 'jetpack' ),
210
			esc_html__( 'If you\'d prefer not to see ads that are personalized based on information from your visits to this site, you can opt-out by toggling the "Do Not Sell My Personal Information" switch below to the On position.', 'jetpack' ),
211
			esc_html__( 'This opt-out is managed through cookies, so if you delete cookies, your browser is set to delete cookies automatically after a certain length of time, or if you visit this site with a different browser, you\'ll need to make this selection again.', 'jetpack' ),
212
			esc_html__( 'After you opt-out you may still see ads, including personalized ones, on this site and other sites - they just won\'t be personalized based on information from your visits to this site.', 'jetpack' )
213
		);
214
215
		/**
216
		 * Filter on the default CCPA disclosure text.
217
		 *
218
		 * @see https://jetpack.com/support/ads/
219
		 *
220
		 * @module wordads
221
		 *
222
		 * @since 8.7.0
223
		 *
224
		 * @param string Default CCPA disclosure for WordAds.
225
		 */
226
		$disclosure = apply_filters( 'wordads_ccpa_disclosure', $default_disclosure );
227
		?>
228
			<div id="ccpa-modal" class="cleanslate">
229
				<div class="components-modal__screen-overlay">
230
					<div tabindex="0"></div>
231
					<div role="dialog" aria-labelledby="dialog_label" aria-modal="true" class="components-modal__frame">
232
						<div class="components-modal__content ccpa-settings">
233
							<div class="components-modal__header">
234
								<div class="components-modal__header-heading-container">
235
									<h1 id="dialog_label" class="components-modal__header-heading"><?php esc_html_e( 'Do Not Sell My Personal Information', 'jetpack' ); ?></h1>
236
								</div>
237
								<button type="button" aria-label="<?php esc_html_e( 'Close dialog', 'jetpack' ); ?>" class="components-button components-icon-button">
238
									<svg aria-hidden="true" role="img" focusable="false" class="dashicon dashicons-no-alt" xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20">
239
										<path d="M14.95 6.46L11.41 10l3.54 3.54-1.41 1.41L10 11.42l-3.53 3.53-1.42-1.42L8.58 10 5.05 6.47l1.42-1.42L10 8.58l3.54-3.53z"></path>
240
									</svg>
241
								</button>
242
							</div>
243
							<div class="ccpa-settings__intro-txt"><?php echo wp_kses( $disclosure, wp_kses_allowed_html( 'post' ) ); ?></div>
244
							<div class="components-modal__footer">
245
								<div role="form" class="ccpa-setting">
246
									<label>
247
										<span class="ccpa-setting__header"><?php esc_html_e( 'Do Not Sell My Personal Information', 'jetpack' ); ?></span>
248
										<span class="ccpa-setting__toggle components-form-toggle">
249
											<input id="ccpa-opt-out" class="components-form-toggle__input opt-out" type="checkbox" value="false" autofocus />
250
											<span class="components-form-toggle__track"></span>
251
											<span class="components-form-toggle__thumb"></span>
252
											<svg class="components-form-toggle__on" width="2" height="6" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 2 6" role="img" aria-hidden="true" focusable="false"><path d="M0 0h2v6H0z"></path></svg>
253
											<svg class="components-form-toggle__off" width="6" height="6" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 6 6" role="img" aria-hidden="true" focusable="false"><path d="M3 1.5c.8 0 1.5.7 1.5 1.5S3.8 4.5 3 4.5 1.5 3.8 1.5 3 2.2 1.5 3 1.5M3 0C1.3 0 0 1.3 0 3s1.3 3 3 3 3-1.3 3-3-1.3-3-3-3z"></path></svg>
254
										</span>
255
										<span class="ccpa-setting__toggle-text ccpa-setting__toggle-text-off"><?php esc_html_e( 'Off', 'jetpack' ); ?></span>
256
										<span class="ccpa-setting__toggle-text ccpa-setting__toggle-text-on"><?php esc_html_e( 'On', 'jetpack' ); ?></span>
257
									</label>
258
								</div>
259
								<div class="components-modal__footer-bottom">
260
									<button class="components-button is-button is-primary"><?php esc_html_e( 'Close', 'jetpack' ); ?></button>
261
									<?php
262
									if ( $policy_url ) {
263
										printf(
264
											'<a href="%s" class="ccpa-privacy">%s</a>',
265
											esc_url( $policy_url ),
266
											esc_html__( 'View Privacy Policy', 'jetpack' )
267
										);
268
									}
269
									?>
270
								</div>
271
							</div>
272
						</div>
273
					</div>
274
				</div>
275
			</div>
276
		<?php
277
278
		wp_die();
279
	}
280
}
281