skyverge/wc-plugin-framework

View on GitHub
woocommerce/Settings_API/Abstract_Settings.php

Summary

Maintainability
B
6 hrs
Test Coverage
<?php
/**
 * WooCommerce Plugin Framework
 *
 * This source file is subject to the GNU General Public License v3.0
 * that is bundled with this package in the file license.txt.
 * It is also available through the world-wide-web at this URL:
 * http://www.gnu.org/licenses/gpl-3.0.html
 * If you did not receive a copy of the license and are unable to
 * obtain it through the world-wide-web, please send an email
 * to license@skyverge.com so we can send you a copy immediately.
 *
 * DISCLAIMER
 *
 * Do not edit or add to this file if you wish to upgrade the plugin to newer
 * versions in the future. If you wish to customize the plugin for your
 * needs please refer to http://www.skyverge.com
 *
 * @package   SkyVerge/WooCommerce/Plugin/Classes
 * @author    SkyVerge
 * @copyright Copyright (c) 2013-2024, SkyVerge, Inc.
 * @license   http://www.gnu.org/licenses/gpl-3.0.html GNU General Public License v3.0
 */

namespace SkyVerge\WooCommerce\PluginFramework\v5_12_3\Settings_API;

use SkyVerge\WooCommerce\PluginFramework\v5_12_3 as Framework;

defined( 'ABSPATH' ) or exit;

if ( ! class_exists( '\\SkyVerge\\WooCommerce\\PluginFramework\\v5_12_3\\Settings_API\\Abstract_Settings' ) ) :


/**
 * The base settings handler.
 *
 * @since 5.7.0
 */
#[\AllowDynamicProperties]
abstract class Abstract_Settings {


    /** @var string settings ID */
    public $id;

    /** @var Setting[] registered settings */
    protected $settings = [];


    /**
     * Constructs the class.
     *
     * @since 5.7.0
     *
     * @param string $id the ID of plugin or payment gateway that owns these settings
     */
    public function __construct( $id ) {

        $this->id = $id;

        $this->register_settings();
        $this->load_settings();
    }


    /**
     * Registers the settings.
     *
     * Plugins or payment gateways should overwrite this method to register their settings.
     *
     * @since 5.7.0
     */
    abstract protected function register_settings();


    /**
     * Loads the values for all registered settings.
     *
     * @since 5.7.0
     */
    protected function load_settings() {

        foreach ( $this->settings as $setting_id => $setting ) {

            $value = get_option( $this->get_option_name_prefix() . '_' . $setting_id, null );
            $value = $this->get_value_from_database( $value, $setting );

            $this->settings[ $setting_id ]->set_value( $value );
        }
    }


    /**
     * Registers a setting.
     *
     * @param string $id unique setting ID
     * @param string $type setting type
     * @param array $args setting arguments
     * @return bool
     */
    public function register_setting( $id, $type, array $args = [] ) {

        try {

            if ( ! empty( $this->settings[ $id ] ) ) {
                throw new Framework\SV_WC_Plugin_Exception( "Setting {$id} is already registered" );
            }

            if ( ! in_array( $type, $this->get_setting_types(), true ) ) {
                throw new Framework\SV_WC_Plugin_Exception( "{$type} is not a valid setting type" );
            }

            $setting = new Setting();

            $setting->set_id( $id );
            $setting->set_type( $type );

            $args = wp_parse_args( $args, [
                'name'         => '',
                'description'  => '',
                'is_multi'     => false,
                'options'      => [],
                'default'      => null,
            ] );

            $setting->set_name( $args['name'] );
            $setting->set_description( $args['description'] );
            $setting->set_default( $args['default'] );
            $setting->set_is_multi( $args['is_multi'] );

            if ( is_array( $args['options'] ) ) {
                $setting->set_options( $args['options'] );
            }

            $this->settings[ $id ] = $setting;

            return true;

        } catch ( \Exception $exception ) {

            wc_doing_it_wrong( __METHOD__, 'Could not register setting: ' . $exception->getMessage(), '5.7.0' );

            return false;
        }
    }


    /**
     * Unregisters a setting.
     *
     * @since 5.7.0
     *
     * @param string $id setting ID to unregister
     */
    public function unregister_setting( $id ) {

        unset( $this->settings[ $id ] );
    }


    /**
     * Registers a control for a setting.
     *
     * @since 5.7.0
     *
     * @param string $setting_id the setting ID
     * @param string $type the control type
     * @param array $args optional args for the control
     * @return bool
     */
    public function register_control( $setting_id, $type, array $args = [] ) {

        try {

            if ( ! in_array( $type, $this->get_control_types(), true ) ) {
                throw new \UnexpectedValueException( "{$type} is not a valid control type" );
            }

            $setting = $this->get_setting( $setting_id );

            if ( ! $setting ) {
                throw new \InvalidArgumentException( "Setting {$setting_id} does not exist" );
            }

            $setting_control_types = $this->get_setting_control_types( $setting );
            if ( ! empty( $setting_control_types ) && ! in_array( $type, $setting_control_types, true ) ) {
                throw new \UnexpectedValueException( "{$type} is not a valid control type for setting {$setting->get_id()} of type {$setting->get_type()}" );
            }

            $args = wp_parse_args( $args, [
                'name'        => $setting->get_name(),
                'description' => $setting->get_description(),
                'options'     => [],
            ] );

            $control = new Control();

            $control->set_setting_id( $setting_id );
            $control->set_type( $type );
            $control->set_name( $args['name'] );
            $control->set_description( $args['description'] );

            if ( is_array( $args['options'] ) ) {
                $control->set_options( $args['options'], $setting->get_options() );
            }

            $setting->set_control( $control );

            return true;

        } catch ( \Exception $exception ) {

            wc_doing_it_wrong( __METHOD__, 'Could not register setting control: ' . $exception->getMessage(), '5.7.0' );

            return false;
        }
    }


    /**
     * Gets the settings ID.
     *
     * @since 5.7.0
     *
     * @return string
     */
    public function get_id() {

        return $this->id;
    }


    /**
     * Gets registered settings.
     *
     * It returns all settings by default, but you can pass an array of IDs to filter the results.
     *
     * @param string[] $ids setting IDs to get
     * @return Setting[]
     */
    public function get_settings( array $ids = [] ) {

        $settings = $this->settings;

        if ( ! empty( $ids ) ) {

            foreach ( array_keys( $this->settings ) as $id ) {

                if ( ! in_array( $id, $ids, true ) ) {
                    unset( $settings[ $id ] );
                }
            }
        }

        return $settings;
    }


    /**
     * Gets a setting object.
     *
     * @since 5.7.0
     *
     * @param string $id setting ID to get
     * @return Setting|null
     */
    public function get_setting( $id ) {

        return ! empty( $this->settings[ $id ] ) ? $this->settings[ $id ] : null;
    }


    /**
     * Gets the stored value for a setting.
     *
     * Optionally, will return the setting's default value if nothing is stored.
     *
     * @since 5.7.0
     *
     * @param string $setting_id setting ID
     * @param bool $with_default whether to return the default value if nothing is stored
     * @return array|bool|float|int|string
     * @throws Framework\SV_WC_Plugin_Exception
     */
    public function get_value( $setting_id, $with_default = true ) {

        $setting = $this->get_setting( $setting_id );

        if ( ! $setting ) {
            throw new Framework\SV_WC_Plugin_Exception( "Setting {$setting_id} does not exist" );
        }

        $value = $setting->get_value();

        if ( $with_default && null === $value ) {
            $value = $setting->get_default();
        }

        return $value;
    }


    /**
     * Updates the stored value for a setting.
     *
     * @since 5.7.0
     *
     * @param string $setting_id setting ID
     * @param array|bool|float|int|string $value
     * @throws Framework\SV_WC_Plugin_Exception
     */
    public function update_value( $setting_id, $value ) {

        $setting = $this->get_setting( $setting_id );

        if ( ! $setting ) {
            throw new Framework\SV_WC_Plugin_Exception( "Setting {$setting_id} does not exist", 404 );
        }

        // performs the validations and updates the value
        $setting->update_value( $value );

        $this->save( $setting_id );
    }


    /**
     * Deletes the stored value for a setting.
     *
     * @since 5.7.0
     *
     * @param string $setting_id setting ID
     * @return bool
     * @throws Framework\SV_WC_Plugin_Exception
     */
    public function delete_value( $setting_id ) {

        $setting = $this->get_setting( $setting_id );

        if ( ! $setting ) {
            throw new Framework\SV_WC_Plugin_Exception( "Setting {$setting_id} does not exist" );
        }

        $setting->set_value( null );

        return delete_option( "{$this->get_option_name_prefix()}_{$setting->get_id()}" );
    }


    /**
     * Saves registered settings in their current state.
     *
     * It saves all settings by default, but you can pass a setting ID to save a specific setting.
     *
     * @since 5.7.0
     *
     * @param string $setting_id setting ID
     */
    public function save( $setting_id = '' ) {

        if ( ! empty( $setting_id ) ) {
            $settings = [ $this->get_setting( $setting_id ) ];
        } else {
            $settings = $this->settings;
        }

        $settings = array_filter( $settings );

        foreach ( $settings as $setting ) {

            $option_name   = "{$this->get_option_name_prefix()}_{$setting->get_id()}";
            $setting_value = $setting->get_value();

            if ( null === $setting_value ) {

                delete_option( $option_name );

            } else {

                update_option( $option_name, $this->get_value_for_database( $setting ) );
            }
        }
    }


    /**
     * Converts the value of a setting to be stored in an option.
     *
     * @since 5.7.0
     *
     * @param Setting $setting
     * @return mixed
     */
    protected function get_value_for_database( Setting $setting ) {

        $value = $setting->get_value();

        if ( null !== $value && Setting::TYPE_BOOLEAN === $setting->get_type() ) {
            $value = wc_bool_to_string( $value );
        }

        return $value;
    }


    /**
     * Converts the stored value of a setting to the proper setting type.
     *
     * @since 5.7.0
     *
     * @param mixed $value the value stored in an option
     * @param Setting $setting
     * @return mixed
     */
    protected function get_value_from_database( $value, Setting $setting ) {

        if ( null !== $value ) {

            switch ( $setting->get_type() ) {

                case Setting::TYPE_BOOLEAN:
                    $value = wc_string_to_bool( $value );
                break;

                case Setting::TYPE_INTEGER:
                    $value = is_numeric( $value ) ? (int) $value : null;
                break;

                case Setting::TYPE_FLOAT:
                    $value = is_numeric( $value ) ? (float) $value : null;
                break;
            }
        }

        return $value;
    }


    /**
     * Gets the list of valid setting types.
     *
     * @since 5.7.0
     *
     * @return string[]
     */
    public function get_setting_types() {

        $setting_types = [
            Setting::TYPE_STRING,
            Setting::TYPE_URL,
            Setting::TYPE_EMAIL,
            Setting::TYPE_INTEGER,
            Setting::TYPE_FLOAT,
            Setting::TYPE_BOOLEAN,
        ];

        /**
         * Filters the list of valid setting types.
         *
         * @param string[] $setting_types valid setting types
         * @param Abstract_Settings $settings the settings handler instance
         */
        return apply_filters( "wc_{$this->get_id()}_settings_api_setting_types", $setting_types, $this );
    }


    /**
     * Gets the list of valid control types.
     *
     * @since 5.7.0
     *
     * @return string[]
     */
    public function get_control_types() {

        $control_types = [
            Control::TYPE_TEXT,
            Control::TYPE_TEXTAREA,
            Control::TYPE_NUMBER,
            Control::TYPE_EMAIL,
            Control::TYPE_PASSWORD,
            Control::TYPE_DATE,
            Control::TYPE_CHECKBOX,
            Control::TYPE_RADIO,
            Control::TYPE_SELECT,
            Control::TYPE_FILE,
            Control::TYPE_COLOR,
            Control::TYPE_RANGE,
        ];

        /**
         * Filters the list of valid control types.
         *
         * @param string[] $control_types valid control types
         * @param Abstract_Settings $settings the settings handler instance
         */
        return apply_filters( "wc_{$this->get_id()}_settings_api_control_types", $control_types, $this );
    }


    /**
     * Returns the valid control types for a setting.
     *
     * @since 5.7.0
     *
     * @param Setting $setting setting object
     * @return string[]
     */
    public function get_setting_control_types( $setting ) {

        /**
         * Filters the list of valid control types for a setting.
         *
         * @param string[] $control_types valid control types
         * @param string $setting_type setting type
         * @param Setting $setting setting object
         * @param Abstract_Settings $settings the settings handler instance
         */
        return apply_filters( "wc_{$this->get_id()}_settings_api_setting_control_types", [], $setting->get_type(), $setting, $this );
    }


    /**
     * Gets the prefix for db option names.
     *
     * @since 5.7.0
     *
     * @return string
     */
    public function get_option_name_prefix() {

        return "wc_{$this->id}";
    }


}

endif;