PluginProbe
SQLite Object Cache / 1.2.3
SQLite Object Cache v1.2.3
1.6.5 trunk 0.1.7 1.0.0 1.1.0 1.1.1 1.2.0 1.2.1 1.2.2 1.2.3 1.3.0 1.3.1 1.3.2 1.3.4 1.3.5 1.3.6 1.3.7 1.3.8 1.4.0 1.4.1 1.5.1 1.5.4 1.5.5 1.5.6 1.5.7 All 30 releases
sqlite-object-cache / includes / class-sqlite-object-cache-settings.php

class-sqlite-object-cache-settings.php in SQLite Object Cache 1.2.3, at includes/class-sqlite-object-cache-settings.php

607 lines 17.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Settings class file.
4 *
5 * @package SQLite Object Cache
6 */
7
8 if ( ! defined( 'ABSPATH' ) ) {
9 exit;
10 }
11
12 /**
13 * Only make one instance of this, please.
14 *
15 * Settings class.
16 */
17 class SQLite_Object_Cache_Settings {
18
19 /**
20 * The main plugin object.
21 *
22 * @var object
23 */
24 public $parent;
25
26 /**
27 * Prefix for plugin settings.
28 *
29 * @var string
30 */
31 public $base = '';
32
33 /**
34 * Available settings for plugin.
35 *
36 * @var array
37 */
38 public $settings = [];
39
40 /**
41 * SQLite3 is available.
42 *
43 * @var string|bool If it's true, we're good. If it's a string, an explanation.
44 */
45 public $has = '';
46
47 /**
48 * Constructor function.
49 *
50 * @param object $parent Parent object.
51 */
52 public function __construct( $parent ) {
53 $this->parent = $parent;
54 $this->has = $parent->has_sqlite();
55 $this->base = 'sqlite_object_cache_';
56
57 // Initialise settings.
58 add_action( 'init', [ $this, 'init_settings' ], 11 );
59
60 // Register plugin settings.
61 add_action( 'admin_init', [ $this, 'register_my_settings' ] );
62
63 // Add settings page to menu.
64 add_action( 'admin_menu', [ $this, 'add_menu_item' ] );
65
66 // Add settings link to plugins page.
67 add_filter(
68 'plugin_action_links_' . plugin_basename( $this->parent->file ),
69 [
70 $this,
71 'add_settings_link',
72 ]
73 );
74
75 // Configure placement of plugin settings page. See readme for implementation.
76 add_filter( $this->base . 'menu_settings', [ $this, 'configure_settings' ] );
77
78 // Load admin JS & CSS.
79 add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_assets' ], 10, 1 );
80 }
81
82 /**
83 * Initialize settings
84 *
85 * @return void
86 */
87 public function init_settings() {
88 $this->settings = $this->settings_fields();
89 }
90
91 /**
92 * Build settings fields
93 *
94 * @return array Fields to be displayed on settings page
95 */
96 private function settings_fields() {
97
98 $settings['standard'] = [
99 'title' => __( 'Settings', 'sqlite-object-cache' ),
100 'submit' => __( 'Save Settings', 'sqlite-object-cache' ),
101 'description' => '',
102 'render_section_header' => [ $this, 'settings_section_header' ],
103 'form_post_callback' => [ $this, 'validate_settings' ],
104 'fields' => [
105 [
106 'id' => 'flush',
107 'label' => __( 'Flush now', 'sqlite-object-cache' ),
108 'description' => __( 'Check to flush the cache (delete all its entries).', 'sqlite-object-cache' ),
109 'type' => 'checkbox',
110 'default' => '',
111 'reset' => '',
112 ],
113 [
114 'id' => 'retention',
115 'label' => __( 'Cached data expires after', 'sqlite-object-cache' ),
116 'description' => __( 'hours.', 'sqlite-object-cache' ),
117 'type' => 'number',
118 'default' => 24,
119 'max' => 24 * 7,
120 'min' => 1,
121 'step' => 'any',
122 'cssclass' => 'narrow',
123 'placeholder' => __( 'Hours to retain.', 'sqlite-object-cache' ),
124 ],
125 [
126 'id' => 'cleanup',
127 'label' => __( 'Clean up now', 'sqlite-object-cache' ),
128 'description' => __( 'Check to clean up the cache (delete expired data).', 'sqlite-object-cache' ),
129 'type' => 'checkbox',
130 'default' => '',
131 'reset' => '',
132 ],
133 [
134 'id' => 'capture',
135 'label' => __( 'Measure performance', 'sqlite-object-cache' ),
136 'description' => __( 'Check to measure cache performance. ', 'sqlite-object-cache' ),
137 'type' => 'checkbox',
138 'default' => '',
139 ],
140 [
141 'id' => 'samplerate',
142 'label' => __( 'Measure', 'sqlite-object-cache' ),
143 'description' => __( 'percent of requests, randomly sampled.', 'sqlite-object-cache' ),
144 'type' => 'number',
145 'default' => 1,
146 'max' => 100,
147 'min' => 0,
148 'step' => 'any',
149 'cssclass' => 'narrow',
150 'placeholder' => __( 'Sampling percentage.', 'sqlite-object-cache' ),
151 ],
152 [
153 'id' => 'retainmeasurements',
154 'label' => __( 'Retain measurements for', 'sqlite-object-cache' ),
155 'description' => __( 'hours.', 'sqlite-object-cache' ),
156 'type' => 'number',
157 'default' => 2,
158 'min' => 0.1,
159 'step' => 'any',
160 'cssclass' => 'narrow',
161 'placeholder' => __( 'Hours to retain.', 'sqlite-object-cache' ),
162 ],
163 ],
164 ];
165
166 $settings['stats'] = [
167 'title' => __( 'Statistics', 'sqlite-object-cache' ),
168 'submit' => __( 'Reset Statistics', 'sqlite-object-cache' ),
169 'render_section_header' => [ $this, 'stats_section_header' ],
170 'form_post_callback' => [ $this, 'validate_reset_stats' ],
171 ];
172
173 return apply_filters( $this->parent->_token . '_settings_fields', $settings );
174 }
175
176 /**
177 * Validate the options presented to the Settings tab.
178 *
179 * This is an options update filter. It filters an option value following sanitization.
180 *
181 * @param mixed $option The sanitized option value.
182 * @param string $name The option name.
183 * @param string $original_value The original value passed to the function.
184 *
185 * @throws Exception Announce SQLite failure.
186 * @since 2.3.0
187 * @since 4.3.0 Added the `$original_value` parameter.
188 *
189 * @noinspection PhpUnusedParameterInspection
190 */
191 public function validate_settings( $option, $name, $original_value ) {
192 if ( ! is_array( $option ) ) {
193 /* weird. not an option array */
194 return $option;
195 }
196 global $wp_object_cache;
197
198 if ( array_key_exists( 'flush', $option ) && $option ['flush'] === 'on' ) {
199 if ( method_exists( $wp_object_cache, 'flush' ) ) {
200 $wp_object_cache->flush( true );
201 }
202 unset ( $option['flush'] );
203 }
204 $retention = $this->numeric_option( $option, 'retention', 7 );
205 if ( array_key_exists( 'cleanup', $option ) && $option ['cleanup'] === 'on' ) {
206 $this->parent->clean();
207 unset ( $option['cleanup'] );
208 }
209
210 $this->numeric_option( $option, 'samplerate', 10 );
211 $this->numeric_option( $option, 'retainmeasurements', 2 );
212
213 if ( array_key_exists( 'capture', $option ) && $option['capture'] === 'on' ) {
214 $option['previouscapture'] = 0;
215 }
216
217 return $option;
218 }
219
220 /**
221 * Retrieve a numeric option, and set the default if it isn't present.
222 *
223 * @param array $option Option array value.
224 * @param string $name Name of the element in the option array.
225 * @param mixed $default Default value to use.
226 *
227 * @return float|int|mixed|string
228 */
229 private function numeric_option( &$option, $name, $default ) {
230 $result = $default;
231 if ( array_key_exists( $name, $option ) && is_numeric( $option[ $name ] ) ) {
232 $result = $option[ $name ];
233 $result = $result ?: $default;
234 } else {
235 $option[ $name ] = $default;
236 }
237
238 return $result;
239 }
240
241 /**
242 * Filters an option value following sanitization.
243 *
244 * @param string $option The sanitized option value.
245 * @param string $name The option name.
246 * @param string $original_value The original value passed to the function.
247 *
248 * @throws Exception Announce SQLite failure.
249 * @since 2.3.0
250 * @since 4.3.0 Added the `$original_value` parameter.
251 *
252 * @noinspection PhpUnusedParameterInspection
253 */
254 public function validate_reset_stats( $option, $name, $original_value ) {
255
256 global $wp_object_cache;
257 if ( method_exists( $wp_object_cache, 'sqlite_reset_statistics' ) ) {
258 $wp_object_cache->sqlite_reset_statistics();
259 }
260
261 /* for this post operation, we don't want to change any plugin options. */
262
263 return get_option( $name );
264 }
265
266 /**
267 * Add settings page to admin menu
268 *
269 * @return void
270 */
271 public function add_menu_item() {
272
273 $args = $this->menu_settings();
274
275 // Do nothing if wrong location key is set.
276 if ( is_array( $args ) && isset( $args['location'] ) && function_exists( 'add_' . $args['location'] . '_page' ) ) {
277 switch ( $args['location'] ) {
278 case 'options':
279 case 'submenu':
280 $page =
281 add_submenu_page( $args['parent_slug'], $args['page_title'], $args['menu_title'], $args['capability'], $args['menu_slug'], $args['function'] );
282 break;
283 case 'menu':
284 $page =
285 add_menu_page( $args['page_title'], $args['menu_title'], $args['capability'], $args['menu_slug'], $args['function'], $args['icon_url'], $args['position'] );
286 break;
287 default:
288 return;
289 }
290 add_action( 'admin_print_styles-' . $page, [ $this, 'settings_assets' ] );
291 }
292 }
293
294 /**
295 * Prepare default settings page arguments
296 *
297 * @return mixed|void
298 */
299 private function menu_settings() {
300 $this->complain_if_sqlite3_unavailable();
301
302 return apply_filters(
303 $this->base . 'menu_settings',
304 [
305 'location' => 'options', // Possible settings: options, menu, submenu.
306 'parent_slug' => 'options-general.php',
307 'page_title' => __( 'SQLite Persistent Object Cache', 'sqlite-object-cache' ),
308 'menu_title' => __( 'Object Cache', 'sqlite-object-cache' ),
309 'capability' => 'manage_options',
310 'menu_slug' => $this->parent->_token . '_settings',
311 'function' => [ $this, 'settings_page' ],
312 'icon_url' => '',
313 'position' => null,
314 ]
315 );
316 }
317
318 /**
319 * Emit a message if SQLite3 is not available.
320 *
321 * @param bool $verbose False means emit a notice. True means emit a longer explanation.
322 *
323 * @return void
324 */
325 private function complain_if_sqlite3_unavailable( $verbose = false ) {
326 if ( true !== $this->has ) {
327 if ( ! $verbose ) {
328 echo '<div class="notice notice-error sql-object-cache">';
329 echo esc_html( $this->has );
330 echo '</div>';
331 } else {
332 echo '<div>';
333 echo '<h3 style="color: #d63638">' . esc_html__( 'Server configuration problem', 'sqlite-object-cache' ) . '</h3>';
334 echo '<p>';
335
336 if ( ! class_exists( 'SQLite3' ) || ! extension_loaded( 'sqlite3' ) ) {
337 echo esc_html__( 'The SQLite Persistent Object Cache plugin requires php\'s SQLite3 extension.', 'sqlite-object-cache' ) . ' ';
338 echo esc_html__( 'That extension is not installed in your server, so the plugin cannot work.', 'sqlite-object-cache' ) . ' ';
339 }
340
341 $sqlite_version = $this->parent->sqlite_get_version();
342 if ( version_compare( $sqlite_version, $this->parent->minimum_sqlite_version ) < 0 ) {
343 echo esc_html( sprintf(
344 /* translators: 1 actual SQLite version. 2 required SQLite version) */
345 __( 'You cannot use the SQLite Object Cache plugin. Your server only offers SQLite3 version %1$s, but at least %2$s is required.', 'sqlite-object-cache' ),
346 $sqlite_version, $this->parent->minimum_sqlite_version ) );
347 }
348
349 echo '</p></div>' . PHP_EOL;
350 }
351 }
352 }
353
354 /**
355 * Container for settings page arguments
356 *
357 * @param array $settings Settings array.
358 *
359 * @return array
360 */
361 public function configure_settings( $settings = [] ) {
362 return $settings;
363 }
364
365 /**
366 * Load settings JS & CSS
367 *
368 * @return void
369 */
370 public function settings_assets() {
371
372 }
373
374 /**
375 * Add settings link to plugin list table
376 *
377 * @param array $links Existing links.
378 *
379 * @return array Modified links.
380 */
381 public function add_settings_link( $links ) {
382 if ( true !== $this->has ) {
383 $settings_link =
384 '<a style="color: #d63638" href="options-general.php?page=' . $this->parent->_token . '_settings">' . __( 'Settings', 'sqlite-object-cache' ) . '</a>';
385 array_unshift( $links, $settings_link );
386 } else {
387 $settings_link =
388 '<a href="options-general.php?page=' . $this->parent->_token . '_settings">' . __( 'Settings', 'sqlite-object-cache' ) . '</a>';
389 $statistics_link =
390 '<a href="options-general.php?page=' . $this->parent->_token . '_settings&tab=stats">' . __( 'Statistics', 'sqlite-object-cache' ) . '</a>';
391 array_unshift( $links, $settings_link, $statistics_link );
392 }
393
394 return $links;
395 }
396
397 /**
398 * Register plugin settings
399 *
400 * @return void
401 */
402 public function register_my_settings() {
403 if ( is_array( $this->settings ) ) {
404
405 /* get the tab chosen by the user ('standard' or 'stats') */
406 $tab = isset ( $_REQUEST['tab'] ) ? sanitize_key( $_REQUEST['tab'] ) : 'standard';
407
408 $default_option = [];
409 $option_name = $this->base . 'settings';
410
411 foreach ( $this->settings as $section => $data ) {
412
413 if ( $tab && $tab !== $section ) {
414 continue;
415 }
416
417 $setting_args = [
418 'description' => $data['title'],
419 'default' => $default_option,
420 ];
421
422 // Validation callback for section.
423 if ( isset( $data['form_post_callback'] ) ) {
424 add_filter( "sanitize_option_$option_name", $data['form_post_callback'], 10, 3 );
425 }
426
427 // Add section to page.
428 add_settings_section( $section, '',
429 $data ['render_section_header'],
430 $this->parent->_token . '_settings' );
431
432 if ( array_key_exists( 'fields', $data ) && is_array( $data['fields'] ) ) {
433 foreach ( $data['fields'] as $field ) {
434 $default_option [ $field['id'] ] = $field['default'];
435 }
436
437 foreach ( $data['fields'] as $field ) {
438 // Add field to page.
439 add_settings_field(
440 $field['id'],
441 $field['label'],
442 [ $this->parent->admin, 'echo_field' ],
443 $this->parent->_token . '_settings',
444 $section,
445 [
446 'field' => $field,
447 'option' => $option_name,
448 ]
449 );
450 }
451 }
452 /* register the settings object */
453 register_setting( $this->parent->_token . '_settings', $option_name, $setting_args );
454 }
455 }
456 }
457
458 /**
459 * Settings section.
460 *
461 * @param array $section Array of section ids.
462 *
463 * @return void
464 * @throws Exception Announce Database Failure.
465 */
466 public function settings_section_header( $section ) {
467
468 $this->support_links();
469 $this->versions();
470
471 if ( array_key_exists( 'description', $this->settings[ $section['id'] ] ) ) {
472 echo '<p> ' . esc_html( $this->settings[ $section['id'] ]['description'] ) . '</p>' . PHP_EOL;
473 }
474 }
475
476 /**
477 * Display support and rating links.
478 *
479 * @return void
480 */
481 private function support_links() {
482
483 $supportUrl = "https://wordpress.org/support/plugin/sqlite-object-cache/";
484 $reviewUrl = "https://wordpress.org/support/plugin/sqlite-object-cache/reviews/";
485 echo '<p>';
486 echo esc_html__( 'For support please', 'sqlite-object-cache' ) . ' ';
487 echo '<a href="' . esc_url( $supportUrl ) . '">' . esc_html__( 'click here', 'sqlite-object-cache' ) . '</a>. ';
488 echo esc_html__( 'To rate this plugin please', 'sqlite-object-cache' ) . ' ';
489 echo '<a href="' . esc_url( $reviewUrl ) . '">' . esc_html__( 'click here', 'sqlite-object-cache' ) . '</a>. ';
490 echo esc_html__( 'Your feedback helps make it better, faster, and more useful', 'sqlite-object-cache' ) . '.';
491 echo '</p>';
492 }
493
494 /**
495 * Display versions.
496 *
497 * @return void
498 * @throws Exception Announce database failure.
499 */
500 private function versions() {
501 global $wp_object_cache;
502 $igbinary = function_exists( 'igbinary_serialize' ) && function_exists( 'igbinary_unserialize' )
503 ? __( 'available', 'sqlite-object-cache' )
504 : __( 'unavailable', 'sqlite-object-cache' );
505
506 if ( method_exists( $wp_object_cache, 'sqlite_get_version' ) ) {
507 echo '<p>' . esc_html( sprintf(
508 /* translators: 1: version for sqlite 2: version for php 3: version for plugin 4: status of igbinary */
509 __( 'Versions: SQLite: %1$s php: %2$s Plugin: %3$s igbinary: %4$s.', 'sqlite-object-cache' ),
510 $wp_object_cache->sqlite_get_version(),
511 PHP_VERSION,
512 $this->parent->_version,
513 $igbinary ) ) . '</p>';
514 }
515 }
516
517 /**
518 * Statistics tab section.
519 *
520 * @param array $section Array of section ids.
521 *
522 * @return void
523 * @throws Exception Announce Database Failure.
524 * @noinspection PhpUnusedParameterInspection
525 */
526 public function stats_section_header( $section ) {
527
528 $this->support_links();
529 $this->versions();
530
531 $stats = new SQLite_Object_Cache_Statistics ( get_option( $this->parent->_token . '_settings', [] ) );
532 $stats->init();
533 $stats->render();
534 $stats->render_usage();
535 }
536
537 /**
538 * Load settings page content.
539 *
540 * @return void
541 */
542 public function settings_page() {
543
544 /* get the tab chosen by the user ('standard' by default or 'stats') */
545 $tab = isset ( $_REQUEST['tab'] ) ? sanitize_key( $_REQUEST['tab'] ) : 'standard';
546
547 // Build page HTML.
548 echo '<div class="wrap" id="' . esc_attr( $this->parent->_token . '_settings' ) . '">' . PHP_EOL;
549 echo '<h2>' . esc_html__( 'SQLite Persistent Object Cache', 'sqlite-object-cache' ) . '</h2>' . PHP_EOL;
550
551 $submit_caption = __( 'Save Settings', 'sqlite-object-cache' );
552 $this->complain_if_sqlite3_unavailable( true );
553
554 // Show page tabs.
555 if ( is_array( $this->settings ) && 1 < count( $this->settings ) ) {
556
557 echo '<h2 class="nav-tab-wrapper">' . PHP_EOL;
558
559 foreach ( $this->settings as $section => $data ) {
560
561 // Set tab class.
562 $class = 'nav-tab';
563 if ( $section === $tab ) {
564 $class .= ' nav-tab-active';
565 $submit_caption = $data['submit'];
566 }
567
568 // Set tab link.
569 $tab_link = add_query_arg( [ 'tab' => $section ] );
570 $tab_link = remove_query_arg( 'settings-updated', $tab_link );
571
572 // Output tab.
573 echo '<a href="' . esc_url( $tab_link ) . '" class="' . esc_attr( $class ) . '">' . esc_html( $data['title'] ) . '</a>' . PHP_EOL;
574 }
575
576 echo '</h2>' . PHP_EOL;
577 }
578
579 /** @noinspection HtmlUnknownTarget */
580 echo '<form method="post" action="options.php" enctype="multipart/form-data">' . PHP_EOL;
581
582 // Get settings fields.
583 settings_fields( $this->parent->_token . '_settings' );
584 do_settings_sections( $this->parent->_token . '_settings' );
585
586 echo '<p class="submit">' . PHP_EOL;
587 echo '<input type="hidden" name="tab" value="' . esc_attr( $tab ) . '" />' . PHP_EOL;
588 echo '<input name="Submit" type="submit" class="button-primary" value="' . esc_attr( $submit_caption ) . '" />' . PHP_EOL;
589 echo '</p></form></div>' . PHP_EOL;
590 }
591
592 /**
593 * Admin enqueue assets
594 *
595 * @param string $hook Hook parameter.
596 *
597 * @return void
598 * @noinspection PhpUnusedParameterInspection
599 */
600 public function enqueue_assets( $hook = '' ) {
601 wp_register_style( $this->parent->_token . '-admin',
602 esc_url( $this->parent->assets_url ) . 'css/admin.css',
603 [], $this->parent->_version );
604 wp_enqueue_style( $this->parent->_token . '-admin' );
605 }
606 }
607