Skip to content
Snippets Groups Projects
class-settings.php 9.49 KiB
Newer Older
Lucas García's avatar
Lucas García committed
<?php

namespace WPCT_ABSTRACT;
Lucas García's avatar
Lucas García committed

if (!class_exists('\WPCT_ABSTRACT\Settings')) :
Lucas García's avatar
Lucas García committed

Lucas García's avatar
Lucas García committed
    {
Lucas García's avatar
Lucas García committed

    abstract class Settings extends Singleton
Lucas García's avatar
Lucas García committed
    {
Lucas García's avatar
Lucas García committed
        public static $schemas = [];
        public static $defaults = [];
Lucas García's avatar
Lucas García committed
        private static $cache = [];
Lucas García's avatar
Lucas García committed

        abstract public function register();
Lucas García's avatar
Lucas García committed

Lucas García's avatar
Lucas García committed
        public static function get_setting($group_name, $setting, $field = null)
Lucas García's avatar
Lucas García committed
            $default = static::get_default($group_name, $setting);
Lucas García's avatar
Lucas García committed
            $setting_name = $group_name . '_' . $setting;
            $setting = isset(static::$cache[$setting_name]) ? static::$cache[$setting_name] : get_option($setting_name, $default);
Lucas García's avatar
Lucas García committed
            static::$cache[$setting_name] = $setting;
Lucas García's avatar
Lucas García committed
            if ($field === null) {
                return $setting;
Lucas García's avatar
Lucas García committed
            return isset($setting[$field]) ? $setting[$field] : null;
Lucas García's avatar
Lucas García committed
        public static function get_default($group_name, $setting, $field = null)
Lucas García's avatar
Lucas García committed
            $setting_name = $group_name . '_' . $setting;
            $default = isset(static::$defaults[$setting_name]) ? static::$defaults[$setting_name] : [];
            $default = apply_filters($setting_name . '_default', $default);

Lucas García's avatar
Lucas García committed
            if ($field === null) {
                return $default;
Lucas García's avatar
Lucas García committed
            return isset($default[$field]) ? $default[$field] : null;
Lucas García's avatar
Lucas García committed
        public static function get_schema($group_name, $setting, $field = null)
Lucas García's avatar
Lucas García committed
        {
Lucas García's avatar
Lucas García committed
            $setting_name = $group_name . '_' . $setting;
Lucas García's avatar
Lucas García committed
            $schema = isset(static::$schemas[$setting_name]) ? static::$schemas[$setting_name] : [];
            $schema = apply_filters($setting_name . '_schema', $schema);

Lucas García's avatar
Lucas García committed
            if ($field === null) {
                return $schema;
Lucas García's avatar
Lucas García committed
            return isset($schema[$field]) ? $schema[$field] : null;
Lucas García's avatar
Lucas García committed
        public function __construct($group_name)
Lucas García's avatar
Lucas García committed
            $this->group_name = $group_name;
Lucas García's avatar
Lucas García committed

Lucas García's avatar
Lucas García committed
        public function get_group_name()
        {
            return $this->group_name;
Lucas García's avatar
Lucas García committed
        }

Lucas García's avatar
Lucas García committed
        public function get_settings()
        {
            $settings = [];
            foreach (array_keys(self::$defaults) as $setting) {
Lucas García's avatar
Lucas García committed
                if (strstr($setting, $this->group_name) !== false) {
Lucas García's avatar
Lucas García committed
                    $settings[] = $setting;
                }
            }

            return $settings;
        }

Lucas García's avatar
Lucas García committed
        public function register_setting($setting, $schema = null, $default = [])
Lucas García's avatar
Lucas García committed
            $setting_name = $this->setting_name($setting);
            self::$schemas[$setting_name] = $schema;
            self::$defaults[$setting_name] = $default;
Lucas García's avatar
Lucas García committed
            $default = self::get_default($this->group_name, $setting);
            $schema = self::get_schema($this->group_name, $setting);
Lucas García's avatar
Lucas García committed
                $setting_name,
                $setting_name,
Lucas García's avatar
Lucas García committed
                    'type' => 'object',
                    'show_in_rest' => $schema ? [
                        'name' => $setting_name,
Lucas García's avatar
Lucas García committed
                        'schema' => [
                            'type' => 'object',
                            'properties' => $schema
                        ],
                    ] : false,
                    'type' => 'object',
            add_action('add_option', function ($option, $value) use ($setting_name) {
                if ($option === $setting_name && !empty($to)) {
                    static::$cache[$setting_name] = $value;
                }
            }, 90, 2);

            add_action('update_option', function ($option, $from, $to) use ($setting_name) {
                if ($option === $setting_name && !empty($to)) {
                    static::$cache[$setting_name] = $to;
                }
            }, 90, 3);

Lucas García's avatar
Lucas García committed
            add_action('admin_init', function () use ($setting_name, $setting) {
Lucas García's avatar
Lucas García committed
                add_settings_section(
Lucas García's avatar
Lucas García committed
                    $setting_name . '_section',
                    __($setting_name . '--title', $this->group_name),
                    function () use ($setting_name) {
                        $title = __($setting_name . '--description', $this->group_name);
Lucas García's avatar
Lucas García committed
                        echo "<p>{$title}</p>";
                    },
Lucas García's avatar
Lucas García committed
                    $setting_name,
Lucas García's avatar
Lucas García committed
                foreach (array_keys(self::$defaults[$setting_name]) as $field) {
                    $this->add_settings_field($field, $setting);
Lucas García's avatar
Lucas García committed

Lucas García's avatar
Lucas García committed
        private function add_settings_field($field_name, $setting)
Lucas García's avatar
Lucas García committed
            $setting_name = $this->setting_name($setting);
            $field_id = $setting_name . '__' . $field_name;
            add_settings_field(
                $field_name,
                __($field_id . '--label', $this->group_name),
Lucas García's avatar
Lucas García committed
                function () use ($setting, $field_name) {
                    echo $this->field_render($setting, $field_name);
Lucas García's avatar
Lucas García committed
                $setting_name,
                $setting_name . '_section',
Lucas García's avatar
Lucas García committed
        }

Lucas García's avatar
Lucas García committed
        protected function field_render()
        {
            $args = func_get_args();
            $setting = $args[0];
            $field = $args[1];
            if (count($args) >= 3) {
                $value = $args[2];
            } else {
                $value = new Undefined();
Lucas García's avatar
Lucas García committed
            }

            return $this->_field_render($setting, $field, $value);
Lucas García's avatar
Lucas García committed
        }

        private function _field_render($setting, $field, $value)
        {
            $is_root = false;
            if ($value instanceof Undefined) {
Lucas García's avatar
Lucas García committed
                $value = self::get_setting($this->group_name, $setting, $field);
Lucas García's avatar
Lucas García committed
            }

            if (!is_array($value)) {
                return $this->input_render($setting, $field, $value);
            } else {
                $fieldset = $this->fieldset_render($setting, $field, $value);
                if ($is_root) {
                    $fieldset = $this->control_style($setting, $field)
                        . $fieldset . $this->control_render($setting, $field);
                }

                return $fieldset;
            }
Lucas García's avatar
Lucas García committed
        }

        protected function input_render($setting, $field, $value)
Lucas García's avatar
Lucas García committed
            $setting_name = $this->setting_name($setting);
            $schema = self::get_schema($this->group_name, $setting);
            $default_value = self::get_default($this->group_name, $setting);
            $keys = explode('][', $field);
            $is_list = is_list($default_value);
            for ($i = 0; $i < count($keys); $i++) {
                $key = $keys[$i];
                if ($is_list) {
                    $key = (int) $key;
                }
Lucas García's avatar
Lucas García committed
                $default_value = $default_value[$key];
                if ($i === 0) {
                    $schema = $schema[$key];
                }
                $is_list = is_list($default_value);
            }
            $is_bool = is_bool($default_value);
            if ($is_bool) {
                $is_bool = true;
                $value = 'on' === $value;
            }

            if ($is_bool) {
Lucas García's avatar
Lucas García committed
                return "<input type='checkbox' name='{$setting_name}[{$field}]' " . ($value ? 'checked' : '') . " />";
Lucas García's avatar
Lucas García committed
                return "<input type='text' name='{$setting_name}[{$field}]' value='{$value}' />";
Lucas García's avatar
Lucas García committed
        private function fieldset_render($setting, $field, $data)
Lucas García's avatar
Lucas García committed
            $setting_name = $this->setting_name($setting);
            $table_id = $setting_name . '__' . str_replace('][', '_', $field);
            $fieldset = "<table id='{$table_id}'>";
            $is_list = is_list($data);
            foreach (array_keys($data) as $key) {
                $fieldset .= '<tr>';
                if (!$is_list) {
                    $fieldset .= "<th>{$key}</th>";
                }
                $_field = $field . '][' . $key;
                $fieldset .= "<td>{$this->field_render($setting, $_field, $data[$key])}</td>";
                $fieldset .= '</tr>';
            }
            $fieldset .= '</table>';
Lucas García's avatar
Lucas García committed

Lucas García's avatar
Lucas García committed
        private function control_render($setting, $field)
Lucas García's avatar
Lucas García committed
            $setting_name = $this->setting_name($setting);
            $default = self::get_default($this->group_name, $setting);
Lucas García's avatar
Lucas García committed
        <div class="<?= $setting_name; ?>__<?= $field ?>--controls">
Lucas García's avatar
Lucas García committed
            <button class="button button-primary" data-action="add">Add</button>
            <button class="button button-secondary" data-action="remove">Remove</button>
        </div>
        <?php include 'fieldset-control-js.php' ?>
<?php
Lucas García's avatar
Lucas García committed

Lucas García's avatar
Lucas García committed
        private function control_style($setting, $field)
            $setting_name = $this->setting_name($setting);
Lucas García's avatar
Lucas García committed
            return "<style>#{$setting_name}__{$field} td td,#{$setting_name}__{$field} td th{padding:0}#{$setting_name}__{$field} table table{margin-bottom:1rem}</style>";
        }

        protected function setting_name($setting)
Lucas García's avatar
Lucas García committed
        {
            return $this->group_name . '_' . $setting;
Lucas García's avatar
Lucas García committed
    }

Lucas García's avatar
Lucas García committed

if (!function_exists('\WPCT_ABSTRACT\is_list')) :
Lucas García's avatar
Lucas García committed

    function is_list($arr)
    {
        if (!is_array($arr)) {
            return false;
        }
        if (sizeof($arr) === 0) {
            return true;
        }
        return array_keys($arr) === range(0, count($arr) - 1);
Lucas García's avatar
Lucas García committed
    }