* @copyright Copyright (c) 2012 - 2017, Cherry Team * @link http://www.cherryframework.com/ * @license http://www.gnu.org/licenses/gpl-3.0.html */ // If this file is called directly, abort. if ( ! defined( 'WPINC' ) ) { die; } if ( ! class_exists( 'Cherry_Interface_Builder' ) ) { /** * Class Cherry Interface Builder. * * @since 1.0.0 */ class Cherry_Interface_Builder { /** * Core version. * * @since 1.5.0 * @access public * @var string */ public $core_version = ''; /** * Module directory path. * * @since 1.5.0 * @access protected * @var srting. */ protected $module_path; /** * Module settings. * * @since 1.0.0 * @access private * @var array */ private $args = array( 'views' => array( 'section' => 'inc/views/section.php', 'component-tab-vertical' => 'inc/views/component-tab-vertical.php', 'component-tab-horizontal' => 'inc/views/component-tab-horizontal.php', 'component-toggle' => 'inc/views/component-toggle.php', 'component-accordion' => 'inc/views/component-accordion.php', 'component-repeater' => 'inc/views/component-repeater.php', 'settings' => 'inc/views/settings.php', 'control' => 'inc/views/control.php', 'settings-children-title' => 'inc/views/settings-children-title.php', 'tab-children-title' => 'inc/views/tab-children-title.php', 'toggle-children-title' => 'inc/views/toggle-children-title.php', 'form' => 'inc/views/form.php', 'html' => 'inc/views/html.php', ), 'views_args' => array( 'parent' => '', 'type' => '', 'view' => '', 'view_wrapping' => true, 'html' => '', 'scroll' => false, 'master' => false, 'title' => '', 'description' => '', ), ); /** * A reference to an instance of this class. * * @since 1.0.0 * @access private * @var object */ private static $instance = null; /** * UI element instance. * * @since 1.0.0 * @access public * @var object */ public $ui_elements = null; /** * The structure of the interface elements. * * @since 1.0.0 * @access private * @var array */ private $structure = array(); /** * Cherry_Interface_Builder constructor. * * @since 1.0.0 * @access public * @return void */ public function __construct( $core, array $args = array() ) { $this->args = array_merge_recursive( $args, $this->args ); $this->core_version = $core->get_core_version(); $this->module_path = $args['module_path']; $this->ui_elements = $core->init_module( 'cherry-ui-elements' ); add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_assets' ) ); } /** * Register element type section. * * @since 1.0.0 * @access public * @param array $args Options section. * @return void */ public function register_section( array $args = array() ) { $this->add_new_element( $args, 'section' ); } /** * Register element type component. * * @since 1.0.0 * @access public * @param array $args Options component. * @return void */ public function register_component( array $args = array() ) { $this->add_new_element( $args, 'component' ); } /** * Register element type settings. * * @since 1.0.0 * @access public * @param array $args Options settings. * @return void */ public function register_settings( array $args = array() ) { $this->add_new_element( $args, 'settings' ); } /** * Register element type control. * * @since 1.0.0 * @access public * @param array $args Options control. * @return void */ public function register_control( array $args = array() ) { $this->add_new_element( $args, 'control' ); } /** * Register element type form. * * @since 1.0.0 * @access public * @param array $args Options form. * @return void */ public function register_form( array $args = array() ) { $this->add_new_element( $args, 'form' ); } /** * Register element type html. * * @since 1.0.0 * @access public * @param array $args Options control. * @return void */ public function register_html( array $args = array() ) { $this->add_new_element( $args, 'html' ); } /** * This function adds a new element to the structure. * * @since 1.0.0 * @access protected * @param array $args Options new element. * @param string $type Type new element. * @return void */ protected function add_new_element( array $args = array(), $type = 'section' ) { if ( ! isset( $args[0] ) && ! is_array( current( $args ) ) ) { if ( 'control' !== $type && 'component' !== $type ) { $args['type'] = $type; } $this->structure[ $args['id'] ] = $args; } else { foreach ( $args as $key => $value ) { if ( 'control' !== $type && 'component' !== $type ) { $value['type'] = $type; } $this->structure[ $key ] = $value; } } } /** * Sorts the elements of the structure, adding child items to the parent. * * @since 1.0.0 * @access protected * @param array $structure The original structure of the elements. * @param string $parent_key The key of the parent element. * @return array */ protected function sort_structure( array $structure = array(), $parent_key = null ) { $new_array = array(); foreach ( $structure as $key => $value ) { if ( ( null === $parent_key && ! isset( $value['parent'] ) ) || null === $parent_key && ! isset( $structure[ $value['parent'] ] ) || ( isset( $value['parent'] ) && $value['parent'] === $parent_key ) ) { if ( ! isset( $value['id'] ) ) { $value['id'] = $key; } if ( ! isset( $value['name'] ) ) { $value['name'] = $key; } $new_array[ $key ] = $value; $children = $this->sort_structure( $structure, $key ); if ( ! empty( $children ) ) { $new_array[ $key ]['children'] = $children; } } } return $new_array; } /** * Reset structure array. * Call this method only after render. * * @since 1.0.1 * @return void */ public function reset_structure() { $this->structure = array(); } /** * Get view for interface elements. * * @since 1.0.0 * @access protected * @param string $type View type. * @param array $args Input data. * @return string */ protected function get_view( $type = 'control', array $args = array() ) { if ( empty( $args['view'] ) ) { $path = ( array_key_exists( $type, $this->args['views'] ) ) ? $this->args['views'][ $type ] : $this->args['views']['control']; $path = is_array( $path ) ? $path[0] : $path; $path = file_exists( $path ) ? $path : $this->module_path . $path; } else { $path = $args['view']; } return Cherry_Toolkit::render_view( $path, $args ); } /** * Render HTML elements. * * @since 1.0.0 * @access public * @param bool $echo Input data. * @param array $args The original structure of the elements. * @return string */ public function render( $echo = true, array $args = array() ) { if ( empty( $args ) ) { $args = $this->structure; } if ( empty( $args ) ) { return false; } $sorted_structure = $this->sort_structure( $args ); $output = $this->build( $sorted_structure ); $output = str_replace( array( "\r\n", "\r", "\n", "\t" ), '', $output ); $this->reset_structure(); return $this->output_method( $output, $echo ); } /** * Render HTML elements. * * @since 1.0.0 * @access protected * @param array $args Input data. * @return string */ protected function build( array $args = array() ) { $output = ''; $views = $this->args['views']; foreach ( $args as $key => $value ) { $value = wp_parse_args( $value, $this->args['views_args'] ); $value['class'] = isset( $value['class'] ) ? $value['class'] . ' ' : ''; $value['class'] .= $value['id'] . ' '; if ( $value['scroll'] ) { $value['class'] .= 'cherry-scroll '; } if ( $value['master'] ) { $value['class'] .= $value['master'] . ' '; } $type = array_key_exists( $value['type'], $views ) ? $value['type'] : 'field'; $has_child = isset( $value['children'] ) && is_array( $value['children'] ) && ! empty( $value['children'] ); switch ( $type ) { case 'component-tab-vertical': case 'component-tab-horizontal': if ( $has_child ) { $value['tabs'] = ''; foreach ( $value['children'] as $key_children => $value_children ) { $value['tabs'] .= $this->get_view( 'tab-children-title', $value_children ); unset( $value['children'][ $key_children ]['title'] ); } } break; case 'component-toggle': case 'component-accordion': if ( $has_child ) { foreach ( $value['children'] as $key_children => $value_children ) { $value['children'][ $key_children ]['title_in_view'] = $this->get_view( 'toggle-children-title', $value_children ); } } break; case 'settings': if ( isset( $value['title'] ) && $value['title'] ) { $value['title'] = isset( $value['title_in_view'] ) ? $value['title_in_view'] : $this->get_view( 'settings-children-title', $value ); } break; case 'html': $value['children'] = $value['html']; break; case 'form': $value['accept-charset'] = isset( $value['accept-charset'] ) ? $value['accept-charset'] : 'utf-8'; $value['action'] = isset( $value['action'] ) ? $value['action'] : '' ; $value['autocomplete'] = isset( $value['autocomplete'] ) ? $value['autocomplete'] : 'on'; $value['enctype'] = isset( $value['enctype'] ) ? $value['enctype'] : 'application/x-www-form-urlencoded'; $value['method'] = isset( $value['method'] ) ? $value['method'] : 'post'; $value['novalidate'] = ( isset( $value['novalidate'] ) && $value['novalidate'] ) ? 'novalidate' : ''; $value['target'] = isset( $value['target'] ) ? $value['target'] : ''; break; case 'field': $ui_args = $value; $ui_args['class'] = isset( $ui_args['child_class'] ) ? $ui_args['child_class'] : '' ; if ( isset( $ui_args['options_callback'] ) ) { $ui_args['options'] = call_user_func( $ui_args['options_callback'] ); } unset( $ui_args['master'] ); $value['children'] = $this->ui_elements->get_ui_element_instance( $ui_args['type'], $ui_args )->render(); break; } if ( $has_child ) { $value['children'] = $this->build( $value['children'] ); } $output .= ( $value['view_wrapping'] ) ? $this->get_view( $type, $value ) : $value['children']; } return $output; } /** * Output HTML. * * @since 1.0.0 * @access protected * @param string $output Output HTML. * @param boolean $echo Output type. * @return string */ protected function output_method( $output = '', $echo = true ) { if ( ! filter_var( $echo, FILTER_VALIDATE_BOOLEAN ) ) { return $output; } else { echo $output; } } /** * Enqueue javascript and stylesheet interface builder. * * @since 4.0.0 * @access public * @return void */ public function enqueue_assets() { wp_enqueue_script( 'cherry-interface-builder', esc_url( Cherry_Core::base_url( 'inc/assets/min/cherry-interface-builder.min.js', $this->module_path ) ), array( 'jquery' ), $this->core_version, true ); wp_enqueue_style( 'cherry-interface-builder', esc_url( Cherry_Core::base_url( 'inc/assets/min/cherry-interface-builder.min.css', $this->module_path ) ), array(), $this->core_version, 'all' ); } /** * Returns the instance. * * @since 1.0.0 * @access public * @return object */ public static function get_instance( $core, $args ) { // If the single instance hasn't been set, set it now. if ( null == self::$instance ) { self::$instance = new self( $core, $args ); } return self::$instance; } } }