balmet.com

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs

class-redux-wordpress-data.php (18652B)


      1 <?php
      2 /**
      3  * Redux WordPress Data Class
      4  *
      5  * @class   Redux_WordPress_Data
      6  * @version 3.0.0
      7  * @package Redux Framework
      8  */
      9 
     10 defined( 'ABSPATH' ) || exit;
     11 
     12 if ( ! class_exists( 'Redux_WordPress_Data', false ) ) {
     13 
     14 	/**
     15 	 * Class Redux_WordPress_Data
     16 	 */
     17 	class Redux_WordPress_Data extends Redux_Class {
     18 
     19 		/**
     20 		 * Holds WordPress data.
     21 		 *
     22 		 * @var null
     23 		 */
     24 		private $wp_data = null;
     25 
     26 		/**
     27 		 * Redux_WordPress_Data constructor.
     28 		 *
     29 		 * @param mixed $parent ReduxFramework pointer or opt_name.
     30 		 */
     31 		public function __construct( $parent = null ) {
     32 			if ( is_string( $parent ) ) {
     33 				$this->opt_name = $parent;
     34 			} else {
     35 				parent::__construct( $parent );
     36 			}
     37 		}
     38 
     39 		/**
     40 		 * Get the data.
     41 		 *
     42 		 * @param string|array $type          Type.
     43 		 * @param array|string $args          Args.
     44 		 * @param string       $opt_name      Opt name.
     45 		 * @param string|int   $current_value Current value.
     46 		 * @param bool         $ajax          Tells if this is an AJAX call.
     47 		 *
     48 		 * @return array|mixed|string
     49 		 */
     50 		public function get( $type, $args = array(), string $opt_name = '', $current_value = '', bool $ajax = false ) {
     51 			$opt_name = $this->opt_name;
     52 
     53 			// We don't want to run this, it's not a string value. Send it back!
     54 			if ( is_array( $type ) ) {
     55 				return $type;
     56 			}
     57 
     58 			/**
     59 			 * Filter 'redux/options/{opt_name}/pre_data/{type}'
     60 			 *
     61 			 * @param string $data
     62 			 */
     63 			$pre_data = apply_filters( "redux/options/$opt_name/pre_data/$type", null ); // phpcs:ignore WordPress.NamingConventions.ValidHookName
     64 			if ( null !== $pre_data || empty( $type ) ) {
     65 				return $pre_data;
     66 			}
     67 
     68 			if ( isset( $args['data_sortby'] ) && in_array( $args['data_sortby'], array( 'value', 'key' ), true ) ) {
     69 				$data_sort = $args['data_sortby'];
     70 				unset( $args['data_sortby'] );
     71 			} else {
     72 				$data_sort = 'value';
     73 			}
     74 			if ( isset( $args['data_order'] ) && in_array( $args['data_order'], array( 'asc', 'desc' ), true ) ) {
     75 				$data_order = $args['data_order'];
     76 				unset( $args['data_order'] );
     77 			} else {
     78 				$data_order = 'asc';
     79 			}
     80 
     81 			$this->maybe_get_translation( $type, $current_value, $args );
     82 
     83 			$current_data = array();
     84 			if ( empty( $current_value ) && ! Redux_Helpers::is_integer( $current_value ) ) {
     85 				$current_value = null;
     86 			} else {
     87 				// Get the args to grab the current data.
     88 				$current_data_args = $this->get_current_data_args( $type, $args, $current_value );
     89 
     90 				// Let's make a unique key for this arg array.
     91 				$current_data_args_key = md5( maybe_serialize( $current_data_args ) );
     92 
     93 				// Check to make sure we haven't already run this call before.
     94 				$current_data = $this->wp_data[ $type . $current_data_args_key ] ?? $this->get_data( $type, $current_data_args, $current_value );
     95 			}
     96 
     97 			// If ajax is enabled AND $current_data is empty, set a dummy value for the init.
     98 			if ( $ajax && ! wp_doing_ajax() ) {
     99 				// Dummy is needed otherwise empty.
    100 				if ( empty( $current_data ) ) {
    101 					$current_data = array(
    102 						'dummy' => '',
    103 					);
    104 				}
    105 
    106 				return $current_data;
    107 			}
    108 
    109 			// phpcs:ignore Squiz.PHP.CommentedOutCode
    110 			$args_key = md5( maybe_serialize( $args ) );
    111 
    112 			// Data caching.
    113 			if ( isset( $this->wp_data[ $type . $args_key ] ) ) {
    114 				$data = $this->wp_data[ $type . $args_key ];
    115 			} else {
    116 				/**
    117 				 * Use data from WordPress to populate options array.
    118 				 * */
    119 				$data = $this->get_data( $type, $args, $current_value );
    120 			}
    121 
    122 			if ( ! empty( $current_data ) ) {
    123 				$data += $current_data;
    124 			}
    125 
    126 			if ( ! empty( $data ) ) {
    127 				$data                               = $this->order_data( $data, $data_sort, $data_order );
    128 				$this->wp_data[ $type . $args_key ] = $data;
    129 			}
    130 
    131 			/**
    132 			 * Filter 'redux/options/{opt_name}/data/{type}'
    133 			 *
    134 			 * @param string $data
    135 			 */
    136 
    137 			// phpcs:ignore WordPress.NamingConventions.ValidHookName
    138 			return apply_filters( "redux/options/$opt_name/data/$type", $data );
    139 		}
    140 
    141 
    142 		/**
    143 		 * Process the results into a proper array, fetching the data elements needed for each data type.
    144 		 *
    145 		 * @param array|WP_Error $results       Results to process in the data array.
    146 		 * @param string|bool    $id_key        Key on object/array that represents the ID.
    147 		 * @param string|bool    $name_key      Key on object/array that represents the name/text.
    148 		 * @param bool           $add_key       If true, the display key will appear in the text.
    149 		 * @param string|bool    $secondary_key If a data type you'd rather display a different ID as the display key.
    150 		 *
    151 		 * @return array
    152 		 */
    153 		private function process_results( $results = array(), $id_key = '', $name_key = '', bool $add_key = true, $secondary_key = 'slug' ): array {
    154 			$data = array();
    155 			if ( ! empty( $results ) && ! is_a( $results, 'WP_Error' ) ) {
    156 				foreach ( $results as $k => $v ) {
    157 					if ( empty( $id_key ) ) {
    158 						$key = $k;
    159 					} else {
    160 						if ( is_object( $v ) ) {
    161 							$key = $v->$id_key;
    162 						} elseif ( is_array( $v ) ) {
    163 							$key = $v[ $id_key ];
    164 						} else {
    165 							$key = $k;
    166 						}
    167 					}
    168 					if ( empty( $name_key ) ) {
    169 						$value = $v;
    170 					} else {
    171 						if ( is_object( $v ) ) {
    172 							$value = $v->$name_key;
    173 						} elseif ( is_array( $v ) ) {
    174 							$value = $v[ $name_key ];
    175 						} else {
    176 							$value = $v;
    177 						}
    178 					}
    179 					$display_key = $key;
    180 					if ( is_object( $v ) && isset( $v->$secondary_key ) ) {
    181 						$display_key = $v->$secondary_key;
    182 					} elseif ( ! is_object( $v ) && isset( $v[ $secondary_key ] ) ) {
    183 						$display_key = $v[ $secondary_key ];
    184 					}
    185 					$data[ $key ] = $value;
    186 					if ( $display_key !== $value && $add_key ) {
    187 						$data[ $key ] = $data[ $key ] . ' [' . $display_key . ']';
    188 					}
    189 				}
    190 			}
    191 
    192 			return $data;
    193 		}
    194 
    195 		/**
    196 		 * Order / Sort the data.
    197 		 *
    198 		 * @param array  $data  Data to sort.
    199 		 * @param string $sort  Way to sort. Accepts: key|value.
    200 		 * @param string $order Order of the sort. Accepts: asc|desc.
    201 		 *
    202 		 * @return array
    203 		 */
    204 		private function order_data( array $data = array(), string $sort = 'value', string $order = 'asc' ): array {
    205 			if ( 'key' === $sort ) {
    206 				if ( 'asc' === $order ) {
    207 					ksort( $data );
    208 				} else {
    209 					krsort( $data );
    210 				}
    211 			} elseif ( 'value' === $sort ) {
    212 				if ( 'asc' === $order ) {
    213 					asort( $data );
    214 				} else {
    215 					arsort( $data );
    216 				}
    217 			}
    218 
    219 			return $data;
    220 		}
    221 
    222 		/**
    223 		 * Fetch the data for a given type.
    224 		 *
    225 		 * @param string       $type          The data type we're fetching.
    226 		 * @param array|string $args          Arguments to pass.
    227 		 * @param mixed|array  $current_value If a current value already set in the database.
    228 		 *
    229 		 * @return array|null|string
    230 		 */
    231 		private function get_data( string $type, $args, $current_value ) {
    232 			$args = $this->get_arg_defaults( $type, $args );
    233 
    234 			$opt_name = $this->opt_name;
    235 			if ( empty( $args ) ) {
    236 				$args = array();
    237 			}
    238 
    239 			$data = array();
    240 			if ( isset( $args['args'] ) && empty( $args['args'] ) ) {
    241 				unset( $args['args'] );
    242 			}
    243 
    244 			$display_keys = false;
    245 			if ( isset( $args['display_keys'] ) ) {
    246 				$display_keys = true;
    247 				unset( $args['display_keys'] );
    248 			}
    249 
    250 			$secondary_key = 'slug';
    251 			if ( isset( $args['secondary_key'] ) ) {
    252 				$display_key = $args['secondary_key'];
    253 				unset( $args['secondary_key'] );
    254 			}
    255 
    256 			switch ( $type ) {
    257 				case 'categories':
    258 				case 'category':
    259 				case 'terms':
    260 				case 'term':
    261 					if ( isset( $args['taxonomies'] ) ) {
    262 						$args['taxonomy'] = $args['taxonomies'];
    263 						unset( $args['taxonomies'] );
    264 					}
    265 					$results = get_terms( $args );
    266 					$data    = $this->process_results( $results, 'term_id', 'name', $display_keys, $secondary_key );
    267 					break;
    268 
    269 				case 'pages':
    270 				case 'page':
    271 					$results = get_pages( $args );
    272 					$data    = $this->process_results( $results, 'ID', 'post_title', $display_keys, $secondary_key );
    273 					break;
    274 
    275 				case 'tags':
    276 				case 'tag':
    277 					$results = get_tags( $args );
    278 					$data    = $this->process_results( $results, 'term_id', 'name', $display_keys, $secondary_key );
    279 					break;
    280 
    281 				case 'menus':
    282 				case 'menu':
    283 					$results = wp_get_nav_menus( $args );
    284 					$data    = $this->process_results( $results, 'term_id', 'name', $display_keys, $secondary_key );
    285 					break;
    286 
    287 				case 'posts':
    288 				case 'post':
    289 					$results = get_posts( $args );
    290 					$data    = $this->process_results( $results, 'ID', 'post_title', $display_keys, $secondary_key );
    291 					break;
    292 
    293 				case 'users':
    294 				case 'user':
    295 					$results = get_users( $args );
    296 					$data    = $this->process_results( $results, 'ID', 'display_name', $display_keys, $secondary_key );
    297 					break;
    298 
    299 				case 'sites':
    300 				case 'site':
    301 					// WP > 4.6.
    302 					if ( function_exists( 'get_sites' ) && class_exists( 'WP_Site_Query' ) ) {
    303 						$sites = get_sites();
    304 						// WP < 4.6.
    305 					} elseif ( function_exists( 'wp_get_sites' ) ) {
    306 						$sites = wp_get_sites(); // phpcs:ignore WordPress.WP.DeprecatedFunctions
    307 					}
    308 					if ( isset( $sites ) ) {
    309 						$results = array();
    310 						foreach ( $sites as $site ) {
    311 							$site = (array) $site;
    312 							$k    = $site['blog_id'];
    313 							$v    = $site['domain'] . $site['path'];
    314 							$name = get_blog_option( $k, 'blogname' );
    315 							if ( ! empty( $name ) ) {
    316 								$v .= ' - [' . $name . ']';
    317 							}
    318 							$results[ $k ] = $v;
    319 						}
    320 						$data = $this->process_results( $results, '', '', $display_keys, $secondary_key );
    321 					}
    322 
    323 					break;
    324 
    325 				case 'taxonomies':
    326 				case 'taxonomy':
    327 				case 'tax':
    328 					$results = get_taxonomies( $args );
    329 					$data    = $this->process_results( $results, '', '', $display_keys, $secondary_key );
    330 					break;
    331 
    332 				case 'post_types':
    333 				case 'post_type':
    334 					global $wp_post_types;
    335 
    336 					$output = $args['output'];
    337 					unset( $args['output'] );
    338 					$operator = $args['operator'];
    339 					unset( $args['operator'] );
    340 
    341 					$post_types = get_post_types( $args, $output, $operator );
    342 
    343 					foreach ( $post_types as $name => $title ) {
    344 						if ( isset( $wp_post_types[ $name ]->labels->menu_name ) ) {
    345 							$data[ $name ] = $wp_post_types[ $name ]->labels->menu_name;
    346 						} else {
    347 							$data[ $name ] = ucfirst( $name );
    348 						}
    349 					}
    350 					break;
    351 
    352 				case 'menu_locations':
    353 				case 'menu_location':
    354 					global $_wp_registered_nav_menus;
    355 					foreach ( $_wp_registered_nav_menus as $k => $v ) {
    356 						$data[ $k ] = $v;
    357 						if ( ! has_nav_menu( $k ) ) {
    358 							$data[ $k ] .= ' ' . __( '[unassigned]', 'redux-framework' );
    359 						}
    360 					}
    361 					break;
    362 
    363 				case 'image_sizes':
    364 				case 'image_size':
    365 					global $_wp_additional_image_sizes;
    366 					$results = array();
    367 					foreach ( $_wp_additional_image_sizes as $size_name => $size_attrs ) {
    368 						$results[ $size_name ] = $size_name . ' - ' . $size_attrs['width'] . ' x ' . $size_attrs['height'];
    369 					}
    370 					$data = $this->process_results( $results, '', '', $display_keys, $secondary_key );
    371 
    372 					break;
    373 
    374 				case 'elusive-icons':
    375 				case 'elusive-icon':
    376 				case 'elusive':
    377 				case 'icons':
    378 				case 'font-icon':
    379 				case 'font-icons':
    380 					$fs    = Redux_Filesystem::get_instance();
    381 					$fonts = $fs->get_contents( Redux_Core::$dir . 'assets/css/vendor/elusive-icons.css' );
    382 					if ( ! empty( $fonts ) ) {
    383 						preg_match_all( '@\.el-(\w+)::before@', $fonts, $matches );
    384 						foreach ( $matches[1] as $item ) {
    385 							if ( 'before' === $item ) {
    386 								continue;
    387 							}
    388 							$data[ 'el el-' . $item ] = $item;
    389 						}
    390 					}
    391 
    392 					/**
    393 					 * Filter 'redux/font-icons'
    394 					 *
    395 					 * @param array $font_icons array of elusive icon classes
    396 					 *
    397 					 * @deprecated
    398 					 */
    399 
    400 					// phpcs:ignore WordPress.NamingConventions.ValidHookName
    401 					$font_icons = apply_filters( 'redux/font-icons', $data );
    402 
    403 					/**
    404 					 * Filter 'redux/{opt_name}/field/font/icons'
    405 					 *
    406 					 * @param array $font_icons array of elusive icon classes
    407 					 *
    408 					 * @deprecated
    409 					 */
    410 
    411 					// phpcs:ignore WordPress.NamingConventions.ValidHookName
    412 					$font_icons = apply_filters( "redux/$opt_name/field/font/icons", $font_icons );
    413 
    414 					break;
    415 
    416 				case 'dashicons':
    417 				case 'dashicon':
    418 				case 'dash':
    419 					$fs    = Redux_Filesystem::get_instance();
    420 					$fonts = $fs->get_contents( ABSPATH . WPINC . '/css/dashicons.css' );
    421 					if ( ! empty( $fonts ) ) {
    422 						preg_match_all( '@\.dashicons-(\w+):before@', $fonts, $matches );
    423 						foreach ( $matches[1] as $item ) {
    424 							if ( 'before' === $item ) {
    425 								continue;
    426 							}
    427 							$data[ 'dashicons dashicons-' . $item ] = $item;
    428 						}
    429 					}
    430 					break;
    431 
    432 				case 'roles':
    433 				case 'role':
    434 					global $wp_roles;
    435 					$results = $wp_roles->get_names();
    436 					$data    = $this->process_results( $results, '', '', $display_keys, $secondary_key );
    437 
    438 					break;
    439 
    440 				case 'sidebars':
    441 				case 'sidebar':
    442 					global $wp_registered_sidebars;
    443 					$data = $this->process_results( $wp_registered_sidebars, '', 'name', $display_keys, $secondary_key );
    444 					break;
    445 				case 'capabilities':
    446 				case 'capability':
    447 					global $wp_roles;
    448 					$results = array();
    449 					foreach ( $wp_roles->roles as $role ) {
    450 						foreach ( $role['capabilities'] as $key => $cap ) {
    451 							$results[ $key ] = ucwords( str_replace( '_', ' ', $key ) );
    452 						}
    453 					}
    454 					$data = $this->process_results( $results, '', '', $display_keys, $secondary_key );
    455 
    456 					break;
    457 
    458 				case 'capabilities_grouped':
    459 				case 'capability_grouped':
    460 				case 'capabilities_group':
    461 				case 'capability_group':
    462 					global $wp_roles;
    463 
    464 					foreach ( $wp_roles->roles as $k => $role ) {
    465 						$caps = array();
    466 						foreach ( $role['capabilities'] as $key => $cap ) {
    467 							$caps[ $key ] = ucwords( str_replace( '_', ' ', $key ) );
    468 						}
    469 						asort( $caps );
    470 						$data[ $role['name'] ] = $caps;
    471 					}
    472 
    473 					break;
    474 
    475 				case 'callback':
    476 					if ( ! empty( $args ) ) {
    477 						$data = call_user_func( $args, $current_value );
    478 					}
    479 					break;
    480 			}
    481 
    482 			return $data;
    483 		}
    484 
    485 
    486 		/**
    487 		 * Router for translation based on the given post type.
    488 		 *
    489 		 * @param string       $type          Type of data request.
    490 		 * @param mixed|array  $current_value Current value stored in DB.
    491 		 * @param array|string $args          Arguments for the call.
    492 		 */
    493 		private function maybe_get_translation( string $type, &$current_value = '', $args = array() ) {
    494 			switch ( $type ) {
    495 				case 'categories':
    496 				case 'category':
    497 					$this->maybe_translate( $current_value, 'category' );
    498 					break;
    499 
    500 				case 'pages':
    501 				case 'page':
    502 					$this->maybe_translate( $current_value, 'page' );
    503 					break;
    504 
    505 				case 'terms':
    506 				case 'term':
    507 					$this->maybe_translate( $current_value, $args['taxonomy'] ?? '' );
    508 					break;
    509 
    510 				case 'tags':
    511 				case 'tag':
    512 					$this->maybe_translate( $current_value, 'post_tag' );
    513 					break;
    514 
    515 				case 'menus':
    516 				case 'menu':
    517 					$this->maybe_translate( $current_value, 'nav_menu' );
    518 					break;
    519 
    520 				case 'post':
    521 				case 'posts':
    522 					$this->maybe_translate( $current_value, 'post' );
    523 					break;
    524 				default:
    525 					$this->maybe_translate( $current_value, '' );
    526 			}
    527 		}
    528 
    529 		/**
    530 		 * Maybe translate the values.
    531 		 *
    532 		 * @param mixed|array $value     Value.
    533 		 * @param mixed|array $post_type Post type.
    534 		 */
    535 		private function maybe_translate( &$value, $post_type ) {
    536 
    537 			// phpcs:ignore WordPress.NamingConventions.ValidHookName
    538 			$value = apply_filters( "redux/options/$this->opt_name/wordpress_data/translate/post_type_value", $value, $post_type );
    539 
    540 			// WPML Integration, see https://wpml.org/documentation/support/creating-multilingual-wordpress-themes/language-dependent-ids/.
    541 			if ( function_exists( 'icl_object_id' ) ) {
    542 				if ( has_filter( 'wpml_object_id' ) ) {
    543 					if ( Redux_Helpers::is_integer( $value ) ) {
    544 						$value = apply_filters( 'wpml_object_id', $value, $post_type, true );
    545 					} elseif ( is_array( $value ) ) {
    546 						$value = array_map(
    547 							function ( $val ) use ( $post_type ) {
    548 								return apply_filters( 'wpml_object_id', $val, $post_type, true );
    549 							},
    550 							$value
    551 						);
    552 					}
    553 				}
    554 			}
    555 		}
    556 
    557 		/**
    558 		 * Set the default arguments for a current query (existing data).
    559 		 *
    560 		 * @param string       $type          Type of data request.
    561 		 * @param array|string $args          Arguments for the call.
    562 		 * @param mixed|array  $current_value Current value stored in DB.
    563 		 *
    564 		 * @return array
    565 		 */
    566 		private function get_current_data_args( string $type, $args, $current_value ): array {
    567 			// In this section we set the default arguments for each data type.
    568 			switch ( $type ) {
    569 				case 'categories':
    570 				case 'category':
    571 				case 'pages':
    572 				case 'page':
    573 				case 'terms':
    574 				case 'term':
    575 				case 'users':
    576 				case 'user':
    577 					$args['include'] = $current_value;
    578 					break;
    579 				case 'tags':
    580 				case 'tag':
    581 					$args['get'] = 'all';
    582 					break;
    583 				case 'menus':
    584 				case 'menu':
    585 					$args['object_ids'] = $current_value;
    586 					break;
    587 				case 'post':
    588 				case 'posts':
    589 					if ( ! empty( $current_value ) ) {
    590 						$args['post__in'] = is_array( $current_value ) ? $current_value : array( $current_value );
    591 					}
    592 					break;
    593 
    594 				default:
    595 					$args = array();
    596 			}
    597 
    598 			return $args;
    599 		}
    600 
    601 
    602 		/**
    603 		 * Get default arguments for a given data type.
    604 		 *
    605 		 * @param string       $type Type of data request.
    606 		 * @param array|string $args Arguments for the call.
    607 		 *
    608 		 * @return array|string
    609 		 */
    610 		private function get_arg_defaults( string $type, $args = array() ) {
    611 			// In this section we set the default arguments for each data type.
    612 			switch ( $type ) {
    613 				case 'categories':
    614 				case 'category':
    615 					$args = wp_parse_args(
    616 						$args,
    617 						array(
    618 							'taxonomy' => 'category',
    619 						)
    620 					);
    621 					break;
    622 
    623 				case 'pages':
    624 				case 'page':
    625 					$args = wp_parse_args(
    626 						$args,
    627 						array(
    628 							'display_keys'   => true,
    629 							'posts_per_page' => 20,
    630 						)
    631 					);
    632 					break;
    633 
    634 				case 'post_type':
    635 				case 'post_types':
    636 					$args = wp_parse_args(
    637 						$args,
    638 						array(
    639 							'public'              => true,
    640 							'exclude_from_search' => false,
    641 							'output'              => 'names',
    642 							'operator'            => 'and',
    643 						)
    644 					);
    645 
    646 					break;
    647 
    648 				case 'tag':
    649 				case 'tags':
    650 					$args = wp_parse_args(
    651 						$args,
    652 						array(
    653 							'get'          => 'all',
    654 							'display_keys' => true,
    655 						)
    656 					);
    657 					break;
    658 
    659 				case 'sidebars':
    660 				case 'sidebar':
    661 				case 'capabilities':
    662 				case 'capability':
    663 					$args = wp_parse_args(
    664 						$args,
    665 						array(
    666 							'display_keys' => true,
    667 						)
    668 					);
    669 					break;
    670 
    671 				case 'capabilities_grouped':
    672 				case 'capability_grouped':
    673 				case 'capabilities_group':
    674 				case 'capability_group':
    675 					$args = wp_parse_args(
    676 						$args,
    677 						array(
    678 							'data_sortby' => '',
    679 						)
    680 					);
    681 					break;
    682 
    683 			}
    684 
    685 			return $args;
    686 		}
    687 	}
    688 }