# tablepress/2.3.2/libraries/freemius/includes/managers/class-fs-option-manager.php

TablePress – Tables in WordPress made easy, version 2.3.2. 477 lines.

- Page: https://pluginprobe.com/plugins/tablepress/2.3.2/code/libraries/freemius/includes/managers/class-fs-option-manager.php
- Raw: https://pluginprobe.com/plugins/tablepress/2.3.2/raw/libraries/freemius/includes/managers/class-fs-option-manager.php
- Modified: 2022-12-19T11:32:06+00:00

Line numbers below start at 1. Link to a line or a range by appending a fragment to the
page URL, for example `https://pluginprobe.com/plugins/tablepress/2.3.2/code/libraries/freemius/includes/managers/class-fs-option-manager.php#L10-L20`.

```php
<?php
	/**
	 * @package     Freemius
	 * @copyright   Copyright (c) 2015, Freemius, Inc.
	 * @license     https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3
	 * @since       1.0.3
	 */

	if ( ! defined( 'ABSPATH' ) ) {
		exit;
	}

	/**
	 * 2-layer lazy options manager.
	 *      layer 2: Memory
	 *      layer 1: Database (options table). All options stored as one option record in the DB to reduce number of DB queries.
	 *
	 * If load() is not explicitly called, starts as empty manager. Same thing about saving the data - you have to explicitly call store().
	 *
	 * Class Freemius_Option_Manager
	 */
	class FS_Option_Manager {
		/**
		 * @var string
		 */
		private $_id;
		/**
		 * @var array|object
		 */
		private $_options;
		/**
		 * @var FS_Logger
		 */
		private $_logger;

		/**
		 * @since 2.0.0
		 * @var int The ID of the blog that is associated with the current site level options.
		 */
		private $_blog_id = 0;

		/**
		 * @since 2.0.0
		 * @var bool
		 */
		private $_is_network_storage;

		/**
		 * @var bool|null
		 */
		private $_autoload;

		/**
		 * @var array[string]FS_Option_Manager {
		 * @key   string
		 * @value FS_Option_Manager
		 * }
		 */
		private static $_MANAGERS = array();

		/**
		 * @author Vova Feldman (@svovaf)
		 * @since  1.0.3
		 *
		 * @param string    $id
		 * @param bool      $load
		 * @param bool|int  $network_level_or_blog_id Since 2.0.0
		 * @param bool|null $autoload
		 */
		private function __construct(
			$id,
			$load = false,
			$network_level_or_blog_id = false,
			$autoload = null
		) {
			$id = strtolower( $id );

			$this->_logger = FS_Logger::get_logger( WP_FS__SLUG . '_opt_mngr_' . $id, WP_FS__DEBUG_SDK, WP_FS__ECHO_DEBUG_SDK );

			$this->_logger->entrance();
			$this->_logger->log( 'id = ' . $id );

			$this->_id = $id;

			$this->_autoload = $autoload;

			if ( is_multisite() ) {
				$this->_is_network_storage = ( true === $network_level_or_blog_id );

				if ( is_numeric( $network_level_or_blog_id ) ) {
					$this->_blog_id = $network_level_or_blog_id;
				}
			} else {
				$this->_is_network_storage = false;
			}

			if ( $load ) {
				$this->load();
			}
		}

		/**
		 * @author Vova Feldman (@svovaf)
		 * @since  1.0.3
		 *
		 * @param string    $id
		 * @param bool      $load
		 * @param bool|int  $network_level_or_blog_id Since 2.0.0
		 * @param bool|null $autoload
		 *
		 * @return \FS_Option_Manager
		 */
		static function get_manager(
			$id,
			$load = false,
			$network_level_or_blog_id = false,
			$autoload = null
		) {
			$key = strtolower( $id );

			if ( is_multisite() ) {
				if ( true === $network_level_or_blog_id ) {
					$key .= ':ms';
				} else if ( is_numeric( $network_level_or_blog_id ) && $network_level_or_blog_id > 0 ) {
					$key .= ":{$network_level_or_blog_id}";
				} else {
					$network_level_or_blog_id = get_current_blog_id();

					$key .= ":{$network_level_or_blog_id}";
				}
			}

			if ( ! isset( self::$_MANAGERS[ $key ] ) ) {
				self::$_MANAGERS[ $key ] = new FS_Option_Manager(
					$id,
					$load,
					$network_level_or_blog_id,
					$autoload
				);
			} // If load required but not yet loaded, load.
			else if ( $load && ! self::$_MANAGERS[ $key ]->is_loaded() ) {
				self::$_MANAGERS[ $key ]->load();
			}

			return self::$_MANAGERS[ $key ];
		}

		/**
		 * @author Vova Feldman (@svovaf)
		 * @since  1.0.3
		 *
		 * @param bool $flush
		 */
		function load( $flush = false ) {
			$this->_logger->entrance();

			if ( ! $flush && isset( $this->_options ) ) {
				return;
			}

			if ( isset( $this->_options ) ) {
				// Clear prev options.
				$this->clear();
			}

			$option_name = $this->get_option_manager_name();

			if ( $this->_is_network_storage ) {
				$this->_options = get_site_option( $option_name );
			} else if ( $this->_blog_id > 0 ) {
				$this->_options = get_blog_option( $this->_blog_id, $option_name );
			} else {
				$this->_options = get_option( $option_name );
			}

			if ( is_string( $this->_options ) ) {
				$this->_options = json_decode( $this->_options );
			}

//					$this->_logger->info('get_option = ' . var_export($this->_options, true));

			if ( false === $this->_options ) {
				$this->clear();
			}
		}

		/**
		 * @author Vova Feldman (@svovaf)
		 * @since  1.0.3
		 *
		 * @return bool
		 */
		function is_loaded() {
			return isset( $this->_options );
		}

		/**
		 * @author Vova Feldman (@svovaf)
		 * @since  1.0.3
		 *
		 * @return bool
		 */
		function is_empty() {
			return ( $this->is_loaded() && false === $this->_options );
		}

		/**
		 * @author Vova Feldman (@svovaf)
		 * @since  1.0.6
		 *
		 * @param bool $flush
		 */
		function clear( $flush = false ) {
			$this->_logger->entrance();

			$this->_options = array();

			if ( $flush ) {
				$this->store();
			}
		}

		/**
		 * Delete options manager from DB.
		 *
		 * @author Vova Feldman (@svovaf)
		 * @since  1.0.9
		 */
		function delete() {
			$option_name = $this->get_option_manager_name();

			if ( $this->_is_network_storage ) {
				delete_site_option( $option_name );
			} else if ( $this->_blog_id > 0 ) {
				delete_blog_option( $this->_blog_id, $option_name );
			} else {
				delete_option( $option_name );
			}
		}

		/**
		 * @author Vova Feldman (@svovaf)
		 * @since  1.0.6
		 *
		 * @param string $option
		 * @param bool   $flush
		 *
		 * @return bool
		 */
		function has_option( $option, $flush = false ) {
			if ( ! $this->is_loaded() || $flush ) {
				$this->load( $flush );
			}

			return array_key_exists( $option, $this->_options );
		}

		/**
		 * @author Vova Feldman (@svovaf)
		 * @since  1.0.3
		 *
		 * @param string $option
		 * @param mixed  $default
		 * @param bool   $flush
		 *
		 * @return mixed
		 */
		function get_option( $option, $default = null, $flush = false ) {
			$this->_logger->entrance( 'option = ' . $option );

			if ( ! $this->is_loaded() || $flush ) {
				$this->load( $flush );
			}

			if ( is_array( $this->_options ) ) {
				$value = isset( $this->_options[ $option ] ) ?
					$this->_options[ $option ] :
					$default;
			} else if ( is_object( $this->_options ) ) {
				$value = isset( $this->_options->{$option} ) ?
					$this->_options->{$option} :
					$default;
			} else {
				$value = $default;
			}

			/**
			 * If it's an object, return a clone of the object, otherwise,
			 * external changes of the object will actually change the value
			 * of the object in the option manager which may lead to an unexpected
			 * behaviour and data integrity when a store() call is triggered.
			 *
			 * Example:
			 *      $object1    = $options->get_option( 'object1' );
			 *      $object1->x = 123;
			 *
			 *      $object2    = $options->get_option( 'object2' );
			 *      $object2->y = 'dummy';
			 *
			 *      $options->set_option( 'object2', $object2, true );
			 *
			 * If we don't return a clone of option 'object1', setting 'object2'
			 * will also store the updated value of 'object1' which is quite not
			 * an expected behaviour.
			 *
			 * @author Vova Feldman
			 */
			return is_object( $value ) ? clone $value : $value;
		}

		/**
		 * @author Vova Feldman (@svovaf)
		 * @since  1.0.3
		 *
		 * @param string $option
		 * @param mixed  $value
		 * @param bool   $flush
		 */
		function set_option( $option, $value, $flush = false ) {
			$this->_logger->entrance( 'option = ' . $option );

			if ( ! $this->is_loaded() ) {
				$this->clear();
			}

			/**
			 * If it's an object, store a clone of the object, otherwise,
			 * external changes of the object will actually change the value
			 * of the object in the options manager which may lead to an unexpected
			 * behaviour and data integrity when a store() call is triggered.
			 *
			 * Example:
			 *      $object1    = new stdClass();
			 *      $object1->x = 123;
			 *
			 *      $options->set_option( 'object1', $object1 );
			 *
			 *      $object1->x = 456;
			 *
			 *      $options->set_option( 'object2', $object2, true );
			 *
			 * If we don't set the option as a clone of option 'object1', setting 'object2'
			 * will also store the updated value of 'object1' ($object1->x = 456 instead of
			 * $object1->x = 123) which is quite not an expected behaviour.
			 *
			 * @author Vova Feldman
			 */
			$copy = is_object( $value ) ? clone $value : $value;

			if ( is_array( $this->_options ) ) {
				$this->_options[ $option ] = $copy;
			} else if ( is_object( $this->_options ) ) {
				$this->_options->{$option} = $copy;
			}

			if ( $flush ) {
				$this->store();
			}
		}

		/**
		 * Unset option.
		 *
		 * @author Vova Feldman (@svovaf)
		 * @since  1.0.3
		 *
		 * @param string $option
		 * @param bool   $flush
		 */
		function unset_option( $option, $flush = false ) {
			$this->_logger->entrance( 'option = ' . $option );

			if ( is_array( $this->_options ) ) {
				if ( ! isset( $this->_options[ $option ] ) ) {
					return;
				}

				unset( $this->_options[ $option ] );

			} else if ( is_object( $this->_options ) ) {
				if ( ! isset( $this->_options->{$option} ) ) {
					return;
				}

				unset( $this->_options->{$option} );
			}

			if ( $flush ) {
				$this->store();
			}
		}

		/**
		 * Dump options to database.
		 *
		 * @author Vova Feldman (@svovaf)
		 * @since  1.0.3
		 */
		function store() {
			$this->_logger->entrance();

			$option_name = $this->get_option_manager_name();

			if ( $this->_logger->is_on() ) {
				$this->_logger->info( $option_name . ' = ' . var_export( $this->_options, true ) );
			}

			// Update DB.
			if ( $this->_is_network_storage ) {
				update_site_option( $option_name, $this->_options );
			} else if ( $this->_blog_id > 0 ) {
				update_blog_option( $this->_blog_id, $option_name, $this->_options );
			} else {
				update_option( $option_name, $this->_options, $this->_autoload );
			}
		}

		/**
		 * Get options keys.
		 *
		 * @author Vova Feldman (@svovaf)
		 * @since  1.0.3
		 *
		 * @return string[]
		 */
		function get_options_keys() {
			if ( is_array( $this->_options ) ) {
				return array_keys( $this->_options );
			} else if ( is_object( $this->_options ) ) {
				return array_keys( get_object_vars( $this->_options ) );
			}

			return array();
		}

		#--------------------------------------------------------------------------------
		#region Migration
		#--------------------------------------------------------------------------------

		/**
		 * Migrate options from site level.
		 *
		 * @author Vova Feldman (@svovaf)
		 * @since  2.0.0
		 */
		function migrate_to_network() {
			$site_options = FS_Option_Manager::get_manager($this->_id, true, false);

			$options = is_object( $site_options->_options ) ?
				get_object_vars( $site_options->_options ) :
				$site_options->_options;

			if ( ! empty( $options ) ) {
				foreach ( $options as $key => $val ) {
					$this->set_option( $key, $val, false );
				}

				$this->store();
			}
		}

		#endregion

		#--------------------------------------------------------------------------------
		#region Helper Methods
		#--------------------------------------------------------------------------------

		/**
		 * @return string
		 */
		private function get_option_manager_name() {
			return $this->_id;
		}

		#endregion
	}

```
