first
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,477 @@
|
||||
<?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.7
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
class FS_Admin_Notice_Manager {
|
||||
/**
|
||||
* @since 1.2.2
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $_module_unique_affix;
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $_id;
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $_title;
|
||||
/**
|
||||
* @var array[string]array
|
||||
*/
|
||||
private $_notices = array();
|
||||
/**
|
||||
* @var FS_Key_Value_Storage
|
||||
*/
|
||||
private $_sticky_storage;
|
||||
/**
|
||||
* @var FS_Logger
|
||||
*/
|
||||
protected $_logger;
|
||||
/**
|
||||
* @since 2.0.0
|
||||
* @var int The ID of the blog that is associated with the current site level admin notices.
|
||||
*/
|
||||
private $_blog_id = 0;
|
||||
/**
|
||||
* @since 2.0.0
|
||||
* @var bool
|
||||
*/
|
||||
private $_is_network_notices;
|
||||
|
||||
/**
|
||||
* @var FS_Admin_Notice_Manager[]
|
||||
*/
|
||||
private static $_instances = array();
|
||||
|
||||
/**
|
||||
* @param string $id
|
||||
* @param string $title
|
||||
* @param string $module_unique_affix
|
||||
* @param bool $is_network_and_blog_admins Whether or not the message should be shown both on
|
||||
* network and blog admin pages.
|
||||
* @param bool $network_level_or_blog_id Since 2.0.0
|
||||
*
|
||||
* @return \FS_Admin_Notice_Manager
|
||||
*/
|
||||
static function instance(
|
||||
$id,
|
||||
$title = '',
|
||||
$module_unique_affix = '',
|
||||
$is_network_and_blog_admins = false,
|
||||
$network_level_or_blog_id = false
|
||||
) {
|
||||
if ( $is_network_and_blog_admins ) {
|
||||
$network_level_or_blog_id = true;
|
||||
}
|
||||
|
||||
$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::$_instances[ $key ] ) ) {
|
||||
self::$_instances[ $key ] = new FS_Admin_Notice_Manager(
|
||||
$id,
|
||||
$title,
|
||||
$module_unique_affix,
|
||||
$is_network_and_blog_admins,
|
||||
$network_level_or_blog_id
|
||||
);
|
||||
}
|
||||
|
||||
return self::$_instances[ $key ];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $id
|
||||
* @param string $title
|
||||
* @param string $module_unique_affix
|
||||
* @param bool $is_network_and_blog_admins Whether or not the message should be shown both on network and
|
||||
* blog admin pages.
|
||||
* @param bool|int $network_level_or_blog_id
|
||||
*/
|
||||
protected function __construct(
|
||||
$id,
|
||||
$title = '',
|
||||
$module_unique_affix = '',
|
||||
$is_network_and_blog_admins = false,
|
||||
$network_level_or_blog_id = false
|
||||
) {
|
||||
$this->_id = $id;
|
||||
$this->_logger = FS_Logger::get_logger( WP_FS__SLUG . '_' . $this->_id . '_data', WP_FS__DEBUG_SDK, WP_FS__ECHO_DEBUG_SDK );
|
||||
$this->_title = ! empty( $title ) ? $title : '';
|
||||
$this->_module_unique_affix = $module_unique_affix;
|
||||
$this->_sticky_storage = FS_Key_Value_Storage::instance( 'admin_notices', $this->_id, $network_level_or_blog_id );
|
||||
|
||||
if ( is_multisite() ) {
|
||||
$this->_is_network_notices = ( 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_notices = false;
|
||||
}
|
||||
|
||||
$is_network_admin = fs_is_network_admin();
|
||||
$is_blog_admin = fs_is_blog_admin();
|
||||
|
||||
if ( ( $this->_is_network_notices && $is_network_admin ) ||
|
||||
( ! $this->_is_network_notices && $is_blog_admin ) ||
|
||||
( $is_network_and_blog_admins && ( $is_network_admin || $is_blog_admin ) )
|
||||
) {
|
||||
if ( 0 < count( $this->_sticky_storage ) ) {
|
||||
$ajax_action_suffix = str_replace( ':', '-', $this->_id );
|
||||
|
||||
// If there are sticky notices for the current slug, add a callback
|
||||
// to the AJAX action that handles message dismiss.
|
||||
add_action( "wp_ajax_fs_dismiss_notice_action_{$ajax_action_suffix}", array(
|
||||
&$this,
|
||||
'dismiss_notice_ajax_callback'
|
||||
) );
|
||||
|
||||
foreach ( $this->_sticky_storage as $msg ) {
|
||||
// Add admin notice.
|
||||
$this->add(
|
||||
$msg['message'],
|
||||
$msg['title'],
|
||||
$msg['type'],
|
||||
true,
|
||||
$msg['id'],
|
||||
false,
|
||||
isset( $msg['wp_user_id'] ) ? $msg['wp_user_id'] : null,
|
||||
! empty( $msg['plugin'] ) ? $msg['plugin'] : null,
|
||||
$is_network_and_blog_admins
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove sticky message by ID.
|
||||
*
|
||||
* @author Vova Feldman (@svovaf)
|
||||
* @since 1.0.7
|
||||
*
|
||||
*/
|
||||
function dismiss_notice_ajax_callback() {
|
||||
check_admin_referer( 'fs_dismiss_notice_action' );
|
||||
|
||||
if ( ! is_numeric( $_POST['message_id'] ) ) {
|
||||
$this->_sticky_storage->remove( $_POST['message_id'] );
|
||||
}
|
||||
|
||||
wp_die();
|
||||
}
|
||||
|
||||
/**
|
||||
* Rendered sticky message dismiss JavaScript.
|
||||
*
|
||||
* @author Vova Feldman (@svovaf)
|
||||
* @since 1.0.7
|
||||
*/
|
||||
static function _add_sticky_dismiss_javascript() {
|
||||
$params = array();
|
||||
fs_require_once_template( 'sticky-admin-notice-js.php', $params );
|
||||
}
|
||||
|
||||
private static $_added_sticky_javascript = false;
|
||||
|
||||
/**
|
||||
* Hook to the admin_footer to add sticky message dismiss JavaScript handler.
|
||||
*
|
||||
* @author Vova Feldman (@svovaf)
|
||||
* @since 1.0.7
|
||||
*/
|
||||
private static function has_sticky_messages() {
|
||||
if ( ! self::$_added_sticky_javascript ) {
|
||||
add_action( 'admin_footer', array( 'FS_Admin_Notice_Manager', '_add_sticky_dismiss_javascript' ) );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle admin_notices by printing the admin messages stacked in the queue.
|
||||
*
|
||||
* @author Vova Feldman (@svovaf)
|
||||
* @since 1.0.4
|
||||
*
|
||||
*/
|
||||
function _admin_notices_hook() {
|
||||
if ( function_exists( 'current_user_can' ) &&
|
||||
! current_user_can( 'manage_options' )
|
||||
) {
|
||||
// Only show messages to admins.
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
$show_admin_notices = ( ! $this->is_gutenberg_page() );
|
||||
|
||||
foreach ( $this->_notices as $id => $msg ) {
|
||||
if ( isset( $msg['wp_user_id'] ) && is_numeric( $msg['wp_user_id'] ) ) {
|
||||
if ( get_current_user_id() != $msg['wp_user_id'] ) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Added a filter to control the visibility of admin notices.
|
||||
*
|
||||
* Usage example:
|
||||
*
|
||||
* /**
|
||||
* * @param bool $show
|
||||
* * @param array $msg {
|
||||
* * @var string $message The actual message.
|
||||
* * @var string $title An optional message title.
|
||||
* * @var string $type The type of the message ('success', 'update', 'warning', 'promotion').
|
||||
* * @var string $id The unique identifier of the message.
|
||||
* * @var string $manager_id The unique identifier of the notices manager. For plugins it would be the plugin's slug, for themes - `<slug>-theme`.
|
||||
* * @var string $plugin The product's title.
|
||||
* * @var string $wp_user_id An optional WP user ID that this admin notice is for.
|
||||
* * }
|
||||
* *
|
||||
* * @return bool
|
||||
* *\/
|
||||
* function my_custom_show_admin_notice( $show, $msg ) {
|
||||
* if ('trial_promotion' != $msg['id']) {
|
||||
* return false;
|
||||
* }
|
||||
*
|
||||
* return $show;
|
||||
* }
|
||||
*
|
||||
* my_fs()->add_filter( 'show_admin_notice', 'my_custom_show_admin_notice', 10, 2 );
|
||||
*
|
||||
* @author Vova Feldman
|
||||
* @since 2.2.0
|
||||
*/
|
||||
$show_notice = call_user_func_array( 'fs_apply_filter', array(
|
||||
$this->_module_unique_affix,
|
||||
'show_admin_notice',
|
||||
$show_admin_notices,
|
||||
$msg
|
||||
) );
|
||||
|
||||
if ( true !== $show_notice ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
fs_require_template( 'admin-notice.php', $msg );
|
||||
|
||||
if ( $msg['sticky'] ) {
|
||||
self::has_sticky_messages();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueue common stylesheet to style admin notice.
|
||||
*
|
||||
* @author Vova Feldman (@svovaf)
|
||||
* @since 1.0.7
|
||||
*/
|
||||
function _enqueue_styles() {
|
||||
fs_enqueue_local_style( 'fs_common', '/admin/common.css' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the current page is the Gutenberg block editor.
|
||||
*
|
||||
* @author Vova Feldman (@svovaf)
|
||||
* @since 2.2.3
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
function is_gutenberg_page() {
|
||||
if ( function_exists( 'is_gutenberg_page' ) &&
|
||||
is_gutenberg_page()
|
||||
) {
|
||||
// The Gutenberg plugin is on.
|
||||
return true;
|
||||
}
|
||||
|
||||
$current_screen = get_current_screen();
|
||||
|
||||
if ( method_exists( $current_screen, 'is_block_editor' ) &&
|
||||
$current_screen->is_block_editor()
|
||||
) {
|
||||
// Gutenberg page on 5+.
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add admin message to admin messages queue, and hook to admin_notices / all_admin_notices if not yet hooked.
|
||||
*
|
||||
* @author Vova Feldman (@svovaf)
|
||||
* @since 1.0.4
|
||||
*
|
||||
* @param string $message
|
||||
* @param string $title
|
||||
* @param string $type
|
||||
* @param bool $is_sticky
|
||||
* @param string $id Message ID
|
||||
* @param bool $store_if_sticky
|
||||
* @param number|null $wp_user_id
|
||||
* @param string|null $plugin_title
|
||||
* @param bool $is_network_and_blog_admins Whether or not the message should be shown both on network
|
||||
* and blog admin pages.
|
||||
*
|
||||
* @uses add_action()
|
||||
*/
|
||||
function add(
|
||||
$message,
|
||||
$title = '',
|
||||
$type = 'success',
|
||||
$is_sticky = false,
|
||||
$id = '',
|
||||
$store_if_sticky = true,
|
||||
$wp_user_id = null,
|
||||
$plugin_title = null,
|
||||
$is_network_and_blog_admins = false
|
||||
) {
|
||||
$notices_type = $this->get_notices_type();
|
||||
|
||||
if ( empty( $this->_notices ) ) {
|
||||
if ( ! $is_network_and_blog_admins ) {
|
||||
add_action( $notices_type, array( &$this, "_admin_notices_hook" ) );
|
||||
} else {
|
||||
add_action( 'network_admin_notices', array( &$this, "_admin_notices_hook" ) );
|
||||
add_action( 'admin_notices', array( &$this, "_admin_notices_hook" ) );
|
||||
}
|
||||
|
||||
add_action( 'admin_enqueue_scripts', array( &$this, '_enqueue_styles' ) );
|
||||
}
|
||||
|
||||
if ( '' === $id ) {
|
||||
$id = md5( $title . ' ' . $message . ' ' . $type );
|
||||
}
|
||||
|
||||
$message_object = array(
|
||||
'message' => $message,
|
||||
'title' => $title,
|
||||
'type' => $type,
|
||||
'sticky' => $is_sticky,
|
||||
'id' => $id,
|
||||
'manager_id' => $this->_id,
|
||||
'plugin' => ( ! is_null( $plugin_title ) ? $plugin_title : $this->_title ),
|
||||
'wp_user_id' => $wp_user_id,
|
||||
);
|
||||
|
||||
if ( $is_sticky && $store_if_sticky ) {
|
||||
$this->_sticky_storage->{$id} = $message_object;
|
||||
}
|
||||
|
||||
$this->_notices[ $id ] = $message_object;
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Vova Feldman (@svovaf)
|
||||
* @since 1.0.7
|
||||
*
|
||||
* @param string|string[] $ids
|
||||
*/
|
||||
function remove_sticky( $ids ) {
|
||||
if ( ! is_array( $ids ) ) {
|
||||
$ids = array( $ids );
|
||||
}
|
||||
|
||||
foreach ( $ids as $id ) {
|
||||
// Remove from sticky storage.
|
||||
$this->_sticky_storage->remove( $id );
|
||||
|
||||
if ( isset( $this->_notices[ $id ] ) ) {
|
||||
unset( $this->_notices[ $id ] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if sticky message exists by id.
|
||||
*
|
||||
* @author Vova Feldman (@svovaf)
|
||||
* @since 1.0.9
|
||||
*
|
||||
* @param $id
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
function has_sticky( $id ) {
|
||||
return isset( $this->_sticky_storage[ $id ] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds sticky admin notification.
|
||||
*
|
||||
* @author Vova Feldman (@svovaf)
|
||||
* @since 1.0.7
|
||||
*
|
||||
* @param string $message
|
||||
* @param string $id Message ID
|
||||
* @param string $title
|
||||
* @param string $type
|
||||
* @param number|null $wp_user_id
|
||||
* @param string|null $plugin_title
|
||||
* @param bool $is_network_and_blog_admins Whether or not the message should be shown both on network
|
||||
* and blog admin pages.
|
||||
*/
|
||||
function add_sticky( $message, $id, $title = '', $type = 'success', $wp_user_id = null, $plugin_title = null, $is_network_and_blog_admins = false ) {
|
||||
if ( ! empty( $this->_module_unique_affix ) ) {
|
||||
$message = fs_apply_filter( $this->_module_unique_affix, "sticky_message_{$id}", $message );
|
||||
$title = fs_apply_filter( $this->_module_unique_affix, "sticky_title_{$id}", $title );
|
||||
}
|
||||
|
||||
$this->add( $message, $title, $type, true, $id, true, $wp_user_id, $plugin_title, $is_network_and_blog_admins );
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear all sticky messages.
|
||||
*
|
||||
* @author Vova Feldman (@svovaf)
|
||||
* @since 1.0.8
|
||||
*/
|
||||
function clear_all_sticky() {
|
||||
$this->_sticky_storage->clear_all();
|
||||
}
|
||||
|
||||
#--------------------------------------------------------------------------------
|
||||
#region Helper Method
|
||||
#--------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @author Vova Feldman (@svovaf)
|
||||
* @since 2.0.0
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function get_notices_type() {
|
||||
return $this->_is_network_notices ?
|
||||
'network_admin_notices' :
|
||||
'admin_notices';
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
@ -0,0 +1,326 @@
|
||||
<?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.1.6
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
class FS_Cache_Manager {
|
||||
/**
|
||||
* @var FS_Option_Manager
|
||||
*/
|
||||
private $_options;
|
||||
/**
|
||||
* @var FS_Logger
|
||||
*/
|
||||
private $_logger;
|
||||
|
||||
/**
|
||||
* @var FS_Cache_Manager[]
|
||||
*/
|
||||
private static $_MANAGERS = array();
|
||||
|
||||
/**
|
||||
* @author Vova Feldman (@svovaf)
|
||||
* @since 1.1.3
|
||||
*
|
||||
* @param string $id
|
||||
*/
|
||||
private function __construct( $id ) {
|
||||
$this->_logger = FS_Logger::get_logger( WP_FS__SLUG . '_cach_mngr_' . $id, WP_FS__DEBUG_SDK, WP_FS__ECHO_DEBUG_SDK );
|
||||
|
||||
$this->_logger->entrance();
|
||||
$this->_logger->log( 'id = ' . $id );
|
||||
|
||||
$this->_options = FS_Option_Manager::get_manager( $id, true, true, false );
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Vova Feldman (@svovaf)
|
||||
* @since 1.1.6
|
||||
*
|
||||
* @param $id
|
||||
*
|
||||
* @return FS_Cache_Manager
|
||||
*/
|
||||
static function get_manager( $id ) {
|
||||
$id = strtolower( $id );
|
||||
|
||||
if ( ! isset( self::$_MANAGERS[ $id ] ) ) {
|
||||
self::$_MANAGERS[ $id ] = new FS_Cache_Manager( $id );
|
||||
}
|
||||
|
||||
return self::$_MANAGERS[ $id ];
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Vova Feldman (@svovaf)
|
||||
* @since 1.1.6
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
function is_empty() {
|
||||
$this->_logger->entrance();
|
||||
|
||||
return $this->_options->is_empty();
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Vova Feldman (@svovaf)
|
||||
* @since 1.1.6
|
||||
*/
|
||||
function clear() {
|
||||
$this->_logger->entrance();
|
||||
|
||||
$this->_options->clear( true );
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete cache manager from DB.
|
||||
*
|
||||
* @author Vova Feldman (@svovaf)
|
||||
* @since 1.0.9
|
||||
*/
|
||||
function delete() {
|
||||
$this->_options->delete();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if there's a cached item.
|
||||
*
|
||||
* @author Vova Feldman (@svovaf)
|
||||
* @since 1.1.6
|
||||
*
|
||||
* @param string $key
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
function has( $key ) {
|
||||
$cache_entry = $this->_options->get_option( $key, false );
|
||||
|
||||
return ( is_object( $cache_entry ) &&
|
||||
isset( $cache_entry->timestamp ) &&
|
||||
is_numeric( $cache_entry->timestamp )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if there's a valid cached item.
|
||||
*
|
||||
* @author Vova Feldman (@svovaf)
|
||||
* @since 1.1.6
|
||||
*
|
||||
* @param string $key
|
||||
* @param null|int $expiration Since 1.2.2.7
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
function has_valid( $key, $expiration = null ) {
|
||||
$cache_entry = $this->_options->get_option( $key, false );
|
||||
|
||||
$is_valid = ( is_object( $cache_entry ) &&
|
||||
isset( $cache_entry->timestamp ) &&
|
||||
is_numeric( $cache_entry->timestamp ) &&
|
||||
$cache_entry->timestamp > WP_FS__SCRIPT_START_TIME
|
||||
);
|
||||
|
||||
if ( $is_valid &&
|
||||
is_numeric( $expiration ) &&
|
||||
isset( $cache_entry->created ) &&
|
||||
is_numeric( $cache_entry->created ) &&
|
||||
$cache_entry->created + $expiration < WP_FS__SCRIPT_START_TIME
|
||||
) {
|
||||
/**
|
||||
* Even if the cache is still valid, since we are checking for validity
|
||||
* with an explicit expiration period, if the period has past, return
|
||||
* `false` as if the cache is invalid.
|
||||
*
|
||||
* @since 1.2.2.7
|
||||
*/
|
||||
$is_valid = false;
|
||||
}
|
||||
|
||||
return $is_valid;
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Vova Feldman (@svovaf)
|
||||
* @since 1.1.6
|
||||
*
|
||||
* @param string $key
|
||||
* @param mixed $default
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
function get( $key, $default = null ) {
|
||||
$this->_logger->entrance( 'key = ' . $key );
|
||||
|
||||
$cache_entry = $this->_options->get_option( $key, false );
|
||||
|
||||
if ( is_object( $cache_entry ) &&
|
||||
isset( $cache_entry->timestamp ) &&
|
||||
is_numeric( $cache_entry->timestamp )
|
||||
) {
|
||||
return $cache_entry->result;
|
||||
}
|
||||
|
||||
return is_object( $default ) ? clone $default : $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Vova Feldman (@svovaf)
|
||||
* @since 1.1.6
|
||||
*
|
||||
* @param string $key
|
||||
* @param mixed $default
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
function get_valid( $key, $default = null ) {
|
||||
$this->_logger->entrance( 'key = ' . $key );
|
||||
|
||||
$cache_entry = $this->_options->get_option( $key, false );
|
||||
|
||||
if ( is_object( $cache_entry ) &&
|
||||
isset( $cache_entry->timestamp ) &&
|
||||
is_numeric( $cache_entry->timestamp ) &&
|
||||
$cache_entry->timestamp > WP_FS__SCRIPT_START_TIME
|
||||
) {
|
||||
return $cache_entry->result;
|
||||
}
|
||||
|
||||
return is_object( $default ) ? clone $default : $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Vova Feldman (@svovaf)
|
||||
* @since 1.1.6
|
||||
*
|
||||
* @param string $key
|
||||
* @param mixed $value
|
||||
* @param int $expiration
|
||||
* @param int $created Since 2.0.0 Cache creation date.
|
||||
*/
|
||||
function set( $key, $value, $expiration = WP_FS__TIME_24_HOURS_IN_SEC, $created = WP_FS__SCRIPT_START_TIME ) {
|
||||
$this->_logger->entrance( 'key = ' . $key );
|
||||
|
||||
$cache_entry = new stdClass();
|
||||
|
||||
$cache_entry->result = $value;
|
||||
$cache_entry->created = $created;
|
||||
$cache_entry->timestamp = $created + $expiration;
|
||||
$this->_options->set_option( $key, $cache_entry, true );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get cached record expiration, or false if not cached or expired.
|
||||
*
|
||||
* @author Vova Feldman (@svovaf)
|
||||
* @since 1.1.7.3
|
||||
*
|
||||
* @param string $key
|
||||
*
|
||||
* @return bool|int
|
||||
*/
|
||||
function get_record_expiration( $key ) {
|
||||
$this->_logger->entrance( 'key = ' . $key );
|
||||
|
||||
$cache_entry = $this->_options->get_option( $key, false );
|
||||
|
||||
if ( is_object( $cache_entry ) &&
|
||||
isset( $cache_entry->timestamp ) &&
|
||||
is_numeric( $cache_entry->timestamp ) &&
|
||||
$cache_entry->timestamp > WP_FS__SCRIPT_START_TIME
|
||||
) {
|
||||
return $cache_entry->timestamp;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Purge cached item.
|
||||
*
|
||||
* @author Vova Feldman (@svovaf)
|
||||
* @since 1.1.6
|
||||
*
|
||||
* @param string $key
|
||||
*/
|
||||
function purge( $key ) {
|
||||
$this->_logger->entrance( 'key = ' . $key );
|
||||
|
||||
$this->_options->unset_option( $key, true );
|
||||
}
|
||||
|
||||
/**
|
||||
* Extend cached item caching period.
|
||||
*
|
||||
* @author Vova Feldman (@svovaf)
|
||||
* @since 2.0.0
|
||||
*
|
||||
* @param string $key
|
||||
* @param int $expiration
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
function update_expiration( $key, $expiration = WP_FS__TIME_24_HOURS_IN_SEC ) {
|
||||
$this->_logger->entrance( 'key = ' . $key );
|
||||
|
||||
$cache_entry = $this->_options->get_option( $key, false );
|
||||
|
||||
if ( ! is_object( $cache_entry ) ||
|
||||
! isset( $cache_entry->timestamp ) ||
|
||||
! is_numeric( $cache_entry->timestamp )
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->set( $key, $cache_entry->result, $expiration, $cache_entry->created );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set cached item as expired.
|
||||
*
|
||||
* @author Vova Feldman (@svovaf)
|
||||
* @since 1.2.2.7
|
||||
*
|
||||
* @param string $key
|
||||
*/
|
||||
function expire( $key ) {
|
||||
$this->_logger->entrance( 'key = ' . $key );
|
||||
|
||||
$cache_entry = $this->_options->get_option( $key, false );
|
||||
|
||||
if ( is_object( $cache_entry ) &&
|
||||
isset( $cache_entry->timestamp ) &&
|
||||
is_numeric( $cache_entry->timestamp )
|
||||
) {
|
||||
// Set to expired.
|
||||
$cache_entry->timestamp = WP_FS__SCRIPT_START_TIME;
|
||||
$this->_options->set_option( $key, $cache_entry, true );
|
||||
}
|
||||
}
|
||||
|
||||
#--------------------------------------------------------------------------------
|
||||
#region Migration
|
||||
#--------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Migrate options from site level.
|
||||
*
|
||||
* @author Vova Feldman (@svovaf)
|
||||
* @since 2.0.0
|
||||
*/
|
||||
function migrate_to_network() {
|
||||
$this->_options->migrate_to_network();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
@ -0,0 +1,202 @@
|
||||
<?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 2.1.0
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
class FS_GDPR_Manager {
|
||||
/**
|
||||
* @var FS_Option_Manager
|
||||
*/
|
||||
private $_storage;
|
||||
/**
|
||||
* @var array {
|
||||
* @type bool $required Are GDPR rules apply on the current context admin.
|
||||
* @type bool $show_opt_in_notice Should the marketing and offers opt-in message be shown to the admin or not. If not set, defaults to `true`.
|
||||
* @type int $notice_shown_at Last time the special GDPR opt-in message was shown to the current admin.
|
||||
* }
|
||||
*/
|
||||
private $_data;
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private $_wp_user_id;
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $_option_name;
|
||||
/**
|
||||
* @var FS_Admin_Notices
|
||||
*/
|
||||
private $_notices;
|
||||
|
||||
#--------------------------------------------------------------------------------
|
||||
#region Singleton
|
||||
#--------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @var FS_GDPR_Manager
|
||||
*/
|
||||
private static $_instance;
|
||||
|
||||
/**
|
||||
* @return FS_GDPR_Manager
|
||||
*/
|
||||
public static function instance() {
|
||||
if ( ! isset( self::$_instance ) ) {
|
||||
self::$_instance = new self();
|
||||
}
|
||||
|
||||
return self::$_instance;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private function __construct() {
|
||||
$this->_storage = FS_Option_Manager::get_manager( WP_FS__GDPR_OPTION_NAME, true, true );
|
||||
$this->_wp_user_id = Freemius::get_current_wp_user_id();
|
||||
$this->_option_name = "u{$this->_wp_user_id}";
|
||||
$this->_data = $this->_storage->get_option( $this->_option_name, array() );
|
||||
$this->_notices = FS_Admin_Notices::instance( 'all_admins', '', '', true );
|
||||
|
||||
if ( ! is_array( $this->_data ) ) {
|
||||
$this->_data = array();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a GDPR option for the current admin and store it.
|
||||
*
|
||||
* @author Vova Feldman (@svovaf)
|
||||
* @since 2.1.0
|
||||
*
|
||||
* @param string $name
|
||||
* @param mixed $value
|
||||
*/
|
||||
private function update_option( $name, $value ) {
|
||||
$this->_data[ $name ] = $value;
|
||||
|
||||
$this->_storage->set_option( $this->_option_name, $this->_data, true );
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Leo Fajardo (@leorw)
|
||||
* @since 2.1.0
|
||||
*
|
||||
* @return bool|null
|
||||
*/
|
||||
public function is_required() {
|
||||
return isset( $this->_data['required'] ) ?
|
||||
$this->_data['required'] :
|
||||
null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Leo Fajardo (@leorw)
|
||||
* @since 2.1.0
|
||||
*
|
||||
* @param bool $is_required
|
||||
*/
|
||||
public function store_is_required( $is_required ) {
|
||||
$this->update_option( 'required', $is_required );
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the GDPR opt-in sticky notice is currently shown.
|
||||
*
|
||||
* @author Vova Feldman (@svovaf)
|
||||
* @since 2.1.0
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function is_opt_in_notice_shown() {
|
||||
return $this->_notices->has_sticky( "gdpr_optin_actions_{$this->_wp_user_id}", true );
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the GDPR opt-in sticky notice.
|
||||
*
|
||||
* @author Vova Feldman (@svovaf)
|
||||
* @since 2.1.0
|
||||
*/
|
||||
public function remove_opt_in_notice() {
|
||||
$this->_notices->remove_sticky( "gdpr_optin_actions_{$this->_wp_user_id}", true );
|
||||
|
||||
$this->disable_opt_in_notice();
|
||||
}
|
||||
|
||||
/**
|
||||
* Prevents the opt-in message from being added/shown.
|
||||
*
|
||||
* @author Leo Fajardo (@leorw)
|
||||
* @since 2.1.0
|
||||
*/
|
||||
public function disable_opt_in_notice() {
|
||||
$this->update_option( 'show_opt_in_notice', false );
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a GDPR opt-in message needs to be shown to the current admin.
|
||||
*
|
||||
* @author Vova Feldman (@svovaf)
|
||||
* @since 2.1.0
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function should_show_opt_in_notice() {
|
||||
return (
|
||||
! isset( $this->_data['show_opt_in_notice'] ) ||
|
||||
true === $this->_data['show_opt_in_notice']
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the last time the GDPR opt-in notice was shown.
|
||||
*
|
||||
* @author Vova Feldman (@svovaf)
|
||||
* @since 2.1.0
|
||||
*
|
||||
* @return false|int
|
||||
*/
|
||||
public function last_time_notice_was_shown() {
|
||||
return isset( $this->_data['notice_shown_at'] ) ?
|
||||
$this->_data['notice_shown_at'] :
|
||||
false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the timestamp of the last time the GDPR opt-in message was shown to now.
|
||||
*
|
||||
* @author Vova Feldman (@svovaf)
|
||||
* @since 2.1.0
|
||||
*/
|
||||
public function notice_was_just_shown() {
|
||||
$this->update_option( 'notice_shown_at', WP_FS__SCRIPT_START_TIME );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $message
|
||||
* @param string|null $plugin_title
|
||||
*
|
||||
* @author Vova Feldman (@svovaf)
|
||||
* @since 2.1.0
|
||||
*/
|
||||
public function add_opt_in_sticky_notice( $message, $plugin_title = null ) {
|
||||
$this->_notices->add_sticky(
|
||||
$message,
|
||||
"gdpr_optin_actions_{$this->_wp_user_id}",
|
||||
'',
|
||||
'promotion',
|
||||
true,
|
||||
$this->_wp_user_id,
|
||||
$plugin_title,
|
||||
true
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,392 @@
|
||||
<?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.7
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Class FS_Key_Value_Storage
|
||||
*
|
||||
* @property int $install_timestamp
|
||||
* @property int $activation_timestamp
|
||||
* @property int $sync_timestamp
|
||||
* @property object $sync_cron
|
||||
* @property int $install_sync_timestamp
|
||||
* @property array $connectivity_test
|
||||
* @property array $is_on
|
||||
* @property object $trial_plan
|
||||
* @property bool $has_trial_plan
|
||||
* @property bool $trial_promotion_shown
|
||||
* @property string $sdk_version
|
||||
* @property string $sdk_last_version
|
||||
* @property bool $sdk_upgrade_mode
|
||||
* @property bool $sdk_downgrade_mode
|
||||
* @property bool $plugin_upgrade_mode
|
||||
* @property bool $plugin_downgrade_mode
|
||||
* @property string $plugin_version
|
||||
* @property string $plugin_last_version
|
||||
* @property bool $is_plugin_new_install
|
||||
* @property bool $was_plugin_loaded
|
||||
* @property object $plugin_main_file
|
||||
* @property bool $prev_is_premium
|
||||
* @property array $is_anonymous
|
||||
* @property bool $is_pending_activation
|
||||
* @property bool $sticky_optin_added
|
||||
* @property object $uninstall_reason
|
||||
* @property object $subscription
|
||||
*/
|
||||
class FS_Key_Value_Storage implements ArrayAccess, Iterator, Countable {
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $_id;
|
||||
|
||||
/**
|
||||
* @since 1.2.2
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $_secondary_id;
|
||||
|
||||
/**
|
||||
* @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_multisite_storage;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $_data;
|
||||
|
||||
/**
|
||||
* @var FS_Key_Value_Storage[]
|
||||
*/
|
||||
private static $_instances = array();
|
||||
|
||||
/**
|
||||
* @var FS_Logger
|
||||
*/
|
||||
protected $_logger;
|
||||
|
||||
/**
|
||||
* @param string $id
|
||||
* @param string $secondary_id
|
||||
* @param bool $network_level_or_blog_id
|
||||
*
|
||||
* @return FS_Key_Value_Storage
|
||||
*/
|
||||
static function instance( $id, $secondary_id, $network_level_or_blog_id = false ) {
|
||||
$key = $id . ':' . $secondary_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::$_instances[ $key ] ) ) {
|
||||
self::$_instances[ $key ] = new FS_Key_Value_Storage( $id, $secondary_id, $network_level_or_blog_id );
|
||||
}
|
||||
|
||||
return self::$_instances[ $key ];
|
||||
}
|
||||
|
||||
protected function __construct( $id, $secondary_id, $network_level_or_blog_id = false ) {
|
||||
$this->_logger = FS_Logger::get_logger( WP_FS__SLUG . '_' . $secondary_id . '_' . $id, WP_FS__DEBUG_SDK, WP_FS__ECHO_DEBUG_SDK );
|
||||
|
||||
$this->_id = $id;
|
||||
$this->_secondary_id = $secondary_id;
|
||||
|
||||
if ( is_multisite() ) {
|
||||
$this->_is_multisite_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_multisite_storage = false;
|
||||
}
|
||||
|
||||
$this->load();
|
||||
}
|
||||
|
||||
protected function get_option_manager() {
|
||||
return FS_Option_Manager::get_manager(
|
||||
WP_FS__ACCOUNTS_OPTION_NAME,
|
||||
true,
|
||||
$this->_is_multisite_storage ?
|
||||
true :
|
||||
( $this->_blog_id > 0 ? $this->_blog_id : false )
|
||||
);
|
||||
}
|
||||
|
||||
protected function get_all_data() {
|
||||
return $this->get_option_manager()->get_option( $this->_id, array() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Load plugin data from local DB.
|
||||
*
|
||||
* @author Vova Feldman (@svovaf)
|
||||
* @since 1.0.7
|
||||
*/
|
||||
function load() {
|
||||
$all_plugins_data = $this->get_all_data();
|
||||
$this->_data = isset( $all_plugins_data[ $this->_secondary_id ] ) ?
|
||||
$all_plugins_data[ $this->_secondary_id ] :
|
||||
array();
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Vova Feldman (@svovaf)
|
||||
* @since 1.0.7
|
||||
*
|
||||
* @param string $key
|
||||
* @param mixed $value
|
||||
* @param bool $flush
|
||||
*/
|
||||
function store( $key, $value, $flush = true ) {
|
||||
if ( $this->_logger->is_on() ) {
|
||||
$this->_logger->entrance( $key . ' = ' . var_export( $value, true ) );
|
||||
}
|
||||
|
||||
if ( array_key_exists( $key, $this->_data ) && $value === $this->_data[ $key ] ) {
|
||||
// No need to store data if the value wasn't changed.
|
||||
return;
|
||||
}
|
||||
|
||||
$all_data = $this->get_all_data();
|
||||
|
||||
$this->_data[ $key ] = $value;
|
||||
|
||||
$all_data[ $this->_secondary_id ] = $this->_data;
|
||||
|
||||
$options_manager = $this->get_option_manager();
|
||||
$options_manager->set_option( $this->_id, $all_data, $flush );
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Vova Feldman (@svovaf)
|
||||
* @since 2.0.0
|
||||
*/
|
||||
function save() {
|
||||
$this->get_option_manager()->store();
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Vova Feldman (@svovaf)
|
||||
* @since 1.0.7
|
||||
*
|
||||
* @param bool $store
|
||||
* @param string[] $exceptions Set of keys to keep and not clear.
|
||||
*/
|
||||
function clear_all( $store = true, $exceptions = array() ) {
|
||||
$new_data = array();
|
||||
foreach ( $exceptions as $key ) {
|
||||
if ( isset( $this->_data[ $key ] ) ) {
|
||||
$new_data[ $key ] = $this->_data[ $key ];
|
||||
}
|
||||
}
|
||||
|
||||
$this->_data = $new_data;
|
||||
|
||||
if ( $store ) {
|
||||
$all_data = $this->get_all_data();
|
||||
$all_data[ $this->_secondary_id ] = $this->_data;
|
||||
$options_manager = $this->get_option_manager();
|
||||
$options_manager->set_option( $this->_id, $all_data, true );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete key-value storage.
|
||||
*
|
||||
* @author Vova Feldman (@svovaf)
|
||||
* @since 1.0.9
|
||||
*/
|
||||
function delete() {
|
||||
$this->_data = array();
|
||||
|
||||
$all_data = $this->get_all_data();
|
||||
unset( $all_data[ $this->_secondary_id ] );
|
||||
$options_manager = $this->get_option_manager();
|
||||
$options_manager->set_option( $this->_id, $all_data, true );
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Vova Feldman (@svovaf)
|
||||
* @since 1.0.7
|
||||
*
|
||||
* @param string $key
|
||||
* @param bool $store
|
||||
*/
|
||||
function remove( $key, $store = true ) {
|
||||
if ( ! array_key_exists( $key, $this->_data ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
unset( $this->_data[ $key ] );
|
||||
|
||||
if ( $store ) {
|
||||
$all_data = $this->get_all_data();
|
||||
$all_data[ $this->_secondary_id ] = $this->_data;
|
||||
$options_manager = $this->get_option_manager();
|
||||
$options_manager->set_option( $this->_id, $all_data, true );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Vova Feldman (@svovaf)
|
||||
* @since 1.0.7
|
||||
*
|
||||
* @param string $key
|
||||
* @param mixed $default
|
||||
*
|
||||
* @return bool|\FS_Plugin
|
||||
*/
|
||||
function get( $key, $default = false ) {
|
||||
return array_key_exists( $key, $this->_data ) ?
|
||||
$this->_data[ $key ] :
|
||||
$default;
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Vova Feldman (@svovaf)
|
||||
* @since 2.0.0
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function get_secondary_id() {
|
||||
return $this->_secondary_id;
|
||||
}
|
||||
|
||||
|
||||
/* ArrayAccess + Magic Access (better for refactoring)
|
||||
-----------------------------------------------------------------------------------*/
|
||||
function __set( $k, $v ) {
|
||||
$this->store( $k, $v );
|
||||
}
|
||||
|
||||
function __isset( $k ) {
|
||||
return array_key_exists( $k, $this->_data );
|
||||
}
|
||||
|
||||
function __unset( $k ) {
|
||||
$this->remove( $k );
|
||||
}
|
||||
|
||||
function __get( $k ) {
|
||||
return $this->get( $k, null );
|
||||
}
|
||||
|
||||
function offsetSet( $k, $v ) {
|
||||
if ( is_null( $k ) ) {
|
||||
throw new Exception( 'Can\'t append value to request params.' );
|
||||
} else {
|
||||
$this->{$k} = $v;
|
||||
}
|
||||
}
|
||||
|
||||
function offsetExists( $k ) {
|
||||
return array_key_exists( $k, $this->_data );
|
||||
}
|
||||
|
||||
function offsetUnset( $k ) {
|
||||
unset( $this->$k );
|
||||
}
|
||||
|
||||
function offsetGet( $k ) {
|
||||
return $this->get( $k, null );
|
||||
}
|
||||
|
||||
/**
|
||||
* (PHP 5 >= 5.0.0)<br/>
|
||||
* Return the current element
|
||||
*
|
||||
* @link http://php.net/manual/en/iterator.current.php
|
||||
* @return mixed Can return any type.
|
||||
*/
|
||||
public function current() {
|
||||
return current( $this->_data );
|
||||
}
|
||||
|
||||
/**
|
||||
* (PHP 5 >= 5.0.0)<br/>
|
||||
* Move forward to next element
|
||||
*
|
||||
* @link http://php.net/manual/en/iterator.next.php
|
||||
* @return void Any returned value is ignored.
|
||||
*/
|
||||
public function next() {
|
||||
next( $this->_data );
|
||||
}
|
||||
|
||||
/**
|
||||
* (PHP 5 >= 5.0.0)<br/>
|
||||
* Return the key of the current element
|
||||
*
|
||||
* @link http://php.net/manual/en/iterator.key.php
|
||||
* @return mixed scalar on success, or null on failure.
|
||||
*/
|
||||
public function key() {
|
||||
return key( $this->_data );
|
||||
}
|
||||
|
||||
/**
|
||||
* (PHP 5 >= 5.0.0)<br/>
|
||||
* Checks if current position is valid
|
||||
*
|
||||
* @link http://php.net/manual/en/iterator.valid.php
|
||||
* @return boolean The return value will be casted to boolean and then evaluated.
|
||||
* Returns true on success or false on failure.
|
||||
*/
|
||||
public function valid() {
|
||||
$key = key( $this->_data );
|
||||
|
||||
return ( $key !== null && $key !== false );
|
||||
}
|
||||
|
||||
/**
|
||||
* (PHP 5 >= 5.0.0)<br/>
|
||||
* Rewind the Iterator to the first element
|
||||
*
|
||||
* @link http://php.net/manual/en/iterator.rewind.php
|
||||
* @return void Any returned value is ignored.
|
||||
*/
|
||||
public function rewind() {
|
||||
reset( $this->_data );
|
||||
}
|
||||
|
||||
/**
|
||||
* (PHP 5 >= 5.1.0)<br/>
|
||||
* Count elements of an object
|
||||
*
|
||||
* @link http://php.net/manual/en/countable.count.php
|
||||
* @return int The custom count as an integer.
|
||||
* </p>
|
||||
* <p>
|
||||
* The return value is cast to an integer.
|
||||
*/
|
||||
public function count() {
|
||||
return count( $this->_data );
|
||||
}
|
||||
}
|
@ -0,0 +1,104 @@
|
||||
<?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.6
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
class FS_License_Manager /*extends FS_Abstract_Manager*/
|
||||
{
|
||||
//
|
||||
//
|
||||
// /**
|
||||
// * @var FS_License_Manager[]
|
||||
// */
|
||||
// private static $_instances = array();
|
||||
//
|
||||
// static function instance( Freemius $fs ) {
|
||||
// $slug = strtolower( $fs->get_slug() );
|
||||
//
|
||||
// if ( ! isset( self::$_instances[ $slug ] ) ) {
|
||||
// self::$_instances[ $slug ] = new FS_License_Manager( $slug, $fs );
|
||||
// }
|
||||
//
|
||||
// return self::$_instances[ $slug ];
|
||||
// }
|
||||
//
|
||||
//// private function __construct($slug) {
|
||||
//// parent::__construct($slug);
|
||||
//// }
|
||||
//
|
||||
// function entry_id() {
|
||||
// return 'licenses';
|
||||
// }
|
||||
//
|
||||
// function sync( $id ) {
|
||||
//
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * @author Vova Feldman (@svovaf)
|
||||
// * @since 1.0.5
|
||||
// * @uses FS_Api
|
||||
// *
|
||||
// * @param number|bool $plugin_id
|
||||
// *
|
||||
// * @return FS_Plugin_License[]|stdClass Licenses or API error.
|
||||
// */
|
||||
// function api_get_user_plugin_licenses( $plugin_id = false ) {
|
||||
// $api = $this->_fs->get_api_user_scope();
|
||||
//
|
||||
// if ( ! is_numeric( $plugin_id ) ) {
|
||||
// $plugin_id = $this->_fs->get_id();
|
||||
// }
|
||||
//
|
||||
// $result = $api->call( "/plugins/{$plugin_id}/licenses.json" );
|
||||
//
|
||||
// if ( ! isset( $result->error ) ) {
|
||||
// for ( $i = 0, $len = count( $result->licenses ); $i < $len; $i ++ ) {
|
||||
// $result->licenses[ $i ] = new FS_Plugin_License( $result->licenses[ $i ] );
|
||||
// }
|
||||
//
|
||||
// $result = $result->licenses;
|
||||
// }
|
||||
//
|
||||
// return $result;
|
||||
// }
|
||||
//
|
||||
// function api_get_many() {
|
||||
//
|
||||
// }
|
||||
//
|
||||
// function api_activate( $id ) {
|
||||
//
|
||||
// }
|
||||
//
|
||||
// function api_deactivate( $id ) {
|
||||
//
|
||||
// }
|
||||
|
||||
/**
|
||||
* @param FS_Plugin_License[] $licenses
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
static function has_premium_license( $licenses ) {
|
||||
if ( is_array( $licenses ) ) {
|
||||
foreach ( $licenses as $license ) {
|
||||
/**
|
||||
* @var FS_Plugin_License $license
|
||||
*/
|
||||
if ( ! $license->is_utilized() && $license->is_features_enabled() ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
@ -0,0 +1,521 @@
|
||||
<?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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 3-layer lazy options manager.
|
||||
* layer 3: Memory
|
||||
* layer 2: Cache (if there's any caching plugin and if WP_FS__DEBUG_SDK is FALSE)
|
||||
* 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();
|
||||
|
||||
$option_name = $this->get_option_manager_name();
|
||||
|
||||
if ( $flush || ! isset( $this->_options ) ) {
|
||||
if ( isset( $this->_options ) ) {
|
||||
// Clear prev options.
|
||||
$this->clear();
|
||||
}
|
||||
|
||||
$cache_group = $this->get_cache_group();
|
||||
|
||||
if ( WP_FS__DEBUG_SDK ) {
|
||||
|
||||
// Don't use cache layer in DEBUG mode.
|
||||
$load_options = empty( $this->_options );
|
||||
|
||||
} else {
|
||||
|
||||
$this->_options = wp_cache_get(
|
||||
$option_name,
|
||||
$cache_group
|
||||
);
|
||||
|
||||
$load_options = ( false === $this->_options );
|
||||
}
|
||||
|
||||
$cached = true;
|
||||
|
||||
if ( $load_options ) {
|
||||
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();
|
||||
}
|
||||
|
||||
$cached = false;
|
||||
}
|
||||
|
||||
if ( ! WP_FS__DEBUG_SDK && ! $cached ) {
|
||||
// Set non encoded cache.
|
||||
wp_cache_set( $option_name, $this->_options, $cache_group );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @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
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
function has_option( $option ) {
|
||||
return array_key_exists( $option, $this->_options );
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Vova Feldman (@svovaf)
|
||||
* @since 1.0.3
|
||||
*
|
||||
* @param string $option
|
||||
* @param mixed $default
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
function get_option( $option, $default = null ) {
|
||||
$this->_logger->entrance( 'option = ' . $option );
|
||||
|
||||
if ( ! $this->is_loaded() ) {
|
||||
$this->load();
|
||||
}
|
||||
|
||||
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 options 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 );
|
||||
}
|
||||
|
||||
if ( ! WP_FS__DEBUG_SDK ) {
|
||||
wp_cache_set( $option_name, $this->_options, $this->get_cache_group() );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Vova Feldman (@svovaf)
|
||||
* @since 2.0.0
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function get_cache_group() {
|
||||
$group = WP_FS__SLUG;
|
||||
|
||||
if ( $this->_is_network_storage ) {
|
||||
$group .= '_ms';
|
||||
} else if ( $this->_blog_id > 0 ) {
|
||||
$group .= "_s{$this->_blog_id}";
|
||||
}
|
||||
|
||||
return $group;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
@ -0,0 +1,162 @@
|
||||
<?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.6
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
class FS_Plan_Manager {
|
||||
/**
|
||||
* @var FS_Plan_Manager
|
||||
*/
|
||||
private static $_instance;
|
||||
|
||||
/**
|
||||
* @return FS_Plan_Manager
|
||||
*/
|
||||
static function instance() {
|
||||
if ( ! isset( self::$_instance ) ) {
|
||||
self::$_instance = new FS_Plan_Manager();
|
||||
}
|
||||
|
||||
return self::$_instance;
|
||||
}
|
||||
|
||||
private function __construct() {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param FS_Plugin_License[] $licenses
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
function has_premium_license( $licenses ) {
|
||||
if ( is_array( $licenses ) ) {
|
||||
/**
|
||||
* @var FS_Plugin_License[] $licenses
|
||||
*/
|
||||
foreach ( $licenses as $license ) {
|
||||
if ( ! $license->is_utilized() && $license->is_features_enabled() ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if plugin has any paid plans.
|
||||
*
|
||||
* @author Vova Feldman (@svovaf)
|
||||
* @since 1.0.7
|
||||
*
|
||||
* @param FS_Plugin_Plan[] $plans
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
function has_paid_plan( $plans ) {
|
||||
if ( ! is_array( $plans ) || 0 === count( $plans ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @var FS_Plugin_Plan[] $plans
|
||||
*/
|
||||
for ( $i = 0, $len = count( $plans ); $i < $len; $i ++ ) {
|
||||
if ( ! $plans[ $i ]->is_free() ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if plugin has any free plan, or is it premium only.
|
||||
*
|
||||
* Note: If no plans configured, assume plugin is free.
|
||||
*
|
||||
* @author Vova Feldman (@svovaf)
|
||||
* @since 1.0.7
|
||||
*
|
||||
* @param FS_Plugin_Plan[] $plans
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
function has_free_plan( $plans ) {
|
||||
if ( ! is_array( $plans ) || 0 === count( $plans ) ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @var FS_Plugin_Plan[] $plans
|
||||
*/
|
||||
for ( $i = 0, $len = count( $plans ); $i < $len; $i ++ ) {
|
||||
if ( $plans[ $i ]->is_free() ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find all plans that have trial.
|
||||
*
|
||||
* @author Vova Feldman (@svovaf)
|
||||
* @since 1.0.9
|
||||
*
|
||||
* @param FS_Plugin_Plan[] $plans
|
||||
*
|
||||
* @return FS_Plugin_Plan[]
|
||||
*/
|
||||
function get_trial_plans( $plans ) {
|
||||
$trial_plans = array();
|
||||
|
||||
if ( is_array( $plans ) && 0 < count( $plans ) ) {
|
||||
/**
|
||||
* @var FS_Plugin_Plan[] $plans
|
||||
*/
|
||||
for ( $i = 0, $len = count( $plans ); $i < $len; $i ++ ) {
|
||||
if ( $plans[ $i ]->has_trial() ) {
|
||||
$trial_plans[] = $plans[ $i ];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $trial_plans;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if plugin has any trial plan.
|
||||
*
|
||||
* @author Vova Feldman (@svovaf)
|
||||
* @since 1.0.9
|
||||
*
|
||||
* @param FS_Plugin_Plan[] $plans
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
function has_trial_plan( $plans ) {
|
||||
if ( ! is_array( $plans ) || 0 === count( $plans ) ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @var FS_Plugin_Plan[] $plans
|
||||
*/
|
||||
for ( $i = 0, $len = count( $plans ); $i < $len; $i ++ ) {
|
||||
if ( $plans[ $i ]->has_trial() ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
@ -0,0 +1,220 @@
|
||||
<?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.6
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
class FS_Plugin_Manager {
|
||||
/**
|
||||
* @since 1.2.2
|
||||
*
|
||||
* @var string|number
|
||||
*/
|
||||
protected $_module_id;
|
||||
/**
|
||||
* @since 1.2.2
|
||||
*
|
||||
* @var FS_Plugin
|
||||
*/
|
||||
protected $_module;
|
||||
|
||||
/**
|
||||
* @var FS_Plugin_Manager[]
|
||||
*/
|
||||
private static $_instances = array();
|
||||
/**
|
||||
* @var FS_Logger
|
||||
*/
|
||||
protected $_logger;
|
||||
|
||||
/**
|
||||
* Option names
|
||||
*
|
||||
* @author Leo Fajardo (@leorw)
|
||||
* @since 1.2.2
|
||||
*/
|
||||
const OPTION_NAME_PLUGINS = 'plugins';
|
||||
const OPTION_NAME_THEMES = 'themes';
|
||||
|
||||
/**
|
||||
* @param string|number $module_id
|
||||
*
|
||||
* @return FS_Plugin_Manager
|
||||
*/
|
||||
static function instance( $module_id ) {
|
||||
$key = 'm_' . $module_id;
|
||||
|
||||
if ( ! isset( self::$_instances[ $key ] ) ) {
|
||||
self::$_instances[ $key ] = new FS_Plugin_Manager( $module_id );
|
||||
}
|
||||
|
||||
return self::$_instances[ $key ];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string|number $module_id
|
||||
*/
|
||||
protected function __construct( $module_id ) {
|
||||
$this->_logger = FS_Logger::get_logger( WP_FS__SLUG . '_' . $module_id . '_' . 'plugins', WP_FS__DEBUG_SDK, WP_FS__ECHO_DEBUG_SDK );
|
||||
$this->_module_id = $module_id;
|
||||
|
||||
$this->load();
|
||||
}
|
||||
|
||||
protected function get_option_manager() {
|
||||
return FS_Option_Manager::get_manager( WP_FS__ACCOUNTS_OPTION_NAME, true, true );
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Leo Fajardo (@leorw)
|
||||
* @since 1.2.2
|
||||
*
|
||||
* @param string|bool $module_type "plugin", "theme", or "false" for all modules.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function get_all_modules( $module_type = false ) {
|
||||
$option_manager = $this->get_option_manager();
|
||||
|
||||
if ( false !== $module_type ) {
|
||||
return fs_get_entities( $option_manager->get_option( $module_type . 's', array() ), FS_Plugin::get_class_name() );
|
||||
}
|
||||
|
||||
return array(
|
||||
self::OPTION_NAME_PLUGINS => fs_get_entities( $option_manager->get_option( self::OPTION_NAME_PLUGINS, array() ), FS_Plugin::get_class_name() ),
|
||||
self::OPTION_NAME_THEMES => fs_get_entities( $option_manager->get_option( self::OPTION_NAME_THEMES, array() ), FS_Plugin::get_class_name() ),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load plugin data from local DB.
|
||||
*
|
||||
* @author Vova Feldman (@svovaf)
|
||||
* @since 1.0.6
|
||||
*/
|
||||
function load() {
|
||||
$all_modules = $this->get_all_modules();
|
||||
|
||||
if ( ! is_numeric( $this->_module_id ) ) {
|
||||
unset( $all_modules[ self::OPTION_NAME_THEMES ] );
|
||||
}
|
||||
|
||||
foreach ( $all_modules as $modules ) {
|
||||
/**
|
||||
* @since 1.2.2
|
||||
*
|
||||
* @var $modules FS_Plugin[]
|
||||
*/
|
||||
foreach ( $modules as $module ) {
|
||||
$found_module = false;
|
||||
|
||||
/**
|
||||
* If module ID is not numeric, it must be a plugin's slug.
|
||||
*
|
||||
* @author Leo Fajardo (@leorw)
|
||||
* @since 1.2.2
|
||||
*/
|
||||
if ( ! is_numeric( $this->_module_id ) ) {
|
||||
if ( $this->_module_id === $module->slug ) {
|
||||
$this->_module_id = $module->id;
|
||||
$found_module = true;
|
||||
}
|
||||
} else if ( $this->_module_id == $module->id ) {
|
||||
$found_module = true;
|
||||
}
|
||||
|
||||
if ( $found_module ) {
|
||||
$this->_module = $module;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Store plugin on local DB.
|
||||
*
|
||||
* @author Vova Feldman (@svovaf)
|
||||
* @since 1.0.6
|
||||
*
|
||||
* @param bool|FS_Plugin $module
|
||||
* @param bool $flush
|
||||
*
|
||||
* @return bool|\FS_Plugin
|
||||
*/
|
||||
function store( $module = false, $flush = true ) {
|
||||
if ( false !== $module ) {
|
||||
$this->_module = $module;
|
||||
}
|
||||
|
||||
$all_modules = $this->get_all_modules( $this->_module->type );
|
||||
$all_modules[ $this->_module->slug ] = $this->_module;
|
||||
|
||||
$options_manager = $this->get_option_manager();
|
||||
$options_manager->set_option( $this->_module->type . 's', $all_modules, $flush );
|
||||
|
||||
return $this->_module;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update local plugin data if different.
|
||||
*
|
||||
* @author Vova Feldman (@svovaf)
|
||||
* @since 1.0.6
|
||||
*
|
||||
* @param \FS_Plugin $plugin
|
||||
* @param bool $store
|
||||
*
|
||||
* @return bool True if plugin was updated.
|
||||
*/
|
||||
function update( FS_Plugin $plugin, $store = true ) {
|
||||
if ( ! ($this->_module instanceof FS_Plugin ) ||
|
||||
$this->_module->slug != $plugin->slug ||
|
||||
$this->_module->public_key != $plugin->public_key ||
|
||||
$this->_module->secret_key != $plugin->secret_key ||
|
||||
$this->_module->parent_plugin_id != $plugin->parent_plugin_id ||
|
||||
$this->_module->title != $plugin->title
|
||||
) {
|
||||
$this->store( $plugin, $store );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Vova Feldman (@svovaf)
|
||||
* @since 1.0.6
|
||||
*
|
||||
* @param FS_Plugin $plugin
|
||||
* @param bool $store
|
||||
*/
|
||||
function set( FS_Plugin $plugin, $store = false ) {
|
||||
$this->_module = $plugin;
|
||||
|
||||
if ( $store ) {
|
||||
$this->store();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Vova Feldman (@svovaf)
|
||||
* @since 1.0.6
|
||||
*
|
||||
* @return bool|\FS_Plugin
|
||||
*/
|
||||
function get() {
|
||||
return isset( $this->_module ) ?
|
||||
$this->_module :
|
||||
false;
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
<?php
|
||||
// Silence is golden.
|
||||
// Hide file structure from users on unprotected servers.
|
Reference in New Issue
Block a user