PluginProbe
GDPRess | Eliminate external requests to increase GDPR compliance / trunk
GDPRess | Eliminate external requests to increase GDPR compliance vtrunk
trunk 1.0.2 1.1.0 1.2.0 1.2.1 1.2.2 1.2.3 1.3.0 1.3.1
gdpr-press / src / Admin / Settings / Manage.php

Manage.php in GDPRess | Eliminate external requests to increase GDPR compliance trunk, at src/Admin/Settings/Manage.php

339 lines 14.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * @package GDPRess
4 * @author Daan van den Bergh
5 * https://daan.dev
6 */
7
8 namespace GDPRess\Admin\Settings;
9
10 use GDPRess\Admin\Settings;
11 use GDPRess\Helper;
12
13 class Manage extends Builder {
14
15 /** @var string $ga_notice */
16 private $ga_notice;
17
18 /** @var string $gf_notice */
19 private $gf_notice;
20
21 /** @var string $webfont_notice */
22 private $webfont_notice;
23
24 /** @var string $exclusion_notice */
25 private $exclusion_notice;
26
27 /** @var string $upsell_notice */
28 private $upsell_notice;
29
30 /** @var string $tooltip_markup */
31 private $tooltip_markup = '<i class="dashicons dashicons-info-outline tooltip"><span class="tooltip-text"><span class="inline-text">%s</span></span></i>';
32
33 /**
34 * Set fields.
35 *
36 * @return void
37 */
38 public function __construct() {
39 $this->init();
40 }
41
42 /**
43 * Filters & Hooks.
44 *
45 * @return void
46 */
47 private function init() {
48 add_action( 'init', [ $this, 'set_translations']);
49
50 // Content
51 add_filter( 'gdpress_manage_content', [ $this, 'manage_section' ], 2 );
52
53 add_filter( 'gdpress_manage_content', [ $this, 'before_settings_section' ], 3);
54 add_filter( 'gdpress_manage_content', [ $this, 'do_before' ], 5 );
55 add_filter( 'gdpress_manage_content', [ $this, 'test_mode' ], 7 );
56 add_filter( 'gdpress_manage_content', [ $this, 'do_after' ], 9 );
57 add_filter( 'gdpress_manage_content', [ $this, 'after_settings_section' ]);
58 }
59
60 public function after_settings_section() {
61 ?>
62 </div>
63 <?php
64 }
65
66 public function before_settings_section() {
67 ?>
68 <div class="gdpress-settings-container">
69 <?php
70 }
71
72 /**
73 * Add Manage section contents.
74 *
75 * @return void
76 */
77 public function manage_section() {
78 ?>
79 <div class="gdpress-manage-container">
80 <span class="option-title"><?php echo __( 'External Requests Manager', 'gdpr-press' ); ?></span>
81 <div class="gdpress-container">
82 <?php if ( Helper::requests() ) : ?>
83 <?php $this->manage_screen(); ?>
84 <?php else : ?>
85 <?php $this->start_screen(); ?>
86 <?php endif; ?>
87 </div>
88 </div>
89 <?php
90 }
91
92 private function manage_screen() {
93 $css_count = isset( Helper::requests()['css'] ) ? count( Helper::requests()['css'] ) : 0;
94 $js_count = isset( Helper::requests()['js'] ) ? count( Helper::requests()['js'] ) : 0;
95 ?>
96 <?php if ( empty( Helper::local() ) ) : ?>
97 <p>
98 <em><?php echo sprintf( __( 'Beep-boop! 🤖 GDPRess Bot has detected %1$s stylesheets and %2$s scripts loaded from 3rd parties. Download them to your server to increase GDPR compliance.', 'gdpr-press' ), (string) $css_count, (string) $js_count ); ?></em>
99 </p>
100 <?php else : ?>
101 <p>
102 <em><?php echo sprintf( __( 'Hurray! 🎉 GDPRess Bot has downloaded %1$s stylesheets and %2$s scripts. Kickback, relax, enjoy your (increased) GDPR compliance and <a href="%3$s" target="_blank">maybe oil my circuits with a 5 ⭐ rating</a>?', 'gdpr-press' ), count( Helper::local()['css'] ?? [] ), count( Helper::local()['js'] ?? [] ), 'https://wordpress.org/support/plugin/gdpr-press/reviews/?rate=5#new-post' ); ?></em> <?php echo sprintf( $this->tooltip_markup, 'GDPRess is a helper bot, not a legal advice bot. Please refer to your country\'s GDPR regulations and make sure you\'ve taken all necessary steps to comply.' ); ?>
103 </p>
104 <?php endif; ?>
105 <table>
106 <thead>
107 <tr>
108 <th class="downloaded" scope="col"><?php /** Header for Downloaded Status column */ ?></th>
109 <th class="name" scope="col"><?php echo __( 'Filename', 'gdpr-press' ); ?></th>
110 <th class="href" scope="col"><?php echo __( 'External URL', 'gdpr-press' ); ?></th>
111 <th class="href" scope="col"><?php echo __( 'Local URL', 'gdpr-press' ); ?></th>
112 <th class="exclude" scope="col"><?php echo __( 'Exclude', 'gdpr-press' ); ?></th>
113 </tr>
114 </thead>
115 <?php foreach ( Helper::requests() as $type => $requests ) : ?>
116 <tbody class="<?php echo esc_attr( $type ); ?>">
117 <tr>
118 <td class="title" colspan="5">
119 <h3><?php echo esc_html( strtoupper( $type ) ); ?></h3>
120 </td>
121 </tr>
122 <?php foreach ( $requests as $i => $request ) : ?>
123 <?php
124 $request_type = $this->get_request_type( $request );
125 $classes = $i % 2 ? 'even ' : '';
126
127 if ( $request_type === 'google_analytics' || $request_type === 'excluded' ) {
128 $classes .= 'warning';
129 } elseif ( $request_type === 'google_fonts' || $request_type === 'webfont_js' || $request_type === 'upsell' ) {
130 $classes .= 'info';
131 }
132
133 $is_google_fonts = Helper::is_google_fonts_request( $request['href'] );
134 $local_url = $is_google_fonts ? Helper::get_local_url_google_font( $request['name'] ) : Helper::get_local_url( $request['href'], $type );
135 $local_path = $is_google_fonts ? Helper::get_local_path_google_font( $request['name'] ) : Helper::get_local_path( $request['href'], $type );
136 $downloaded = $local_path && file_exists( $local_path );
137 $tooltip_text = $this->get_tooltip_text( $request_type );
138 ?>
139 <tr <?php echo "class='" . esc_attr( $classes ) . "'"; ?>>
140 <td class="downloaded"><?php echo $request_type ? sprintf( $this->tooltip_markup, wp_kses_post( $tooltip_text ) ) : ( $downloaded ? '<i class="dashicons dashicons-yes"></i>' : '' ); ?></td>
141 <th class="name" scope="row"><?php echo esc_attr( $request['name'] ); ?></th>
142 <td class="href"><span title="<?php echo esc_url( $request['href'] ); ?>"><?php echo esc_url( $request['href'] ); ?></span></td>
143 <td class="href"><span title="<?php echo esc_url( $local_url ); ?>"><?php echo esc_url( $local_url ); ?></span></td>
144 <td class="exclude">
145 <input type="checkbox" <?php echo Helper::is_excluded( $type, $request['href'] ) || $request_type === 'google_analytics' || $request_type === 'excluded' ? 'checked' : ''; ?>
146 <?php echo $request_type === 'google_analytics' || $request_type === 'excluded' ? 'class="locked"' : ''; ?>
147 name="<?php echo esc_attr( Settings::GDPRESS_MANAGE_SETTING_EXCLUDED ); ?>[<?php echo esc_attr( $type ); ?>][]" value="<?php echo esc_url( $request['href'] ); ?>"
148 />
149 </td>
150 </tr>
151 <?php endforeach; ?>
152 </tbody>
153 <?php endforeach; ?>
154 <tbody class="gdpress-manage-cache">
155 <tr>
156 <th>
157 <?php echo esc_html__('Manage cache', 'gdpr-press') ;?>
158 </th>
159 <td>
160 <input type="button" name="button" id="gdpress-fetch" class="button" value="<?php echo __( 'Re-scan', 'gdpr-press' ); ?>" data-nonce="<?php echo wp_create_nonce( Settings::GDPRESS_ADMIN_PAGE ); ?>">
161 <a href="#" id="gdpress-flush" data-nonce="<?php echo wp_create_nonce( Settings::GDPRESS_ADMIN_PAGE ); ?>" class="gdpress-flush button button-cancel"><?php _e( 'Empty cache directory', 'gdpr-press' ); ?></a>
162 </td>
163 </tr>
164 </tbody>
165 </table>
166 <input type="hidden" name="<?php echo esc_attr( Settings::GDPRESS_MANAGE_SETTING_REQUESTS ); ?>" value="<?php echo base64_encode( serialize( Helper::requests() ) ); ?>"/>
167 <?php
168 }
169
170 /**
171 * @param array $request
172 *
173 * @return string
174 */
175 private function get_request_type( $request ) {
176 $is_ga = str_contains( $request['href'], 'google-analytics' ) || str_contains( $request['href'], 'googletagmanager' );
177 $is_gf = Helper::is_google_fonts_request( $request['href'] );
178 $is_webfont = Helper::is_webfont_loader_request( $request['href'] );
179 $is_excl = false;
180 $is_upsell = false;
181
182 foreach ( Helper::exclusion_list() as $pattern ) {
183 if ( str_contains( $request['href'], $pattern ) ) {
184 $is_excl = true;
185 break;
186 }
187 }
188
189 foreach ( Helper::upsell_list() as $pattern ) {
190 if ( str_contains( $request['href'], $pattern ) ) {
191 $is_upsell = true;
192 break;
193 }
194 }
195
196 // Only suggest OMGF if there's a serious number of fonts in use.
197 if ( $is_gf && ! $is_upsell ) {
198 $is_gf = $this->count_gf( $request['href'] ) > 2 || $this->count_gf_variations( $request['href'] ) > 5;
199 }
200
201 if ( $is_ga ) {
202 return 'google_analytics';
203 }
204
205 if ( $is_excl ) {
206 return 'excluded';
207 }
208
209 if ( $is_upsell ) {
210 return 'upsell';
211 }
212
213 if ( $is_gf ) {
214 return 'google_fonts';
215 }
216
217 if ( $is_webfont ) {
218 return 'webfont_js';
219 }
220
221 return '';
222 }
223
224 /**
225 * Count Google Fonts families in an URL.
226 *
227 * @param string $url
228 *
229 * @return int
230 */
231 private function count_gf( $url ) {
232 $parts = parse_url( $url );
233
234 if ( $parts['path'] === '/css2' ) {
235 // CSS2
236 $count = substr_count( $parts['query'] ?? '', 'family' );
237 } else {
238 // Regular ("legacy") API
239 parse_str( $parts['query'], $params );
240
241 $count = substr_count( $params['family'] ?? '', '|' ) + 1;
242 }
243
244 return $count;
245 }
246
247 /**
248 * Count Google Fonts variations in an URL
249 *
250 * @param string $url
251 *
252 * @return int
253 */
254 private function count_gf_variations( $url ) {
255 // Count fonts.
256 $google_fonts = parse_url( $url );
257
258 if ( $google_fonts['path'] === '/css2' ) {
259 // CSS2
260 $google_fonts_var_count = substr_count( $google_fonts['query'] ?? '', ';' );
261 } else {
262 // Regular ("legacy") API
263 parse_str( $google_fonts['query'], $params );
264
265 $google_fonts_var_count = substr_count( $params['family'] ?? '', ',' );
266 }
267
268 // This means all variations are loaded, which is never good. So manually bump up the value to display the suggestion.
269 if ( $google_fonts_var_count === 0 ) {
270 $google_fonts_var_count = 6;
271 }
272
273 return $google_fonts_var_count;
274 }
275
276 /**
277 * @param string $request_type
278 *
279 * @return string
280 */
281 private function get_tooltip_text( $request_type ) {
282 switch ( $request_type ) {
283 case 'google_analytics':
284 return sprintf( $this->ga_notice, admin_url( 'plugin-install.php?s=CAOS&tab=search&type=term' ) );
285 case 'excluded':
286 return $this->exclusion_notice;
287 case 'upsell':
288 return sprintf($this->upsell_notice, 'https://daan.dev/wordpress/omgf-pro/');
289 case 'google_fonts':
290 return sprintf( $this->gf_notice, admin_url( 'plugin-install.php?s=OMGF&tab=search&type=term' ) );
291 case 'webfont_js':
292 return sprintf( $this->webfont_notice, 'https://daan.dev/wordpress/omgf-pro/' );
293 default:
294 return '';
295 }
296 }
297
298 private function start_screen() {
299 if ( is_array( Helper::requests( true ) ) ) : ?>
300 <p>
301 <em><?php echo sprintf( __( 'Does not compute! 😱 GDPRess Bot experienced issues while scanning the website. If you\'re certain your site contains 3rd party resources, try <a href="%s" target="_blank">contacting my support human</a>?', 'gdpr-press' ), 'https://wordpress.org/support/plugin/gdpr-press/' ); ?></em>
302 </p>
303 <?php else : ?>
304 <p>
305 <em><?php echo __( 'Wow, such empty! 🐼 GDPRess Bot suggests you try giving this big button a steady push.', 'gdpr-press' ); ?></em>
306 </p>
307 <?php endif; ?>
308 <p>
309 <button data-nonce="<?php echo wp_create_nonce( Settings::GDPRESS_ADMIN_PAGE ); ?>" id="gdpress-fetch" class="button button-primary button-hero">
310 <?php echo __( 'Scan website', 'gdpr-press' ); ?>
311 </button>
312 </p>
313 <?php
314 }
315
316 /**
317 * @return void
318 */
319 public function set_translations() {
320 $this->ga_notice = __( '<strong>Warning!</strong> 🤖 Due to the sensitive nature of using Google Analytics in compliance with GDPR, GDPRess Bot will ignore this file automatically. I suggest optimizing this request using <a href="%s" target="_blank" rel="noopener noreferrer">CAOS</a> (free).', 'gdpr-press' );
321 $this->gf_notice = __( '<strong>Uh-oh!</strong> 😵 GDPRess Bot has detected <strong>a lot</strong> of Google Fonts! I can download all of them, but I doubt you need (all of) them. I suggest optimizing this request using <a href="%s" target="_blank" rel="noopener noreferrer">OMGF</a> (free).', 'gdpr-press' );
322 $this->webfont_notice = __( '<strong>Heads up!</strong> 🔍 GDPRess Bot has detected a Web Font Loader script. I can download it for you, but the Google Fonts it loads will still be requested externally. Want to optimize those too? <a href="%s" target="_blank" rel="noopener noreferrer">OMGF Pro</a> can automatically preload, swap or unload individual font families — without any manual configuration.', 'gdpr-press' );
323 $this->exclusion_notice = __( '<strong>Beep-boop!</strong> 🤖 GDPRess Bot has automatically marked this resource as excluded because it\'s known to break when locally hosted. You\'re welcome!', 'gdpr-press' );
324 $this->upsell_notice = __( '<strong>Psst!</strong> 💡 GDPRess Bot detected a Google Fonts request. I can download it — but humans shouldn\'t be trusted with font optimization. <a href="%s" target="_blank" rel="noopener noreferrer">OMGF Pro</a> automatically preloads, unloads and subsets your fonts. No human error.', 'gdpr-press' );
325 }
326
327 /**
328 * Add Test Mode setting.
329 */
330 public function test_mode() {
331 $this->do_checkbox(
332 __( 'Test mode', 'gdpr-press' ),
333 Settings::GDPRESS_MANAGE_SETTING_TEST_MODE,
334 GDPRESS_TEST_MODE,
335 __( '<strong>Warning!</strong> Test thoroughly, before disabling this option. While this setting is enabled, any changes made by GDPRess will only be visible to logged in administrators or when <code>?gdpress</code> is added to an URL in the frontend.', 'gdpr-press' )
336 );
337 }
338 }
339