Your IP : 216.73.216.215


Current Path : /home/flapst5/www/wp-content/plugins/wpmudev-updates/includes/
Upload File :
Current File : /home/flapst5/www/wp-content/plugins/wpmudev-updates/includes/class-wpmudev-dashboard-settings.php

<?php
/**
 * Class that handles settings functionality.
 *
 * @link    https://wpmudev.com
 * @since   4.11.10
 * @author  Joel James <joel@incsub.com>
 * @package WPMUDEV_Dashboard_Settings
 */

// If this file is called directly, abort.
defined( 'WPINC' ) || die;

/**
 * Class WPMUDEV_Dashboard_Settings
 */
class WPMUDEV_Dashboard_Settings {

	/**
	 * Internal option keys.
	 *
	 * @var string[]
	 */
	private array $internal_options
		= array(
			'remote_access',
			'updates_data',
			'profile_data',
			'updates_available',
			'translation_updates_available',
			'notifications',
		);

	/**
	 * Set up actions for settings.
	 *
	 * @since 5.0.0
	 */
	public function __construct() {
		add_action( 'update_site_option_wdp_un_general', array( $this, 'sync_translation_update' ), 10, 3 );
	}

	/**
	 * Returns the value of a plugin option.
	 *
	 * This can handle both grouped item and single options.
	 * If group argument is omitted it will get the non-grouped option.
	 *
	 * @since 4.11.10
	 *
	 * @param string $name          The option name.
	 * @param string $group         The group name (Optional for non grouped option).
	 * @param mixed  $default_value Optional. Set value to return if option not found.
	 *
	 * @return mixed The option value.
	 */
	public function get( $name, $group = false, $default_value = false ) {
		// Handle grouped options.
		if ( ! empty( $group ) ) {
			// Get option value.
			$value = $this->get_option( $group, array() );

			// Return value.
			return isset( $value[ $name ] ) ? $value[ $name ] : $default_value;
		}

		return $this->get_option( $name, $default_value );
	}

	/**
	 * Returns the value of a plugin option.
	 *
	 * The plugins option-prefix is automatically added to the option name.
	 * Use this function instead of direct access via get_site_option().
	 *
	 * @since 4.11.10
	 *
	 * @param string $name          The name of the option.
	 * @param mixed  $default_value Default value.
	 *
	 * @return mixed The option value.
	 */
	public function get_option( $name, $default_value = false ) {
		$value = get_site_option( 'wdp_un_' . $name, $default_value );

		/**
		 * Override the settings value.
		 *
		 * @since 5.0.0
		 */
		return apply_filters( 'wpmudev_dashboard_settings_get_option', $value, $name, $default_value );
	}

	/**
	 * Returns all settings in a grouped array.
	 *
	 * @since 5.0.0
	 *
	 * @param array $skip Skip some options.
	 *
	 * @return array
	 */
	public function get_all( $skip = array() ) {
		$settings = array();
		// Get the default settings.
		$defaults = $this->defaults();

		foreach ( $defaults as $group => $default_value ) {
			// Skip internal options.
			if ( ! empty( $skip ) && is_array( $skip ) && in_array( $group, $skip, true ) ) {
				continue;
			}

			$settings[ $group ] = $this->get_option( $group, $default_value );
		}

		return $settings;
	}

	/**
	 * Updates the value of a single plugin option.
	 *
	 * Can update a single item of a group or event an option without
	 * any group.
	 *
	 * @since 4.11.10
	 *
	 * @param string $name  The option name.
	 * @param mixed  $value The new option value.
	 * @param string $group The group name (Optional for non grouped option).
	 *
	 * @return bool
	 */
	public function set( $name, $value, $group = false ) {
		// Handle grouped options.
		if ( ! empty( $group ) ) {
			// Get option value.
			$group_value = $this->get_option( $group, array() );
			// Merge values.
			$values = wp_parse_args(
				array( $name => $value ),
				$group_value
			);
		} else {
			$group  = $name;
			$values = $value;
		}

		$success = $this->set_option( $group, $values );

		if ( $success ) {
			/**
			 * Action hook to run after Dashboard option is updated.
			 *
			 * @since 4.11.22
			 *
			 * @param string $name  Name of the option.
			 * @param mixed  $value Value to update.
			 * @param string $group Group name.
			 */
			do_action( 'wpmudev_dashboard_settings_after_set', $name, $value, $group );
		}

		return $success;
	}

	/**
	 * Updates the value of a plugin option.
	 * The plugins option-prefix is automatically added to the option name.
	 *
	 * Use this function instead of direct access via update_site_option()
	 *
	 * @since 4.11.10
	 *
	 * @param string $name  The option name.
	 * @param mixed  $value The new option value.
	 *
	 * @return bool
	 */
	public function set_option( $name, $value ) {
		if ( empty( $name ) ) {
			return false;
		}

		// Return true early if updating value is same as old value.
		$old_value = $this->get_option( $name );
		if ( $value === $old_value ) {
			return true;
		}

		$success = update_site_option( 'wdp_un_' . $name, $value );

		if ( $success ) {
			/**
			 * Action hook to run after Dashboard option is updated.
			 *
			 * @since 4.11.22
			 *
			 * @param string $name  Name of the option.
			 * @param mixed  $value Value to update.
			 */
			do_action( 'wpmudev_dashboard_settings_after_set_option', $name, $value );
		}

		return $success;
	}

	/**
	 * Add a new plugin setting to the database.
	 *
	 * Can add a single item of a group or event an option without
	 * any group. If group name is omitted it will add as a single option.
	 *
	 * @since 4.11.10
	 *
	 * @param string $name  The option name.
	 * @param mixed  $value The new option value.
	 * @param string $group The group name (Optional for non grouped option).
	 *
	 * @return bool
	 */
	public function add( $name, $value, $group = false ) {
		// Get existing value for grouped option.
		if ( ! empty( $group ) ) {
			$existing = $this->get_option( $group, array() );

			// Already exist, don't add.
			if ( isset( $existing[ $name ] ) ) {
				return false;
			}

			// Add new value.
			$existing[ $name ] = $value;

			// Update option.
			return $this->set_option( $group, $value );
		}

		return $this->add_option( $name, $value );
	}

	/**
	 * Add a new single plugin setting to the database.
	 *
	 * The plugins option-prefix is automatically added to the option name.
	 * This function will only save the value if the option does not exist yet!
	 * Use this function instead of direct access via add_site_option().
	 *
	 * @since 4.11.10
	 *
	 * @param string $name  The option name.
	 * @param mixed  $value The new option value.
	 *
	 * @return bool
	 */
	public function add_option( $name, $value ) {
		return add_site_option( 'wdp_un_' . $name, $value );
	}

	/**
	 * Returns the value of a plugin transient.
	 *
	 * The plugins option-prefix is automatically added to the transient name.
	 * Use this function instead of direct access via get_site_transient().
	 *
	 * @since 4.11.10
	 *
	 * @param string $name   The transient name.
	 * @param bool   $prefix Optional. Set to false to not prefix the name.
	 *
	 * @return mixed The transient value.
	 */
	public function get_transient( $name, $prefix = true ) {
		$key = $prefix ? 'wdp_un_' . $name : $name;

		// Transient name cannot be longer than 167 characters
		// 150 is being safe.
		$key = substr( $key, 0, 150 );

		return get_site_transient( $key );
	}

	/**
	 * Updates the value of a plugin transient.
	 *
	 * The plugins option-prefix is automatically added to the transient name.
	 * Use this function instead of direct access via set_site_transient().
	 *
	 * @since 4.11.10
	 * @since 5.0.0     Returns delete transient result when value is null.
	 *
	 * @param string $name       The transient name.
	 * @param mixed  $value      The new transient value. Passing null as value will delete the transient.
	 * @param int    $expiration Time until expiration. Default: No expiration.
	 * @param bool   $prefix     Optional. Set to false to not prefix the name.
	 *
	 * @return bool
	 */
	public function set_transient( $name, $value, $expiration = 0, $prefix = true ) {
		$key = $prefix ? 'wdp_un_' . $name : $name;

		// Transient name cannot be longer than 167 characters
		// 150 is being safe.
		$key = substr( $key, 0, 150 );

		// Fix to prevent WP from hashing PHP objects.
		$result = delete_site_transient( $key );

		if ( null !== $value ) {
			return set_site_transient( $key, $value, $expiration );
		}

		return $result;
	}

	/**
	 * Initialize all plugin options in the DB during activation.
	 *
	 * This function is called by the `activate_plugin` plugin in the main
	 * plugin file. Do not call this on every page load.
	 *
	 * @since 4.11.10
	 *
	 * @return void
	 */
	public function init() {
		// Get the default settings.
		$defaults = $this->defaults();

		foreach ( $defaults as $name => $value ) {
			// This is a grouped option.
			if ( is_array( $value ) ) {
				$update = false;
				// Get existing value.
				$existing = $this->get_option( $name, array() );
				// Go through each item and add if not found.
				foreach ( $value as $sub_name => $sub_value ) {
					if ( ! isset( $existing[ $sub_name ] ) ) {
						// Adding new value, so needs update.
						$update = true;
						// Set new value.
						$existing[ $sub_name ] = null === $sub_value ? '' : $sub_value;
					}
				}

				// If needs an update.
				if ( $update ) {
					$this->set_option( $name, $existing );
				}
			} else {
				$value = null === $value ? '' : $value;
				// Add only if doesn't exist.
				$this->add_option( $name, $value );
			}
		}
	}

	/**
	 * Reset all settings back to default.
	 *
	 * This will reset setting items found in the WPMUDEV_Dashboard_Settings::defaults() list.
	 * If the default value of a field is null we will skip it from reset.
	 *
	 * @since 4.11.10
	 *
	 * @return void
	 */
	public function reset() {
		// Get the default settings.
		$defaults = $this->defaults();

		foreach ( $defaults as $name => $value ) {
			// This is a grouped option.
			if ( is_array( $value ) && ! empty( $value ) ) {
				// Get existing value.
				$values = $this->get_option( $name, array() );
				// Go through each item and add if not found.
				foreach ( $value as $sub_name => $sub_value ) {
					if ( null !== $sub_value ) {
						// Set default value.
						$values[ $sub_name ] = $sub_value;
					}
				}

				// Update with new values.
				$this->set_option( $name, $values );
			} elseif ( null !== $value ) {
				$this->set_option( $name, $value );
			}
		}
	}

	/**
	 * Get the default settings values.
	 *
	 * This should be used to init and rest settings.
	 * To register new options use `wpmudev_dashboard_settings_defaults` filter.
	 * Only items registered here will be used for init and reset actions.
	 * If the value is null during reset it will be skipped.
	 *
	 * @since 4.11.10
	 *
	 * @return array
	 */
	public function defaults() {
		$settings = array(
			// Bigger options.
			// updates_data is excluded from reset, so any integration ( such as forminator addons ) can _still_ work-ish ( its stale, but its not nothing ).
			'remote_access'                 => '',
			'profile_data'                  => '',
			'updates_available'             => array(),
			'translation_updates_available' => array(),
			'notifications'                 => array(),
			// Whitelabel options.
			'whitelabel'                    => array(
				'enabled'                  => false,
				'branding_enabled'         => false,
				'branding_enabled_subsite' => false,
				'branding_type'            => 'default',
				'branding_image'           => '',
				'branding_image_id'        => 0,
				'branding_image_link'      => '',
				'footer_enabled'           => false,
				'footer_text'              => '',
				'labels_enabled'           => false,
				'labels_config'            => false,
				'labels_config_selected'   => '',
				'labels_networkwide'       => true,
				'labels_subsites'          => array(),
				'doc_links_enabled'        => false,
			),
			// Analytics options.
			'analytics'                     => array(
				'enabled'    => false,
				'tracker'    => '',
				'site_id'    => '',
				'script_url' => '',
				'metrics'    => array(
					'pageviews',
					'unique_pageviews',
					'page_time',
					'visits',
					'bounce_rate',
					'exit_rate',
				),
				'role'       => 'administrator',
			),
			// SSO.
			'sso'                           => array(
				'enabled'        => false,
				'userid'         => false,
				'previous_token' => '',
				'active_token'   => '',
			),
			'flags'                         => array(
				'refresh_remote'              => false,
				'refresh_profile'             => false,
				'redirected_v4'               => false,
				'highlights_dismissed'        => true,
				'first_setup'                 => false,
				'autoupdate_dashboard'        => true,
				'enable_auto_translation'     => false,
				'uninstall_preserve_settings' => true,
				'uninstall_keep_data'         => true,
			),
			// Data settings on uninstall.
			'data'                          => array(
				'preserve_settings' => true,
				'keep_data'         => true,
			),
			// Other small options.
			'general'                       => array(
				// last_run_updates is not going to reset, because we also not resetting updates_data,
				// its a pair, @see WPMUDEV_Dashboard_Api::refresh_projects_data().
				'last_run_profile'     => 0,
				'last_run_sync'        => 0,
				'last_run_translation' => 0,
				'staff_notes'          => '',
				'translation_locale'   => 'en_US',
				'version'              => WPMUDEV_Dashboard::$version,
				'limit_to_user'        => array(),
				'auth_user'            => null,
				'connected_admin'      => 0,
			),
		);

		/**
		 * Filter to modify default settings.
		 *
		 * @since 4.11.10
		 *
		 * @param array $settings Default settings.
		 */
		return apply_filters( 'wpmudev_dashboard_settings_defaults', $settings );
	}

	/**
	 * Get multiple options into single array assoc.
	 *
	 * This function will match expectation structure,
	 * Array returned from this function should be predictable.
	 *
	 * @since 4.6.0
	 * @since 4.11.10 Moved to new class and renamed.
	 *
	 * @param array $options Optional array assoc with setting name as key.
	 *
	 * @return array
	 */
	public function as_array( $options = array() ) {
		$settings = array();

		foreach ( $options as $name => $item ) {
			// Make sure all required properties set.
			$item = wp_parse_args(
				$item,
				array(
					'option'  => '',
					'group'   => false,
					'type'    => false,
					'default' => false,
				)
			);

			// If option name is not given use default value.
			if ( empty( $item['option'] ) ) {
				$settings[ $name ] = $this->sanitize( $item['default'], $item['type'] );
				continue;
			}

			// Get the sanitized value.
			$settings[ $name ] = $this->sanitize(
				$this->get( $item['option'], $item['group'], $item['default'] ),
				$item['type']
			);
		}

		return $settings;
	}

	/**
	 * Get internal option keys.
	 *
	 * @return array
	 */
	public function get_internal_options() {
		return $this->internal_options;
	}

	/**
	 * Upgrade old settings to new grouped structure.
	 *
	 * A few items won't be upgraded because it is still in old
	 * structure without any group.
	 *
	 * @since 4.11.10
	 *
	 * @return void
	 */
	public function upgrade_41110() {
		$mapping = $this->deprecated_mappings();

		// Upgrade old options.
		foreach ( $mapping as $name => $item ) {
			// Get the old value.
			$value = $this->get_option( $name, null );
			// If value found.
			if ( null !== $value ) {
				// Delete old option.
				delete_site_option( 'wdp_un_' . $name );

				// Set group.
				$group = isset( $item['group'] ) ? $item['group'] : false;

				// Set new name.
				if ( isset( $item['name'] ) ) {
					$name = $item['name'];
				}

				// Set new option.
				$this->set( $name, $value, $group );
			}
		}

		// Unused options cleanup.
		$deprecated_options = array( 'farm133_themes', 'last_check_upfront' );

		foreach ( $deprecated_options as $option ) {
			delete_site_option( 'wdp_un_' . $option );
		}
	}

	/**
	 * Get the mapping for a deprecated option name.
	 *
	 * This is here only for backward compatibility.
	 *
	 * @since      4.11.10
	 *
	 * @param string $name Field name.
	 *
	 * @return array
	 * @deprecated 4.11.10 For backward compatibility only.
	 */
	public function deprecated_get_field_mapping( $name ) {
		$mapping = $this->deprecated_mappings();

		$mapped = array(
			'name'  => $name,
			'group' => false,
		);

		// If old option has new structure.
		if ( isset( $mapping[ $name ] ) ) {
			if ( isset( $mapping[ $name ]['name'] ) ) {
				$mapped['name'] = $mapping[ $name ]['name'];
			}

			if ( isset( $mapping[ $name ]['group'] ) ) {
				$mapped['group'] = $mapping[ $name ]['group'];
			}
		}

		return $mapped;
	}

	/**
	 * Make changes when translation settings are updated.
	 *
	 * @param string $option    Name of the network option.
	 * @param mixed  $value     Current value of the network option.
	 * @param mixed  $old_value Old value of the network option.
	 *
	 * @return void
	 */
	public function sync_translation_update( $option, $value, $old_value ) {
		$old_locale = $old_value['translation_locale'] ?? 'en_US';
		$new_locale = $value['translation_locale'] ?? $old_locale;

		// Force a hub-sync, since the translation setting changed.
		if ( $old_locale !== $new_locale ) {
			WPMUDEV_Dashboard::$api->calculate_translation_upgrades( true );
		}
	}

	/**
	 * Get the mapping for deprecated option names.
	 *
	 * This is here for backward compatibility. Few of our plugins
	 * still use the old option names.
	 * If some of the options are not found here, which means they are
	 * still in old form.
	 *
	 * @since      4.11.10
	 * @return array
	 * @deprecated 4.11.10 For backward compatibility only.
	 */
	private function deprecated_mappings() {
		return array(
			'limit_to_user'                       => array(
				'group' => 'general',
			),
			'last_run_updates'                    => array(
				'group' => 'general',
			),
			'last_run_profile'                    => array(
				'group' => 'general',
			),
			'last_run_sync'                       => array(
				'group' => 'general',
			),
			'staff_notes'                         => array(
				'group' => 'general',
			),
			'translation_locale'                  => array(
				'group' => 'general',
			),
			'auth_user'                           => array(
				'group' => 'general',
			),
			'version'                             => array(
				'group' => 'general',
			),
			'redirected_v4'                       => array(
				'group' => 'flags',
			),
			'refresh_remote_flag'                 => array(
				'group' => 'flags',
			),
			'refresh_profile_flag'                => array(
				'group' => 'flags',
			),
			'autoupdate_dashboard'                => array(
				'group' => 'flags',
			),
			'enable_auto_translation'             => array(
				'group' => 'flags',
			),
			'highlights_dismissed'                => array(
				'group' => 'flags',
			),
			'first_setup'                         => array(
				'group' => 'flags',
			),
			'data_preserve_settings'              => array(
				'name'  => 'uninstall_preserve_settings',
				'group' => 'flags',
			),
			'data_keep_data'                      => array(
				'name'  => 'uninstall_keep_data',
				'group' => 'flags',
			),
			'whitelabel_enabled'                  => array(
				'name'  => 'enabled',
				'group' => 'whitelabel',
			),
			'whitelabel_branding_enabled'         => array(
				'name'  => 'branding_enabled',
				'group' => 'whitelabel',
			),
			'whitelabel_branding_enabled_subsite' => array(
				'name'  => 'branding_enabled_subsite',
				'group' => 'whitelabel',
			),
			'whitelabel_branding_type'            => array(
				'name'  => 'branding_type',
				'group' => 'whitelabel',
			),
			'whitelabel_branding_image'           => array(
				'name'  => 'branding_image',
				'group' => 'whitelabel',
			),
			'whitelabel_branding_image_id'        => array(
				'name'  => 'branding_image_id',
				'group' => 'whitelabel',
			),
			'whitelabel_branding_image_link'      => array(
				'name'  => 'branding_image_link',
				'group' => 'whitelabel',
			),
			'whitelabel_footer_enabled'           => array(
				'name'  => 'footer_enabled',
				'group' => 'whitelabel',
			),
			'whitelabel_footer_text'              => array(
				'name'  => 'footer_text',
				'group' => 'whitelabel',
			),
			'whitelabel_labels_enabled'           => array(
				'name'  => 'labels_enabled',
				'group' => 'whitelabel',
			),
			'whitelabel_labels_config'            => array(
				'name'  => 'labels_config',
				'group' => 'whitelabel',
			),
			'whitelabel_labels_config_selected'   => array(
				'name'  => 'labels_config_selected',
				'group' => 'whitelabel',
			),
			'whitelabel_labels_networkwide'       => array(
				'name'  => 'labels_networkwide',
				'group' => 'whitelabel',
			),
			'whitelabel_labels_subsites'          => array(
				'name'  => 'labels_subsites',
				'group' => 'whitelabel',
			),
			'whitelabel_doc_links_enabled'        => array(
				'name'  => 'doc_links_enabled',
				'group' => 'whitelabel',
			),
			'analytics_enabled'                   => array(
				'name'  => 'enabled',
				'group' => 'analytics',
			),
			'analytics_tracker'                   => array(
				'name'  => 'tracker',
				'group' => 'analytics',
			),
			'analytics_site_id'                   => array(
				'name'  => 'site_id',
				'group' => 'analytics',
			),
			'analytics_metrics'                   => array(
				'name'  => 'metrics',
				'group' => 'analytics',
			),
			'analytics_role'                      => array(
				'name'  => 'role',
				'group' => 'analytics',
			),
			'enable_sso'                          => array(
				'name'  => 'enabled',
				'group' => 'sso',
			),
			'sso_userid'                          => array(
				'name'  => 'userid',
				'group' => 'sso',
			),
			'previous_sso_token'                  => array(
				'name'  => 'previous_token',
				'group' => 'sso',
			),
			'active_sso_token'                    => array(
				'name'  => 'active_token',
				'group' => 'sso',
			),
		);
	}

	/**
	 * Sanitize given value to match a type.
	 *
	 * If not one of possible type, value won't be sanitized.
	 *
	 * @since 4.11.10
	 *
	 * @param mixed  $value Value to sanitize.
	 * @param string $type  Type of value.
	 *
	 * @return mixed
	 */
	private function sanitize( $value, $type = false ) {
		switch ( $type ) {
			case 'boolean':
				$value = filter_var( $value, FILTER_VALIDATE_BOOLEAN );
				break;
			case 'string':
				// String expected, when its `empty`(NULL, false, etc) or its not string lets return empty string.
				if ( empty( $value ) || ! is_string( $value ) ) {
					$value = '';
				}
				break;
			case 'numeric':
				// numeric expected, its safe to return "0.7" even the explicit type is string
				// since PHP will auto coerce the type naturally.
				if ( ! is_numeric( $value ) ) {
					$value = 0;
				}
				break;
			case 'array':
				if ( ! is_array( $value ) ) {
					// Only array please.
					$value = empty( $value ) ? array() : (array) $value;
				}
				break;
		}

		return $value;
	}

	/**
	 * Upgrade to version 5.0.0
	 *
	 * @since 5.0.0
	 *
	 * @return void
	 */
	public function upgrade_500() {
		// clean up hub_nonce from options.
		$general = $this->get_option( 'general' );
		$general = is_array( $general ) ? $general : array();

		$update = false;
		foreach ( $general as $key => $value ) {
			if ( str_starts_with( $key, 'hub_nonce_' ) ) {
				unset( $general[ $key ] );
				$update = true;
			}
		}

		if ( $update ) {
			$this->set_option( 'general', $general );
		}

		if ( did_action( 'init' ) ) {
			$this->upgrade_500_on_init();
		} else {
			add_action( 'init', array( $this, 'upgrade_500_on_init' ) );
		}
	}

	/**
	 * Upgrade to version 5.0.0 on init.
	 * The plugin upgrades executed on plugins_loaded hook,
	 * but calculate upgrades need to be done on or after init hook, because it contains user check and translations
	 * hence, this function is separated from the usual data/options update
	 *
	 * @return void
	 */
	public function upgrade_500_on_init() {
		// re-calculate upgrades, added new property `is_addon`.
		WPMUDEV_Dashboard::$api->calculate_upgrades();
	}
}