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

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