PluginProbe
WP-Stateless – Google Cloud Storage / 3.1.0
WP-Stateless – Google Cloud Storage v3.1.0
4.4.3 2.1.7 2.1.8 2.1.9 2.2.0 2.2.1 2.2.2 2.2.3 2.2.4 2.2.5 2.2.6 2.2.7 2.3.0 2.3.1 2.3.2 3.0 3.0.1 3.0.2 3.0.3 3.0.4 3.1.0 3.1.1 3.2.0 3.2.1 3.2.2 All 62 releases
wp-stateless / lib / classes / class-settings.php

class-settings.php in WP-Stateless – Google Cloud Storage 3.1.0, at lib/classes/class-settings.php

591 lines 20.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Settings management and UI
4 *
5 * @since 0.2.0
6 */
7 namespace wpCloud\StatelessMedia {
8
9 if( !class_exists( 'wpCloud\StatelessMedia\Settings' ) ) {
10
11 final class Settings extends \UsabilityDynamics\Settings {
12
13 /**
14 * @var false|null|string
15 */
16 public $setup_wizard_ui = null;
17
18 /**
19 * @var Array
20 */
21 public $wildcards = array();
22
23 /**
24 * @var false|null|string
25 */
26 public $stateless_settings = null;
27
28 /**
29 * Instance of
30 * - ud_get_stateless_media
31 * - wpCloud\StatelessMedia\Bootstrap
32 * @var false|null|string
33 */
34 public $bootstrap = null;
35
36 private $settings = array(
37 'mode' => array('WP_STATELESS_MEDIA_MODE', 'ephemeral'),
38 'body_rewrite' => array('WP_STATELESS_MEDIA_BODY_REWRITE', 'false'),
39 'body_rewrite_types' => array('WP_STATELESS_MEDIA_BODY_REWRITE_TYPES', 'jpg jpeg png gif pdf'),
40 'bucket' => array('WP_STATELESS_MEDIA_BUCKET', ''),
41 'root_dir' => array('WP_STATELESS_MEDIA_ROOT_DIR', ['/%date_year/date_month%/', '/sites/%site_id%/%date_year/date_month%/']),
42 'key_json' => array('WP_STATELESS_MEDIA_JSON_KEY', ''),
43 'cache_control' => array('WP_STATELESS_MEDIA_CACHE_CONTROL', ''),
44 'delete_remote' => array('WP_STATELESS_MEDIA_DELETE_REMOTE', 'true'),
45 'custom_domain' => array('WP_STATELESS_MEDIA_CUSTOM_DOMAIN', ''),
46 'organize_media' => array('', 'true'),
47 'hashify_file_name' => array(['WP_STATELESS_MEDIA_HASH_FILENAME' => 'WP_STATELESS_MEDIA_CACHE_BUSTING'], 'false'),
48 );
49
50 private $network_only_settings = array(
51 'hide_settings_panel' => array('WP_STATELESS_MEDIA_HIDE_SETTINGS_PANEL', false),
52 'hide_setup_assistant' => array('WP_STATELESS_MEDIA_HIDE_SETUP_ASSISTANT', false),
53 );
54
55 private $strings = array(
56 'network' => 'Currently configured via Network Settings.',
57 'constant' => 'Currently configured via a constant.',
58 'environment' => 'Currently configured via an environment variable.',
59 );
60
61 /**
62 *
63 * Settings constructor.
64 * @param null $bootstrap
65 */
66 public function __construct($bootstrap = null) {
67 $this->bootstrap = $bootstrap ? $bootstrap : ud_get_stateless_media();
68
69
70 /* Add 'Settings' link for SM plugin on plugins page. */
71 $_basename = plugin_basename( $this->bootstrap->boot_file );
72
73 parent::__construct( array(
74 'store' => 'options',
75 'format' => 'json',
76 'data' => array(
77 'sm' => array()
78 )
79 ));
80
81 // Setting sm variable
82 $this->refresh();
83
84 $this->set('page_url.stateless_setup', $this->bootstrap->get_settings_page_url('?page=stateless-setup'));
85 $this->set('page_url.stateless_settings', $this->bootstrap->get_settings_page_url('?page=stateless-settings'));
86
87 /** Register options */
88 add_action( 'init', array( $this, 'init' ), 3 );
89 // apply wildcard to root dir.
90 add_filter( 'wp_stateless_handle_root_dir', array( $this, 'root_dir_wildcards' ), 10, 3);
91
92 // Parse root dir by wildcards
93 add_filter( 'wp_stateless_unhandle_root_dir', array( $this, 'parse_root_dir_wildcards' ), 10, 3);
94
95 $site_url = parse_url( site_url() );
96 $site_url['path'] = isset($site_url['path']) ? $site_url['path'] : '';
97 $this->wildcards = array(
98 'sites' => [
99 'sites',
100 __("sites", $this->bootstrap->domain),
101 __("Sites uses for multisite.", $this->bootstrap->domain),
102 ],
103 '%site_id%' => [
104 get_current_blog_id(),
105 __("site id", $this->bootstrap->domain),
106 __("Site ID, for example 1.", $this->bootstrap->domain),
107 ],
108 '%site_url%' => [
109 trim( $site_url['host'] . $site_url['path'], '/ ' ),
110 __("site url", $this->bootstrap->domain),
111 __("Site URL, for example example.com/site-1.", $this->bootstrap->domain),
112 ],
113 '%site_url_host%' => [
114 trim( $site_url['host'], '/ ' ),
115 __("host name", $this->bootstrap->domain),
116 __("Host name, for example example.com.", $this->bootstrap->domain),
117 ],
118 '%site_url_path%' => [
119 trim( $site_url['path'], '/ ' ),
120 __("site path", $this->bootstrap->domain),
121 __("Site path, for example site-1.", $this->bootstrap->domain),
122 ],
123 '%date_year/date_month%' => [
124 date('Y').'/'.date('m'),
125 __("year and monthnum", $this->bootstrap->domain),
126 __("The year of the post, four digits, for example 2004. Month of the year, for example 05", $this->bootstrap->domain),
127 "\d{4}\/\d{2}"
128 ]
129 );
130 }
131
132 /**
133 * Init
134 */
135 public function init(){
136 $this->save_media_settings();
137
138 add_action('admin_menu', array( $this, 'admin_menu' ));
139 /**
140 * Manage specific Network Settings
141 */
142 if( is_network_admin() ) {
143 add_action( 'network_admin_menu', array( $this, 'network_admin_menu' ));
144 }
145
146 }
147
148 /**
149 * Refresh settings
150 */
151 public function refresh() {
152 $this->set( "sm.readonly", []);
153 $google_app_key_file = getenv('GOOGLE_APPLICATION_CREDENTIALS') ?: getenv('GOOGLE_APPLICATION_CREDENTIALS');
154
155 foreach ($this->settings as $option => $array) {
156 $value = '';
157 $_option = 'sm_' . $option;
158 $constant = $array[0]; // Constant name
159 $default = is_array($array[1]) ? $array[1] : array($array[1], $array[1]); // Default value
160
161 // Getting settings
162 $value = get_option($_option, $default[0]);
163
164 if ($option == 'body_rewrite_types' && empty($value) && !is_multisite()) {
165 $value = $default[0];
166 }
167
168 if ($option == 'hashify_file_name' && in_array($this->get("sm.mode"), array( 'stateless', 'ephemeral' ) )) {
169 $value = true;
170 }
171
172 // If constant is set then override by constant
173 if(is_array($constant)){
174 foreach($constant as $old_const => $new_const){
175 if(defined($new_const)){
176 $value = constant($new_const);
177 $this->set( "sm.readonly.{$option}", "constant" );
178 break;
179 }
180 if(is_string($old_const) && defined($old_const)){
181 $value = constant($old_const);
182 $this->bootstrap->errors->add( array(
183 'key' => $new_const,
184 'title' => sprintf( __( "%s: Deprecated Notice (%s)", $this->bootstrap->domain ), $this->bootstrap->name, $new_const ),
185 'message' => sprintf(__("<i>%s</i> constant is deprecated, please use <i>%s</i> instead.", $this->bootstrap->domain), $old_const, $new_const),
186 ), 'notice' );
187 $this->set( "sm.readonly.{$option}", "constant" );
188 break;
189 }
190 }
191 }
192 elseif(defined($constant)){
193 $value = constant($constant);
194 $this->set( "sm.readonly.{$option}", "constant" );
195 }
196
197 // Getting network settings
198 if(is_multisite() && $option != 'organize_media' && !$this->get( "sm.readonly.{$option}")){
199
200 $network = get_site_option( $_option, $default[1] );
201 // If network settings available then override by network settings.
202 if($network || is_network_admin()){
203 $value = $network;
204 if(!is_network_admin())
205 $this->set( "sm.readonly.{$option}", "network" );
206 }
207
208 }
209
210 // Converting to string true false for angular.
211 if(is_bool($value)){
212 $value = $value === true ? "true" : "false";
213 }
214
215 $this->set( "sm.$option", $value);
216 }
217
218 // Network only settings, to hide settings page
219 foreach ($this->network_only_settings as $option => $array) {
220 $value = '';
221 $_option = 'sm_' . $option;
222 $constant = $array[0]; // Constant name
223 $default = $array[1]; // Default value
224
225 // If constant is set then override by constant
226 if(is_array($constant)){
227 foreach($constant as $old_const => $new_const){
228 if(defined($new_const)){
229 $value = constant($new_const);
230 break;
231 }
232 if(is_string($old_const) && defined($old_const)){
233 $value = constant($old_const);
234 trigger_error(__(sprintf("<i>%s</i> constant is deprecated, please use <i>%s</i> instead.", $old_const, $new_const)), E_USER_WARNING);
235 break;
236 }
237 }
238 }
239 elseif(defined($constant)){
240 $value = constant($constant);
241 }
242 // Getting network settings
243 elseif(is_multisite()){
244 $value = get_site_option( $_option, $default );
245 }
246
247 // Converting to string true false for angular.
248 if(is_bool($value)){
249 $value = $value === true ? "true" : "false";
250 }
251
252 $this->set( "sm.$option", $value);
253 }
254
255 /**
256 * JSON key file path
257 */
258 /* Use constant value for JSON key file path, if set. */
259 if (defined('WP_STATELESS_MEDIA_KEY_FILE_PATH') || $google_app_key_file !== false) {
260 /* Maybe fix the path to p12 file. */
261 $key_file_path = (defined('WP_STATELESS_MEDIA_KEY_FILE_PATH')) ? WP_STATELESS_MEDIA_KEY_FILE_PATH : $google_app_key_file;
262
263 if( !empty( $key_file_path ) ) {
264 $upload_dir = wp_upload_dir();
265 /* Check if file exists */
266 switch( true ) {
267 /* Determine if default path is correct */
268 case (file_exists($key_file_path)):
269 /* Path is correct. Do nothing */
270 break;
271 /* Look using WP root. */
272 case (file_exists( ABSPATH . $key_file_path ) ):
273 $key_file_path = ABSPATH . $key_file_path;
274 break;
275 /* Look in wp-content dir */
276 case (file_exists( WP_CONTENT_DIR . $key_file_path ) ):
277 $key_file_path = WP_CONTENT_DIR . $key_file_path;
278 break;
279 /* Look in uploads dir */
280 case (file_exists( wp_normalize_path( $upload_dir[ 'basedir' ] ) . '/' . $key_file_path ) ):
281 $key_file_path = wp_normalize_path( $upload_dir[ 'basedir' ] ) . '/' . $key_file_path;
282 break;
283 /* Look using Plugin root */
284 case (file_exists($this->bootstrap->path( $key_file_path, 'dir') ) ):
285 $key_file_path = $this->bootstrap->path( $key_file_path, 'dir' );
286 break;
287
288 }
289 if(is_readable($key_file_path)) {
290 $this->set( 'sm.key_json', file_get_contents($key_file_path) );
291 if(defined('WP_STATELESS_MEDIA_KEY_FILE_PATH'))
292 $this->set( "sm.readonly.key_json", "constant" );
293 else
294 $this->set("sm.readonly.key_json", "environment");
295 }
296 }
297 }
298
299 $this->set( 'sm.strings', $this->strings );
300 }
301
302 /**
303 * Remove settings
304 * @param bool $network
305 */
306 public function reset($network = false) {
307 foreach ($this->settings as $option => $array) {
308 if($option == 'organize_media')
309 continue;
310 $_option = 'sm_' . $option;
311
312 if($network && current_user_can('manage_network')){
313 delete_site_option($_option);
314 delete_option($_option);
315 }
316 else{
317 delete_option($_option);
318 }
319 }
320
321 foreach ($this->network_only_settings as $option => $array) {
322 $_option = 'sm_' . $option;
323 if($network && current_user_can('manage_network')){
324 delete_site_option($_option);
325 delete_option($_option);
326 }
327 }
328
329 $this->set('sm', []);
330 $this->refresh();
331 }
332
333 /**
334 * Replacing wildcards with real values
335 * @param $root_dir
336 * @param bool $regex
337 * @param array $current_values
338 * @return mixed|null|string|string[]
339 *
340 */
341 public function root_dir_wildcards( $root_dir, $regex = false, $current_values = [] ) {
342
343 $not_allowed_char = '/[^A-Za-z0-9\/_.\.\-]/';
344 $wildcards = apply_filters('wp_stateless_root_dir_wildcard', $this->wildcards);
345
346 if($regex){
347 $root_dir = preg_quote($root_dir);
348 $not_allowed_char = '/[^A-Za-z0-9\/_.\.\-\\\\{}]/';
349 }
350
351 if ( is_array( $wildcards ) && !empty( $wildcards ) ) {
352 foreach ($wildcards as $wildcard => $values) {
353 if (!empty($wildcard)) {
354 $replace = $values[0];
355 if($regex){
356 $replace = isset($values[3]) ? $values[3] : preg_quote($values[0]);
357 }
358 if ( isset($current_values[$wildcard]) ) {
359 $replace = $current_values[$wildcard];
360 }
361 $root_dir = str_replace($wildcard, $replace, $root_dir);
362 }
363 }
364 }
365
366 //removing all special chars except slash
367 $root_dir = preg_replace($not_allowed_char, '', $root_dir);
368 $root_dir = preg_replace('/(\/+)/', '/', $root_dir);
369 $root_dir = trim( $root_dir, '/ ' ); // Remove any forward slash and empty space.
370
371 return $root_dir;
372 }
373
374
375 /**
376 * Parse path by wildcards and return array ('wildcard' => 'value')
377 * The perpose of this filter is to return Y/M or other dynamic fields from the file path.
378 * For now only Y/M is dynamic. We will get it via using regex.
379 * @param $path
380 * @return array
381 */
382 public function parse_root_dir_wildcards ( $path ) {
383 $result = [];
384
385 /**
386 * removing GS host from path
387 */
388 $gs_url = $this->bootstrap->get_gs_host();
389 if( 0 === strpos( $path, $gs_url . '/' ) ) {
390 $path = substr( $path, strlen( $gs_url . '/' ) );
391 }
392
393 /**
394 * removing filename and last slash
395 */
396 $path = untrailingslashit( str_replace(basename($path), '', $path) );
397 $wildcards = apply_filters('wp_stateless_root_dir_wildcard', $this->wildcards);
398
399 /**
400 * Checking if a wildcard have regex field in it.
401 * Then return the matching value using regex.
402 */
403 foreach ($wildcards as $key => $value) {
404 if(isset($value[3])){
405 if(preg_match("@" . $value[3] . "@", $path, $matches)){
406 $result[$key] = $matches[0];
407 }
408 }
409 }
410
411 return $result;
412 }
413
414
415
416 /**
417 * Add menu options
418 */
419 public function admin_menu() {
420 $key_json = $this->get('sm.key_json');
421 if($this->get('sm.hide_setup_assistant') != 'true' && empty($key_json) ){
422 $this->setup_wizard_ui = add_media_page( __( 'Stateless Setup', $this->bootstrap->domain ), __( 'Stateless Setup', $this->bootstrap->domain ), 'manage_options', 'stateless-setup', array($this, 'setup_wizard_interface') );
423 }
424
425 if($this->get('sm.hide_settings_panel') != 'true'){
426 $this->stateless_settings = add_media_page( __( 'Stateless Settings', $this->bootstrap->domain ), __( 'Stateless Settings', $this->bootstrap->domain ), 'manage_options', 'stateless-settings', array($this, 'settings_interface') );
427 }
428 }
429
430 /**
431 * Add menu options
432 * @param $slug
433 */
434 public function network_admin_menu($slug) {
435 $this->setup_wizard_ui = add_submenu_page( 'settings.php', __( 'Stateless Setup', $this->bootstrap->domain ), __( 'Stateless Setup', $this->bootstrap->domain ), 'manage_options', 'stateless-setup', array($this, 'setup_wizard_interface') );
436 $this->stateless_settings = add_submenu_page( 'settings.php', __( 'Stateless Settings', $this->bootstrap->domain ), __( 'Stateless Settings', $this->bootstrap->domain ), 'manage_options', 'stateless-settings', array($this, 'settings_interface') );
437 }
438
439 /**
440 * Draw interface
441 */
442 public function settings_interface() {
443 $wildcards = apply_filters('wp_stateless_root_dir_wildcard', $this->wildcards);
444 $wildcard_year_month = '%date_year/date_month%';
445 $root_dir = $this->get( 'sm.root_dir' );
446
447 $use_year_month = (strpos($root_dir, $wildcard_year_month) !== false) ?: false;
448
449 /**
450 * removing year/month wildcard
451 */
452 if ($use_year_month) {
453 $root_dir = str_replace($wildcard_year_month, '%YM%', $root_dir);
454 }
455
456 /**
457 * preparing array with wildcards
458 */
459 $root_dir_values = explode('/', $root_dir);
460
461 /**
462 * adding year/month wildcard
463 */
464 if ($use_year_month) {
465 if ( !empty($root_dir_values) ) {
466 foreach( $root_dir_values as $k=>$root_dir_value ) {
467 if ( $root_dir_value == '%YM%' ) {
468 $root_dir_values[$k] = $wildcard_year_month;
469 }
470 }
471 } else {
472 $root_dir_values[] = $wildcard_year_month;
473 }
474 }
475
476 /**
477 * first slash
478 */
479 array_unshift($root_dir_values , '/');
480
481 /**
482 * removing empty values
483 */
484 $root_dir_values = array_filter($root_dir_values);
485
486 /**
487 * merging user's wildcards with default values
488 */
489 if (!empty($root_dir_values)) {
490 $wildcards = array_merge(array_flip($root_dir_values), $wildcards);
491 }
492
493 include $this->bootstrap->path( '/static/views/settings_interface.php', 'dir' );
494 }
495
496 /**
497 * Draw interface
498 */
499 public function regenerate_interface() {
500 include $this->bootstrap->path( '/static/views/regenerate_interface.php', 'dir' );
501 }
502
503 /**
504 * Draw interface
505 */
506 public function setup_wizard_interface() {
507 include ud_get_stateless_media()->path( '/static/views/setup_wizard_interface.php', 'dir' );
508 }
509
510 /**
511 * Handles saving SM data.
512 *
513 * @author alim@UD
514 */
515 public function save_media_settings(){
516 if(isset($_POST['action']) && $_POST['action'] == 'stateless_settings' && wp_verify_nonce( $_POST['_smnonce'], 'wp-stateless-settings' )){
517
518 $settings = apply_filters('stateless::settings::save', $_POST['sm']);
519 $root_dir_value = false;
520
521 foreach ( $settings as $name => $value ) {
522
523 /**
524 * root_dir settings
525 */
526 if ( 'root_dir' == $name && is_array($value) ) {
527 //managed in WP-Stateless settings (via Bucket Folder control)
528 if ( in_array('%date_year/date_month%', $value)) {
529 update_option( 'uploads_use_yearmonth_folders', '1' );
530 } else {
531 update_option( 'uploads_use_yearmonth_folders', '0' );
532 }
533
534 /**
535 * preparing path from tags
536 */
537 $value = implode('/', $value);
538 $root_dir_value = true;
539 }
540
541 $option = 'sm_'. $name;
542
543 if($name == 'organize_media'){
544 $option = 'uploads_use_yearmonth_folders';
545 }
546 elseif($name == 'key_json'){
547 $value = stripslashes($value);
548 }
549
550 // Be sure to cleanup values before saving
551 $value = trim($value);
552
553 if(is_network_admin()){
554 update_site_option( $option, $value );
555 }
556 else{
557 update_option( $option, $value );
558 }
559 }
560
561 if ( !$root_dir_value ) {
562 if(is_network_admin()){
563 update_site_option( 'sm_root_dir', '' );
564 }
565 else{
566 update_option( 'sm_root_dir', '' );
567 }
568 }
569
570 $this->bootstrap->flush_transients();
571 $this->refresh();
572 }
573 }
574
575 /**
576 * Wrapper for setting value.
577 * @param string $key
578 * @param bool $value
579 * @param bool $bypass_validation
580 * @return \UsabilityDynamics\Settings
581 */
582 public function set( $key = '', $value = false, $bypass_validation = false ) {
583 return parent::set( $key, $value, $bypass_validation );
584 }
585
586 }
587
588 }
589
590 }
591