PluginProbe
SQLite Object Cache / 1.3.6
SQLite Object Cache v1.3.6
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.3.6, at includes/class-sqlite-object-cache-settings.php

640 lines 20.1 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 = array();
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', array( $this, 'init_settings' ), 11 );
59
60 // Register plugin settings.
61 add_action( 'admin_init', array( $this, 'register_my_settings' ) );
62
63 // Add settings page to menu.
64 add_action( 'admin_menu', array( $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 array(
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', array( $this, 'configure_settings' ) );
77
78 // Load admin JS & CSS.
79 add_action( 'admin_enqueue_scripts', array( $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'] = array(
99 'title' => __( 'Settings', 'sqlite-object-cache' ),
100 'submit' => __( 'Save Settings', 'sqlite-object-cache' ),
101 'description' => '',
102 'render_section_header' => array( $this, 'settings_section_header' ),
103 'form_post_callback' => array( $this, 'validate_settings' ),
104 'fields' => array(
105 array(
106 'id' => 'flush',
107 'label' => __( 'Flush now', 'sqlite-object-cache' ),
108 'description' => __( 'Check to flush the cache (delete all its entries) now.', 'sqlite-object-cache' ) . ' ' .
109 __( 'This briefly puts your site into maintenance mode.', 'sqlite-object-cache' ),
110 'type' => 'checkbox',
111 'default' => '',
112 'reset' => '',
113 ),
114 array(
115 'id' => 'target_size',
116 'label' => __( 'Cached data size', 'sqlite-object-cache' ),
117 'description' => __( 'MiB. When data in the cache grows larger than this, hourly cleanup removes the oldest entries.', 'sqlite-object-cache' ),
118 'type' => 'number',
119 'default' => 16,
120 'min' => 1,
121 'step' => 'any',
122 'cssclass' => 'narrow',
123 'placeholder' => __( 'MiB.', 'sqlite-object-cache' ),
124 ),
125 array(
126 'id' => 'cleanup',
127 'label' => __( 'Clean up now', 'sqlite-object-cache' ),
128 'description' => __( 'Check to clean up the cache (delete old data) now.', 'sqlite-object-cache' ),
129 'type' => 'checkbox',
130 'default' => '',
131 'reset' => '',
132 ),
133 array(
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 array(
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 array(
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'] = array(
167 'title' => __( 'Statistics', 'sqlite-object-cache' ),
168 'submit' => __( 'Reset Statistics', 'sqlite-object-cache' ),
169 'render_section_header' => array( $this, 'stats_section_header' ),
170 'form_post_callback' => array( $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 try {
201 $this->enter_maintenance_mode();
202 $wp_object_cache->flush( true );
203 } finally {
204 $this->exit_maintenance_mode();
205 }
206 } else {
207 wp_cache_flush();
208 }
209 unset ( $option['flush'] );
210 }
211 if ( array_key_exists( 'cleanup', $option ) && $option ['cleanup'] === 'on' ) {
212 $this->parent->clean_job();
213 unset ( $option['cleanup'] );
214 }
215
216 $this->numeric_option( $option, 'target_size', 4 );
217 $this->numeric_option( $option, 'samplerate', 10 );
218 $this->numeric_option( $option, 'retainmeasurements', 2 );
219
220 if ( array_key_exists( 'capture', $option ) && $option['capture'] === 'on' ) {
221 $option['previouscapture'] = 0;
222 }
223
224 return $option;
225 }
226
227 /**
228 * Retrieve a numeric option, and set the default if it isn't present.
229 *
230 * @param array $option Option array value.
231 * @param string $name Name of the element in the option array.
232 * @param mixed $default Default value to use.
233 *
234 * @return float|int|mixed|string
235 */
236 private function numeric_option( &$option, $name, $default ) {
237 $result = $default;
238 if ( array_key_exists( $name, $option ) && is_numeric( $option[ $name ] ) ) {
239 $result = $option[ $name ];
240 $result = $result ?: $default;
241 } else {
242 $option[ $name ] = $default;
243 }
244
245 return $result;
246 }
247
248 /**
249 * Filters an option value following sanitization.
250 *
251 * @param string $option The sanitized option value.
252 * @param string $name The option name.
253 * @param string $original_value The original value passed to the function.
254 *
255 * @throws Exception Announce SQLite failure.
256 * @since 2.3.0
257 * @since 4.3.0 Added the `$original_value` parameter.
258 *
259 * @noinspection PhpUnusedParameterInspection
260 */
261 public function validate_reset_stats( $option, $name, $original_value ) {
262
263 global $wp_object_cache;
264 if ( method_exists( $wp_object_cache, 'sqlite_reset_statistics' ) ) {
265 $wp_object_cache->sqlite_reset_statistics();
266 }
267
268 /* for this post operation, we don't want to change any plugin options. */
269
270 return get_option( $name );
271 }
272
273 /**
274 * Add settings page to admin menu
275 *
276 * @return void
277 */
278 public function add_menu_item() {
279
280 $args = $this->menu_settings();
281
282 // Do nothing if wrong location key is set.
283 if ( is_array( $args ) && isset( $args['location'] ) && function_exists( 'add_' . $args['location'] . '_page' ) ) {
284 switch ( $args['location'] ) {
285 case 'options':
286 case 'submenu':
287 $page =
288 add_submenu_page( $args['parent_slug'], $args['page_title'], $args['menu_title'], $args['capability'], $args['menu_slug'], $args['function'] );
289 break;
290 case 'menu':
291 $page =
292 add_menu_page( $args['page_title'], $args['menu_title'], $args['capability'], $args['menu_slug'], $args['function'], $args['icon_url'], $args['position'] );
293 break;
294 default:
295 return;
296 }
297 add_action( 'admin_print_styles-' . $page, array( $this, 'settings_assets' ) );
298 }
299 }
300
301 /**
302 * Prepare default settings page arguments
303 *
304 * @return mixed|void
305 */
306 private function menu_settings() {
307 $this->complain_if_sqlite3_unavailable();
308
309 return apply_filters(
310 $this->base . 'menu_settings',
311 array(
312 'location' => 'options', // Possible settings: options, menu, submenu.
313 'parent_slug' => 'options-general.php',
314 'page_title' => __( 'SQLite Persistent Object Cache', 'sqlite-object-cache' ),
315 'menu_title' => __( 'Object Cache', 'sqlite-object-cache' ),
316 'capability' => 'manage_options',
317 'menu_slug' => $this->parent->_token . '_settings',
318 'function' => array( $this, 'settings_page' ),
319 'icon_url' => '',
320 'position' => null,
321 )
322 );
323 }
324
325 /**
326 * Emit a message if SQLite3 is not available.
327 *
328 * @param bool $verbose False means emit a notice. True means emit a longer explanation.
329 *
330 * @return void
331 */
332 private function complain_if_sqlite3_unavailable( $verbose = false ) {
333 if ( true !== $this->has ) {
334 if ( ! $verbose ) {
335 echo '<div class="notice notice-error sql-object-cache">';
336 echo esc_html( $this->has );
337 echo '</div>';
338 } else {
339 echo '<div>';
340 echo '<h3 style="color: #d63638">' . esc_html__( 'Server configuration problem', 'sqlite-object-cache' ) . '</h3>';
341 echo '<p>';
342
343 if ( ! class_exists( 'SQLite3' ) || ! extension_loaded( 'sqlite3' ) ) {
344 echo esc_html__( 'The SQLite Persistent Object Cache plugin requires php\'s SQLite3 extension.', 'sqlite-object-cache' ) . ' ';
345 echo esc_html__( 'That extension is not installed in your server, so the plugin cannot work.', 'sqlite-object-cache' ) . ' ';
346 }
347
348 $sqlite_version = $this->parent->sqlite_get_version();
349 if ( version_compare( $sqlite_version, $this->parent->minimum_sqlite_version ) < 0 ) {
350 echo esc_html( sprintf(
351 /* translators: 1 actual SQLite version. 2 required SQLite version) */
352 __( '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' ),
353 $sqlite_version, $this->parent->minimum_sqlite_version ) );
354 }
355
356 echo '</p></div>' . PHP_EOL;
357 }
358 }
359 }
360
361 /**
362 * Container for settings page arguments
363 *
364 * @param array $settings Settings array.
365 *
366 * @return array
367 */
368 public function configure_settings( $settings = array() ) {
369 return $settings;
370 }
371
372 /**
373 * Load settings JS & CSS
374 *
375 * @return void
376 */
377 public function settings_assets() {
378
379 }
380
381 /**
382 * Add settings link to plugin list table
383 *
384 * @param array $links Existing links.
385 *
386 * @return array Modified links.
387 */
388 public function add_settings_link( $links ) {
389 if ( true !== $this->has ) {
390 $settings_link =
391 '<a style="color: #d63638" href="options-general.php?page=' . $this->parent->_token . '_settings">' . __( 'Settings', 'sqlite-object-cache' ) . '</a>';
392 array_unshift( $links, $settings_link );
393 } else {
394 $settings_link =
395 '<a href="options-general.php?page=' . $this->parent->_token . '_settings">' . __( 'Settings', 'sqlite-object-cache' ) . '</a>';
396 $statistics_link =
397 '<a href="options-general.php?page=' . $this->parent->_token . '_settings&tab=stats">' . __( 'Statistics', 'sqlite-object-cache' ) . '</a>';
398 array_unshift( $links, $settings_link, $statistics_link );
399 }
400
401 return $links;
402 }
403
404 /**
405 * Register plugin settings
406 *
407 * @return void
408 */
409 public function register_my_settings() {
410 if ( is_array( $this->settings ) ) {
411
412 /* get the tab chosen by the user ('standard' or 'stats') */
413 $tab = isset ( $_REQUEST['tab'] ) ? sanitize_key( $_REQUEST['tab'] ) : 'standard';
414
415 $default_option = array();
416 $option_name = $this->base . 'settings';
417
418 foreach ( $this->settings as $section => $data ) {
419
420 if ( $tab && $tab !== $section ) {
421 continue;
422 }
423
424 $setting_args = array(
425 'description' => $data['title'],
426 'default' => $default_option,
427 );
428
429 // Validation callback for section.
430 if ( isset( $data['form_post_callback'] ) ) {
431 add_filter( "sanitize_option_$option_name", $data['form_post_callback'], 10, 3 );
432 }
433
434 // Add section to page.
435 add_settings_section( $section, '',
436 $data ['render_section_header'],
437 $this->parent->_token . '_settings' );
438
439 if ( array_key_exists( 'fields', $data ) && is_array( $data['fields'] ) ) {
440 foreach ( $data['fields'] as $field ) {
441 $default_option [ $field['id'] ] = $field['default'];
442 }
443
444 foreach ( $data['fields'] as $field ) {
445 // Add field to page.
446 add_settings_field(
447 $field['id'],
448 $field['label'],
449 array( $this->parent->admin, 'echo_field' ),
450 $this->parent->_token . '_settings',
451 $section,
452 array(
453 'field' => $field,
454 'option' => $option_name,
455 )
456 );
457 }
458 }
459 /* register the settings object */
460 register_setting( $this->parent->_token . '_settings', $option_name, $setting_args );
461 }
462 }
463 }
464
465 /**
466 * Settings section.
467 *
468 * @param array $section Array of section ids.
469 *
470 * @return void
471 * @throws Exception Announce Database Failure.
472 */
473 public function settings_section_header( $section ) {
474
475 $this->support_links();
476 $this->versions();
477
478 if ( array_key_exists( 'description', $this->settings[ $section['id'] ] ) ) {
479 echo '<p> ' . esc_html( $this->settings[ $section['id'] ]['description'] ) . '</p>' . PHP_EOL;
480 }
481 }
482
483 /**
484 * Display support and rating links.
485 *
486 * @return void
487 */
488 private function support_links() {
489
490 $supportUrl = "https://wordpress.org/support/plugin/sqlite-object-cache/";
491 $reviewUrl = "https://wordpress.org/support/plugin/sqlite-object-cache/reviews/";
492 echo '<p>';
493 echo esc_html__( 'For support please', 'sqlite-object-cache' ) . ' ';
494 echo '<a href="' . esc_url( $supportUrl ) . '">' . esc_html__( 'click here', 'sqlite-object-cache' ) . '</a>. ';
495 echo esc_html__( 'To rate this plugin please', 'sqlite-object-cache' ) . ' ';
496 echo '<a href="' . esc_url( $reviewUrl ) . '">' . esc_html__( 'click here', 'sqlite-object-cache' ) . '</a>. ';
497 echo esc_html__( 'Your feedback helps make it better, faster, and more useful', 'sqlite-object-cache' ) . '.';
498 echo '</p>';
499 }
500
501 /**
502 * Display versions.
503 *
504 * @return void
505 * @throws Exception Announce database failure.
506 */
507 private function versions() {
508 global $wp_object_cache;
509 $igbinary = function_exists( 'igbinary_serialize' ) && function_exists( 'igbinary_unserialize' )
510 ? __( 'available', 'sqlite-object-cache' )
511 : __( 'unavailable', 'sqlite-object-cache' );
512
513 if ( method_exists( $wp_object_cache, 'sqlite_get_version' ) ) {
514 echo '<p>' . esc_html( sprintf(
515 /* translators: 1: version for sqlite 2: version for php 3: webserver version 4: version for plugin 5: status of igbinary */
516 __( 'Versions: SQLite: %1$s php: %2$s Server: %3$s Plugin: %4$s igbinary: %5$s.', 'sqlite-object-cache' ),
517 $wp_object_cache->sqlite_get_version(),
518 PHP_VERSION,
519 $_SERVER['SERVER_SOFTWARE'],
520 $this->parent->_version,
521 $igbinary ) ) . '</p>';
522 }
523 }
524
525 /**
526 * Statistics tab section.
527 *
528 * @param array $section Array of section ids.
529 *
530 * @return void
531 * @throws Exception Announce Database Failure.
532 * @noinspection PhpUnusedParameterInspection
533 */
534 public function stats_section_header( $section ) {
535
536 $this->support_links();
537 $this->versions();
538
539 $stats = new SQLite_Object_Cache_Statistics ( get_option( $this->parent->_token . '_settings', array() ) );
540 $stats->init();
541 $stats->render();
542 $stats->render_usage();
543 }
544
545 /**
546 * Load settings page content.
547 *
548 * @return void
549 */
550 public function settings_page() {
551
552 /* get the tab chosen by the user ('standard' by default or 'stats') */
553 $tab = isset ( $_REQUEST['tab'] ) ? sanitize_key( $_REQUEST['tab'] ) : 'standard';
554
555 // Build page HTML.
556 echo '<div class="wrap" id="' . esc_attr( $this->parent->_token . '_settings' ) . '">' . PHP_EOL;
557 echo '<h2>' . esc_html__( 'SQLite Persistent Object Cache', 'sqlite-object-cache' ) . '</h2>' . PHP_EOL;
558
559 $submit_caption = __( 'Save Settings', 'sqlite-object-cache' );
560 $this->complain_if_sqlite3_unavailable( true );
561
562 // Show page tabs.
563 if ( is_array( $this->settings ) && 1 < count( $this->settings ) ) {
564
565 echo '<h2 class="nav-tab-wrapper">' . PHP_EOL;
566
567 foreach ( $this->settings as $section => $data ) {
568
569 // Set tab class.
570 $class = 'nav-tab';
571 if ( $section === $tab ) {
572 $class .= ' nav-tab-active';
573 $submit_caption = $data['submit'];
574 }
575
576 // Set tab link.
577 $tab_link = add_query_arg( array( 'tab' => $section ) );
578 $tab_link = remove_query_arg( 'settings-updated', $tab_link );
579
580 // Output tab.
581 echo '<a href="' . esc_url( $tab_link ) . '" class="' . esc_attr( $class ) . '">' . esc_html( $data['title'] ) . '</a>' . PHP_EOL;
582 }
583
584 echo '</h2>' . PHP_EOL;
585 }
586
587 /** @noinspection HtmlUnknownTarget */
588 echo '<form method="post" action="options.php" enctype="multipart/form-data">' . PHP_EOL;
589
590 // Get settings fields.
591 settings_fields( $this->parent->_token . '_settings' );
592 do_settings_sections( $this->parent->_token . '_settings' );
593
594 echo '<p class="submit">' . PHP_EOL;
595 echo '<input type="hidden" name="tab" value="' . esc_attr( $tab ) . '" />' . PHP_EOL;
596 echo '<input name="Submit" type="submit" class="button-primary" value="' . esc_attr( $submit_caption ) . '" />' . PHP_EOL;
597 echo '</p></form></div>' . PHP_EOL;
598 }
599
600 /**
601 * Admin enqueue assets
602 *
603 * @param string $hook Hook parameter.
604 *
605 * @return void
606 * @noinspection PhpUnusedParameterInspection
607 */
608 public function enqueue_assets( $hook = '' ) {
609 wp_register_style( $this->parent->_token . '-admin',
610 esc_url( $this->parent->assets_url ) . 'css/admin.css',
611 array(), $this->parent->_version );
612 wp_enqueue_style( $this->parent->_token . '-admin' );
613 }
614
615 /**
616 * Enters maintenance mode.
617 *
618 * @return void
619 */
620 private function enter_maintenance_mode() {
621 $maintenanceFileName = ABSPATH . '.maintenance';
622 $maintain = array();
623 array_push( $maintain,
624 '<?php',
625 '$upgrading = ' . time() . ';',
626 '?>' );
627 file_put_contents( $maintenanceFileName, implode( PHP_EOL, $maintain ) );
628 }
629
630 /**
631 * Exits maintenance mode.
632 *
633 * @return void
634 */
635 private function exit_maintenance_mode() {
636 $maintenanceFileName = ABSPATH . '.maintenance';
637 unlink( $maintenanceFileName );
638 }
639 }
640