first commit
This commit is contained in:
@@ -0,0 +1,43 @@
|
||||
<?php if (!defined('FW')) die('Forbidden');
|
||||
|
||||
/**
|
||||
* Used in public callbacks to allow call only from known caller
|
||||
*
|
||||
* For e.g. Inside some class is created an instance of FW_Access_Key with unique key 'whatever',
|
||||
* so nobody else can create another instance with same key, only that class owns that unique key.
|
||||
* Some public callback (function or method) that wants to allow to be called only by that class,
|
||||
* sets an requirement that some parameter should be an instance on FW_Access_Key and its key should be 'whatever'
|
||||
*
|
||||
* function my_function(FW_Access_Key $key, $another_parameter) {
|
||||
* if ($key->get_key() !== 'whatever') {
|
||||
* trigger_error('Call denied', E_USER_ERROR);
|
||||
* }
|
||||
*
|
||||
* //...
|
||||
* }
|
||||
*/
|
||||
final class FW_Access_Key
|
||||
{
|
||||
private static $created_keys = array();
|
||||
|
||||
private $key;
|
||||
|
||||
final public function get_key()
|
||||
{
|
||||
return $this->key;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $unique_key unique
|
||||
*/
|
||||
final public function __construct($unique_key)
|
||||
{
|
||||
if (isset(self::$created_keys[$unique_key])) {
|
||||
trigger_error('Key "'. $unique_key .'" already defined', E_USER_ERROR);
|
||||
}
|
||||
|
||||
self::$created_keys[$unique_key] = true;
|
||||
|
||||
$this->key = $unique_key;
|
||||
}
|
||||
}
|
||||
309
wp-content/plugins/unyson/framework/helpers/class-fw-cache.php
Normal file
309
wp-content/plugins/unyson/framework/helpers/class-fw-cache.php
Normal file
@@ -0,0 +1,309 @@
|
||||
<?php if (!defined('FW')) die('Forbidden');
|
||||
|
||||
/**
|
||||
* Memory Cache
|
||||
*
|
||||
* Recommended usage example:
|
||||
* try {
|
||||
* $value = FW_Cache::get('some/key');
|
||||
* } catch(FW_Cache_Not_Found_Exception $e) {
|
||||
* $value = get_value_from_somewhere();
|
||||
*
|
||||
* FW_Cache::set('some/key', $value);
|
||||
*
|
||||
* // (!) after set, do not do this:
|
||||
* $value = FW_Cache::get('some/key');
|
||||
* // because there is no guaranty that FW_Cache::set('some/key', $value); succeeded
|
||||
* // trust only your $value, cache can do clean-up right after set() and remove the value you tried to set
|
||||
* }
|
||||
*
|
||||
* // use $value ...
|
||||
*/
|
||||
class FW_Cache
|
||||
{
|
||||
/**
|
||||
* The actual cache
|
||||
* @var array
|
||||
*/
|
||||
protected static $cache = array();
|
||||
|
||||
/**
|
||||
* If the PHP will have less that this memory, the cache will try to delete parts from its array to free memory
|
||||
*
|
||||
* (1024 * 1024 = 1048576 = 1 Mb) * 10
|
||||
*/
|
||||
protected static $min_free_memory = 10485760;
|
||||
|
||||
/**
|
||||
* A special value that is used to detect if value was found in cache
|
||||
* We can't use null|false because these can be values set by user and we can't treat them as not existing values
|
||||
*/
|
||||
protected static $not_found_value;
|
||||
|
||||
/**
|
||||
* The amount of times the data was already stored in the cache.
|
||||
* @var int
|
||||
* @since 2.4.17
|
||||
*/
|
||||
protected static $hits = 0;
|
||||
|
||||
/**
|
||||
* Amount of times the cache did not have the value in cache.
|
||||
* @var int
|
||||
* @since 2.4.17
|
||||
*/
|
||||
protected static $misses = 0;
|
||||
|
||||
/**
|
||||
* Amount of times the cache free was called.
|
||||
* @var int
|
||||
* @since 2.4.17
|
||||
*/
|
||||
protected static $freed = 0;
|
||||
|
||||
protected static function get_memory_limit()
|
||||
{
|
||||
$memory_limit = ini_get('memory_limit');
|
||||
|
||||
if ($memory_limit === '-1') { // This happens in WP CLI
|
||||
return 256 * 1024 * 1024;
|
||||
}
|
||||
|
||||
switch (substr($memory_limit, -1)) {
|
||||
case 'M': return intval($memory_limit) * 1024 * 1024;
|
||||
case 'K': return intval($memory_limit) * 1024;
|
||||
case 'G': return intval($memory_limit) * 1024 * 1024 * 1024;
|
||||
default: return intval($memory_limit) * 1024 * 1024;
|
||||
}
|
||||
}
|
||||
|
||||
protected static function memory_exceeded()
|
||||
{
|
||||
return memory_get_usage(false) >= self::get_memory_limit() - self::$min_free_memory;
|
||||
|
||||
// about memory_get_usage(false) http://stackoverflow.com/a/16239377/1794248
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
public static function _init()
|
||||
{
|
||||
self::$not_found_value = new FW_Cache_Not_Found_Exception();
|
||||
|
||||
/**
|
||||
* Listen often triggered hooks to clear the memory
|
||||
* instead of tick function https://github.com/ThemeFuse/Unyson/issues/1197
|
||||
* @since 2.4.17
|
||||
*/
|
||||
foreach (array(
|
||||
'query' => true,
|
||||
'plugins_loaded' => true,
|
||||
'wp_get_object_terms' => true,
|
||||
'created_term' => true,
|
||||
'wp_upgrade' => true,
|
||||
'added_option' => true,
|
||||
'updated_option' => true,
|
||||
'deleted_option' => true,
|
||||
'wp_after_admin_bar_render' => true,
|
||||
'http_response' => true,
|
||||
'oembed_result' => true,
|
||||
'customize_post_value_set' => true,
|
||||
'customize_save_after' => true,
|
||||
'customize_render_panel' => true,
|
||||
'customize_render_control' => true,
|
||||
'customize_render_section' => true,
|
||||
'role_has_cap' => true,
|
||||
'user_has_cap' => true,
|
||||
'theme_page_templates' => true,
|
||||
'pre_get_users' => true,
|
||||
'request' => true,
|
||||
'send_headers' => true,
|
||||
'updated_usermeta' => true,
|
||||
'added_usermeta' => true,
|
||||
'image_memory_limit' => true,
|
||||
'upload_dir' => true,
|
||||
'wp_head' => true,
|
||||
'wp_footer' => true,
|
||||
'wp' => true,
|
||||
'wp_init' => true,
|
||||
'fw_init' => true,
|
||||
'init' => true,
|
||||
'updated_postmeta' => true,
|
||||
'deleted_postmeta' => true,
|
||||
'setted_transient' => true,
|
||||
'registered_post_type' => true,
|
||||
'wp_count_posts' => true,
|
||||
'wp_count_attachments' => true,
|
||||
'after_delete_post' => true,
|
||||
'post_updated' => true,
|
||||
'wp_insert_post' => true,
|
||||
'deleted_post' => true,
|
||||
'clean_post_cache' => true,
|
||||
'wp_restore_post_revision' => true,
|
||||
'wp_delete_post_revision' => true,
|
||||
'get_term' => true,
|
||||
'edited_term_taxonomies' => true,
|
||||
'deleted_term_taxonomy' => true,
|
||||
'edited_terms' => true,
|
||||
'created_term' => true,
|
||||
'clean_term_cache' => true,
|
||||
'edited_term_taxonomy' => true,
|
||||
'switch_theme' => true,
|
||||
'wp_get_update_data' => true,
|
||||
'clean_user_cache' => true,
|
||||
'process_text_diff_html' => true,
|
||||
) as $hook => $tmp) {
|
||||
add_filter($hook, array(__CLASS__, 'free_memory'), 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Flush the cache when something major is changed (files or db values)
|
||||
*/
|
||||
foreach (array(
|
||||
'switch_blog' => true,
|
||||
'upgrader_post_install' => true,
|
||||
'upgrader_process_complete' => true,
|
||||
'switch_theme' => true,
|
||||
) as $hook => $tmp) {
|
||||
add_filter($hook, array(__CLASS__, 'clear'), 1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method does nothing @since 2.4.17
|
||||
* but we can't delete it because it's public and maybe somebody is calling it
|
||||
* @return bool
|
||||
*/
|
||||
public static function is_enabled()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $dummy
|
||||
* @return mixed
|
||||
*/
|
||||
public static function free_memory($dummy = null)
|
||||
{
|
||||
while (self::memory_exceeded() && !empty(self::$cache)) {
|
||||
reset(self::$cache);
|
||||
|
||||
$key = key(self::$cache);
|
||||
|
||||
unset(self::$cache[$key]);
|
||||
}
|
||||
|
||||
++self::$freed;
|
||||
|
||||
/**
|
||||
* This method is used in add_filter() so to not break anything return filter value
|
||||
*/
|
||||
return $dummy;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $keys
|
||||
* @param $value
|
||||
* @param $keys_delimiter
|
||||
*/
|
||||
public static function set($keys, $value, $keys_delimiter = '/')
|
||||
{
|
||||
if (!self::is_enabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
self::free_memory();
|
||||
|
||||
fw_aks($keys, $value, self::$cache, $keys_delimiter);
|
||||
|
||||
self::free_memory();
|
||||
}
|
||||
|
||||
/**
|
||||
* Unset key from cache
|
||||
* @param $keys
|
||||
* @param $keys_delimiter
|
||||
*/
|
||||
public static function del($keys, $keys_delimiter = '/')
|
||||
{
|
||||
fw_aku($keys, self::$cache, $keys_delimiter);
|
||||
|
||||
self::free_memory();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $keys
|
||||
* @param $keys_delimiter
|
||||
* @return mixed
|
||||
* @throws FW_Cache_Not_Found_Exception
|
||||
*/
|
||||
public static function get($keys, $keys_delimiter = '/')
|
||||
{
|
||||
$keys = (string)$keys;
|
||||
$keys_arr = explode($keys_delimiter, $keys);
|
||||
|
||||
$key = $keys_arr;
|
||||
$key = array_shift($key);
|
||||
|
||||
if ($key === '' || $key === null) {
|
||||
trigger_error('First key must not be empty', E_USER_ERROR);
|
||||
}
|
||||
|
||||
self::free_memory();
|
||||
|
||||
$value = fw_akg($keys, self::$cache, self::$not_found_value, $keys_delimiter);
|
||||
|
||||
self::free_memory();
|
||||
|
||||
if ($value === self::$not_found_value) {
|
||||
++self::$misses;
|
||||
|
||||
throw new FW_Cache_Not_Found_Exception();
|
||||
} else {
|
||||
++self::$hits;
|
||||
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Empty the cache
|
||||
* @param mixed $dummy When method is used in add_filter()
|
||||
* @return mixed
|
||||
*/
|
||||
public static function clear($dummy = null)
|
||||
{
|
||||
self::$cache = array();
|
||||
|
||||
/**
|
||||
* This method is used in add_filter() so to not break anything return filter value
|
||||
*/
|
||||
return $dummy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Debug information
|
||||
* <?php add_action('admin_footer', function(){ FW_Cache::stats(); });
|
||||
* @since 2.4.17
|
||||
*/
|
||||
public static function stats() {
|
||||
echo '<div style="z-index: 10000; position: relative; background: #fff; padding: 15px;">';
|
||||
echo '<p>';
|
||||
echo '<strong>Cache Hits:</strong> '. self::$hits .'<br />';
|
||||
echo '<strong>Cache Misses:</strong> '. self::$misses .'<br />';
|
||||
echo '<strong>Cache Freed:</strong> '. self::$freed .'<br />';
|
||||
echo '<strong>PHP Memory Peak Usage:</strong> '. fw_human_bytes(memory_get_peak_usage(false)) .'<br />';
|
||||
echo '</p>';
|
||||
echo '<ul>';
|
||||
foreach (self::$cache as $group => $cache) {
|
||||
echo "<li><strong>Group:</strong> $group - ( " . number_format( strlen( serialize( $cache ) ) / KB_IN_BYTES, 2 ) . 'k )</li>';
|
||||
}
|
||||
echo '</ul>';
|
||||
echo '</div>';
|
||||
}
|
||||
}
|
||||
|
||||
class FW_Cache_Not_Found_Exception extends Exception {}
|
||||
|
||||
FW_Cache::_init();
|
||||
@@ -0,0 +1,132 @@
|
||||
<?php if ( ! defined( 'FW' ) ) {
|
||||
die( 'Forbidden' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Class FW_Callback
|
||||
*
|
||||
* @since 2.6.14
|
||||
*/
|
||||
class FW_Callback {
|
||||
/**
|
||||
* @var $callback string|array
|
||||
*/
|
||||
private $callback;
|
||||
|
||||
/**
|
||||
* @var array $args
|
||||
*/
|
||||
private $args;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private $cache;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $id;
|
||||
|
||||
/**
|
||||
* FW_Callback constructor.
|
||||
*
|
||||
* @param string|array|Closure $callback Callback function
|
||||
* @param array $args Callback arguments
|
||||
* @param bool $cache Whenever you want to cache the function value after it's first call or not
|
||||
* Recommend when the function call may require many resources or time (database requests) , or the value is small
|
||||
* Not recommended using on very large values
|
||||
*
|
||||
*/
|
||||
public function __construct( $callback, array $args = array(), $cache = true ) {
|
||||
$this->callback = $callback;
|
||||
$this->args = $args;
|
||||
$this->cache = (bool) $cache;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return callback function
|
||||
* @return array|string
|
||||
*/
|
||||
public function get_callback() {
|
||||
return $this->callback;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return callback function arguments
|
||||
* @return array
|
||||
*/
|
||||
public function get_args() {
|
||||
return $this->args;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute callback function
|
||||
* @return mixed
|
||||
*/
|
||||
public function execute() {
|
||||
if ( $this->cache ) {
|
||||
try {
|
||||
return FW_Cache::get( $this->get_id() );
|
||||
} catch ( FW_Cache_Not_Found_Exception $e ) {
|
||||
FW_Cache::set(
|
||||
$this->get_id(),
|
||||
$value = $this->get_value()
|
||||
);
|
||||
|
||||
return $value;
|
||||
}
|
||||
} else {
|
||||
return $this->get_value();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Whenever you want to clear the cached value or the function
|
||||
*/
|
||||
public function clear_cache() {
|
||||
FW_Cache::del( $this->get_id() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get raw callback value, ignoring the cache
|
||||
* @return mixed
|
||||
*/
|
||||
protected function get_value() {
|
||||
return call_user_func_array( $this->callback, $this->args );
|
||||
}
|
||||
|
||||
protected function get_id() {
|
||||
if ( ! is_string( $this->id ) ) {
|
||||
//$this->id = 'fw-callback-' . md5( $this->serialize_callback() . serialize( $this->args ) );
|
||||
//Disabled temporary for optimization reasons
|
||||
//Maybe later will come with a better idea.
|
||||
$this->id = uniqid( 'fw-callback-' );
|
||||
}
|
||||
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
protected function serialize_callback() {
|
||||
|
||||
if ( is_string( $this->callback ) ) {
|
||||
return $this->callback;
|
||||
}
|
||||
|
||||
if ( is_object( $this->callback ) ) {
|
||||
return spl_object_hash( $this->callback );
|
||||
}
|
||||
|
||||
if ( is_array( $this->callback ) ) {
|
||||
$callback = $this->callback;
|
||||
|
||||
if ( is_object( ( $first = array_shift( $callback ) ) ) ) {
|
||||
return spl_object_hash( $first ) . serialize( $callback );
|
||||
}
|
||||
|
||||
return serialize( $this->callback );
|
||||
}
|
||||
|
||||
return uniqid();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,330 @@
|
||||
<?php if (!defined('FW')) die('Forbidden');
|
||||
|
||||
/**
|
||||
* Lets you create easy functions for get/set database option values
|
||||
* it will handle all clever logic with default values, multikeys and processing options fw-storage parameter
|
||||
* @since 2.5.9
|
||||
*/
|
||||
abstract class FW_Db_Options_Model {
|
||||
/**
|
||||
* @return string Must not contain '/'
|
||||
*/
|
||||
abstract protected function get_id();
|
||||
|
||||
/**
|
||||
* @param null|int|string $item_id
|
||||
* @param array $extra_data
|
||||
* @return mixed
|
||||
*/
|
||||
abstract protected function get_values($item_id, array $extra_data = array());
|
||||
|
||||
/**
|
||||
* @param null|int|string $item_id
|
||||
* @param mixed $values
|
||||
* @param array $extra_data
|
||||
* @return void
|
||||
*/
|
||||
abstract protected function set_values($item_id, $values, array $extra_data = array());
|
||||
|
||||
/**
|
||||
* @param null|int|string $item_id
|
||||
* @param array $extra_data
|
||||
* @return array
|
||||
*/
|
||||
abstract protected function get_options($item_id, array $extra_data = array());
|
||||
|
||||
/**
|
||||
* @param null|int|string $item_id
|
||||
* @param array $extra_data
|
||||
* @return array E.g. for post options {'post-id': $item_id}
|
||||
* @see fw_db_option_storage_type()
|
||||
*/
|
||||
abstract protected function get_fw_storage_params($item_id, array $extra_data = array());
|
||||
|
||||
abstract protected function _init();
|
||||
|
||||
/**
|
||||
* @param null|int|string $item_id
|
||||
* @param null|string $option_id
|
||||
* @param null|string $sub_keys
|
||||
* @param mixed $old_value
|
||||
* @param array $extra_data
|
||||
*/
|
||||
protected function _after_set($item_id, $option_id, $sub_keys, $old_value, array $extra_data = array()) {}
|
||||
|
||||
/**
|
||||
* Get sub-key. For e.g. if each item must have a separate key or not.
|
||||
* @param string $key
|
||||
* @param null|int|string $item_id
|
||||
* @param array $extra_data
|
||||
* @return null|string
|
||||
*/
|
||||
protected function _get_cache_key($key, $item_id, array $extra_data = array()) {
|
||||
return empty($item_id) ? null : $item_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @var array {'id': mixed}
|
||||
*/
|
||||
private static $instances = array();
|
||||
|
||||
/**
|
||||
* @param string $id
|
||||
* @return FW_Db_Options_Model
|
||||
* @internal
|
||||
*/
|
||||
final public static function _get_instance($id) {
|
||||
return self::$instances[$id];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
* @since 2.6.7
|
||||
*/
|
||||
final public function get_main_cache_key() {
|
||||
return 'fw-options-model:'. $this->get_id();
|
||||
}
|
||||
|
||||
final public function __construct() {
|
||||
if (isset(self::$instances[ $this->get_id() ])) {
|
||||
trigger_error(__CLASS__ .' with id "'. $this->get_id() .'" was already defined', E_USER_ERROR);
|
||||
} else {
|
||||
self::$instances[ $this->get_id() ] = $this;
|
||||
}
|
||||
|
||||
$this->_init();
|
||||
}
|
||||
|
||||
private function get_cache_key($key, $item_id, array $extra_data = array()) {
|
||||
$item_key = $this->_get_cache_key($key, $item_id, $extra_data);
|
||||
|
||||
return $this->get_main_cache_key() .'/'. $key . (empty($item_key) ? '' : '/'. $item_key);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param null|int|string $item_id
|
||||
* @param null|string $option_id
|
||||
* @param mixed $default_value
|
||||
* @param array $extra_data
|
||||
* @return mixed
|
||||
*/
|
||||
final public function get( $item_id = null, $option_id = null, $default_value = null, array $extra_data = array() ) {
|
||||
|
||||
if ( is_preview() ) {
|
||||
global $wp_query;
|
||||
|
||||
if ( $wp_query->queried_object && ( is_single( $item_id ) || is_page( $item_id ) ) ) {
|
||||
$reset_get_rev = wp_get_post_revisions( $item_id );
|
||||
$item_id = ( $rewisions = reset( $reset_get_rev ) ) && isset( $rewisions->ID ) ? $rewisions->ID : $item_id;
|
||||
}
|
||||
}
|
||||
|
||||
if ( empty( $option_id ) ) {
|
||||
$sub_keys = null;
|
||||
} else {
|
||||
$option_id = explode( '/', $option_id ); // 'option_id/sub/keys'
|
||||
$_option_id = array_shift( $option_id ); // 'option_id'
|
||||
$sub_keys = empty( $option_id ) ? null : implode( '/', $option_id ); // 'sub/keys'
|
||||
$option_id = $_option_id;
|
||||
unset( $_option_id );
|
||||
}
|
||||
|
||||
try {
|
||||
// Cached because values are merged with extracted default values
|
||||
$values = FW_Cache::get( $cache_key_values = $this->get_cache_key( 'values', $item_id, $extra_data ) );
|
||||
|
||||
} catch ( FW_Cache_Not_Found_Exception $e ) {
|
||||
|
||||
FW_Cache::set(
|
||||
$cache_key_values,
|
||||
$values = ( is_array( $values = $this->get_values( $item_id, $extra_data ) ) ? $values : array() )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* If db value is not found and default value is provided
|
||||
* return default value before the options file is loaded
|
||||
*/
|
||||
if ( ! is_null( $default_value ) ) {
|
||||
if ( empty( $option_id ) ) {
|
||||
if ( empty( $values )
|
||||
&& (
|
||||
is_array( $default_value )
|
||||
||
|
||||
fw_is_callback( is_array( $default_value ) )
|
||||
)
|
||||
) {
|
||||
return fw_call( $default_value );
|
||||
}
|
||||
} else {
|
||||
if ( is_null( $sub_keys ) ) {
|
||||
if ( ! isset( $values[ $option_id ] ) ) {
|
||||
return fw_call( $default_value );
|
||||
}
|
||||
} else {
|
||||
if ( ! isset( $values[ $option_id ] ) || is_null( fw_akg( $sub_keys, $values[ $option_id ] ) ) ) {
|
||||
return fw_call( $default_value );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
$options = FW_Cache::get( $cache_key = $this->get_cache_key( 'options', $item_id, $extra_data ) );
|
||||
} catch ( FW_Cache_Not_Found_Exception $e ) {
|
||||
FW_Cache::set( $cache_key, array() ); // prevent recursion
|
||||
FW_Cache::set( $cache_key, $options = fw_extract_only_options( $this->get_options( $item_id, $extra_data ) ) );
|
||||
}
|
||||
|
||||
if ( $options ) {
|
||||
try {
|
||||
FW_Cache::get(
|
||||
// fixes https://github.com/ThemeFuse/Unyson/issues/2034
|
||||
$cache_key_values_processed = $this->get_cache_key( 'values:processed', $item_id, $extra_data )
|
||||
);
|
||||
} catch ( FW_Cache_Not_Found_Exception $e ) {
|
||||
/**
|
||||
* Set cache value before processing options
|
||||
* Fixes https://github.com/ThemeFuse/Unyson/issues/2034#issuecomment-248571149
|
||||
*/
|
||||
FW_Cache::set( $cache_key_values_processed, true );
|
||||
|
||||
// Complete missing db values with default values from options array
|
||||
{
|
||||
try {
|
||||
$skip_types_process = FW_Cache::get( $cache_key = 'fw:options-default-values:skip-types' );
|
||||
} catch ( FW_Cache_Not_Found_Exception $e ) {
|
||||
FW_Cache::set(
|
||||
$cache_key,
|
||||
$skip_types_process = apply_filters( 'fw:options-default-values:skip-types', array(// 'type' => true
|
||||
) )
|
||||
);
|
||||
}
|
||||
|
||||
foreach ( array_diff_key( fw_extract_only_options( $options ), $values ) as $id => $option ) {
|
||||
$values[ $id ] = isset( $skip_types_process[ $option['type'] ] )
|
||||
? (
|
||||
isset( $option['value'] )
|
||||
? $option['value']
|
||||
: fw()->backend->option_type( $option['type'] )->get_defaults( 'value' )
|
||||
)
|
||||
: fw()->backend->option_type( $option['type'] )->get_value_from_input( $option, null );
|
||||
}
|
||||
}
|
||||
|
||||
foreach ( $options as $id => $option ) {
|
||||
$values[ $id ] = fw()->backend->option_type( $option['type'] )->storage_load(
|
||||
$id,
|
||||
$option,
|
||||
isset( $values[ $id ] ) ? $values[ $id ] : null,
|
||||
$this->get_fw_storage_params( $item_id, $extra_data )
|
||||
);
|
||||
}
|
||||
|
||||
FW_Cache::set( $cache_key_values, $values );
|
||||
}
|
||||
}
|
||||
|
||||
if ( empty( $option_id ) ) {
|
||||
return ( empty( $values ) && ( is_array( $default_value ) || fw_is_callback( $default_value ) ) )
|
||||
? fw_call( $default_value )
|
||||
: $values;
|
||||
} else {
|
||||
if ( is_null( $sub_keys ) ) {
|
||||
return isset( $values[ $option_id ] )
|
||||
? $values[ $option_id ]
|
||||
: fw_call( $default_value );
|
||||
} else {
|
||||
return isset( $values[ $option_id ] )
|
||||
? fw_akg( $sub_keys, $values[ $option_id ], $default_value )
|
||||
: fw_call( $default_value );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final public function set( $item_id = null, $option_id = null, $value, array $extra_data = array() ) {
|
||||
FW_Cache::del($cache_key_values = $this->get_cache_key('values', $item_id, $extra_data));
|
||||
FW_Cache::del($cache_key_values_processed = $this->get_cache_key('values:processed', $item_id, $extra_data));
|
||||
|
||||
try {
|
||||
$options = FW_Cache::get($cache_key = $this->get_cache_key('options', $item_id, $extra_data));
|
||||
} catch (FW_Cache_Not_Found_Exception $e) {
|
||||
FW_Cache::set($cache_key, array()); // prevent recursion
|
||||
FW_Cache::set($cache_key, $options = fw_extract_only_options($this->get_options($item_id, $extra_data)));
|
||||
}
|
||||
|
||||
$sub_keys = null;
|
||||
|
||||
if ($option_id) {
|
||||
$option_id = explode('/', $option_id); // 'option_id/sub/keys'
|
||||
$_option_id = array_shift($option_id); // 'option_id'
|
||||
$sub_keys = empty($option_id) ? null : implode('/', $option_id); // 'sub/keys'
|
||||
$option_id = $_option_id;
|
||||
unset($_option_id);
|
||||
|
||||
$old_values = is_array($old_values = $this->get_values($item_id, $extra_data)) ? $old_values : array();
|
||||
$old_value = isset($old_values[$option_id]) ? $old_values[$option_id] : null;
|
||||
|
||||
if ($sub_keys) { // update sub_key in old_value and use the entire value
|
||||
$new_value = $old_value;
|
||||
fw_aks($sub_keys, $value, $new_value);
|
||||
$value = $new_value;
|
||||
unset($new_value);
|
||||
|
||||
$old_value = fw_akg($sub_keys, $old_value);
|
||||
}
|
||||
|
||||
if (isset($options[$option_id])) {
|
||||
$value = fw()->backend->option_type($options[$option_id]['type'])->storage_save(
|
||||
$option_id,
|
||||
$options[$option_id],
|
||||
$value,
|
||||
$this->get_fw_storage_params($item_id, $extra_data)
|
||||
);
|
||||
}
|
||||
|
||||
$old_values[$option_id] = $value;
|
||||
|
||||
$this->set_values($item_id, $old_values, $extra_data);
|
||||
|
||||
unset($old_values);
|
||||
} else {
|
||||
$old_value = is_array($old_values = $this->get_values($item_id, $extra_data)) ? $old_values : array();
|
||||
|
||||
if ( ! is_array($value) ) {
|
||||
$value = array();
|
||||
}
|
||||
|
||||
if (empty($value)) {
|
||||
// All options reset. Reset all fw-storage values too
|
||||
// Fixes https://github.com/ThemeFuse/Unyson/issues/2179
|
||||
foreach ($options as $_option_id => $_option) {
|
||||
fw()->backend->option_type($options[$_option_id]['type'])->storage_save(
|
||||
$_option_id,
|
||||
$_option,
|
||||
fw()->backend->option_type($options[$_option_id]['type'])->get_defaults('value'),
|
||||
$this->get_fw_storage_params($item_id, $extra_data)
|
||||
);
|
||||
}
|
||||
} else {
|
||||
foreach ($value as $_option_id => $_option_value) {
|
||||
if (isset($options[$_option_id])) {
|
||||
$value[$_option_id] = fw()->backend->option_type($options[$_option_id]['type'])->storage_save(
|
||||
$_option_id,
|
||||
$options[$_option_id],
|
||||
$_option_value,
|
||||
$this->get_fw_storage_params($item_id, $extra_data)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->set_values($item_id, $value, $extra_data);
|
||||
}
|
||||
|
||||
FW_Cache::del($cache_key_values); // fixes https://github.com/ThemeFuse/Unyson/issues/1538
|
||||
FW_Cache::del($cache_key_values_processed);
|
||||
|
||||
$this->_after_set($item_id, $option_id, $sub_keys, $old_value, $extra_data);
|
||||
}
|
||||
}
|
||||
124
wp-content/plugins/unyson/framework/helpers/class-fw-dumper.php
Normal file
124
wp-content/plugins/unyson/framework/helpers/class-fw-dumper.php
Normal file
@@ -0,0 +1,124 @@
|
||||
<?php
|
||||
|
||||
// original source: https://code.google.com/p/prado3/source/browse/trunk/framework/Util/TVar_dumper.php
|
||||
|
||||
/**
|
||||
* TVar_dumper class.
|
||||
*
|
||||
* TVar_dumper is intended to replace the buggy PHP function var_dump and print_r.
|
||||
* It can correctly identify the recursively referenced objects in a complex
|
||||
* object structure. It also has a recursive depth control to avoid indefinite
|
||||
* recursive display of some peculiar variables.
|
||||
*
|
||||
* TVar_dumper can be used as follows,
|
||||
* <code>
|
||||
* echo TVar_dumper::dump($var);
|
||||
* </code>
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @version $Id$
|
||||
* @package System.Util
|
||||
* @since 3.0
|
||||
*/
|
||||
class FW_Dumper
|
||||
{
|
||||
private static $_objects;
|
||||
private static $_output;
|
||||
private static $_depth;
|
||||
|
||||
/**
|
||||
* Converts a variable into a string representation.
|
||||
* This method achieves the similar functionality as var_dump and print_r
|
||||
* but is more robust when handling complex objects such as PRADO controls.
|
||||
* @param mixed $var Variable to be dumped
|
||||
* @param integer $depth Maximum depth that the dumper should go into the variable. Defaults to 10.
|
||||
* @return string the string representation of the variable
|
||||
*/
|
||||
public static function dump($var, $depth=10)
|
||||
{
|
||||
self::reset_internals();
|
||||
|
||||
self::$_depth=$depth;
|
||||
self::dump_internal($var,0);
|
||||
|
||||
$output = self::$_output;
|
||||
|
||||
self::reset_internals();
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
private static function reset_internals()
|
||||
{
|
||||
self::$_output='';
|
||||
self::$_objects=array();
|
||||
self::$_depth=10;
|
||||
}
|
||||
|
||||
private static function dump_internal($var,$level)
|
||||
{
|
||||
switch(gettype($var)) {
|
||||
case 'boolean':
|
||||
self::$_output.=$var?'true':'false';
|
||||
break;
|
||||
case 'integer':
|
||||
self::$_output.="$var";
|
||||
break;
|
||||
case 'double':
|
||||
self::$_output.="$var";
|
||||
break;
|
||||
case 'string':
|
||||
self::$_output.="'$var'";
|
||||
break;
|
||||
case 'resource':
|
||||
self::$_output.='{resource}';
|
||||
break;
|
||||
case 'NULL':
|
||||
self::$_output.="null";
|
||||
break;
|
||||
case 'unknown type':
|
||||
self::$_output.='{unknown}';
|
||||
break;
|
||||
case 'array':
|
||||
if(self::$_depth<=$level)
|
||||
self::$_output.='array(...)';
|
||||
else if(empty($var))
|
||||
self::$_output.='array()';
|
||||
else
|
||||
{
|
||||
$keys=array_keys($var);
|
||||
$spaces=str_repeat(' ',$level*4);
|
||||
self::$_output.="array\n".$spaces.'(';
|
||||
foreach($keys as $key)
|
||||
{
|
||||
self::$_output.="\n".$spaces." [$key] => ";
|
||||
self::$_output.=self::dump_internal($var[$key],$level+1);
|
||||
}
|
||||
self::$_output.="\n".$spaces.')';
|
||||
}
|
||||
break;
|
||||
case 'object':
|
||||
if(($id=array_search($var,self::$_objects,true))!==false)
|
||||
self::$_output.=get_class($var).'(...)';
|
||||
else if(self::$_depth<=$level)
|
||||
self::$_output.=get_class($var).'(...)';
|
||||
else
|
||||
{
|
||||
$id=array_push(self::$_objects,$var);
|
||||
$class_name=get_class($var);
|
||||
$members=(array)$var;
|
||||
$keys=array_keys($members);
|
||||
$spaces=str_repeat(' ',$level*4);
|
||||
self::$_output.="$class_name\n".$spaces.'(';
|
||||
foreach($keys as $key)
|
||||
{
|
||||
$key_display=strtr(trim($key),array("\0"=>':'));
|
||||
self::$_output.="\n".$spaces." [$key_display] => ";
|
||||
self::$_output.=self::dump_internal($members[$key],$level+1);
|
||||
}
|
||||
self::$_output.="\n".$spaces.')';
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,218 @@
|
||||
<?php if (!defined('FW')) die('Forbidden');
|
||||
|
||||
/**
|
||||
* Set flash messages
|
||||
**
|
||||
* Store messages in session (to not be lost between redirects) and remove them after they were shown to the user
|
||||
*/
|
||||
class FW_Flash_Messages
|
||||
{
|
||||
private static $available_types = array(
|
||||
// 'type' => 'backend class/type' (only 2 backend types exists: error and updated)
|
||||
'error' => 'error',
|
||||
'warning' => 'update-nag',
|
||||
'info' => 'updated',
|
||||
'success' => 'updated'
|
||||
);
|
||||
|
||||
private static $session_key = 'fw_flash_messages';
|
||||
|
||||
private static $frontend_printed = false;
|
||||
|
||||
private static function get_messages()
|
||||
{
|
||||
$messages = FW_Session::get(self::$session_key);
|
||||
|
||||
if (empty($messages) || !is_array($messages)) {
|
||||
$messages = array_fill_keys(array_keys(self::$available_types), array());
|
||||
}
|
||||
|
||||
return $messages;
|
||||
}
|
||||
|
||||
private static function set_messages(array $messages)
|
||||
{
|
||||
FW_Session::set(self::$session_key, $messages);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove messages with ids from pending remove
|
||||
*/
|
||||
private static function process_pending_remove_ids()
|
||||
{
|
||||
$pending_remove = array();
|
||||
|
||||
foreach (self::get_messages() as $messages) {
|
||||
if (empty($messages)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ($messages as $message) {
|
||||
if (empty($message['remove_ids'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ($message['remove_ids'] as $remove_id) {
|
||||
$pending_remove[$remove_id] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($pending_remove)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$types = self::get_messages();
|
||||
|
||||
foreach ($types as $type => $messages) {
|
||||
if (empty($messages)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ($messages as $id => $message) {
|
||||
if (isset($pending_remove[$id])) {
|
||||
unset($types[$type][$id]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self::set_messages( $types );
|
||||
}
|
||||
|
||||
/**
|
||||
* Add flash message
|
||||
**
|
||||
* @param string $id Unique id of the message
|
||||
* @param string $message Message (can be html)
|
||||
* @param string $type Type from $available_types
|
||||
* @param array $removed_ids Remove flashes with this id(s)
|
||||
* (For e.g. your message is success and some known error messages ids needs to be removed
|
||||
* because they are not relevant anymore, your success message suppress/cancels them)
|
||||
*/
|
||||
public static function add($id, $message, $type = 'info', array $removed_ids = array())
|
||||
{
|
||||
if (!isset(self::$available_types[$type])) {
|
||||
trigger_error(sprintf(__('Invalid flash message type: %s', 'tfuse'), $type), E_USER_WARNING);
|
||||
$type = 'info';
|
||||
}
|
||||
|
||||
$messages = self::get_messages();
|
||||
|
||||
$messages[$type][$id] = array(
|
||||
'message' => $message,
|
||||
'remove_ids' => $removed_ids,
|
||||
);
|
||||
|
||||
self::set_messages($messages);
|
||||
}
|
||||
|
||||
/**
|
||||
* Use this method to print messages html in backend
|
||||
* (used in action at the end of the file)
|
||||
* @internal
|
||||
*/
|
||||
public static function _print_backend()
|
||||
{
|
||||
if (!session_id()) {
|
||||
return; // fixes https://github.com/ThemeFuse/Unyson/issues/2219
|
||||
}
|
||||
|
||||
self::process_pending_remove_ids();
|
||||
|
||||
$html = array_fill_keys(array_keys(self::$available_types), '');
|
||||
|
||||
$all_messages = self::get_messages();
|
||||
|
||||
foreach ($all_messages as $type => $messages) {
|
||||
if (!empty($messages)) {
|
||||
foreach ($messages as $id => $data) {
|
||||
$html[$type] .=
|
||||
'<div class="'. self::$available_types[$type] .' fw-flash-message">'.
|
||||
'<p data-id="'. esc_attr($id) .'">'. $data['message'] .'</p>'.
|
||||
'</div>';
|
||||
|
||||
unset($all_messages[$type][$id]);
|
||||
}
|
||||
|
||||
$html[$type] = '<div class="fw-flash-type-'. $type .'">'. $html[$type] .'</div>';
|
||||
}
|
||||
}
|
||||
|
||||
unset($success, $error, $info);
|
||||
|
||||
self::set_messages($all_messages);
|
||||
|
||||
echo '<div class="fw-flash-messages">'. implode("\n\n", $html) .'</div>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Use this method to print messages html in frontend
|
||||
* @return bool If some html was printed or not
|
||||
*/
|
||||
public static function _print_frontend()
|
||||
{
|
||||
self::process_pending_remove_ids();
|
||||
|
||||
$html = array_fill_keys(array_keys(self::$available_types), '');
|
||||
$all_messages = self::get_messages();
|
||||
|
||||
$messages_exists = false;
|
||||
|
||||
foreach ($all_messages as $type => $messages) {
|
||||
if (empty($messages)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ($messages as $id => $data) {
|
||||
$html[$type] .= '<li class="fw-flash-message">'. nl2br($data['message']) .'</li>';
|
||||
|
||||
unset($all_messages[$type][$id]);
|
||||
}
|
||||
|
||||
$html[$type] = '<ul class="fw-flash-type-'. $type .'">'. $html[$type] .'</ul>';
|
||||
|
||||
$messages_exists = true;
|
||||
}
|
||||
|
||||
self::set_messages($all_messages);
|
||||
|
||||
self::$frontend_printed = true;
|
||||
|
||||
if ($messages_exists) {
|
||||
echo '<div class="fw-flash-messages">';
|
||||
echo implode("\n\n", $html);
|
||||
echo '</div>';
|
||||
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static function _frontend_printed()
|
||||
{
|
||||
return self::$frontend_printed;
|
||||
}
|
||||
|
||||
public static function _get_messages($clear = false)
|
||||
{
|
||||
self::process_pending_remove_ids();
|
||||
|
||||
$messages = self::get_messages();
|
||||
|
||||
if ($clear) {
|
||||
self::_clear();
|
||||
}
|
||||
|
||||
return $messages;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the FW_Flash_Messages messages
|
||||
*
|
||||
* @since 2.6.15
|
||||
*/
|
||||
public static function _clear() {
|
||||
self::set_messages(array());
|
||||
}
|
||||
}
|
||||
651
wp-content/plugins/unyson/framework/helpers/class-fw-form.php
Normal file
651
wp-content/plugins/unyson/framework/helpers/class-fw-form.php
Normal file
@@ -0,0 +1,651 @@
|
||||
<?php if ( ! defined( 'FW' ) ) {
|
||||
die( 'Forbidden' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Dynamic forms
|
||||
*/
|
||||
class FW_Form {
|
||||
/**
|
||||
* Store all form ids created with this class
|
||||
* @var FW_Form[] {'form_id' => instance}
|
||||
*
|
||||
* @deprecated 2.6.15 Use FW_Form::get_forms()
|
||||
*/
|
||||
protected static $forms = array();
|
||||
|
||||
/**
|
||||
* The id of the submitted form id
|
||||
* @var string
|
||||
*
|
||||
* @deprecated 2.6.15
|
||||
*/
|
||||
protected static $submitted_id;
|
||||
|
||||
/**
|
||||
* Hidden input name that stores the form id
|
||||
* @var string
|
||||
*
|
||||
* @deprecated 2.6.15 Use self::get_form_id_name()
|
||||
*/
|
||||
protected static $id_input_name = 'fwf';
|
||||
|
||||
/**
|
||||
* Form id
|
||||
* @var string
|
||||
*
|
||||
* @deprecated 2.6.15 Use $this->get_id()
|
||||
*/
|
||||
protected $id;
|
||||
|
||||
/**
|
||||
* Html attributes for <form> tag
|
||||
* @var array
|
||||
*
|
||||
* @deprecated 2.6.15 Use $this->attr()
|
||||
*/
|
||||
protected $attr = array();
|
||||
|
||||
/**
|
||||
* Found validation errors
|
||||
* @var array
|
||||
*/
|
||||
protected $errors;
|
||||
|
||||
/**
|
||||
* If the get_errors() method was called at leas once
|
||||
* @var bool
|
||||
*/
|
||||
protected $errors_accessed = false;
|
||||
|
||||
/**
|
||||
* If current request is the submit of this form
|
||||
* @var bool
|
||||
*
|
||||
* @deprecated 2.6.15 Use $this->is_submitted()
|
||||
*/
|
||||
protected $is_submitted;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*
|
||||
* @deprecated 2.6.15
|
||||
*/
|
||||
protected $validate_and_save_called = false;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*
|
||||
* @deprecated 2.6.15 Use $this->get_callbacks()
|
||||
*/
|
||||
protected $callbacks = array(
|
||||
'render' => false,
|
||||
'validate' => false,
|
||||
'save' => false
|
||||
);
|
||||
|
||||
private $request;
|
||||
|
||||
/**
|
||||
* @param string $id Unique
|
||||
* @param array $data (optional)
|
||||
* array(
|
||||
* 'render' => callback // The callback that will render the form's html
|
||||
* 'validate' => callback // The callback that will validate user input
|
||||
* 'save' => callback // The callback that will save successfully validated user input
|
||||
* 'attr' => array() // Custom <form ...> attributes
|
||||
* )
|
||||
*/
|
||||
public function __construct( $id, $data = array() ) {
|
||||
try {
|
||||
self::get_form( $id );
|
||||
trigger_error( sprintf( __( 'Form with id "%s" was already defined', 'fw' ), $id ), E_USER_ERROR );
|
||||
|
||||
return;
|
||||
} catch ( FW_Form_Not_Found_Exception $e ) {
|
||||
}
|
||||
|
||||
$this
|
||||
// set id
|
||||
->set_id( $id )
|
||||
// prepare callbacks
|
||||
->set_callbacks( array(
|
||||
'render' => fw_akg( 'render', $data, false ),
|
||||
'validate' => fw_akg( 'validate', $data, false ),
|
||||
'save' => fw_akg( 'save', $data, false ),
|
||||
) )
|
||||
// prepare attributes
|
||||
->set_attr( (array) fw_akg( 'attr', $data, array() ) );
|
||||
|
||||
self::$forms[ $this->get_id() ] =& $this;
|
||||
|
||||
if ( did_action( 'wp_loaded' ) ) {
|
||||
// in case if form instance was created after action
|
||||
$this->_validate_and_save();
|
||||
} else {
|
||||
// attach to an action before 'send_headers' action, to be able to do redirects
|
||||
add_action( 'wp_loaded', array( $this, '_validate_and_save' ), 101 );
|
||||
}
|
||||
|
||||
add_action( 'fw_form_display:before_form', array( $this, '_action_fw_form_show_errors' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function get_id() {
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get validation errors
|
||||
* @return array
|
||||
*/
|
||||
public function get_errors() {
|
||||
if ( ! $this->validate_and_save_called ) {
|
||||
fw_print( debug_backtrace() );
|
||||
trigger_error( __METHOD__ . ' called before validation', E_USER_WARNING );
|
||||
|
||||
return array( '~' => true );
|
||||
}
|
||||
|
||||
$this->errors_accessed = true;
|
||||
|
||||
return $this->_get_errors();
|
||||
}
|
||||
|
||||
public function get_callbacks() {
|
||||
return $this->callbacks;
|
||||
}
|
||||
|
||||
public function errors_accessed() {
|
||||
return $this->errors_accessed;
|
||||
}
|
||||
|
||||
/**
|
||||
* If current form was submitted, validate and save it
|
||||
*
|
||||
* Note: This callback can abort script execution if save does redirect
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
public function _validate_and_save() {
|
||||
|
||||
if ( ! self::is_form_submitted( $this->get_id() ) || $this->validate_and_save_called ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->validate_and_save_called = true;
|
||||
|
||||
try {
|
||||
$data = $this->submit( self::get_form_request( $this->get_id() ) );
|
||||
|
||||
if ( $this->_is_ajax() ) {
|
||||
wp_send_json_success( array(
|
||||
'save_data' => $data,
|
||||
'flash_messages' => self::collect_flash_messages(),
|
||||
) );
|
||||
}
|
||||
|
||||
if ( ( $redirect = fw_akg( 'redirect', $data ) ) ) {
|
||||
wp_redirect( $redirect );
|
||||
exit;
|
||||
}
|
||||
} catch ( FW_Form_Invalid_Submission_Exception $e ) {
|
||||
if ( $this->_is_ajax() ) {
|
||||
wp_send_json_error( array(
|
||||
'errors' => $this->get_errors(),
|
||||
'flash_messages' => self::collect_flash_messages()
|
||||
) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param FW_Form $form
|
||||
*
|
||||
* @internal
|
||||
*
|
||||
* You can overwrite it in case you do not need the errors to be shown for your form
|
||||
*/
|
||||
public function _action_fw_form_show_errors( $form ) {
|
||||
if (
|
||||
$form->get_id() != $this->get_id()
|
||||
// errors in admin side are displayed by a script at the end of this file
|
||||
|| is_admin()
|
||||
|| ! $form->is_submitted()
|
||||
|| $form->is_valid()
|
||||
|| $form->errors_accessed()
|
||||
) {
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use this action to customize errors display in your theme
|
||||
*/
|
||||
do_action( 'fw_form_display_errors_frontend', $form );
|
||||
|
||||
$errors = $form->get_errors();
|
||||
|
||||
if ( empty( $errors ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
echo '<ul class="fw-form-errors">';
|
||||
|
||||
foreach ( $errors as $input_name => $error_message ) {
|
||||
echo fw_html_tag(
|
||||
'li',
|
||||
array(
|
||||
'data-input-name' => $input_name,
|
||||
),
|
||||
$error_message
|
||||
);
|
||||
}
|
||||
|
||||
echo '</ul>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get html attribute(s)
|
||||
*
|
||||
* @param null|string $name
|
||||
*
|
||||
* @return array|string
|
||||
*/
|
||||
public function attr( $name = null ) {
|
||||
return $name !== null
|
||||
? fw_akg( $name, $this->attr )
|
||||
: $this->attr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Render form's html
|
||||
*
|
||||
* @param array $data
|
||||
*/
|
||||
public function render( $data = array() ) {
|
||||
$render_data = array(
|
||||
'submit' => array(
|
||||
'value' => __( 'Submit', 'fw' ),
|
||||
/**
|
||||
* you can set here custom submit button html
|
||||
* and the 'value' parameter will not be used
|
||||
*/
|
||||
'html' => null,
|
||||
),
|
||||
'data' => $data,
|
||||
'attr' => $this->attr(),
|
||||
);
|
||||
|
||||
$html = '';
|
||||
|
||||
if ( $render_callback = fw_akg( 'render', $this->get_callbacks() ) ) {
|
||||
ob_start();
|
||||
|
||||
$data = call_user_func_array( $render_callback, array( $render_data, $this ) );
|
||||
|
||||
$html = ob_get_clean();
|
||||
|
||||
if ( empty( $data ) ) {
|
||||
// fix if returned wrong data from callback
|
||||
$data = $render_data;
|
||||
}
|
||||
|
||||
$render_data = $data;
|
||||
}
|
||||
|
||||
do_action( 'fw_form_display:before_form', $this );
|
||||
|
||||
// display form errors in frontend
|
||||
echo '<form ' . fw_attr_to_html( $render_data['attr'] ) . ' >';
|
||||
|
||||
do_action( 'fw_form_display:before', $this );
|
||||
|
||||
echo fw_html_tag( 'input',
|
||||
array(
|
||||
'type' => 'hidden',
|
||||
'name' => self::get_form_id_name(),
|
||||
'value' => $this->get_id(),
|
||||
) );
|
||||
|
||||
wp_nonce_field( $this->get_nonce_action(), $this->get_nonce_name( $render_data ) );
|
||||
|
||||
if ( ! empty( $render_data['attr']['action'] ) && $render_data['attr']['method'] == 'get' ) {
|
||||
/**
|
||||
* Add query vars from the action attribute url to hidden inputs to not loose them
|
||||
*/
|
||||
|
||||
parse_str( parse_url( $render_data['attr']['action'], PHP_URL_QUERY ), $query_vars );
|
||||
|
||||
if ( ! empty( $query_vars ) ) {
|
||||
foreach ( $query_vars as $var_name => $var_value ) {
|
||||
echo fw_html_tag( 'input',
|
||||
array(
|
||||
'type' => 'hidden',
|
||||
'name' => $var_name,
|
||||
'value' => $var_value,
|
||||
) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
echo $html;
|
||||
|
||||
// In filter can be defined custom html for submit button
|
||||
if ( isset( $render_data['submit']['html'] ) ) {
|
||||
echo $render_data['submit']['html'];
|
||||
} else {
|
||||
echo fw_html_tag( 'input',
|
||||
array(
|
||||
'type' => 'submit',
|
||||
'value' => $render_data['submit']['value']
|
||||
) );
|
||||
}
|
||||
|
||||
do_action( 'fw_form_display:after', $this );
|
||||
|
||||
echo '</form>';
|
||||
|
||||
do_action( 'fw_form_display:after_form', $this );
|
||||
}
|
||||
|
||||
/**
|
||||
* If now is a submit of this form
|
||||
* @return bool
|
||||
*/
|
||||
public function is_submitted() {
|
||||
return $this->request !== null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function is_valid() {
|
||||
if ( ! $this->is_submitted() ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return count( $this->_get_errors() ) == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $request
|
||||
*
|
||||
* @throws FW_Form_Invalid_Submission_Exception
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function submit( array $request = array() ) {
|
||||
$this->request = $request;
|
||||
//Updated the deprecated member for those that extended the class and use it in code
|
||||
$this->is_submitted = true;
|
||||
|
||||
$errors = $this->validate();
|
||||
|
||||
if ( ! empty( $errors ) ) {
|
||||
throw new FW_Form_Invalid_Submission_Exception( $errors );
|
||||
}
|
||||
|
||||
return $this->save();
|
||||
}
|
||||
|
||||
protected function get_default_attr() {
|
||||
return array(
|
||||
'data-fw-form-id' => $this->get_id(),
|
||||
'method' => 'post',
|
||||
'action' => fw_current_url(),
|
||||
'class' => 'fw_form_' . $this->get_id()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $attr
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
protected function set_attr( array $attr ) {
|
||||
$this->attr = array_merge( $this->get_default_attr(), $attr );
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param null $key
|
||||
*
|
||||
* @return array|mixed|null
|
||||
*
|
||||
* @since 2.6.15
|
||||
*/
|
||||
protected function get_request( $key = null ) {
|
||||
return $key === null ? (array) $this->request : fw_akg( $key, $this->request );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string|null
|
||||
*
|
||||
* @since 2.6.15
|
||||
*/
|
||||
protected function get_nonce() {
|
||||
return $this->get_request( $this->get_nonce_name() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns forms errors without counting them as accessed
|
||||
* @return array
|
||||
*/
|
||||
protected function _get_errors() {
|
||||
return $this->errors;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*
|
||||
* @since 2.6.15
|
||||
*/
|
||||
protected function get_nonce_action() {
|
||||
return 'submit_fwf';
|
||||
}
|
||||
|
||||
protected function check_nonce( $nonce ) {
|
||||
return wp_verify_nonce( $nonce, $this->get_nonce_action() );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
protected function validate() {
|
||||
/**
|
||||
* Errors array {'input[name]' => 'Error message'}
|
||||
*/
|
||||
$errors = array();
|
||||
|
||||
if ( ! $this->check_nonce( $this->get_nonce() ) ) {
|
||||
$errors[ $this->get_nonce_name() ] = esc_html__( 'Your session expired. Please refresh page and try again.', 'fw' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Call validate callback
|
||||
*
|
||||
* Callback must 'manually' extract input values from $_POST (or $_GET)
|
||||
*/
|
||||
if ( ( $validate = fw_akg( 'validate', $this->get_callbacks() ) ) ) {
|
||||
$errors = (array) call_user_func( $validate, $errors );
|
||||
}
|
||||
|
||||
return $this->set_errors( $errors )->_get_errors();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array|mixed
|
||||
*/
|
||||
protected function save() {
|
||||
$save_data = array(
|
||||
// you can set here a url for redirect after save
|
||||
'redirect' => null
|
||||
);
|
||||
|
||||
/**
|
||||
* Call save callback
|
||||
*
|
||||
* Callback must 'manually' extract input values from $_POST (or $_GET)
|
||||
*/
|
||||
if ( ( $save_callback = fw_akg( 'save', $this->get_callbacks() ) ) ) {
|
||||
$data = call_user_func_array( $save_callback, array( $save_data ) );
|
||||
|
||||
if ( ! is_array( $data ) ) {
|
||||
// fix if returned wrong data from callback
|
||||
$data = $save_data;
|
||||
}
|
||||
|
||||
$save_data = $data;
|
||||
|
||||
unset( $data );
|
||||
}
|
||||
|
||||
return $save_data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*
|
||||
* @deprecated 2.6.15
|
||||
*/
|
||||
protected function is_ajax() {
|
||||
return self::_is_ajax();
|
||||
}
|
||||
|
||||
protected function set_id( $id ) {
|
||||
$this->id = $id;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $callbacks
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
protected function set_callbacks( array $callbacks ) {
|
||||
$this->callbacks = $callbacks;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
protected function set_errors( array $errors ) {
|
||||
$this->errors = $errors;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Some forms (like Forms extension frontend form) uses the same FW_Form instance for all sub-forms
|
||||
* and they must be differentiated somehow.
|
||||
* Fixes https://github.com/ThemeFuse/Unyson/issues/2033
|
||||
*
|
||||
* @param array $render_data
|
||||
*
|
||||
* @return string
|
||||
* @since 2.6.6
|
||||
*/
|
||||
private function get_nonce_name( $render_data = array() ) {
|
||||
return '_nonce_' . md5( $this->id . apply_filters( 'fw:form:nonce-name-data', '', $this, $render_data ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return FW_Form[]
|
||||
*
|
||||
* @since 2.6.15
|
||||
*/
|
||||
public static function get_forms() {
|
||||
return self::$forms;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $id
|
||||
*
|
||||
* @return FW_Form
|
||||
* @throws FW_Form_Not_Found_Exception
|
||||
*
|
||||
* @since 2.6.15
|
||||
*/
|
||||
public static function get_form( $id ) {
|
||||
if ( ! isset( self::$forms[ $id ] ) ) {
|
||||
throw new FW_Form_Not_Found_Exception( "FW_Form $id was not defined" );
|
||||
}
|
||||
|
||||
return self::$forms[ $id ];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get submitted form instance (or false if no form is currently submitted)
|
||||
* @return FW_Form|false
|
||||
*/
|
||||
public static function get_submitted() {
|
||||
foreach ( self::get_forms() as $id => $form ) {
|
||||
if ( self::is_form_submitted( $id ) ) {
|
||||
return $form;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*
|
||||
* @since 2.6.15
|
||||
*/
|
||||
public static function _is_ajax() {
|
||||
return ( defined( 'DOING_AJAX' ) && DOING_AJAX )
|
||||
||
|
||||
strtolower( fw_akg( 'HTTP_X_REQUESTED_WITH', $_SERVER ) ) == 'xmlhttprequest';
|
||||
}
|
||||
|
||||
public static function get_form_request( $id ) {
|
||||
if ( FW_Request::POST( self::get_form_id_name() ) == $id ) {
|
||||
return FW_Request::POST();
|
||||
}
|
||||
|
||||
if ( FW_Request::GET( self::get_form_id_name() ) == $id ) {
|
||||
return FW_Request::GET();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*
|
||||
* @since 2.6.15
|
||||
*/
|
||||
protected static function get_form_id_name() {
|
||||
return 'fwf';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $id
|
||||
*
|
||||
* @return bool
|
||||
*
|
||||
* @since 2.6.15
|
||||
*/
|
||||
protected static function is_form_submitted( $id ) {
|
||||
return self::get_form_request( $id ) !== null;
|
||||
}
|
||||
|
||||
private static function collect_flash_messages() {
|
||||
$flash_messages = array();
|
||||
|
||||
foreach ( FW_Flash_Messages::_get_messages( true ) as $type => $messages ) {
|
||||
$flash_messages[ $type ] = array();
|
||||
|
||||
foreach ( $messages as $id => $message_data ) {
|
||||
$flash_messages[ $type ][ $id ] = $message_data['message'];
|
||||
}
|
||||
}
|
||||
|
||||
return $flash_messages;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
<?php if (!defined('FW')) die('Forbidden');
|
||||
|
||||
/**
|
||||
* WordPress automatically adds slashes to:
|
||||
* $_REQUEST
|
||||
* $_POST
|
||||
* $_GET
|
||||
* $_COOKIE
|
||||
*
|
||||
* For e.g.
|
||||
*
|
||||
* If value is simple, get value directly:
|
||||
* $foo = isset($_GET['bar']) && $_GET['bar'] == 'yes';
|
||||
*
|
||||
* If value can contain some user input and can have quotes or json from some option, then use this helper:
|
||||
* $foo = json_decode(FW_Request::POST('bar')); // json_decode($_POST('bar')) will not work if json will contain quotes
|
||||
*
|
||||
* You can test that problem.
|
||||
* Add somewhere this code:
|
||||
fw_print(array(
|
||||
$_GET['test'],
|
||||
json_decode($_GET['test']),
|
||||
FW_Request::GET('test'),
|
||||
json_decode(FW_Request::GET('test'))
|
||||
));
|
||||
* and access: http://your-site.com/?test={'a':1}
|
||||
*/
|
||||
class FW_Request
|
||||
{
|
||||
protected static function prepare_key($key)
|
||||
{
|
||||
return (get_magic_quotes_gpc() && is_string($key) ? addslashes($key) : $key);
|
||||
}
|
||||
|
||||
protected static function get_set_key($multikey = null, $set_value = null, &$value)
|
||||
{
|
||||
$multikey = self::prepare_key($multikey);
|
||||
|
||||
if ($set_value === null) { // get
|
||||
return fw_stripslashes_deep_keys($multikey === null ? $value : fw_akg($multikey, $value));
|
||||
} else { // set
|
||||
fw_aks($multikey, fw_addslashes_deep_keys($set_value), $value);
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
public static function GET($multikey = null, $default_value = null)
|
||||
{
|
||||
return fw_stripslashes_deep_keys(
|
||||
$multikey === null
|
||||
? $_GET
|
||||
: fw_akg($multikey, $_GET, $default_value)
|
||||
);
|
||||
}
|
||||
|
||||
public static function POST($multikey = null, $default_value = null)
|
||||
{
|
||||
return fw_stripslashes_deep_keys(
|
||||
$multikey === null
|
||||
? $_POST
|
||||
: fw_akg($multikey, $_POST, $default_value)
|
||||
);
|
||||
}
|
||||
|
||||
public static function COOKIE($multikey = null, $set_value = null, $expire = 0, $path = null)
|
||||
{
|
||||
if ($set_value !== null) {
|
||||
|
||||
// transforms a string ( key1/key2/key3 => key1][key2][key3] )
|
||||
$multikey = str_replace('/', '][', $multikey) . ']';
|
||||
|
||||
// removes the first closed square bracket ( key1][key2][key3] => key1[key2][key3] )
|
||||
$multikey = preg_replace('/\]/', '', $multikey, 1);
|
||||
|
||||
return setcookie($multikey, $set_value, $expire, $path);
|
||||
} else {
|
||||
return self::get_set_key($multikey, $set_value, $_COOKIE);
|
||||
}
|
||||
}
|
||||
|
||||
public static function REQUEST($multikey = null, $default_value = null)
|
||||
{
|
||||
return fw_stripslashes_deep_keys(
|
||||
$multikey === null
|
||||
? $_REQUEST
|
||||
: fw_akg($multikey, $_REQUEST, $default_value)
|
||||
);
|
||||
}
|
||||
}
|
||||
158
wp-content/plugins/unyson/framework/helpers/class-fw-resize.php
Normal file
158
wp-content/plugins/unyson/framework/helpers/class-fw-resize.php
Normal file
@@ -0,0 +1,158 @@
|
||||
<?php if ( ! defined( 'FW' ) ) {
|
||||
die( 'Forbidden' );
|
||||
}
|
||||
|
||||
if ( ! class_exists( 'FW_Resize' ) ) {
|
||||
class FW_Resize {
|
||||
/**
|
||||
* The singleton instance
|
||||
*/
|
||||
static private $instance = null;
|
||||
|
||||
/**
|
||||
* No initialization allowed
|
||||
*/
|
||||
private function __construct() {
|
||||
}
|
||||
|
||||
/**
|
||||
* No cloning allowed
|
||||
*/
|
||||
private function __clone() {
|
||||
}
|
||||
|
||||
static public function getInstance() {
|
||||
if ( self::$instance == null ) {
|
||||
self::$instance = new self;
|
||||
}
|
||||
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
private function get_attachment_info( $attachment ) {
|
||||
|
||||
$row = $this->get_attachment( $attachment );
|
||||
$path = get_attached_file( $row['ID'] );
|
||||
|
||||
return ( ! isset( $row ) || ! $path ) ? false : array(
|
||||
'id' => intval( $row['ID'] ),
|
||||
'path' => $path,
|
||||
'url' => is_ssl() ? preg_replace( "/^http:/i", "https:", $row['guid'] ) : $row['guid']
|
||||
);
|
||||
}
|
||||
|
||||
private function get_attachment( $attachment ) {
|
||||
/**
|
||||
* @var WPDB $wpdb
|
||||
*/
|
||||
global $wpdb;
|
||||
|
||||
if ( is_numeric( $attachment ) ) {
|
||||
return $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $wpdb->posts WHERE ID=%d LIMIT 1", $attachment ), ARRAY_A );
|
||||
} else {
|
||||
|
||||
$attachment = str_replace( array( 'http:', 'https:' ), '', $attachment );
|
||||
|
||||
return $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $wpdb->posts WHERE guid LIKE %s LIMIT 1", '%' . $wpdb->esc_like($attachment) ), ARRAY_A );
|
||||
}
|
||||
}
|
||||
|
||||
public function process( $attachment, $width = false, $height = false, $crop = false ) {
|
||||
|
||||
$attachment_info = $this->get_attachment_info( $attachment );
|
||||
|
||||
if ( ! $attachment_info ) {
|
||||
return new WP_Error( 'invalid_attachment', 'Invalid Attachment', $attachment );
|
||||
}
|
||||
|
||||
$file_path = $attachment_info['path'];
|
||||
|
||||
$info = pathinfo( $file_path );
|
||||
$dir = $info['dirname'];
|
||||
$ext = ( isset( $info['extension'] ) ) ? $info['extension'] : 'jpg';
|
||||
$name = wp_basename( $file_path, ".$ext" );
|
||||
$name = preg_replace( '/(.+)(\-\d+x\d+)$/', '$1', $name );
|
||||
|
||||
{
|
||||
if ( ! $width || ! $height ) {
|
||||
$editor = wp_get_image_editor( $file_path );
|
||||
|
||||
if (is_wp_error($editor)) {
|
||||
return $editor;
|
||||
}
|
||||
|
||||
$size = $editor->get_size();
|
||||
$orig_width = $size['width'];
|
||||
$orig_height = $size['height'];
|
||||
if ( ! $height && $width ) {
|
||||
$height = round( ( $orig_height * $width ) / $orig_width );
|
||||
} elseif ( ! $width && $height ) {
|
||||
$width = round( ( $orig_width * $height ) / $orig_height );
|
||||
} else {
|
||||
return $attachment;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Suffix applied to filename
|
||||
$suffix = "{$width}x{$height}";
|
||||
|
||||
// Get the destination file name
|
||||
$destination_file_name = "{$dir}/{$name}-{$suffix}.{$ext}";
|
||||
// No need to resize & create a new image if it already exists
|
||||
if ( ! file_exists( $destination_file_name ) ) {
|
||||
//Image Resize
|
||||
$editor = (isset($editor)) ? $editor : wp_get_image_editor( $file_path );
|
||||
|
||||
if ( is_wp_error( $editor ) ) {
|
||||
return new WP_Error( 'wp_image_editor', 'WP Image editor can\'t resize this attachment', $attachment );
|
||||
}
|
||||
|
||||
// Get the original image size
|
||||
$size = $editor->get_size();
|
||||
$orig_width = $size['width'];
|
||||
$orig_height = $size['height'];
|
||||
|
||||
$src_x = $src_y = 0;
|
||||
$src_w = $orig_width;
|
||||
$src_h = $orig_height;
|
||||
|
||||
if ( $crop ) {
|
||||
|
||||
$cmp_x = $orig_width / $width;
|
||||
$cmp_y = $orig_height / $height;
|
||||
|
||||
// Calculate x or y coordinate, and width or height of source
|
||||
if ( $cmp_x > $cmp_y ) {
|
||||
$src_w = round( $orig_width / $cmp_x * $cmp_y );
|
||||
$src_x = round( ( $orig_width - ( $orig_width / $cmp_x * $cmp_y ) ) / 2 );
|
||||
} else if ( $cmp_y > $cmp_x ) {
|
||||
$src_h = round( $orig_height / $cmp_y * $cmp_x );
|
||||
$src_y = round( ( $orig_height - ( $orig_height / $cmp_y * $cmp_x ) ) / 2 );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
$editor->crop( $src_x, $src_y, $src_w, $src_h, $width, $height );
|
||||
|
||||
$saved = $editor->save( $destination_file_name );
|
||||
|
||||
$images = wp_get_attachment_metadata( $attachment_info['id'] );
|
||||
if ( ! empty( $images['resizes'] ) && is_array( $images['resizes'] ) ) {
|
||||
foreach ( $images['resizes'] as $image_size => $image_path ) {
|
||||
$images['resizes'][ $image_size ] = addslashes( $image_path );
|
||||
}
|
||||
}
|
||||
$uploads_dir = wp_upload_dir();
|
||||
$images['resizes'][ $suffix ] = $uploads_dir['subdir'] . '/' . $saved['file'];
|
||||
wp_update_attachment_metadata( $attachment_info['id'], $images );
|
||||
|
||||
}
|
||||
|
||||
return array(
|
||||
'id' => $attachment_info['id'],
|
||||
'src' => str_replace( basename( $attachment_info['url'] ), basename( $destination_file_name ), $attachment_info['url'] )
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
<?php if ( ! defined( 'FW' ) ) {
|
||||
die( 'Forbidden' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Work with $_SESSION
|
||||
*
|
||||
* Advantages: Do not session_start() on every refresh, but only when it is accessed
|
||||
*/
|
||||
class FW_Session {
|
||||
private static function start_session() {
|
||||
if ( apply_filters( 'fw_use_sessions', true ) && ! session_id() ) {
|
||||
session_start();
|
||||
}
|
||||
}
|
||||
|
||||
public static function get( $key, $default_value = null ) {
|
||||
if ( ! apply_filters( 'fw_use_sessions', true ) ) {
|
||||
return array();
|
||||
}
|
||||
|
||||
self::start_session();
|
||||
|
||||
return fw_akg( $key, $_SESSION, $default_value );
|
||||
}
|
||||
|
||||
public static function set( $key, $value ) {
|
||||
self::start_session();
|
||||
|
||||
fw_aks( $key, $value, $_SESSION );
|
||||
}
|
||||
|
||||
public static function del( $key ) {
|
||||
self::start_session();
|
||||
|
||||
fw_aku( $key, $_SESSION );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,364 @@
|
||||
<?php if (!defined('FW')) die('Forbidden');
|
||||
|
||||
/**
|
||||
* Helps you create settings forms
|
||||
* @since 2.6.9
|
||||
*/
|
||||
abstract class FW_Settings_Form {
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
abstract public function get_options();
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
abstract public function get_values();
|
||||
|
||||
/**
|
||||
* @param array|callable $values
|
||||
* @return $this
|
||||
*/
|
||||
abstract public function set_values($values);
|
||||
|
||||
/**
|
||||
* Make sure all instances have unique id
|
||||
* @var array
|
||||
*/
|
||||
private static $ids = array();
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $id;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private $is_side_tabs = false;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private $is_ajax_submit = false;
|
||||
|
||||
/**
|
||||
* @var FW_Form
|
||||
*/
|
||||
private $fw_form;
|
||||
|
||||
/**
|
||||
* Translated text ( initialized in __construct() )
|
||||
* @var array
|
||||
*/
|
||||
private $strings;
|
||||
|
||||
private static $input_name_reset = '_fw_reset_options';
|
||||
private static $input_name_save = '_fw_save_options';
|
||||
|
||||
final public function __construct($id) {
|
||||
if (isset(self::$ids[$id])) {
|
||||
trigger_error(__CLASS__ .' with id "'. $id .'" was already defined', E_USER_ERROR);
|
||||
} else {
|
||||
self::$ids[$id] = true;
|
||||
}
|
||||
|
||||
$this->id = $id;
|
||||
$this->fw_form = new FW_Form('fw-settings-form:'. $this->get_id(), array(
|
||||
'render' => array($this, '_form_render'),
|
||||
'validate' => array($this, '_form_validate'),
|
||||
'save' => array($this, '_form_save'),
|
||||
));
|
||||
$this->strings = array(
|
||||
'title' => __('Settings', 'fw'),
|
||||
'save_button' => __('Save Changes', 'fw'),
|
||||
'reset_button' => __('Reset Options', 'fw'),
|
||||
'reset_warning' => __("Click OK to reset.\nAll settings will be lost and replaced with default settings!", 'fw'),
|
||||
);
|
||||
|
||||
$this->_init();
|
||||
}
|
||||
|
||||
protected function _init() {}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
final public function get_id() {
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
final public function get_is_ajax_submit() {
|
||||
return $this->is_ajax_submit;
|
||||
}
|
||||
|
||||
/**
|
||||
* In order for this to work, you must call $this->enqueue_static() on `admin_enqueue_scripts` action
|
||||
* @param bool $is_ajax_submit
|
||||
* @return $this
|
||||
*/
|
||||
final public function set_is_ajax_submit($is_ajax_submit) {
|
||||
$this->is_ajax_submit = (bool)$is_ajax_submit;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
final public function get_is_side_tabs() {
|
||||
return $this->is_side_tabs;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $is_side_tabs
|
||||
* @return $this
|
||||
*/
|
||||
final public function set_is_side_tabs($is_side_tabs) {
|
||||
$this->is_side_tabs = (bool)$is_side_tabs;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $id
|
||||
* @return string
|
||||
*/
|
||||
final public function get_string($id) {
|
||||
return isset($this->strings[$id]) ? $this->strings[$id] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $id
|
||||
* @param string $value
|
||||
* @return bool
|
||||
*/
|
||||
final public function set_string($id, $value) {
|
||||
if (isset($this->strings[$id])) {
|
||||
$this->strings[$id] = $value;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function form_capability() {
|
||||
return 'manage_options';
|
||||
}
|
||||
|
||||
public function enqueue_static() {
|
||||
fw()->backend->enqueue_options_static($this->get_options());
|
||||
|
||||
if ($this->get_is_ajax_submit()) {
|
||||
wp_enqueue_script('fw-form-helpers');
|
||||
}
|
||||
}
|
||||
|
||||
final public function render() {
|
||||
echo '<div class="wrap">';
|
||||
|
||||
if ( $this->get_is_side_tabs() ) {
|
||||
// this is needed for flash messages (admin notices) to be displayed properly
|
||||
echo '<h2 class="fw-hidden"></h2>';
|
||||
} else {
|
||||
echo '<h2>'. esc_html( $this->get_string('title') ) .'</h2><br/>';
|
||||
}
|
||||
|
||||
$this->fw_form->render();
|
||||
|
||||
echo '</div>';
|
||||
|
||||
{
|
||||
remove_action( // In case render is called multiple times
|
||||
'admin_print_footer_scripts',
|
||||
array($this, '_action_admin_print_footer_scripts')
|
||||
);
|
||||
add_action(
|
||||
'admin_print_footer_scripts',
|
||||
array($this, '_action_admin_print_footer_scripts'),
|
||||
20
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Previously the functionality from this class was hardcoded in fw()->backend for Theme Settings
|
||||
* and there were hooks that developers use now, so we should use old hooks for Theme Settings form
|
||||
* Backwards Compatibility
|
||||
* @return bool
|
||||
*/
|
||||
private function is_theme_settings() {
|
||||
return $this->get_id() === 'theme-settings';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
* @return array
|
||||
* @internal
|
||||
*/
|
||||
public function _form_render($data) {
|
||||
$options = $this->get_options();
|
||||
|
||||
if ( empty( $options ) ) {
|
||||
echo '<p><em>', esc_html__('No options to display.', 'fw'), '</em></p>';
|
||||
return $data;
|
||||
}
|
||||
|
||||
if ($this->is_theme_settings()) {
|
||||
do_action('fw_settings_form_render', array(
|
||||
'ajax_submit' => $this->get_is_ajax_submit(),
|
||||
'side_tabs' => $this->get_is_side_tabs()
|
||||
));
|
||||
|
||||
{
|
||||
$texts = apply_filters('fw_settings_form_texts', array(
|
||||
'save_button' => __('Save Changes', 'fw'),
|
||||
'reset_button' => __('Reset Options', 'fw'),
|
||||
));
|
||||
|
||||
$this->set_string('save_button', $texts['save_button']);
|
||||
$this->set_string('reset_button', $texts['reset_button']);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
$data['attr']['class'] = 'fw-settings-form';
|
||||
|
||||
if ( $this->get_is_side_tabs() ) {
|
||||
$data['attr']['class'] .= ' fw-backend-side-tabs';
|
||||
}
|
||||
}
|
||||
|
||||
$data['submit']['html'] = '<!-- -->'; // it's generated in view
|
||||
|
||||
fw_render_view( fw_get_framework_directory( '/views/backend-settings-form.php' ), array(
|
||||
'form' => $this,
|
||||
'values' => (
|
||||
($values = FW_Request::POST( fw()->backend->get_options_name_attr_prefix() ))
|
||||
// This is form submit, extract values from $_POST
|
||||
? ($values = fw_get_options_values_from_input( $options, $values ))
|
||||
// Use saved values
|
||||
: ($values = $this->get_values())
|
||||
),
|
||||
'is_theme_settings' => $this->is_theme_settings(),
|
||||
'input_name_reset' => self::$input_name_reset,
|
||||
'input_name_save' => self::$input_name_save,
|
||||
'js_form_selector' => 'form[data-fw-form-id="'. esc_js($this->fw_form->get_id()) .'"]',
|
||||
), false );
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $errors
|
||||
* @return array
|
||||
* @internal
|
||||
*/
|
||||
public function _form_validate( $errors ) {
|
||||
if ( ! current_user_can($this->form_capability()) ) {
|
||||
$errors['_no_permission'] = __( 'You have no permissions to change settings options', 'fw' );
|
||||
}
|
||||
|
||||
return $errors;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
* @return array
|
||||
* @internal
|
||||
*/
|
||||
public function _form_save( $data ) {
|
||||
$flash_id = 'fw-settings-form:save:'. $this->get_id();
|
||||
$old_values = (array)$this->get_values();
|
||||
|
||||
if ( ! empty( $_POST[ self::$input_name_reset ] ) ) { // The "Reset" button was pressed
|
||||
/**
|
||||
* Some values that don't relate to design, like API credentials, are useful to not be wiped out.
|
||||
*
|
||||
* Usage:
|
||||
*
|
||||
* add_filter('fw_settings_form_reset:values', '_filter_add_persisted_option', 10, 2);
|
||||
* function _filter_add_persisted_option ($current_persisted, $old_values) {
|
||||
* $value_to_persist = fw_akg('my/multi/key', $old_values);
|
||||
* fw_aks('my/multi/key', $value_to_persist, $current_persisted);
|
||||
*
|
||||
* return $current_persisted;
|
||||
* }
|
||||
*/
|
||||
$new_values = $this->is_theme_settings()
|
||||
? apply_filters( 'fw_settings_form_reset:values', array(), $old_values )
|
||||
: apply_filters( 'fw:settings-form:' . $this->get_id() . ':reset:values', array(), $old_values );
|
||||
|
||||
$this->set_values( $new_values );
|
||||
|
||||
FW_Flash_Messages::add(
|
||||
$flash_id,
|
||||
__( 'The options were successfully reset', 'fw' ),
|
||||
'success'
|
||||
);
|
||||
|
||||
if ( $this->is_theme_settings() ) {
|
||||
do_action( 'fw_settings_form_reset', $old_values, $new_values );
|
||||
} else {
|
||||
do_action( 'fw:settings-form:' . $this->get_id() . ':reset', $old_values, $new_values );
|
||||
}
|
||||
} else { // The "Save" button was pressed
|
||||
$new_values = fw_get_options_values_from_input( $this->get_options() );
|
||||
|
||||
$this->set_values( $new_values );
|
||||
|
||||
FW_Flash_Messages::add(
|
||||
$flash_id,
|
||||
__( 'The options were successfully saved', 'fw' ),
|
||||
'success'
|
||||
);
|
||||
|
||||
if ($this->is_theme_settings()) {
|
||||
do_action('fw_settings_form_saved', $old_values, $new_values);
|
||||
} else {
|
||||
do_action('fw:settings-form:'. $this->get_id() .':saved', $old_values, $new_values);
|
||||
}
|
||||
}
|
||||
|
||||
$data['redirect'] = fw_current_url();
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
public function _action_admin_print_footer_scripts() {
|
||||
?>
|
||||
<script type="text/javascript">
|
||||
(function ($) {
|
||||
var fwLoadingId = 'fw-settings-form:<?php echo esc_js($this->get_id()); ?>';
|
||||
|
||||
<?php if (wp_script_is('fw-option-types')): ?>
|
||||
// there are options on the page. show loading now and hide it after the options were initialized
|
||||
{
|
||||
fw.loading.show(fwLoadingId);
|
||||
|
||||
fwEvents.one('fw:options:init', function (data) {
|
||||
fw.loading.hide(fwLoadingId);
|
||||
});
|
||||
}
|
||||
<?php endif; ?>
|
||||
|
||||
$(function ($) {
|
||||
$(document.body).on({
|
||||
'fw:settings-form:before-html-reset': function () {
|
||||
fw.loading.show(fwLoadingId);
|
||||
},
|
||||
'fw:settings-form:reset': function () {
|
||||
fw.loading.hide(fwLoadingId);
|
||||
}
|
||||
});
|
||||
});
|
||||
})(jQuery);
|
||||
</script>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,378 @@
|
||||
<?php if (!defined('FW')) die('Forbidden');
|
||||
|
||||
class FW_WP_Filesystem
|
||||
{
|
||||
/**
|
||||
* Request WP Filesystem access
|
||||
* @param string $context
|
||||
* @param string $url
|
||||
* @param array $extra_fields
|
||||
* @return null|bool // todo: Create a new method that will return WP_Error with message on failure
|
||||
* null - if has no access and the input credentials form was displayed
|
||||
* false - if user submitted wrong credentials
|
||||
* true - if we have filesystem access
|
||||
*/
|
||||
final public static function request_access($context = null, $url = null, $extra_fields = array())
|
||||
{
|
||||
/** @var WP_Filesystem_Base $wp_filesystem */
|
||||
global $wp_filesystem;
|
||||
|
||||
if ($wp_filesystem) {
|
||||
if (
|
||||
is_object($wp_filesystem)
|
||||
&&
|
||||
!(is_wp_error($wp_filesystem->errors) && $wp_filesystem->errors->get_error_code())
|
||||
) {
|
||||
return true; // already initialized
|
||||
}
|
||||
}
|
||||
|
||||
if ( empty( $url ) ) {
|
||||
$url = fw_current_url();
|
||||
}
|
||||
|
||||
if ( get_filesystem_method() === 'direct' ) {
|
||||
// in case if direct access is available
|
||||
|
||||
/* you can safely run request_filesystem_credentials() without any issues and don't need to worry about passing in a URL */
|
||||
$creds = request_filesystem_credentials( site_url() . '/wp-admin/', '', false, false, null );
|
||||
|
||||
/* initialize the API */
|
||||
if ( ! WP_Filesystem( $creds ) ) {
|
||||
/* any problems and we exit */
|
||||
trigger_error( __( 'Cannot connect to Filesystem directly', 'fw' ), E_USER_WARNING );
|
||||
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
$creds = request_filesystem_credentials( $url, '', false, $context, $extra_fields );
|
||||
|
||||
if ( ! $creds ) {
|
||||
// the form was printed to the user
|
||||
return null;
|
||||
}
|
||||
|
||||
/* initialize the API */
|
||||
if ( ! WP_Filesystem( $creds ) ) {
|
||||
/* any problems and we exit */
|
||||
request_filesystem_credentials( $url, '', true, $context, $extra_fields ); // the third parameter is true to show error to the user
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
! is_object($wp_filesystem)
|
||||
||
|
||||
(is_wp_error($wp_filesystem->errors) && $wp_filesystem->errors->get_error_code())
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (
|
||||
$wp_filesystem->abspath()
|
||||
&&
|
||||
$wp_filesystem->wp_content_dir()
|
||||
&&
|
||||
$wp_filesystem->wp_plugins_dir()
|
||||
&&
|
||||
$wp_filesystem->wp_themes_dir()
|
||||
&&
|
||||
$wp_filesystem->find_folder($context)
|
||||
) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array {base_dir_real_path => base_dir_wp_filesystem_path}
|
||||
*/
|
||||
public static function get_base_dirs_map()
|
||||
{
|
||||
/** @var WP_Filesystem_Base $wp_filesystem */
|
||||
global $wp_filesystem;
|
||||
|
||||
if (!$wp_filesystem) {
|
||||
trigger_error('Filesystem is not available', E_USER_ERROR);
|
||||
} elseif (is_wp_error($wp_filesystem->errors) && $wp_filesystem->errors->get_error_code()) {
|
||||
trigger_error('Filesystem: '. $wp_filesystem->errors->get_error_message(), E_USER_ERROR);
|
||||
}
|
||||
|
||||
try {
|
||||
$cache_key = 'fw_wp_filesystem/base_dirs_map';
|
||||
|
||||
return FW_Cache::get($cache_key);
|
||||
} catch (FW_Cache_Not_Found_Exception $e) {
|
||||
// code from $wp_filesystem->wp_themes_dir()
|
||||
{
|
||||
$themes_dir = get_theme_root();
|
||||
|
||||
// Account for relative theme roots
|
||||
if ( '/themes' == $themes_dir || ! is_dir( $themes_dir ) ) {
|
||||
$themes_dir = WP_CONTENT_DIR . $themes_dir;
|
||||
}
|
||||
}
|
||||
|
||||
$dirs = array(
|
||||
fw_fix_path(ABSPATH) => fw_fix_path($wp_filesystem->abspath()),
|
||||
fw_fix_path(WP_CONTENT_DIR) => fw_fix_path($wp_filesystem->wp_content_dir()),
|
||||
fw_fix_path(WP_PLUGIN_DIR) => fw_fix_path($wp_filesystem->wp_plugins_dir()),
|
||||
fw_fix_path($themes_dir) => fw_fix_path($wp_filesystem->wp_themes_dir()),
|
||||
);
|
||||
|
||||
FW_Cache::set($cache_key, $dirs);
|
||||
|
||||
return $dirs;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert real file path to WP Filesystem path
|
||||
* @param string $real_path
|
||||
* @return string|false
|
||||
*/
|
||||
final public static function real_path_to_filesystem_path($real_path) {
|
||||
/** @var WP_Filesystem_Base $wp_filesystem */
|
||||
global $wp_filesystem;
|
||||
|
||||
if (!$wp_filesystem) {
|
||||
trigger_error('Filesystem is not available', E_USER_ERROR);
|
||||
} elseif (is_wp_error($wp_filesystem->errors) && $wp_filesystem->errors->get_error_code()) {
|
||||
trigger_error('Filesystem: '. $wp_filesystem->errors->get_error_message(), E_USER_ERROR);
|
||||
}
|
||||
|
||||
$real_path = fw_fix_path($real_path);
|
||||
|
||||
foreach (self::get_base_dirs_map() as $base_real_path => $base_wp_filesystem_path) {
|
||||
$prefix_regex = '/^'. preg_quote($base_real_path, '/') .'($|\/.*)/';
|
||||
|
||||
// check if path is inside base path
|
||||
if (!preg_match($prefix_regex, $real_path)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($base_real_path === '/') {
|
||||
$relative_path = $real_path;
|
||||
} else {
|
||||
$relative_path = preg_replace($prefix_regex, '$1', $real_path);
|
||||
}
|
||||
|
||||
return $base_wp_filesystem_path . $relative_path;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert WP Filesystem path to real file path
|
||||
* @param string $wp_filesystem_path
|
||||
* @return string|false
|
||||
*/
|
||||
final public static function filesystem_path_to_real_path($wp_filesystem_path) {
|
||||
/** @var WP_Filesystem_Base $wp_filesystem */
|
||||
global $wp_filesystem;
|
||||
|
||||
if (!$wp_filesystem) {
|
||||
trigger_error('Filesystem is not available', E_USER_ERROR);
|
||||
} elseif (is_wp_error($wp_filesystem->errors) && $wp_filesystem->errors->get_error_code()) {
|
||||
trigger_error('Filesystem: '. $wp_filesystem->errors->get_error_message(), E_USER_ERROR);
|
||||
}
|
||||
|
||||
$wp_filesystem_path = fw_fix_path($wp_filesystem_path);
|
||||
|
||||
foreach (self::get_base_dirs_map() as $base_real_path => $base_wp_filesystem_path) {
|
||||
$prefix_regex = '/^'. preg_quote($base_wp_filesystem_path, '/') .'($|\/.*)/';
|
||||
|
||||
// check if path is inside base path
|
||||
if (!preg_match($prefix_regex, $wp_filesystem_path)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($base_wp_filesystem_path === '/') {
|
||||
$relative_path = $wp_filesystem_path;
|
||||
} else {
|
||||
$relative_path = preg_replace($prefix_regex, '$1', $wp_filesystem_path);
|
||||
}
|
||||
|
||||
return $base_real_path . $relative_path;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if there is direct filesystem access, so we can make changes without asking the credentials via form
|
||||
* @param string|null $context
|
||||
* @return bool
|
||||
*/
|
||||
final public static function has_direct_access($context = null)
|
||||
{
|
||||
/** @var WP_Filesystem_Base $wp_filesystem */
|
||||
global $wp_filesystem;
|
||||
|
||||
if ($wp_filesystem) {
|
||||
if (is_wp_error($wp_filesystem->errors) && $wp_filesystem->errors->get_error_code()) {
|
||||
return false;
|
||||
} else {
|
||||
return $wp_filesystem->method === 'direct';
|
||||
}
|
||||
}
|
||||
|
||||
if (get_filesystem_method(array(), $context) === 'direct') {
|
||||
ob_start();
|
||||
{
|
||||
$creds = request_filesystem_credentials(admin_url(), '', false, $context, null);
|
||||
}
|
||||
ob_end_clean();
|
||||
|
||||
if ( WP_Filesystem($creds) ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create wp filesystem directory recursive
|
||||
* @param string $wp_filesystem_dir_path
|
||||
* @return bool
|
||||
*/
|
||||
final public static function mkdir_recursive($wp_filesystem_dir_path) {
|
||||
/** @var WP_Filesystem_Base $wp_filesystem */
|
||||
global $wp_filesystem;
|
||||
|
||||
if (!$wp_filesystem) {
|
||||
trigger_error('Filesystem is not available', E_USER_ERROR);
|
||||
} elseif (is_wp_error($wp_filesystem->errors) && $wp_filesystem->errors->get_error_code()) {
|
||||
trigger_error('Filesystem: '. $wp_filesystem->errors->get_error_message(), E_USER_ERROR);
|
||||
}
|
||||
|
||||
$wp_filesystem_dir_path = fw_fix_path($wp_filesystem_dir_path);
|
||||
|
||||
$path = false;
|
||||
|
||||
foreach (self::get_base_dirs_map() as $base_real_path => $base_wp_filesystem_path) {
|
||||
$prefix_regex = '/^'. preg_quote($base_wp_filesystem_path, '/') .'($|\/)/';
|
||||
|
||||
// check if path is inside base path
|
||||
if (!preg_match($prefix_regex, $wp_filesystem_dir_path)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$path = $base_wp_filesystem_path;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!$path) {
|
||||
trigger_error(
|
||||
sprintf(
|
||||
__('Cannot create directory "%s". It must be inside "%s"', 'fw'),
|
||||
$wp_filesystem_dir_path,
|
||||
implode(__('" or "', 'fw'), self::get_base_dirs_map())
|
||||
),
|
||||
E_USER_WARNING
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($path === '/') {
|
||||
$rel_path = $wp_filesystem_dir_path;
|
||||
} else {
|
||||
$rel_path = preg_replace('/^'. preg_quote($path, '/') .'($|\/.*)/', '$1', $wp_filesystem_dir_path);
|
||||
}
|
||||
|
||||
// improvement: do not check directory for existence if it's known that sure it doesn't exist
|
||||
$check_if_exists = true;
|
||||
|
||||
foreach (explode('/', ltrim($rel_path, '/')) as $dir_name) {
|
||||
$path .= '/' . $dir_name;
|
||||
|
||||
// When WP FS abspath is '/', $path can be '//wp-content'. Fix it '/wp-content'
|
||||
$path = fw_fix_path($path);
|
||||
|
||||
if ($check_if_exists) {
|
||||
if ($wp_filesystem->is_dir($path)) {
|
||||
// do nothing if exists
|
||||
continue;
|
||||
} else {
|
||||
// do not check anymore, next directories sure doesn't exist
|
||||
$check_if_exists = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$wp_filesystem->mkdir($path)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $file_path
|
||||
* @param $content
|
||||
*
|
||||
* @return bool|WP_Error
|
||||
*/
|
||||
public static function put( $file_path, $content ) {
|
||||
|
||||
self::init_file_system();
|
||||
|
||||
/** @var WP_Filesystem_Base $wp_filesystem */
|
||||
global $wp_filesystem;
|
||||
|
||||
if ( ! $wp_filesystem->put_contents( $file_path, $content ) ) {
|
||||
return new WP_Error( 'fs_error_put_content', esc_html__( 'Error writing to file: ', 'fw' ) . wp_basename( $file_path ) );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $file_path
|
||||
*
|
||||
* @return bool|mixed|WP_Error
|
||||
*/
|
||||
public static function get( $file_path ) {
|
||||
|
||||
self::init_file_system();
|
||||
|
||||
/** @var WP_Filesystem_Base $wp_filesystem */
|
||||
global $wp_filesystem;
|
||||
|
||||
$content = $wp_filesystem->get_contents( $file_path );
|
||||
|
||||
if ( false === $content ) {
|
||||
return new WP_Error( 'fs_error_get_content', esc_html__( 'Error to get content from file: ', 'fw' ) . wp_basename( $file_path ) );
|
||||
}
|
||||
|
||||
return $content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize wp files system.
|
||||
*/
|
||||
public static function init_file_system() {
|
||||
if ( self::is_ready() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
include_once( ABSPATH . '/wp-admin/includes/file.php' );
|
||||
|
||||
WP_Filesystem();
|
||||
}
|
||||
|
||||
/**
|
||||
* If is initialized and has no errors
|
||||
* @return bool
|
||||
* @since 2.6.8
|
||||
*/
|
||||
public static function is_ready() {
|
||||
/** @var WP_Filesystem_Base $wp_filesystem */
|
||||
global $wp_filesystem;
|
||||
|
||||
return $wp_filesystem && is_wp_error($wp_filesystem->errors) && !$wp_filesystem->errors->get_error_code();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,968 @@
|
||||
<?php if ( ! defined( 'FW' ) ) {
|
||||
die( 'Forbidden' );
|
||||
}
|
||||
/**
|
||||
* Base class for displaying a list of items in an ajaxified HTML table.
|
||||
*
|
||||
* @package WordPress
|
||||
* @subpackage List_Table
|
||||
* @since 3.1.0
|
||||
* @access private
|
||||
*/
|
||||
class FW_WP_List_Table {
|
||||
|
||||
/**
|
||||
* The current list of items
|
||||
*
|
||||
* @since 3.1.0
|
||||
* @var array
|
||||
* @access protected
|
||||
*/
|
||||
var $items;
|
||||
|
||||
/**
|
||||
* Various information about the current table
|
||||
*
|
||||
* @since 3.1.0
|
||||
* @var array
|
||||
* @access private
|
||||
*/
|
||||
var $_args;
|
||||
|
||||
/**
|
||||
* Various information needed for displaying the pagination
|
||||
*
|
||||
* @since 3.1.0
|
||||
* @var array
|
||||
* @access private
|
||||
*/
|
||||
var $_pagination_args = array();
|
||||
|
||||
/**
|
||||
* The current screen
|
||||
*
|
||||
* @since 3.1.0
|
||||
* @var object
|
||||
* @access protected
|
||||
*/
|
||||
var $screen;
|
||||
|
||||
/**
|
||||
* Cached bulk actions
|
||||
*
|
||||
* @since 3.1.0
|
||||
* @var array
|
||||
* @access private
|
||||
*/
|
||||
var $_actions;
|
||||
|
||||
/**
|
||||
* Cached pagination output
|
||||
*
|
||||
* @since 3.1.0
|
||||
* @var string
|
||||
* @access private
|
||||
*/
|
||||
var $_pagination;
|
||||
|
||||
/**
|
||||
* Constructor. The child class should call this constructor from its own constructor
|
||||
*
|
||||
* @param array $args An associative array with information about the current table
|
||||
* @access protected
|
||||
*/
|
||||
function __construct( $args = array() ) {
|
||||
$args = wp_parse_args( $args, array(
|
||||
'plural' => '',
|
||||
'singular' => '',
|
||||
'ajax' => false,
|
||||
'screen' => null,
|
||||
) );
|
||||
|
||||
$this->screen = convert_to_screen( $args['screen'] );
|
||||
|
||||
add_filter( "manage_{$this->screen->id}_columns", array( $this, 'get_columns' ), 0 );
|
||||
|
||||
if ( !$args['plural'] )
|
||||
$args['plural'] = $this->screen->base;
|
||||
|
||||
$args['plural'] = sanitize_key( $args['plural'] );
|
||||
$args['singular'] = sanitize_key( $args['singular'] );
|
||||
|
||||
$this->_args = $args;
|
||||
|
||||
if ( $args['ajax'] ) {
|
||||
// wp_enqueue_script( 'list-table' );
|
||||
add_action( 'admin_footer', array( $this, '_js_vars' ) );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the current user's permissions
|
||||
* @uses wp_die()
|
||||
*
|
||||
* @since 3.1.0
|
||||
* @access public
|
||||
* @abstract
|
||||
*/
|
||||
function ajax_user_can() {
|
||||
die( 'function WP_List_Table::ajax_user_can() must be over-ridden in a sub-class.' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares the list of items for displaying.
|
||||
* @uses WP_List_Table::set_pagination_args()
|
||||
*
|
||||
* @since 3.1.0
|
||||
* @access public
|
||||
* @abstract
|
||||
*/
|
||||
function prepare_items() {
|
||||
die( 'function WP_List_Table::prepare_items() must be over-ridden in a sub-class.' );
|
||||
}
|
||||
|
||||
/**
|
||||
* An internal method that sets all the necessary pagination arguments
|
||||
*
|
||||
* @param array $args An associative array with information about the pagination
|
||||
* @access protected
|
||||
*/
|
||||
function set_pagination_args( $args ) {
|
||||
$args = wp_parse_args( $args, array(
|
||||
'total_items' => 0,
|
||||
'total_pages' => 0,
|
||||
'per_page' => 0,
|
||||
) );
|
||||
|
||||
if ( !$args['total_pages'] && $args['per_page'] > 0 )
|
||||
$args['total_pages'] = ceil( $args['total_items'] / $args['per_page'] );
|
||||
|
||||
// redirect if page number is invalid and headers are not already sent
|
||||
if ( ! headers_sent() && ( ! defined( 'DOING_AJAX' ) || ! DOING_AJAX ) && $args['total_pages'] > 0 && $this->get_pagenum() > $args['total_pages'] ) {
|
||||
wp_redirect( add_query_arg( 'paged', $args['total_pages'] ) );
|
||||
exit;
|
||||
}
|
||||
|
||||
$this->_pagination_args = $args;
|
||||
}
|
||||
|
||||
/**
|
||||
* Access the pagination args
|
||||
*
|
||||
* @since 3.1.0
|
||||
* @access public
|
||||
*
|
||||
* @param string $key
|
||||
* @return array
|
||||
*/
|
||||
function get_pagination_arg( $key ) {
|
||||
if ( 'page' == $key )
|
||||
return $this->get_pagenum();
|
||||
|
||||
if ( isset( $this->_pagination_args[$key] ) )
|
||||
return $this->_pagination_args[$key];
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the table has items to display or not
|
||||
*
|
||||
* @since 3.1.0
|
||||
* @access public
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
function has_items() {
|
||||
return !empty( $this->items );
|
||||
}
|
||||
|
||||
/**
|
||||
* Message to be displayed when there are no items
|
||||
*
|
||||
* @since 3.1.0
|
||||
* @access public
|
||||
*/
|
||||
function no_items() {
|
||||
_e( 'No items found.', 'fw' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the search box.
|
||||
*
|
||||
* @since 3.1.0
|
||||
* @access public
|
||||
*
|
||||
* @param string $text The search button text
|
||||
* @param string $input_id The search input id
|
||||
*/
|
||||
function search_box( $text, $input_id ) {
|
||||
if ( empty( $_REQUEST['s'] ) && !$this->has_items() )
|
||||
return;
|
||||
|
||||
$input_id = $input_id . '-search-input';
|
||||
|
||||
if ( ! empty( $_REQUEST['orderby'] ) )
|
||||
echo '<input type="hidden" name="orderby" value="' . esc_attr( $_REQUEST['orderby'] ) . '" />';
|
||||
if ( ! empty( $_REQUEST['order'] ) )
|
||||
echo '<input type="hidden" name="order" value="' . esc_attr( $_REQUEST['order'] ) . '" />';
|
||||
if ( ! empty( $_REQUEST['post_mime_type'] ) )
|
||||
echo '<input type="hidden" name="post_mime_type" value="' . esc_attr( $_REQUEST['post_mime_type'] ) . '" />';
|
||||
if ( ! empty( $_REQUEST['detached'] ) )
|
||||
echo '<input type="hidden" name="detached" value="' . esc_attr( $_REQUEST['detached'] ) . '" />';
|
||||
?>
|
||||
<p class="search-box">
|
||||
<label class="screen-reader-text" for="<?php echo esc_attr($input_id) ?>"><?php echo $text; ?>:</label>
|
||||
<input type="search" id="<?php echo esc_attr($input_id) ?>" name="s" value="<?php _admin_search_query(); ?>" />
|
||||
<?php submit_button( $text, 'button', false, false, array('id' => 'search-submit') ); ?>
|
||||
</p>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an associative array ( id => link ) with the list
|
||||
* of views available on this table.
|
||||
*
|
||||
* @since 3.1.0
|
||||
* @access protected
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function get_views() {
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the list of views available on this table.
|
||||
*
|
||||
* @since 3.1.0
|
||||
* @access public
|
||||
*/
|
||||
function views() {
|
||||
$views = $this->get_views();
|
||||
/**
|
||||
* Filter the list of available list table views.
|
||||
*
|
||||
* The dynamic portion of the hook name, $this->screen->id, refers
|
||||
* to the ID of the current screen, usually a string.
|
||||
*
|
||||
* @since 3.5.0
|
||||
*
|
||||
* @param array $views An array of available list table views.
|
||||
*/
|
||||
$views = apply_filters( "views_{$this->screen->id}", $views );
|
||||
|
||||
if ( empty( $views ) )
|
||||
return;
|
||||
|
||||
echo "<ul class='subsubsub'>\n";
|
||||
foreach ( $views as $class => $view ) {
|
||||
$views[ $class ] = "\t<li class='$class'>$view";
|
||||
}
|
||||
echo implode( " |</li>\n", $views ) . "</li>\n";
|
||||
echo "</ul>";
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an associative array ( option_name => option_title ) with the list
|
||||
* of bulk actions available on this table.
|
||||
*
|
||||
* @since 3.1.0
|
||||
* @access protected
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function get_bulk_actions() {
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the bulk actions dropdown.
|
||||
*
|
||||
* @since 3.1.0
|
||||
* @access public
|
||||
*/
|
||||
function bulk_actions() {
|
||||
if ( is_null( $this->_actions ) ) {
|
||||
$no_new_actions = $this->_actions = $this->get_bulk_actions();
|
||||
/**
|
||||
* Filter the list table Bulk Actions drop-down.
|
||||
*
|
||||
* The dynamic portion of the hook name, $this->screen->id, refers
|
||||
* to the ID of the current screen, usually a string.
|
||||
*
|
||||
* This filter can currently only be used to remove bulk actions.
|
||||
*
|
||||
* @since 3.5.0
|
||||
*
|
||||
* @param array $actions An array of the available bulk actions.
|
||||
*/
|
||||
$this->_actions = apply_filters( "bulk_actions-{$this->screen->id}", $this->_actions );
|
||||
$this->_actions = array_intersect_assoc( $this->_actions, $no_new_actions );
|
||||
$two = '';
|
||||
} else {
|
||||
$two = '2';
|
||||
}
|
||||
|
||||
if ( empty( $this->_actions ) )
|
||||
return;
|
||||
|
||||
echo "<select name='action$two'>\n";
|
||||
echo "<option value='-1' selected='selected'>" . __( 'Bulk Actions', 'fw' ) . "</option>\n";
|
||||
|
||||
foreach ( $this->_actions as $name => $title ) {
|
||||
$class = 'edit' == $name ? ' class="hide-if-no-js"' : '';
|
||||
|
||||
echo "\t<option value='$name'$class>$title</option>\n";
|
||||
}
|
||||
|
||||
echo "</select>\n";
|
||||
|
||||
submit_button( __( 'Apply', 'fw' ), 'action', false, false, array( 'id' => "doaction$two" ) );
|
||||
echo "\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current action selected from the bulk actions dropdown.
|
||||
*
|
||||
* @since 3.1.0
|
||||
* @access public
|
||||
*
|
||||
* @return string|bool The action name or False if no action was selected
|
||||
*/
|
||||
function current_action() {
|
||||
if ( isset( $_REQUEST['action'] ) && -1 != $_REQUEST['action'] )
|
||||
return $_REQUEST['action'];
|
||||
|
||||
if ( isset( $_REQUEST['action2'] ) && -1 != $_REQUEST['action2'] )
|
||||
return $_REQUEST['action2'];
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate row actions div
|
||||
*
|
||||
* @since 3.1.0
|
||||
* @access protected
|
||||
*
|
||||
* @param array $actions The list of actions
|
||||
* @param bool $always_visible Whether the actions should be always visible
|
||||
* @return string
|
||||
*/
|
||||
function row_actions( $actions, $always_visible = false ) {
|
||||
$action_count = count( $actions );
|
||||
$i = 0;
|
||||
|
||||
if ( !$action_count )
|
||||
return '';
|
||||
|
||||
$out = '<div class="' . ( $always_visible ? 'row-actions visible' : 'row-actions' ) . '">';
|
||||
foreach ( $actions as $action => $link ) {
|
||||
++$i;
|
||||
( $i == $action_count ) ? $sep = '' : $sep = ' | ';
|
||||
$out .= "<span class='$action'>$link$sep</span>";
|
||||
}
|
||||
$out .= '</div>';
|
||||
|
||||
return $out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Display a monthly dropdown for filtering items
|
||||
*
|
||||
* @since 3.1.0
|
||||
* @access protected
|
||||
*/
|
||||
function months_dropdown( $post_type ) {
|
||||
global $wpdb, $wp_locale;
|
||||
|
||||
$months = $wpdb->get_results( $wpdb->prepare( "
|
||||
SELECT DISTINCT YEAR( post_date ) AS year, MONTH( post_date ) AS month
|
||||
FROM $wpdb->posts
|
||||
WHERE post_type = %s
|
||||
ORDER BY post_date DESC
|
||||
", $post_type ) );
|
||||
|
||||
/**
|
||||
* Filter the 'Months' drop-down results.
|
||||
*
|
||||
* @since 3.7.0
|
||||
*
|
||||
* @param object $months The months drop-down query results.
|
||||
* @param string $post_type The post type.
|
||||
*/
|
||||
$months = apply_filters( 'months_dropdown_results', $months, $post_type );
|
||||
|
||||
$month_count = count( $months );
|
||||
|
||||
if ( !$month_count || ( 1 == $month_count && 0 == $months[0]->month ) )
|
||||
return;
|
||||
|
||||
$m = isset( $_GET['m'] ) ? (int) $_GET['m'] : 0;
|
||||
?>
|
||||
<select name='m'>
|
||||
<option<?php selected( $m, 0 ); ?> value='0'><?php _e( 'All dates', 'fw' ); ?></option>
|
||||
<?php
|
||||
foreach ( $months as $arc_row ) {
|
||||
if ( 0 == $arc_row->year )
|
||||
continue;
|
||||
|
||||
$month = zeroise( $arc_row->month, 2 );
|
||||
$year = $arc_row->year;
|
||||
|
||||
printf( "<option %s value='%s'>%s</option>\n",
|
||||
selected( $m, $year . $month, false ),
|
||||
esc_attr( $arc_row->year . $month ),
|
||||
/* translators: 1: month name, 2: 4-digit year */
|
||||
sprintf( __( '%1$s %2$d', 'fw' ), $wp_locale->get_month( $month ), $year )
|
||||
);
|
||||
}
|
||||
?>
|
||||
</select>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* Display a view switcher
|
||||
*
|
||||
* @since 3.1.0
|
||||
* @access protected
|
||||
*/
|
||||
function view_switcher( $current_mode ) {
|
||||
$modes = array(
|
||||
'list' => __( 'List View', 'fw' ),
|
||||
'excerpt' => __( 'Excerpt View', 'fw' )
|
||||
);
|
||||
|
||||
?>
|
||||
<input type="hidden" name="mode" value="<?php echo esc_attr( $current_mode ); ?>" />
|
||||
<div class="view-switch">
|
||||
<?php
|
||||
foreach ( $modes as $mode => $title ) {
|
||||
$class = ( $current_mode == $mode ) ? 'class="current"' : '';
|
||||
echo "<a href='" . esc_url( add_query_arg( 'mode', $mode, $_SERVER['REQUEST_URI'] ) ) . "' $class><img id='view-switch-$mode' src='" . esc_url( includes_url( 'images/blank.gif' ) ) . "' width='20' height='20' title='$title' alt='$title' /></a>\n";
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* Display a comment count bubble
|
||||
*
|
||||
* @since 3.1.0
|
||||
* @access protected
|
||||
*
|
||||
* @param int $post_id
|
||||
* @param int $pending_comments
|
||||
*/
|
||||
function comments_bubble( $post_id, $pending_comments ) {
|
||||
$pending_phrase = sprintf( __( '%s pending', 'fw' ), number_format( $pending_comments ) );
|
||||
|
||||
if ( $pending_comments )
|
||||
echo '<strong>';
|
||||
|
||||
echo "<a href='" . esc_url( add_query_arg( 'p', $post_id, admin_url( 'edit-comments.php' ) ) ) . "' title='" . esc_attr( $pending_phrase ) . "' class='post-com-count'><span class='comment-count'>" . number_format_i18n( get_comments_number() ) . "</span></a>";
|
||||
|
||||
if ( $pending_comments )
|
||||
echo '</strong>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current page number
|
||||
*
|
||||
* @since 3.1.0
|
||||
* @access protected
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
function get_pagenum() {
|
||||
$pagenum = isset( $_REQUEST['paged'] ) ? absint( $_REQUEST['paged'] ) : 0;
|
||||
|
||||
if( isset( $this->_pagination_args['total_pages'] ) && $pagenum > $this->_pagination_args['total_pages'] )
|
||||
$pagenum = $this->_pagination_args['total_pages'];
|
||||
|
||||
return max( 1, $pagenum );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get number of items to display on a single page
|
||||
*
|
||||
* @since 3.1.0
|
||||
* @access protected
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
function get_items_per_page( $option, $default = 20 ) {
|
||||
$per_page = (int) get_user_option( $option );
|
||||
if ( empty( $per_page ) || $per_page < 1 )
|
||||
$per_page = $default;
|
||||
|
||||
/**
|
||||
* Filter the number of items to be displayed on each page of the list table.
|
||||
*
|
||||
* The dynamic hook name, $option, refers to the per page option depending
|
||||
* on the type of list table in use. Possible values may include:
|
||||
* 'edit_comments_per_page', 'sites_network_per_page', 'site_themes_network_per_page',
|
||||
* 'themes_netework_per_page', 'users_network_per_page', 'edit_{$post_type}', etc.
|
||||
*
|
||||
* @since 2.9.0
|
||||
*
|
||||
* @param int $per_page Number of items to be displayed. Default 20.
|
||||
*/
|
||||
return (int) apply_filters( $option, $per_page );
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the pagination.
|
||||
*
|
||||
* @since 3.1.0
|
||||
* @access protected
|
||||
*/
|
||||
function pagination( $which ) {
|
||||
if ( empty( $this->_pagination_args ) )
|
||||
return;
|
||||
|
||||
extract( $this->_pagination_args, EXTR_SKIP );
|
||||
|
||||
$output = '<span class="displaying-num">' . sprintf( _n( '1 item', '%s items', $total_items ), number_format_i18n( $total_items ) ) . '</span>';
|
||||
|
||||
$current = $this->get_pagenum();
|
||||
|
||||
$current_url = fw_current_url();
|
||||
|
||||
$current_url = remove_query_arg( array( 'hotkeys_highlight_last', 'hotkeys_highlight_first' ), $current_url );
|
||||
|
||||
$page_links = array();
|
||||
|
||||
$disable_first = $disable_last = '';
|
||||
if ( $current == 1 )
|
||||
$disable_first = ' disabled';
|
||||
if ( $current == $total_pages )
|
||||
$disable_last = ' disabled';
|
||||
|
||||
$page_links[] = sprintf( "<a class='%s' title='%s' href='%s'>%s</a>",
|
||||
'first-page' . $disable_first,
|
||||
esc_attr__( 'Go to the first page', 'fw' ),
|
||||
esc_url( remove_query_arg( 'paged', $current_url ) ),
|
||||
'«'
|
||||
);
|
||||
|
||||
$page_links[] = sprintf( "<a class='%s' title='%s' href='%s'>%s</a>",
|
||||
'prev-page' . $disable_first,
|
||||
esc_attr__( 'Go to the previous page', 'fw' ),
|
||||
esc_url( add_query_arg( 'paged', max( 1, $current-1 ), $current_url ) ),
|
||||
'‹'
|
||||
);
|
||||
|
||||
if ( 'bottom' == $which )
|
||||
$html_current_page = $current;
|
||||
else
|
||||
$html_current_page = sprintf( "<input class='current-page' title='%s' type='text' name='paged' value='%s' size='%d' />",
|
||||
esc_attr__( 'Current page', 'fw' ),
|
||||
$current,
|
||||
strlen( $total_pages )
|
||||
);
|
||||
|
||||
$html_total_pages = sprintf( "<span class='total-pages'>%s</span>", number_format_i18n( $total_pages ) );
|
||||
$page_links[] = '<span class="paging-input">' . sprintf( _x( '%1$s of %2$s', 'paging', 'fw' ), $html_current_page, $html_total_pages ) . '</span>';
|
||||
|
||||
$page_links[] = sprintf( "<a class='%s' title='%s' href='%s'>%s</a>",
|
||||
'next-page' . $disable_last,
|
||||
esc_attr__( 'Go to the next page', 'fw' ),
|
||||
esc_url( add_query_arg( 'paged', min( $total_pages, $current+1 ), $current_url ) ),
|
||||
'›'
|
||||
);
|
||||
|
||||
$page_links[] = sprintf( "<a class='%s' title='%s' href='%s'>%s</a>",
|
||||
'last-page' . $disable_last,
|
||||
esc_attr__( 'Go to the last page', 'fw' ),
|
||||
esc_url( add_query_arg( 'paged', $total_pages, $current_url ) ),
|
||||
'»'
|
||||
);
|
||||
|
||||
$pagination_links_class = 'pagination-links';
|
||||
if ( ! empty( $infinite_scroll ) )
|
||||
$pagination_links_class = ' hide-if-js';
|
||||
$output .= "\n<span class='$pagination_links_class'>" . join( "\n", $page_links ) . '</span>';
|
||||
|
||||
if ( $total_pages )
|
||||
$page_class = $total_pages < 2 ? ' one-page' : '';
|
||||
else
|
||||
$page_class = ' no-pages';
|
||||
|
||||
$this->_pagination = "<div class='tablenav-pages{$page_class}'>$output</div>";
|
||||
|
||||
echo $this->_pagination;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of columns. The format is:
|
||||
* 'internal-name' => 'Title'
|
||||
*
|
||||
* @since 3.1.0
|
||||
* @access protected
|
||||
* @abstract
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function get_columns() {
|
||||
die( 'function WP_List_Table::get_columns() must be over-ridden in a sub-class.' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of sortable columns. The format is:
|
||||
* 'internal-name' => 'orderby'
|
||||
* or
|
||||
* 'internal-name' => array( 'orderby', true )
|
||||
*
|
||||
* The second format will make the initial sorting order be descending
|
||||
*
|
||||
* @since 3.1.0
|
||||
* @access protected
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function get_sortable_columns() {
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of all, hidden and sortable columns, with filter applied
|
||||
*
|
||||
* @since 3.1.0
|
||||
* @access protected
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function get_column_info() {
|
||||
if ( isset( $this->_column_headers ) )
|
||||
return $this->_column_headers;
|
||||
|
||||
$columns = get_column_headers( $this->screen );
|
||||
$hidden = get_hidden_columns( $this->screen );
|
||||
|
||||
$sortable_columns = $this->get_sortable_columns();
|
||||
/**
|
||||
* Filter the list table sortable columns for a specific screen.
|
||||
*
|
||||
* The dynamic portion of the hook name, $this->screen->id, refers
|
||||
* to the ID of the current screen, usually a string.
|
||||
*
|
||||
* @since 3.5.0
|
||||
*
|
||||
* @param array $sortable_columns An array of sortable columns.
|
||||
*/
|
||||
$_sortable = apply_filters( "manage_{$this->screen->id}_sortable_columns", $sortable_columns );
|
||||
|
||||
$sortable = array();
|
||||
foreach ( $_sortable as $id => $data ) {
|
||||
if ( empty( $data ) )
|
||||
continue;
|
||||
|
||||
$data = (array) $data;
|
||||
if ( !isset( $data[1] ) )
|
||||
$data[1] = false;
|
||||
|
||||
$sortable[$id] = $data;
|
||||
}
|
||||
|
||||
$this->_column_headers = array( $columns, $hidden, $sortable );
|
||||
|
||||
return $this->_column_headers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return number of visible columns
|
||||
*
|
||||
* @since 3.1.0
|
||||
* @access public
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
function get_column_count() {
|
||||
list ( $columns, $hidden ) = $this->get_column_info();
|
||||
$hidden = array_intersect( array_keys( $columns ), array_filter( $hidden ) );
|
||||
return count( $columns ) - count( $hidden );
|
||||
}
|
||||
|
||||
/**
|
||||
* Print column headers, accounting for hidden and sortable columns.
|
||||
*
|
||||
* @since 3.1.0
|
||||
* @access protected
|
||||
*
|
||||
* @param bool $with_id Whether to set the id attribute or not
|
||||
*/
|
||||
function print_column_headers( $with_id = true ) {
|
||||
list( $columns, $hidden, $sortable ) = $this->get_column_info();
|
||||
|
||||
$current_url = fw_current_url();
|
||||
$current_url = remove_query_arg( 'paged', $current_url );
|
||||
|
||||
if ( isset( $_GET['orderby'] ) )
|
||||
$current_orderby = $_GET['orderby'];
|
||||
else
|
||||
$current_orderby = '';
|
||||
|
||||
if ( isset( $_GET['order'] ) && 'desc' == $_GET['order'] )
|
||||
$current_order = 'desc';
|
||||
else
|
||||
$current_order = 'asc';
|
||||
|
||||
if ( ! empty( $columns['cb'] ) ) {
|
||||
static $cb_counter = 1;
|
||||
$columns['cb'] = '<label class="screen-reader-text" for="cb-select-all-' . $cb_counter . '">' . __( 'Select All', 'fw' ) . '</label>'
|
||||
. '<input id="cb-select-all-' . $cb_counter . '" type="checkbox" />';
|
||||
$cb_counter++;
|
||||
}
|
||||
|
||||
foreach ( $columns as $column_key => $column_display_name ) {
|
||||
$class = array( 'manage-column', "column-$column_key" );
|
||||
|
||||
$style = '';
|
||||
if ( in_array( $column_key, $hidden ) )
|
||||
$style = 'display:none;';
|
||||
|
||||
$style = ' style="' . $style . '"';
|
||||
|
||||
if ( 'cb' == $column_key )
|
||||
$class[] = 'check-column';
|
||||
elseif ( in_array( $column_key, array( 'posts', 'comments', 'links' ) ) )
|
||||
$class[] = 'num';
|
||||
|
||||
if ( isset( $sortable[$column_key] ) ) {
|
||||
list( $orderby, $desc_first ) = $sortable[$column_key];
|
||||
|
||||
if ( $current_orderby == $orderby ) {
|
||||
$order = 'asc' == $current_order ? 'desc' : 'asc';
|
||||
$class[] = 'sorted';
|
||||
$class[] = $current_order;
|
||||
} else {
|
||||
$order = $desc_first ? 'desc' : 'asc';
|
||||
$class[] = 'sortable';
|
||||
$class[] = $desc_first ? 'asc' : 'desc';
|
||||
}
|
||||
|
||||
$column_display_name = '<a href="' . esc_url( add_query_arg( compact( 'orderby', 'order' ), $current_url ) ) . '"><span>' . $column_display_name . '</span><span class="sorting-indicator"></span></a>';
|
||||
}
|
||||
|
||||
$id = $with_id ? "id='$column_key'" : '';
|
||||
|
||||
if ( !empty( $class ) )
|
||||
$class = "class='" . join( ' ', $class ) . "'";
|
||||
|
||||
echo "<th scope='col' $id $class $style>$column_display_name</th>";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the table
|
||||
*
|
||||
* @since 3.1.0
|
||||
* @access public
|
||||
*/
|
||||
function display() {
|
||||
extract( $this->_args );
|
||||
|
||||
$this->display_tablenav( 'top' );
|
||||
|
||||
?>
|
||||
<table class="wp-list-table <?php echo implode( ' ', $this->get_table_classes() ); ?>">
|
||||
<thead>
|
||||
<tr>
|
||||
<?php $this->print_column_headers(); ?>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tfoot>
|
||||
<tr>
|
||||
<?php $this->print_column_headers( false ); ?>
|
||||
</tr>
|
||||
</tfoot>
|
||||
|
||||
<tbody id="the-list"<?php if ( $singular ) echo " data-wp-lists='list:$singular'"; ?>>
|
||||
<?php $this->display_rows_or_placeholder(); ?>
|
||||
</tbody>
|
||||
</table>
|
||||
<?php
|
||||
$this->display_tablenav( 'bottom' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of CSS classes for the <table> tag
|
||||
*
|
||||
* @since 3.1.0
|
||||
* @access protected
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function get_table_classes() {
|
||||
return array( 'widefat', 'fixed', $this->_args['plural'] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the table navigation above or below the table
|
||||
*
|
||||
* @since 3.1.0
|
||||
* @access protected
|
||||
*/
|
||||
function display_tablenav( $which ) {
|
||||
if ( 'top' == $which )
|
||||
wp_nonce_field( 'bulk-' . $this->_args['plural'] );
|
||||
?>
|
||||
<div class="tablenav <?php echo esc_attr( $which ); ?>">
|
||||
|
||||
<div class="alignleft actions bulkactions">
|
||||
<?php $this->bulk_actions(); ?>
|
||||
</div>
|
||||
<?php
|
||||
$this->extra_tablenav( $which );
|
||||
$this->pagination( $which );
|
||||
?>
|
||||
|
||||
<br class="clear" />
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* Extra controls to be displayed between bulk actions and pagination
|
||||
*
|
||||
* @since 3.1.0
|
||||
* @access protected
|
||||
*/
|
||||
function extra_tablenav( $which ) {}
|
||||
|
||||
/**
|
||||
* Generate the <tbody> part of the table
|
||||
*
|
||||
* @since 3.1.0
|
||||
* @access protected
|
||||
*/
|
||||
function display_rows_or_placeholder() {
|
||||
if ( $this->has_items() ) {
|
||||
$this->display_rows();
|
||||
} else {
|
||||
list( $columns, $hidden ) = $this->get_column_info();
|
||||
echo '<tr class="no-items"><td class="colspanchange" colspan="' . $this->get_column_count() . '">';
|
||||
$this->no_items();
|
||||
echo '</td></tr>';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the table rows
|
||||
*
|
||||
* @since 3.1.0
|
||||
* @access protected
|
||||
*/
|
||||
function display_rows() {
|
||||
foreach ( $this->items as $item )
|
||||
$this->single_row( $item );
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates content for a single row of the table
|
||||
*
|
||||
* @since 3.1.0
|
||||
* @access protected
|
||||
*
|
||||
* @param object $item The current item
|
||||
*/
|
||||
function single_row( $item ) {
|
||||
static $row_class = '';
|
||||
$row_class = ( $row_class == '' ? ' class="alternate"' : '' );
|
||||
|
||||
echo '<tr' . $row_class . '>';
|
||||
$this->single_row_columns( $item );
|
||||
echo '</tr>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the columns for a single row of the table
|
||||
*
|
||||
* @since 3.1.0
|
||||
* @access protected
|
||||
*
|
||||
* @param object $item The current item
|
||||
*/
|
||||
function single_row_columns( $item ) {
|
||||
list( $columns, $hidden ) = $this->get_column_info();
|
||||
|
||||
foreach ( $columns as $column_name => $column_display_name ) {
|
||||
$class = "class='$column_name column-$column_name'";
|
||||
|
||||
$style = '';
|
||||
if ( in_array( $column_name, $hidden ) )
|
||||
$style = ' style="display:none;"';
|
||||
|
||||
$attributes = "$class$style";
|
||||
|
||||
if ( 'cb' == $column_name ) {
|
||||
echo '<th scope="row" class="check-column">';
|
||||
echo $this->column_cb( $item );
|
||||
echo '</th>';
|
||||
}
|
||||
elseif ( method_exists( $this, 'column_' . $column_name ) ) {
|
||||
echo "<td $attributes>";
|
||||
echo call_user_func( array( $this, 'column_' . $column_name ), $item );
|
||||
echo "</td>";
|
||||
}
|
||||
else {
|
||||
echo "<td $attributes>";
|
||||
echo $this->column_default( $item, $column_name );
|
||||
echo "</td>";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle an incoming ajax request (called from admin-ajax.php)
|
||||
*
|
||||
* @since 3.1.0
|
||||
* @access public
|
||||
*/
|
||||
function ajax_response() {
|
||||
$this->prepare_items();
|
||||
|
||||
extract( $this->_args );
|
||||
extract( $this->_pagination_args, EXTR_SKIP );
|
||||
|
||||
ob_start();
|
||||
if ( ! empty( $_REQUEST['no_placeholder'] ) )
|
||||
$this->display_rows();
|
||||
else
|
||||
$this->display_rows_or_placeholder();
|
||||
|
||||
$rows = ob_get_clean();
|
||||
|
||||
$response = array( 'rows' => $rows );
|
||||
|
||||
if ( isset( $total_items ) )
|
||||
$response['total_items_i18n'] = sprintf( _n( '1 item', '%s items', $total_items ), number_format_i18n( $total_items ) );
|
||||
|
||||
if ( isset( $total_pages ) ) {
|
||||
$response['total_pages'] = $total_pages;
|
||||
$response['total_pages_i18n'] = number_format_i18n( $total_pages );
|
||||
}
|
||||
|
||||
die( json_encode( $response ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Send required variables to JavaScript land
|
||||
*
|
||||
* @access private
|
||||
*/
|
||||
function _js_vars() {
|
||||
$args = array(
|
||||
'class' => get_class( $this ),
|
||||
'screen' => array(
|
||||
'id' => $this->screen->id,
|
||||
'base' => $this->screen->base,
|
||||
)
|
||||
);
|
||||
|
||||
printf( "<script type='text/javascript'>list_args = %s;</script>\n", json_encode( $args ) );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
<?php if ( ! defined( 'FW' ) ) {
|
||||
die( 'Forbidden' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Features:
|
||||
* - Works with "multi keys"
|
||||
*/
|
||||
class FW_WP_Meta {
|
||||
/**
|
||||
* @param string $meta_type
|
||||
* @param int $object_id
|
||||
* @param string $multi_key 'abc' or 'ab/c/def'
|
||||
* @param array|string|int|bool $set_value
|
||||
*/
|
||||
public static function set( $meta_type, $object_id, $multi_key, $set_value ) {
|
||||
if ( empty( $multi_key ) ) {
|
||||
trigger_error( 'Key not specified', E_USER_WARNING );
|
||||
return;
|
||||
}
|
||||
|
||||
$multi_key = explode( '/', $multi_key );
|
||||
$key = array_shift( $multi_key );
|
||||
$multi_key = implode( '/', $multi_key );
|
||||
|
||||
if ( empty( $multi_key ) && $multi_key !== '0' ) { // Replace entire meta
|
||||
fw_update_metadata( $meta_type, $object_id, $key, $set_value );
|
||||
} else { // Change only specified key
|
||||
$value = self::get( $meta_type, $object_id, $key, true );
|
||||
fw_aks( $multi_key, $set_value, $value );
|
||||
fw_update_metadata( $meta_type, $object_id, $key, $value );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $meta_type
|
||||
* @param int $object_id
|
||||
* @param string $multi_key 'abc' or 'ab/c/def'
|
||||
* @param null|mixed $default_value If no option found in the database, this value will be returned
|
||||
* @param bool|null $get_original_value REMOVED https://github.com/ThemeFuse/Unyson/issues/1676
|
||||
*
|
||||
* @return mixed|null
|
||||
*/
|
||||
public static function get( $meta_type, $object_id, $multi_key, $default_value = null, $get_original_value = null ) {
|
||||
if ( ! is_null($get_original_value) ) {
|
||||
_doing_it_wrong(__FUNCTION__, '$get_original_value parameter was removed', 'Unyson 2.5.8');
|
||||
}
|
||||
|
||||
if ( empty( $multi_key ) ) {
|
||||
trigger_error( 'Key not specified', E_USER_WARNING );
|
||||
return null;
|
||||
}
|
||||
|
||||
$multi_key = explode( '/', $multi_key );
|
||||
$key = array_shift( $multi_key );
|
||||
$multi_key = implode( '/', $multi_key );
|
||||
|
||||
$value = get_metadata( $meta_type, $object_id, $key, true );
|
||||
|
||||
if ( empty( $multi_key ) && $multi_key !== '0' ) {
|
||||
return $value;
|
||||
} else {
|
||||
return fw_akg($multi_key, $value, $default_value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
<?php if (!defined('FW')) die('Forbidden');
|
||||
|
||||
/**
|
||||
* Alternative to WordPress get_option() and update_option() functions
|
||||
*
|
||||
* Features:
|
||||
* - Works with "multi keys"
|
||||
*/
|
||||
class FW_WP_Option
|
||||
{
|
||||
/**
|
||||
* @param string $option_name
|
||||
* @param string|null $specific_multi_key 'ab/c/def'
|
||||
* @param null|mixed $default_value If no option found in the database, this value will be returned
|
||||
* @param bool|null $get_original_value REMOVED https://github.com/ThemeFuse/Unyson/issues/1676
|
||||
* @return mixed|null
|
||||
*/
|
||||
public static function get($option_name, $specific_multi_key = null, $default_value = null, $get_original_value = null)
|
||||
{
|
||||
if ( ! is_null($get_original_value) ) {
|
||||
_doing_it_wrong(__FUNCTION__, '$get_original_value parameter was removed', 'Unyson 2.5.8');
|
||||
}
|
||||
|
||||
$value = get_option($option_name, null);
|
||||
|
||||
if (empty($specific_multi_key) && $specific_multi_key !== '0') {
|
||||
return is_null($value) ? fw_call( $default_value ) : $value;
|
||||
} else {
|
||||
return fw_akg($specific_multi_key, $value, $default_value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Alternative for update_option()
|
||||
* @param string $option_name
|
||||
* @param string|null $specific_multi_key
|
||||
* @param array|string|int|bool $set_value
|
||||
*/
|
||||
public static function set($option_name, $specific_multi_key = null, $set_value)
|
||||
{
|
||||
if ($specific_multi_key === null) { // Replace entire option
|
||||
update_option($option_name, $set_value, false);
|
||||
} else { // Change only specified key
|
||||
$value = self::get($option_name, null, true);
|
||||
fw_aks($specific_multi_key, $set_value, $value);
|
||||
update_option($option_name, $value, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
713
wp-content/plugins/unyson/framework/helpers/database.php
Normal file
713
wp-content/plugins/unyson/framework/helpers/database.php
Normal file
@@ -0,0 +1,713 @@
|
||||
<?php if ( ! defined( 'FW' ) ) {
|
||||
die( 'Forbidden' );
|
||||
}
|
||||
|
||||
// Theme Settings Options
|
||||
class FW_Db_Options_Model_Settings extends FW_Db_Options_Model {
|
||||
protected function get_id() {
|
||||
return 'settings';
|
||||
}
|
||||
|
||||
protected function get_options($item_id, array $extra_data = array()) {
|
||||
return fw()->theme->get_settings_options();
|
||||
}
|
||||
|
||||
protected function get_values($item_id, array $extra_data = array()) {
|
||||
return FW_WP_Option::get('fw_theme_settings_options:'. fw()->theme->manifest->get_id(), null, array());
|
||||
}
|
||||
|
||||
protected function set_values($item_id, $values, array $extra_data = array()) {
|
||||
FW_WP_Option::set('fw_theme_settings_options:' . fw()->theme->manifest->get_id(), null, $values);
|
||||
}
|
||||
|
||||
protected function get_fw_storage_params($item_id, array $extra_data = array()) {
|
||||
return array(
|
||||
'settings' => true
|
||||
);
|
||||
}
|
||||
|
||||
protected function _after_set($item_id, $option_id, $sub_keys, $old_value, array $extra_data = array()) {
|
||||
/**
|
||||
* @since 2.6.0
|
||||
*/
|
||||
do_action('fw_settings_options_update', array(
|
||||
/**
|
||||
* Option id
|
||||
* First level multi-key
|
||||
* For e.g. if $option_id is 'hello/world/7' this will be 'hello'
|
||||
*/
|
||||
'option_id' => $option_id,
|
||||
/**
|
||||
* The remaining sub-keys
|
||||
* For e.g.
|
||||
* if $option_id is 'hello/world/7' this will be array('world', '7')
|
||||
* if $option_id is 'hello' this will be array()
|
||||
*/
|
||||
'sub_keys' => explode('/', $sub_keys),
|
||||
/**
|
||||
* Old option(s) value
|
||||
*/
|
||||
'old_value' => $old_value
|
||||
));
|
||||
}
|
||||
|
||||
protected function _init() {
|
||||
/**
|
||||
* Get a theme settings option value from the database
|
||||
*
|
||||
* @param string|null $option_id Specific option id (accepts multikey). null - all options
|
||||
* @param null|mixed $default_value If no option found in the database, this value will be returned
|
||||
* @param null|bool $get_original_value REMOVED https://github.com/ThemeFuse/Unyson/issues/1676
|
||||
*
|
||||
* @return mixed|null
|
||||
*/
|
||||
function fw_get_db_settings_option( $option_id = null, $default_value = null, $get_original_value = null ) {
|
||||
return FW_Db_Options_Model_Settings::_get_instance('settings')->get(null, $option_id, $default_value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a theme settings option value in database
|
||||
*
|
||||
* @param null $option_id Specific option id (accepts multikey). null - all options
|
||||
* @param mixed $value
|
||||
*/
|
||||
function fw_set_db_settings_option( $option_id = null, $value ) {
|
||||
FW_Db_Options_Model_Settings::_get_instance('settings')->set(null, $option_id, $value);
|
||||
}
|
||||
}
|
||||
}
|
||||
new FW_Db_Options_Model_Settings();
|
||||
|
||||
// Post Options
|
||||
class FW_Db_Options_Model_Post extends FW_Db_Options_Model {
|
||||
protected function get_id() {
|
||||
return 'post';
|
||||
}
|
||||
|
||||
private function get_cache_key($key, $item_id = null, array $extra_data = array()) {
|
||||
return 'fw-options-model:'. $this->get_id() .'/'. $key;
|
||||
}
|
||||
|
||||
private function get_post_id($post_id) {
|
||||
$post_id = intval($post_id);
|
||||
|
||||
try {
|
||||
// Prevent too often execution of wp_get_post_autosave() because it does WP Query
|
||||
return FW_Cache::get($cache_key = $this->get_cache_key('id/'. $post_id));
|
||||
} catch (FW_Cache_Not_Found_Exception $e) {
|
||||
if ( ! $post_id ) {
|
||||
/** @var WP_Post $post */
|
||||
global $post;
|
||||
|
||||
if ( ! $post ) {
|
||||
return null;
|
||||
} else {
|
||||
$post_id = $post->ID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if is Preview and use the preview post_id instead of real/current post id
|
||||
*
|
||||
* Note: WordPress changes the global $post content on preview:
|
||||
* 1. https://github.com/WordPress/WordPress/blob/2096b451c704715db3c4faf699a1184260deade9/wp-includes/query.php#L3573-L3583
|
||||
* 2. https://github.com/WordPress/WordPress/blob/4a31dd6fe8b774d56f901a29e72dcf9523e9ce85/wp-includes/revision.php#L485-L528
|
||||
*/
|
||||
if ( is_preview() && is_object($preview = wp_get_post_autosave($post->ID)) ) {
|
||||
$post_id = $preview->ID;
|
||||
}
|
||||
}
|
||||
|
||||
FW_Cache::set($cache_key, $post_id);
|
||||
|
||||
return $post_id;
|
||||
}
|
||||
}
|
||||
|
||||
private function get_post_type($post_id) {
|
||||
$post_id = $this->get_post_id($post_id);
|
||||
|
||||
try {
|
||||
return FW_Cache::get($cache_key = $this->get_cache_key('type/'. $post_id));
|
||||
} catch (FW_Cache_Not_Found_Exception $e) {
|
||||
FW_Cache::set(
|
||||
$cache_key,
|
||||
$post_type = get_post_type(
|
||||
($post_revision_id = wp_is_post_revision($post_id)) ? $post_revision_id : $post_id
|
||||
)
|
||||
);
|
||||
|
||||
return $post_type;
|
||||
}
|
||||
}
|
||||
|
||||
protected function get_options($item_id, array $extra_data = array()) {
|
||||
$post_type = $this->get_post_type($item_id);
|
||||
|
||||
if (apply_filters('fw_get_db_post_option:fw-storage-enabled',
|
||||
/**
|
||||
* Slider extension has too many fw_get_db_post_option()
|
||||
* inside post options altering filter and it creates recursive mess.
|
||||
* add_filter() was added in Slider extension
|
||||
* but this hardcode can be replaced with `true`
|
||||
* only after all users will install new version 1.1.15.
|
||||
*/
|
||||
$post_type !== 'fw-slider',
|
||||
$post_type
|
||||
)) {
|
||||
return fw()->theme->get_post_options( $post_type );
|
||||
} else {
|
||||
return array();
|
||||
}
|
||||
}
|
||||
|
||||
protected function get_values($item_id, array $extra_data = array()) {
|
||||
return FW_WP_Meta::get( 'post', $this->get_post_id($item_id), 'fw_options', array() );
|
||||
}
|
||||
|
||||
protected function set_values($item_id, $values, array $extra_data = array()) {
|
||||
FW_WP_Meta::set( 'post', $this->get_post_id($item_id), 'fw_options', $values );
|
||||
}
|
||||
|
||||
protected function get_fw_storage_params($item_id, array $extra_data = array()) {
|
||||
return array( 'post-id' => $this->get_post_id($item_id) );
|
||||
}
|
||||
|
||||
protected function _get_cache_key($key, $item_id, array $extra_data = array()) {
|
||||
if ($key === 'options') {
|
||||
// Cache options grouped by post-type, not by post id
|
||||
return ($post_type = $this->get_post_type($item_id)) ? $post_type : '?';
|
||||
} else {
|
||||
return $this->get_post_id($item_id);
|
||||
}
|
||||
}
|
||||
|
||||
protected function _after_set($post_id, $option_id, $sub_keys, $old_value, array $extra_data = array()) {
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
fw()->backend->_sync_post_separate_meta($post_id);
|
||||
|
||||
/**
|
||||
* @since 2.2.8
|
||||
*/
|
||||
do_action('fw_post_options_update',
|
||||
$post_id,
|
||||
/**
|
||||
* Option id
|
||||
* First level multi-key
|
||||
* For e.g. if $option_id is 'hello/world/7' this will be 'hello'
|
||||
*/
|
||||
$option_id,
|
||||
/**
|
||||
* The remaining sub-keys
|
||||
* For e.g.
|
||||
* if $option_id is 'hello/world/7' this will be array('world', '7')
|
||||
* if $option_id is 'hello' this will be array()
|
||||
*/
|
||||
explode('/', $sub_keys),
|
||||
/**
|
||||
* Old post option(s) value
|
||||
* @since 2.3.3
|
||||
*/
|
||||
$old_value
|
||||
);
|
||||
}
|
||||
|
||||
protected function _init() {
|
||||
/**
|
||||
* Get post option value from the database
|
||||
*
|
||||
* @param null|int $post_id
|
||||
* @param string|null $option_id Specific option id (accepts multikey). null - all options
|
||||
* @param null|mixed $default_value If no option found in the database, this value will be returned
|
||||
* @param null|bool $get_original_value REMOVED https://github.com/ThemeFuse/Unyson/issues/1676
|
||||
*
|
||||
* @return mixed|null
|
||||
*/
|
||||
function fw_get_db_post_option($post_id = null, $option_id = null, $default_value = null, $get_original_value = null) {
|
||||
return FW_Db_Options_Model::_get_instance('post')->get(intval($post_id), $option_id, $default_value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set post option value in database
|
||||
*
|
||||
* @param null|int $post_id
|
||||
* @param string|null $option_id Specific option id (accepts multikey). null - all options
|
||||
* @param $value
|
||||
*/
|
||||
function fw_set_db_post_option( $post_id = null, $option_id = null, $value ) {
|
||||
FW_Db_Options_Model::_get_instance('post')->set(intval($post_id), $option_id, $value);
|
||||
}
|
||||
|
||||
// todo: add_action() to clear the FW_Cache
|
||||
}
|
||||
}
|
||||
new FW_Db_Options_Model_Post();
|
||||
|
||||
// Term Options
|
||||
class FW_Db_Options_Model_Term extends FW_Db_Options_Model {
|
||||
protected function get_id() {
|
||||
return 'term';
|
||||
}
|
||||
|
||||
protected function get_values($item_id, array $extra_data = array()) {
|
||||
self::migrate($item_id);
|
||||
|
||||
return (array)get_term_meta( $item_id, 'fw_options', true);
|
||||
}
|
||||
|
||||
protected function set_values($item_id, $values, array $extra_data = array()) {
|
||||
self::migrate($item_id);
|
||||
|
||||
update_term_meta($item_id, 'fw_options', $values);
|
||||
}
|
||||
|
||||
protected function get_options($item_id, array $extra_data = array()) {
|
||||
return fw()->theme->get_taxonomy_options($extra_data['taxonomy']);
|
||||
}
|
||||
|
||||
protected function get_fw_storage_params($item_id, array $extra_data = array()) {
|
||||
return array(
|
||||
'term-id' => $item_id,
|
||||
'taxonomy' => $extra_data['taxonomy'],
|
||||
);
|
||||
}
|
||||
|
||||
protected function _get_cache_key($key, $item_id, array $extra_data = array()) {
|
||||
if ($key === 'options') {
|
||||
return $extra_data['taxonomy']; // Cache options grouped by taxonomy, not by term id
|
||||
} else {
|
||||
return $item_id;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Cache termmeta table name if exists
|
||||
* @var string|false
|
||||
*/
|
||||
private static $old_table_name;
|
||||
|
||||
/**
|
||||
* @return string|false
|
||||
*/
|
||||
private static function get_old_table_name() {
|
||||
if (is_null(self::$old_table_name)) {
|
||||
/** @var WPDB $wpdb */
|
||||
global $wpdb;
|
||||
|
||||
$table_name = $wpdb->get_results( "show tables like '{$wpdb->prefix}fw_termmeta'", ARRAY_A );
|
||||
$table_name = $table_name ? array_pop($table_name[0]) : false;
|
||||
|
||||
if ( $table_name && ! $wpdb->get_results( "SELECT 1 FROM `{$table_name}` LIMIT 1" ) ) {
|
||||
// The table is empty, delete it
|
||||
$wpdb->query( "DROP TABLE `{$table_name}`" );
|
||||
$table_name = false;
|
||||
}
|
||||
|
||||
self::$old_table_name = $table_name;
|
||||
}
|
||||
|
||||
return self::$old_table_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
public static function _action_switch_blog() {
|
||||
self::$old_table_name = null; // reset
|
||||
}
|
||||
|
||||
/**
|
||||
* When a term is deleted, delete its meta from old fw_termmeta table
|
||||
*
|
||||
* @param mixed $term_id
|
||||
*
|
||||
* @return void
|
||||
* @internal
|
||||
*/
|
||||
public static function _action_fw_delete_term( $term_id ) {
|
||||
if ( ! ( $table_name = self::get_old_table_name() ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$term_id = (int) $term_id;
|
||||
|
||||
if ( ! $term_id ) {
|
||||
return;
|
||||
}
|
||||
|
||||
/** @var WPDB $wpdb */
|
||||
global $wpdb;
|
||||
|
||||
$wpdb->delete( $table_name, array( 'fw_term_id' => $term_id ), array( '%d' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* In WP 4.4 was introduced native term meta https://codex.wordpress.org/Version_4.4#For_Developers
|
||||
* All data from old table must be migrated to native term meta
|
||||
* @param int $term_id
|
||||
* @return bool
|
||||
*/
|
||||
private static function migrate($term_id) {
|
||||
global $wpdb; /** @var wpdb $wpdb */
|
||||
|
||||
if (
|
||||
( $old_table_name = self::get_old_table_name() )
|
||||
&&
|
||||
( $value = $wpdb->get_col( $wpdb->prepare(
|
||||
"SELECT meta_value FROM `{$old_table_name}` WHERE fw_term_id = %d AND meta_key = 'fw_options' LIMIT 1",
|
||||
$term_id
|
||||
) ) )
|
||||
&&
|
||||
( $value = unserialize( $value[0] ) )
|
||||
) {
|
||||
$wpdb->delete( $old_table_name, array( 'fw_term_id' => $term_id ), array( '%d' ) );
|
||||
|
||||
update_term_meta( $term_id, 'fw_options', $value );
|
||||
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
protected function _after_set($item_id, $option_id, $sub_keys, $old_value, array $extra_data = array()) {
|
||||
/**
|
||||
* @since 2.6.0
|
||||
*/
|
||||
do_action('fw_term_options_update', array(
|
||||
'term_id' => $item_id,
|
||||
'taxonomy' => $extra_data['taxonomy'],
|
||||
/**
|
||||
* Option id
|
||||
* First level multi-key
|
||||
* For e.g. if $option_id is 'hello/world/7' this will be 'hello'
|
||||
*/
|
||||
'option_id' => $option_id,
|
||||
/**
|
||||
* The remaining sub-keys
|
||||
* For e.g.
|
||||
* if $option_id is 'hello/world/7' this will be array('world', '7')
|
||||
* if $option_id is 'hello' this will be array()
|
||||
*/
|
||||
'sub_keys' => explode('/', $sub_keys),
|
||||
/**
|
||||
* Old option(s) value
|
||||
*/
|
||||
'old_value' => $old_value
|
||||
));
|
||||
}
|
||||
|
||||
protected function _init() {
|
||||
/**
|
||||
* Get term option value from the database
|
||||
*
|
||||
* @param int $term_id
|
||||
* @param string $taxonomy
|
||||
* @param string|null $option_id Specific option id (accepts multikey). null - all options
|
||||
* @param null|mixed $default_value If no option found in the database, this value will be returned
|
||||
* @param null|bool $get_original_value REMOVED https://github.com/ThemeFuse/Unyson/issues/1676
|
||||
*
|
||||
* @return mixed|null
|
||||
*/
|
||||
function fw_get_db_term_option( $term_id, $taxonomy, $option_id = null, $default_value = null, $get_original_value = null ) {
|
||||
if ( ! taxonomy_exists( $taxonomy ) ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return FW_Db_Options_Model::_get_instance('term')->get(intval($term_id), $option_id, $default_value, array(
|
||||
'taxonomy' => $taxonomy
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Set term option value in database
|
||||
*
|
||||
* @param int $term_id
|
||||
* @param string $taxonomy
|
||||
* @param string|null $option_id Specific option id (accepts multikey). null - all options
|
||||
* @param mixed $value
|
||||
*
|
||||
* @return null
|
||||
*/
|
||||
function fw_set_db_term_option( $term_id, $taxonomy, $option_id = null, $value ) {
|
||||
if ( ! taxonomy_exists( $taxonomy ) ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
FW_Db_Options_Model::_get_instance('term')->set(intval($term_id), $option_id, $value, array(
|
||||
'taxonomy' => $taxonomy
|
||||
));
|
||||
}
|
||||
|
||||
add_action( 'switch_blog', array( __CLASS__, '_action_switch_blog' ) );
|
||||
add_action( 'delete_term', array( __CLASS__, '_action_fw_delete_term' ) );
|
||||
}
|
||||
}
|
||||
new FW_Db_Options_Model_Term();
|
||||
|
||||
// Extensions Settings Options
|
||||
class FW_Db_Options_Model_Extension extends FW_Db_Options_Model {
|
||||
protected function get_id() {
|
||||
return 'extension';
|
||||
}
|
||||
|
||||
protected function get_values($item_id, array $extra_data = array()) {
|
||||
return FW_WP_Option::get( 'fw_ext_settings_options:' . $item_id, null, array() );
|
||||
}
|
||||
|
||||
protected function set_values($item_id, $values, array $extra_data = array()) {
|
||||
FW_WP_Option::set( 'fw_ext_settings_options:' . $item_id, null, $values );
|
||||
}
|
||||
|
||||
protected function get_options($item_id, array $extra_data = array()) {
|
||||
return fw_ext($item_id)->get_settings_options();
|
||||
}
|
||||
|
||||
protected function get_fw_storage_params($item_id, array $extra_data = array()) {
|
||||
return array(
|
||||
'extension' => $item_id,
|
||||
);
|
||||
}
|
||||
|
||||
protected function _init() {
|
||||
/**
|
||||
* Get extension's settings option value from the database
|
||||
*
|
||||
* @param string $extension_name
|
||||
* @param string|null $option_id
|
||||
* @param null|mixed $default_value If no option found in the database, this value will be returned
|
||||
* @param null|bool $get_original_value REMOVED https://github.com/ThemeFuse/Unyson/issues/1676
|
||||
*
|
||||
* @return mixed|null
|
||||
*/
|
||||
function fw_get_db_ext_settings_option( $extension_name, $option_id = null, $default_value = null, $get_original_value = null ) {
|
||||
if ( ! ( $extension = fw_ext( $extension_name ) ) ) {
|
||||
trigger_error( 'Invalid extension: ' . $extension_name, E_USER_WARNING );
|
||||
return null;
|
||||
}
|
||||
|
||||
return FW_Db_Options_Model::_get_instance('extension')->get($extension_name, $option_id, $default_value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set extension's setting option value in database
|
||||
*
|
||||
* @param string $extension_name
|
||||
* @param string|null $option_id
|
||||
* @param mixed $value
|
||||
*/
|
||||
function fw_set_db_ext_settings_option( $extension_name, $option_id = null, $value ) {
|
||||
if ( ! fw_ext( $extension_name ) ) {
|
||||
trigger_error( 'Invalid extension: ' . $extension_name, E_USER_WARNING );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
FW_Db_Options_Model::_get_instance('extension')->set($extension_name, $option_id, $value);
|
||||
}
|
||||
}
|
||||
}
|
||||
new FW_Db_Options_Model_Extension();
|
||||
|
||||
// Customizer Options
|
||||
class FW_Db_Options_Model_Customizer extends FW_Db_Options_Model {
|
||||
protected function get_id() {
|
||||
return 'customizer';
|
||||
}
|
||||
|
||||
protected function get_values($item_id, array $extra_data = array()) {
|
||||
return get_theme_mod('fw_options', array());
|
||||
}
|
||||
|
||||
protected function set_values($item_id, $values, array $extra_data = array()) {
|
||||
set_theme_mod('fw_options', $values);
|
||||
}
|
||||
|
||||
protected function get_options($item_id, array $extra_data = array()) {
|
||||
return fw()->theme->get_customizer_options();
|
||||
}
|
||||
|
||||
protected function get_fw_storage_params($item_id, array $extra_data = array()) {
|
||||
return array(
|
||||
'customizer' => true
|
||||
);
|
||||
}
|
||||
|
||||
protected function _after_set($item_id, $option_id, $sub_keys, $old_value, array $extra_data = array()) {
|
||||
/**
|
||||
* @since 2.6.0
|
||||
*/
|
||||
do_action('fw_customizer_options_update', array(
|
||||
/**
|
||||
* Option id
|
||||
* First level multi-key
|
||||
* For e.g. if $option_id is 'hello/world/7' this will be 'hello'
|
||||
*/
|
||||
'option_id' => $option_id,
|
||||
/**
|
||||
* The remaining sub-keys
|
||||
* For e.g.
|
||||
* if $option_id is 'hello/world/7' this will be array('world', '7')
|
||||
* if $option_id is 'hello' this will be array()
|
||||
*/
|
||||
'sub_keys' => explode('/', $sub_keys),
|
||||
/**
|
||||
* Old option(s) value
|
||||
*/
|
||||
'old_value' => $old_value
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
public function _reset_cache() {
|
||||
FW_Cache::del($this->get_main_cache_key());
|
||||
}
|
||||
|
||||
protected function _init() {
|
||||
/**
|
||||
* Get a customizer framework option value from the database
|
||||
*
|
||||
* @param string|null $option_id Specific option id (accepts multikey). null - all options
|
||||
* @param null|mixed $default_value If no option found in the database, this value will be returned
|
||||
*
|
||||
* @return mixed|null
|
||||
*/
|
||||
function fw_get_db_customizer_option( $option_id = null, $default_value = null ) {
|
||||
return FW_Db_Options_Model::_get_instance('customizer')->get(null, $option_id, $default_value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a theme customizer option value in database
|
||||
*
|
||||
* @param null $option_id Specific option id (accepts multikey). null - all options
|
||||
* @param mixed $value
|
||||
*/
|
||||
function fw_set_db_customizer_option( $option_id = null, $value ) {
|
||||
FW_Db_Options_Model::_get_instance('customizer')->set(null, $option_id, $value);
|
||||
}
|
||||
|
||||
// Fixes https://github.com/ThemeFuse/Unyson/issues/2053
|
||||
add_action('customize_preview_init', array($this, '_reset_cache'),
|
||||
1 // Fixes https://github.com/ThemeFuse/Unyson/issues/2104
|
||||
);
|
||||
}
|
||||
}
|
||||
new FW_Db_Options_Model_Customizer();
|
||||
|
||||
{
|
||||
/**
|
||||
* Get user meta set by specific extension
|
||||
*
|
||||
* @param int $user_id
|
||||
* @param string $extension_name
|
||||
* @param string $keys
|
||||
*
|
||||
* If the extension doesn't exist or is disabled, or meta key doesn't exist, returns null,
|
||||
* else returns the meta key value
|
||||
*
|
||||
* @return mixed|null
|
||||
*/
|
||||
function fw_get_db_extension_user_data( $user_id, $extension_name, $keys = null ) {
|
||||
if ( ! fw()->extensions->get( $extension_name ) ) {
|
||||
trigger_error( 'Invalid extension: ' . $extension_name, E_USER_WARNING );
|
||||
|
||||
return null;
|
||||
}
|
||||
$data = get_user_meta( $user_id, 'fw_data', true );
|
||||
|
||||
if ( is_null( $keys ) ) {
|
||||
return fw_akg( $extension_name, $data );
|
||||
}
|
||||
|
||||
return fw_akg( $extension_name . '/' . $keys, $data );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $user_id
|
||||
* @param string $extension_name
|
||||
* @param mixed $value
|
||||
* @param string $keys
|
||||
*
|
||||
* In case the extension doesn't exist or is disabled, or the value is equal to previous, returns false
|
||||
*
|
||||
* @return bool|int
|
||||
*/
|
||||
function fw_set_db_extension_user_data( $user_id, $extension_name, $value, $keys = null ) {
|
||||
if ( ! fw()->extensions->get( $extension_name ) ) {
|
||||
trigger_error( 'Invalid extension: ' . $extension_name, E_USER_WARNING );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
$data = get_user_meta( $user_id, 'fw_data', true );
|
||||
|
||||
if ( $keys == null ) {
|
||||
fw_aks( $extension_name, $value, $data );
|
||||
} else {
|
||||
fw_aks( $extension_name . '/' . $keys, $value, $data );
|
||||
}
|
||||
|
||||
return fw_update_user_meta( $user_id, 'fw_data', $data );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extensions Data
|
||||
*
|
||||
* Used by extensions to store custom data in database.
|
||||
* By using these functions, extension prevent database spam with wp options for each extension,
|
||||
* because these functions store all data in one wp option.
|
||||
*/
|
||||
{
|
||||
/**
|
||||
* Get extension's data from the database
|
||||
*
|
||||
* @param string $extension_name
|
||||
* @param string|null $multi_key The key of the data you want to get. null - all data
|
||||
* @param null|mixed $default_value If no option found in the database, this value will be returned
|
||||
* @param null|bool $get_original_value REMOVED https://github.com/ThemeFuse/Unyson/issues/1676
|
||||
*
|
||||
* @return mixed|null
|
||||
*/
|
||||
function fw_get_db_extension_data( $extension_name, $multi_key = null, $default_value = null, $get_original_value = null ) {
|
||||
if ( ! fw()->extensions->get( $extension_name ) ) {
|
||||
trigger_error( 'Invalid extension: ' . $extension_name, E_USER_WARNING );
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
if ( $multi_key ) {
|
||||
$multi_key = $extension_name . '/' . $multi_key;
|
||||
} else {
|
||||
$multi_key = $extension_name;
|
||||
}
|
||||
|
||||
return FW_WP_Option::get( 'fw_extensions', $multi_key, $default_value, $get_original_value );
|
||||
}
|
||||
|
||||
/**
|
||||
* Set some extension's data in database
|
||||
*
|
||||
* @param string $extension_name
|
||||
* @param string|null $multi_key The key of the data you want to set. null - all data
|
||||
* @param mixed $value
|
||||
*/
|
||||
function fw_set_db_extension_data( $extension_name, $multi_key = null, $value ) {
|
||||
if ( ! fw()->extensions->get( $extension_name ) ) {
|
||||
trigger_error( 'Invalid extension: ' . $extension_name, E_USER_WARNING );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ( $multi_key ) {
|
||||
$multi_key = $extension_name . '/' . $multi_key;
|
||||
} else {
|
||||
$multi_key = $extension_name;
|
||||
}
|
||||
|
||||
FW_WP_Option::set( 'fw_extensions', $multi_key, $value );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
<?php if ( ! defined( 'FW' ) ) {
|
||||
die( 'Forbidden' );
|
||||
}
|
||||
|
||||
class FW_Form_Invalid_Submission_Exception extends Exception {
|
||||
|
||||
private $errors = array();
|
||||
|
||||
public function __construct( array $errors ) {
|
||||
parent::__construct();
|
||||
|
||||
$this->set_errors( $errors );
|
||||
}
|
||||
|
||||
public function get_errors() {
|
||||
return $this->errors;
|
||||
}
|
||||
|
||||
protected function set_errors( array $errors ) {
|
||||
$this->errors = $errors;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
<?php if ( ! defined( 'FW' ) ) {
|
||||
die( 'Forbidden' );
|
||||
}
|
||||
|
||||
class FW_Form_Not_Found_Exception extends Exception {
|
||||
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
116
wp-content/plugins/unyson/framework/helpers/fw-storage.php
Normal file
116
wp-content/plugins/unyson/framework/helpers/fw-storage.php
Normal file
@@ -0,0 +1,116 @@
|
||||
<?php if (!defined('FW')) die('Forbidden');
|
||||
|
||||
// Process the `fw-storage` option parameter
|
||||
|
||||
/**
|
||||
* @param string $id
|
||||
* @param array $option
|
||||
* @param mixed $value
|
||||
* @param array $params
|
||||
*
|
||||
* @return mixed
|
||||
*
|
||||
* @since 2.5.0
|
||||
*/
|
||||
function fw_db_option_storage_save($id, array $option, $value, array $params = array()) {
|
||||
if (
|
||||
!empty($option['fw-storage'])
|
||||
&&
|
||||
($storage = is_array($option['fw-storage'])
|
||||
? $option['fw-storage']
|
||||
: array('type' => $option['fw-storage'])
|
||||
)
|
||||
&&
|
||||
!empty($storage['type'])
|
||||
&&
|
||||
($storage_type = fw_db_option_storage_type($storage['type']))
|
||||
) {
|
||||
$option['fw-storage'] = $storage;
|
||||
} else {
|
||||
return $value;
|
||||
}
|
||||
|
||||
/** @var FW_Option_Storage_Type $storage_type */
|
||||
|
||||
return $storage_type->save($id, $option, $value, $params);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $id
|
||||
* @param array $option
|
||||
* @param mixed $value
|
||||
* @param array $params
|
||||
*
|
||||
* @return mixed
|
||||
*
|
||||
* @since 2.5.0
|
||||
*/
|
||||
function fw_db_option_storage_load($id, array $option, $value, array $params = array()) {
|
||||
if (
|
||||
!empty($option['fw-storage'])
|
||||
&&
|
||||
($storage = is_array($option['fw-storage'])
|
||||
? $option['fw-storage']
|
||||
: array('type' => $option['fw-storage'])
|
||||
)
|
||||
&&
|
||||
!empty($storage['type'])
|
||||
&&
|
||||
($storage_type = fw_db_option_storage_type($storage['type']))
|
||||
) {
|
||||
// Fixes https://github.com/ThemeFuse/Unyson/issues/2265
|
||||
if (isset($params['customizer']) && is_customize_preview()) {
|
||||
/** @var WP_Customize_Manager $wp_customize */
|
||||
global $wp_customize;
|
||||
|
||||
if (
|
||||
($setting = $wp_customize->get_setting($setting_id = 'fw_options[' . $id . ']'))
|
||||
&&
|
||||
!is_null($wp_customize->post_value($setting))
|
||||
) {
|
||||
// Use POST preview value
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
|
||||
$option['fw-storage'] = $storage;
|
||||
} else {
|
||||
return $value;
|
||||
}
|
||||
|
||||
/** @var FW_Option_Storage_Type $storage_type */
|
||||
|
||||
return $storage_type->load($id, $option, $value, $params);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param null|string $type
|
||||
* @return FW_Option_Storage_Type|FW_Option_Storage_Type[]|null
|
||||
* @since 2.5.0
|
||||
*/
|
||||
function fw_db_option_storage_type($type = null) {
|
||||
static $types = null;
|
||||
|
||||
if (is_null($types)) {
|
||||
$access_key = new FW_Access_Key('fw:option-storage-register');
|
||||
$register = new _FW_Option_Storage_Type_Register($access_key->get_key());
|
||||
|
||||
{
|
||||
$register->register(new FW_Option_Storage_Type_WP_Option());
|
||||
$register->register(new FW_Option_Storage_Type_Post_Meta());
|
||||
$register->register(new FW_Option_Storage_Type_Term_Meta());
|
||||
}
|
||||
|
||||
do_action('fw:option-storage-types:register', $register);
|
||||
|
||||
$types = $register->_get_types($access_key);
|
||||
}
|
||||
|
||||
if (empty($type)) {
|
||||
return $types;
|
||||
} elseif (isset($types[$type])) {
|
||||
return $types[$type];
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
2004
wp-content/plugins/unyson/framework/helpers/general.php
Normal file
2004
wp-content/plugins/unyson/framework/helpers/general.php
Normal file
File diff suppressed because it is too large
Load Diff
663
wp-content/plugins/unyson/framework/helpers/meta.php
Normal file
663
wp-content/plugins/unyson/framework/helpers/meta.php
Normal file
@@ -0,0 +1,663 @@
|
||||
<?php if ( ! defined( 'FW' ) ) {
|
||||
die( 'Forbidden' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Wordpress alternatives
|
||||
* update_post_meta() strip slashes and it's impossible to save json or "\'" in post meta
|
||||
* https://core.trac.wordpress.org/ticket/21767
|
||||
*/
|
||||
|
||||
/**
|
||||
* Add metadata for the specified object.
|
||||
*
|
||||
* @uses $wpdb WordPress database object for queries.
|
||||
*
|
||||
* @param string $meta_type Type of object metadata is for (e.g., comment, post, or user)
|
||||
* @param int $object_id ID of the object metadata is for
|
||||
* @param string $meta_key Metadata key
|
||||
* @param mixed $meta_value Metadata value. Must be serializable if non-scalar.
|
||||
* @param bool $unique Optional, default is false. Whether the specified metadata key should be
|
||||
* unique for the object. If true, and the object already has a value for the specified
|
||||
* metadata key, no change will be made
|
||||
*
|
||||
* @return int|bool The meta ID on success, false on failure.
|
||||
*/
|
||||
function fw_add_metadata( $meta_type, $object_id, $meta_key, $meta_value, $unique = false ) {
|
||||
|
||||
/**
|
||||
* @var WPDB $wpdb
|
||||
*/
|
||||
global $wpdb;
|
||||
|
||||
if ( ! $meta_type || ! $meta_key || ! is_numeric( $object_id ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$object_id = absint( $object_id );
|
||||
if ( ! $object_id ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$table = _get_meta_table( $meta_type );
|
||||
if ( ! $table ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$column = sanitize_key( $meta_type . '_id' );
|
||||
|
||||
// expected_slashed ($meta_key)
|
||||
//$meta_key = wp_unslash($meta_key);
|
||||
//$meta_value = wp_unslash($meta_value);
|
||||
$meta_value = sanitize_meta( $meta_key, $meta_value, $meta_type );
|
||||
|
||||
/**
|
||||
* Filter whether to add metadata of a specific type.
|
||||
*
|
||||
* The dynamic portion of the hook, $meta_type, refers to the meta
|
||||
* object type (comment, post, or user). Returning a non-null value
|
||||
* will effectively short-circuit the function.
|
||||
*
|
||||
* @param null|bool $check Whether to allow adding metadata for the given type.
|
||||
* @param int $object_id Object ID.
|
||||
* @param string $meta_key Meta key.
|
||||
* @param mixed $meta_value Meta value. Must be serializable if non-scalar.
|
||||
* @param bool $unique Whether the specified meta key should be unique
|
||||
* for the object. Optional. Default false.
|
||||
*/
|
||||
$check = apply_filters( "add_{$meta_type}_metadata", null, $object_id, $meta_key, $meta_value, $unique );
|
||||
if ( null !== $check ) {
|
||||
return $check;
|
||||
}
|
||||
|
||||
if ( $unique && $wpdb->get_var( $wpdb->prepare(
|
||||
"SELECT COUNT(*) FROM $table WHERE meta_key = %s AND $column = %d LIMIT 1",
|
||||
$meta_key, $object_id ) )
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$_meta_value = $meta_value;
|
||||
$meta_value = maybe_serialize( $meta_value );
|
||||
|
||||
/**
|
||||
* Fires immediately before meta of a specific type is added.
|
||||
*
|
||||
* The dynamic portion of the hook, $meta_type, refers to the meta
|
||||
* object type (comment, post, or user).
|
||||
*
|
||||
* @param int $object_id Object ID.
|
||||
* @param string $meta_key Meta key.
|
||||
* @param mixed $meta_value Meta value.
|
||||
*/
|
||||
do_action( "add_{$meta_type}_meta", $object_id, $meta_key, $_meta_value );
|
||||
|
||||
$result = $wpdb->insert( $table, array(
|
||||
$column => $object_id,
|
||||
'meta_key' => $meta_key,
|
||||
'meta_value' => $meta_value,
|
||||
) );
|
||||
if ( ! $result ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$mid = (int) $wpdb->insert_id;
|
||||
|
||||
wp_cache_delete( $object_id, $meta_type . '_meta' );
|
||||
|
||||
/**
|
||||
* Fires immediately after meta of a specific type is added.
|
||||
*
|
||||
* The dynamic portion of the hook, $meta_type, refers to the meta
|
||||
* object type (comment, post, or user).
|
||||
*
|
||||
* @param int $mid The meta ID after successful update.
|
||||
* @param int $object_id Object ID.
|
||||
* @param string $meta_key Meta key.
|
||||
* @param mixed $meta_value Meta value.
|
||||
*/
|
||||
do_action( "added_{$meta_type}_meta", $mid, $object_id, $meta_key, $_meta_value );
|
||||
|
||||
return $mid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update metadata for the specified object. If no value already exists for the specified object
|
||||
* ID and metadata key, the metadata will be added.
|
||||
*
|
||||
* @uses $wpdb WordPress database object for queries.
|
||||
*
|
||||
* @param string $meta_type Type of object metadata is for (e.g., comment, post, or user)
|
||||
* @param int $object_id ID of the object metadata is for
|
||||
* @param string $meta_key Metadata key
|
||||
* @param mixed $meta_value Metadata value. Must be serializable if non-scalar.
|
||||
* @param mixed $prev_value Optional. If specified, only update existing metadata entries with
|
||||
* the specified value. Otherwise, update all entries.
|
||||
*
|
||||
* @return int|bool Meta ID if the key didn't exist, true on successful update, false on failure.
|
||||
*/
|
||||
function fw_update_metadata( $meta_type, $object_id, $meta_key, $meta_value, $prev_value = '' ) {
|
||||
global $wpdb;
|
||||
|
||||
if ( ! $meta_type || ! $meta_key || ! is_numeric( $object_id ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$object_id = absint( $object_id );
|
||||
if ( ! $object_id ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$table = _get_meta_table( $meta_type );
|
||||
if ( ! $table ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$column = sanitize_key( $meta_type . '_id' );
|
||||
$id_column = 'user' == $meta_type ? 'umeta_id' : 'meta_id';
|
||||
|
||||
// expected_slashed ($meta_key)
|
||||
//$meta_key = wp_unslash($meta_key);
|
||||
$passed_value = $meta_value;
|
||||
//$meta_value = wp_unslash($meta_value);
|
||||
$meta_value = sanitize_meta( $meta_key, $meta_value, $meta_type );
|
||||
|
||||
/**
|
||||
* Filter whether to update metadata of a specific type.
|
||||
*
|
||||
* The dynamic portion of the hook, $meta_type, refers to the meta
|
||||
* object type (comment, post, or user). Returning a non-null value
|
||||
* will effectively short-circuit the function.
|
||||
*
|
||||
* @param null|bool $check Whether to allow updating metadata for the given type.
|
||||
* @param int $object_id Object ID.
|
||||
* @param string $meta_key Meta key.
|
||||
* @param mixed $meta_value Meta value. Must be serializable if non-scalar.
|
||||
* @param mixed $prev_value Optional. If specified, only update existing
|
||||
* metadata entries with the specified value.
|
||||
* Otherwise, update all entries.
|
||||
*/
|
||||
$check = apply_filters( "update_{$meta_type}_metadata", null, $object_id, $meta_key, $meta_value, $prev_value );
|
||||
if ( null !== $check ) {
|
||||
return (bool) $check;
|
||||
}
|
||||
|
||||
// Compare existing value to new value if no prev value given and the key exists only once.
|
||||
if ( empty( $prev_value ) ) {
|
||||
$old_value = get_metadata( $meta_type, $object_id, $meta_key );
|
||||
if ( count( $old_value ) == 1 ) {
|
||||
if ( $old_value[0] === $meta_value ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! $meta_id = $wpdb->get_var( $wpdb->prepare( "SELECT $id_column FROM $table WHERE meta_key = %s AND $column = %d LIMIT 1", $meta_key, $object_id ) ) ) {
|
||||
return fw_add_metadata( $meta_type, $object_id, $meta_key, $passed_value );
|
||||
}
|
||||
|
||||
$_meta_value = $meta_value;
|
||||
$meta_value = maybe_serialize( $meta_value );
|
||||
|
||||
$data = compact( 'meta_value' );
|
||||
$where = array( $column => $object_id, 'meta_key' => $meta_key );
|
||||
|
||||
if ( ! empty( $prev_value ) ) {
|
||||
$prev_value = maybe_serialize( $prev_value );
|
||||
$where['meta_value'] = $prev_value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fires immediately before updating metadata of a specific type.
|
||||
*
|
||||
* The dynamic portion of the hook, $meta_type, refers to the meta
|
||||
* object type (comment, post, or user).
|
||||
*
|
||||
* @param int $meta_id ID of the metadata entry to update.
|
||||
* @param int $object_id Object ID.
|
||||
* @param string $meta_key Meta key.
|
||||
* @param mixed $meta_value Meta value.
|
||||
*/
|
||||
do_action( "update_{$meta_type}_meta", $meta_id, $object_id, $meta_key, $_meta_value );
|
||||
|
||||
if ( 'post' == $meta_type ) {
|
||||
/**
|
||||
* Fires immediately before updating a post's metadata.
|
||||
*
|
||||
* @param int $meta_id ID of metadata entry to update.
|
||||
* @param int $object_id Object ID.
|
||||
* @param string $meta_key Meta key.
|
||||
* @param mixed $meta_value Meta value.
|
||||
*/
|
||||
do_action( 'update_postmeta', $meta_id, $object_id, $meta_key, $meta_value );
|
||||
}
|
||||
|
||||
$result = $wpdb->update( $table, $data, $where );
|
||||
if ( ! $result ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
wp_cache_delete( $object_id, $meta_type . '_meta' );
|
||||
|
||||
/**
|
||||
* Fires immediately after updating metadata of a specific type.
|
||||
*
|
||||
* The dynamic portion of the hook, $meta_type, refers to the meta
|
||||
* object type (comment, post, or user).
|
||||
*
|
||||
* @param int $meta_id ID of updated metadata entry.
|
||||
* @param int $object_id Object ID.
|
||||
* @param string $meta_key Meta key.
|
||||
* @param mixed $meta_value Meta value.
|
||||
*/
|
||||
do_action( "updated_{$meta_type}_meta", $meta_id, $object_id, $meta_key, $_meta_value );
|
||||
|
||||
if ( 'post' == $meta_type ) {
|
||||
/**
|
||||
* Fires immediately after updating a post's metadata.
|
||||
*
|
||||
* @param int $meta_id ID of updated metadata entry.
|
||||
* @param int $object_id Object ID.
|
||||
* @param string $meta_key Meta key.
|
||||
* @param mixed $meta_value Meta value.
|
||||
*/
|
||||
do_action( 'updated_postmeta', $meta_id, $object_id, $meta_key, $meta_value );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
;
|
||||
|
||||
/**
|
||||
* Delete metadata for the specified object.
|
||||
*
|
||||
* @uses $wpdb WordPress database object for queries.
|
||||
*
|
||||
* @param string $meta_type Type of object metadata is for (e.g., comment, post, or user)
|
||||
* @param int $object_id ID of the object metadata is for
|
||||
* @param string $meta_key Metadata key
|
||||
* @param mixed $meta_value Optional. Metadata value. Must be serializable if non-scalar. If specified, only delete metadata entries
|
||||
* with this value. Otherwise, delete all entries with the specified meta_key.
|
||||
* @param bool $delete_all Optional, default is false. If true, delete matching metadata entries
|
||||
* for all objects, ignoring the specified object_id. Otherwise, only delete matching
|
||||
* metadata entries for the specified object_id.
|
||||
*
|
||||
* @return bool True on successful delete, false on failure.
|
||||
*/
|
||||
function fw_delete_metadata( $meta_type, $object_id, $meta_key, $meta_value = '', $delete_all = false ) {
|
||||
/**
|
||||
* @var WPDB $wpdb
|
||||
*/
|
||||
global $wpdb;
|
||||
|
||||
if ( ! $meta_type || ! $meta_key || ! is_numeric( $object_id ) && ! $delete_all ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$object_id = absint( $object_id );
|
||||
if ( ! $object_id && ! $delete_all ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$table = _get_meta_table( $meta_type );
|
||||
if ( ! $table ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$type_column = sanitize_key( $meta_type . '_id' );
|
||||
$id_column = 'user' == $meta_type ? 'umeta_id' : 'meta_id';
|
||||
// expected_slashed ($meta_key)
|
||||
//$meta_key = wp_unslash($meta_key);
|
||||
//$meta_value = wp_unslash($meta_value);
|
||||
|
||||
/**
|
||||
* Filter whether to delete metadata of a specific type.
|
||||
*
|
||||
* The dynamic portion of the hook, $meta_type, refers to the meta
|
||||
* object type (comment, post, or user). Returning a non-null value
|
||||
* will effectively short-circuit the function.
|
||||
*
|
||||
* @param null|bool $delete Whether to allow metadata deletion of the given type.
|
||||
* @param int $object_id Object ID.
|
||||
* @param string $meta_key Meta key.
|
||||
* @param mixed $meta_value Meta value. Must be serializable if non-scalar.
|
||||
* @param bool $delete_all Whether to delete the matching metadata entries
|
||||
* for all objects, ignoring the specified $object_id.
|
||||
* Default false.
|
||||
*/
|
||||
$check = apply_filters( "delete_{$meta_type}_metadata", null, $object_id, $meta_key, $meta_value, $delete_all );
|
||||
if ( null !== $check ) {
|
||||
return (bool) $check;
|
||||
}
|
||||
|
||||
$_meta_value = $meta_value;
|
||||
$meta_value = maybe_serialize( $meta_value );
|
||||
|
||||
$query = $wpdb->prepare( "SELECT $id_column FROM $table WHERE meta_key = %s", $meta_key );
|
||||
|
||||
if ( ! $delete_all ) {
|
||||
$query .= $wpdb->prepare( " AND $type_column = %d", $object_id );
|
||||
}
|
||||
|
||||
if ( $meta_value ) {
|
||||
$query .= $wpdb->prepare( " AND meta_value = %s", $meta_value );
|
||||
}
|
||||
|
||||
$meta_ids = $wpdb->get_col( $query );
|
||||
if ( ! count( $meta_ids ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( $delete_all ) {
|
||||
$object_ids = $wpdb->get_col( $wpdb->prepare( "SELECT $type_column FROM $table WHERE meta_key = %s", $meta_key ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Fires immediately before deleting metadata of a specific type.
|
||||
*
|
||||
* The dynamic portion of the hook, $meta_type, refers to the meta
|
||||
* object type (comment, post, or user).
|
||||
*
|
||||
* @param array $meta_ids An array of metadata entry IDs to delete.
|
||||
* @param int $object_id Object ID.
|
||||
* @param string $meta_key Meta key.
|
||||
* @param mixed $meta_value Meta value.
|
||||
*/
|
||||
do_action( "delete_{$meta_type}_meta", $meta_ids, $object_id, $meta_key, $_meta_value );
|
||||
|
||||
// Old-style action.
|
||||
if ( 'post' == $meta_type ) {
|
||||
/**
|
||||
* Fires immediately before deleting metadata for a post.
|
||||
*
|
||||
* @param array $meta_ids An array of post metadata entry IDs to delete.
|
||||
*/
|
||||
do_action( 'delete_postmeta', $meta_ids );
|
||||
}
|
||||
|
||||
$query = "DELETE FROM $table WHERE $id_column IN( " . implode( ',', $meta_ids ) . " )";
|
||||
|
||||
$count = $wpdb->query( $query );
|
||||
|
||||
if ( ! $count ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( $delete_all ) {
|
||||
foreach ( (array) $object_ids as $o_id ) {
|
||||
wp_cache_delete( $o_id, $meta_type . '_meta' );
|
||||
}
|
||||
} else {
|
||||
wp_cache_delete( $object_id, $meta_type . '_meta' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Fires immediately after deleting metadata of a specific type.
|
||||
*
|
||||
* The dynamic portion of the hook name, $meta_type, refers to the meta
|
||||
* object type (comment, post, or user).
|
||||
*
|
||||
* @param array $meta_ids An array of deleted metadata entry IDs.
|
||||
* @param int $object_id Object ID.
|
||||
* @param string $meta_key Meta key.
|
||||
* @param mixed $meta_value Meta value.
|
||||
*/
|
||||
do_action( "deleted_{$meta_type}_meta", $meta_ids, $object_id, $meta_key, $_meta_value );
|
||||
|
||||
// Old-style action.
|
||||
if ( 'post' == $meta_type ) {
|
||||
/**
|
||||
* Fires immediately after deleting metadata for a post.
|
||||
*
|
||||
* @param array $meta_ids An array of deleted post metadata entry IDs.
|
||||
*/
|
||||
do_action( 'deleted_postmeta', $meta_ids );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add meta data field to a user.
|
||||
*
|
||||
* Post meta data is called "Custom Fields" on the Administration Screens.
|
||||
*
|
||||
* @param int $user_id User ID.
|
||||
* @param string $meta_key Metadata name.
|
||||
* @param mixed $meta_value Metadata value.
|
||||
* @param bool $unique Optional, default is false. Whether the same key should not be added.
|
||||
*
|
||||
* @return int|bool Meta ID on success, false on failure.
|
||||
*/
|
||||
function fw_add_user_meta( $user_id, $meta_key, $meta_value, $unique = false ) {
|
||||
return fw_add_metadata( 'user', $user_id, $meta_key, $meta_value, $unique );
|
||||
}
|
||||
|
||||
/**
|
||||
* Update user meta field based on user ID.
|
||||
*
|
||||
* Use the $prev_value parameter to differentiate between meta fields with the
|
||||
* same key and user ID.
|
||||
*
|
||||
* If the meta field for the user does not exist, it will be added.
|
||||
*
|
||||
* @param int $user_id User ID.
|
||||
* @param string $meta_key Metadata key.
|
||||
* @param mixed $meta_value Metadata value.
|
||||
* @param mixed $prev_value Optional. Previous value to check before removing.
|
||||
*
|
||||
* @return int|bool Meta ID if the key didn't exist, true on successful update, false on failure.
|
||||
*/
|
||||
function fw_update_user_meta( $user_id, $meta_key, $meta_value, $prev_value = '' ) {
|
||||
return fw_update_metadata( 'user', $user_id, $meta_key, $meta_value, $prev_value );
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove metadata matching criteria from a user.
|
||||
*
|
||||
* You can match based on the key, or key and value. Removing based on key and
|
||||
* value, will keep from removing duplicate metadata with the same key. It also
|
||||
* allows removing all metadata matching key, if needed.
|
||||
*
|
||||
* @param int $user_id user ID
|
||||
* @param string $meta_key Metadata name.
|
||||
* @param mixed $meta_value Optional. Metadata value.
|
||||
*
|
||||
* @return bool True on success, false on failure.
|
||||
*/
|
||||
function fw_delete_user_meta( $user_id, $meta_key, $meta_value = '' ) {
|
||||
return fw_delete_metadata( 'user', $user_id, $meta_key, $meta_value );
|
||||
}
|
||||
|
||||
/**
|
||||
* Add meta data field to a post.
|
||||
*
|
||||
* Post meta data is called "Custom Fields" on the Administration Screen.
|
||||
*
|
||||
* @param int $post_id Post ID.
|
||||
* @param string $meta_key Metadata name.
|
||||
* @param mixed $meta_value Metadata value. Must be serializable if non-scalar.
|
||||
* @param bool $unique Optional. Whether the same key should not be added.
|
||||
* Default false.
|
||||
*
|
||||
* @return int|bool Meta ID on success, false on failure.
|
||||
*/
|
||||
function fw_add_post_meta( $post_id, $meta_key, $meta_value, $unique = false ) {
|
||||
// Make sure meta is added to the post, not a revision. // fixme: why this is needed?
|
||||
/*if ( $the_post = wp_is_post_revision( $post_id ) ) {
|
||||
$post_id = $the_post;
|
||||
}*/
|
||||
|
||||
return fw_add_metadata( 'post', $post_id, $meta_key, $meta_value, $unique );
|
||||
}
|
||||
|
||||
/**
|
||||
* Update post meta field based on post ID.
|
||||
*
|
||||
* Use the $prev_value parameter to differentiate between meta fields with the
|
||||
* same key and post ID.
|
||||
*
|
||||
* If the meta field for the post does not exist, it will be added.
|
||||
*
|
||||
* @param int $post_id Post ID.
|
||||
* @param string $meta_key Metadata key.
|
||||
* @param mixed $meta_value Metadata value. Must be serializable if non-scalar.
|
||||
* @param mixed $prev_value Optional. Previous value to check before removing.
|
||||
* Default empty.
|
||||
*
|
||||
* @return int|bool Meta ID if the key didn't exist, true on successful update,
|
||||
* false on failure.
|
||||
*/
|
||||
function fw_update_post_meta( $post_id, $meta_key, $meta_value, $prev_value = '' ) {
|
||||
// Make sure meta is added to the post, not a revision. fixme: why this is needed?
|
||||
/*if ( $the_post = wp_is_post_revision( $post_id ) ) {
|
||||
$post_id = $the_post;
|
||||
}*/
|
||||
|
||||
return fw_update_metadata( 'post', $post_id, $meta_key, $meta_value, $prev_value );
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove metadata matching criteria from a post.
|
||||
*
|
||||
* You can match based on the key, or key and value. Removing based on key and
|
||||
* value, will keep from removing duplicate metadata with the same key. It also
|
||||
* allows removing all metadata matching key, if needed.
|
||||
*
|
||||
* @param int $post_id Post ID.
|
||||
* @param string $meta_key Metadata name.
|
||||
* @param mixed $meta_value Optional. Metadata value. Must be serializable if
|
||||
* non-scalar. Default empty.
|
||||
*
|
||||
* @return bool True on success, false on failure.
|
||||
*/
|
||||
function fw_delete_post_meta( $post_id, $meta_key, $meta_value = '' ) {
|
||||
// Make sure meta is added to the post, not a revision. // fixme: why this is needed?
|
||||
/*if ( $the_post = wp_is_post_revision( $post_id ) ) {
|
||||
$post_id = $the_post;
|
||||
}*/
|
||||
|
||||
return delete_metadata( 'post', $post_id, $meta_key, $meta_value );
|
||||
}
|
||||
|
||||
//
|
||||
// Comment meta functions
|
||||
//
|
||||
|
||||
/**
|
||||
* Add meta data field to a comment.
|
||||
*
|
||||
* @param int $comment_id Comment ID.
|
||||
* @param string $meta_key Metadata name.
|
||||
* @param mixed $meta_value Metadata value.
|
||||
* @param bool $unique Optional, default is false. Whether the same key should not be added.
|
||||
*
|
||||
* @return int|bool Meta ID on success, false on failure.
|
||||
*/
|
||||
function fw_add_comment_meta( $comment_id, $meta_key, $meta_value, $unique = false ) {
|
||||
return fw_add_metadata( 'comment', $comment_id, $meta_key, $meta_value, $unique );
|
||||
}
|
||||
|
||||
/**
|
||||
* Update comment meta field based on comment ID.
|
||||
*
|
||||
* Use the $prev_value parameter to differentiate between meta fields with the
|
||||
* same key and comment ID.
|
||||
*
|
||||
* If the meta field for the comment does not exist, it will be added.
|
||||
*
|
||||
* @param int $comment_id Comment ID.
|
||||
* @param string $meta_key Metadata key.
|
||||
* @param mixed $meta_value Metadata value.
|
||||
* @param mixed $prev_value Optional. Previous value to check before removing.
|
||||
*
|
||||
* @return int|bool Meta ID if the key didn't exist, true on successful update, false on failure.
|
||||
*/
|
||||
function fw_update_comment_meta( $comment_id, $meta_key, $meta_value, $prev_value = '' ) {
|
||||
return fw_update_metadata( 'comment', $comment_id, $meta_key, $meta_value, $prev_value );
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove metadata matching criteria from a comment.
|
||||
*
|
||||
* You can match based on the key, or key and value. Removing based on key and
|
||||
* value, will keep from removing duplicate metadata with the same key. It also
|
||||
* allows removing all metadata matching key, if needed.
|
||||
*
|
||||
* @param int $comment_id comment ID
|
||||
* @param string $meta_key Metadata name.
|
||||
* @param mixed $meta_value Optional. Metadata value.
|
||||
*
|
||||
* @return bool True on success, false on failure.
|
||||
*/
|
||||
function fw_delete_comment_meta( $comment_id, $meta_key, $meta_value = '' ) {
|
||||
return fw_delete_metadata( 'comment', $comment_id, $meta_key, $meta_value );
|
||||
}
|
||||
|
||||
//
|
||||
// Term meta functions
|
||||
//http://core.trac.wordpress.org/ticket/10142
|
||||
//
|
||||
/**
|
||||
* Add meta data field to a term.
|
||||
*
|
||||
* @param int $term_id Post ID.
|
||||
* @param string $key Metadata name.
|
||||
* @param mixed $value Metadata value.
|
||||
* @param bool $unique Optional, default is false. Whether the same key should not be added.
|
||||
* @return bool False for failure. True for success.
|
||||
*/
|
||||
function fw_add_term_meta( $term_id, $meta_key, $meta_value, $unique = false ) {
|
||||
return fw_add_metadata( 'fw_term', $term_id, $meta_key, $meta_value, $unique );
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove metadata matching criteria from a term.
|
||||
*
|
||||
* You can match based on the key, or key and value. Removing based on key and
|
||||
* value, will keep from removing duplicate metadata with the same key. It also
|
||||
* allows removing all metadata matching key, if needed.
|
||||
*
|
||||
* @param int $term_id term ID
|
||||
* @param string $meta_key Metadata name.
|
||||
* @param mixed $meta_value Optional. Metadata value.
|
||||
*
|
||||
* @return bool False for failure. True for success.
|
||||
*/
|
||||
function fw_delete_term_meta( $term_id, $meta_key, $meta_value = '' ) {
|
||||
return fw_delete_metadata( 'fw_term', $term_id, $meta_key, $meta_value );
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve term meta field for a term.
|
||||
*
|
||||
* @param int $term_id Term ID.
|
||||
* @param string $key The meta key to retrieve.
|
||||
* @param bool $single Whether to return a single value.
|
||||
*
|
||||
* @return mixed Will be an array if $single is false. Will be value of meta data field if $single
|
||||
* is true.
|
||||
*/
|
||||
function fw_get_term_meta( $term_id, $key, $single = false ) {
|
||||
return get_metadata( 'fw_term', $term_id, $key, $single );
|
||||
}
|
||||
|
||||
/**
|
||||
* Update term meta field based on term ID.
|
||||
*
|
||||
* Use the $prev_value parameter to differentiate between meta fields with the
|
||||
* same key and term ID.
|
||||
*
|
||||
* If the meta field for the term does not exist, it will be added.
|
||||
*
|
||||
* @param int $term_id Term ID.
|
||||
* @param string $key Metadata key.
|
||||
* @param mixed $value Metadata value.
|
||||
* @param mixed $prev_value Optional. Previous value to check before removing.
|
||||
*
|
||||
* @return bool False on failure, true if success.
|
||||
*/
|
||||
function fw_update_term_meta( $term_id, $meta_key, $meta_value, $prev_value = '' ) {
|
||||
return fw_update_metadata( 'fw_term', $term_id, $meta_key, $meta_value, $prev_value );
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
<?php if ( ! defined( 'FW' ) ) die( 'Forbidden' );
|
||||
|
||||
/**
|
||||
* Give users the possibility to register a type safely
|
||||
* Instead of doing apply_filters('my_types', $types) where someone can mess your data
|
||||
* with this class you do do_action('register_my_types', $types)
|
||||
* and users will be able only to $types->register(new Allowed_Type_Class())
|
||||
* @since 2.4.10
|
||||
*/
|
||||
abstract class FW_Type_Register {
|
||||
/**
|
||||
* Check if the type is instance of the required class (or other requirements)
|
||||
* @param FW_Type $type
|
||||
* @return bool|WP_Error
|
||||
*/
|
||||
abstract protected function validate_type(FW_Type $type);
|
||||
|
||||
/**
|
||||
* @var FW_Type[]
|
||||
*/
|
||||
protected $types = array();
|
||||
|
||||
/**
|
||||
* Only these access keys will be able to access the registered types
|
||||
* @var array {'key': true}
|
||||
*/
|
||||
protected $access_keys = array();
|
||||
|
||||
final public function __construct($access_keys) {
|
||||
{
|
||||
if (is_string($access_keys)) {
|
||||
$access_keys = array(
|
||||
$access_keys => true,
|
||||
);
|
||||
} elseif (!is_array($access_keys)) {
|
||||
trigger_error('Invalid access key', E_USER_ERROR);
|
||||
}
|
||||
|
||||
$this->access_keys = $access_keys;
|
||||
}
|
||||
}
|
||||
|
||||
public function register(FW_Type $type) {
|
||||
if (isset($this->task_types[$type->get_type()])) {
|
||||
throw new Exception('Type '. $type->get_type() .' already registered');
|
||||
} elseif (
|
||||
is_wp_error($validation_result = $this->validate_type($type))
|
||||
||
|
||||
!$validation_result
|
||||
) {
|
||||
throw new Exception(
|
||||
'Invalid type '. $type->get_type()
|
||||
.(is_wp_error($validation_result) ? ': '. $validation_result->get_error_message() : '')
|
||||
);
|
||||
}
|
||||
|
||||
$this->types[$type->get_type()] = $type;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param FW_Access_Key $access_key
|
||||
*
|
||||
* @return FW_Type[]
|
||||
* @internal
|
||||
*/
|
||||
public function _get_types(FW_Access_Key $access_key) {
|
||||
if (!isset($this->access_keys[$access_key->get_key()])) {
|
||||
trigger_error('Method call denied', E_USER_ERROR);
|
||||
}
|
||||
|
||||
return $this->types;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param FW_Access_Key $access_key
|
||||
* @param $type
|
||||
*
|
||||
* @return FW_Type|null
|
||||
* @internal
|
||||
* @since 2.5.12
|
||||
*/
|
||||
public function _get_type(FW_Access_Key $access_key, $type) {
|
||||
if (!isset($this->access_keys[$access_key->get_key()])) {
|
||||
trigger_error('Method call denied', E_USER_ERROR);
|
||||
}
|
||||
|
||||
return isset($this->types[$type]) ? $this->types[$type] : null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
<?php if ( ! defined( 'FW' ) ) die( 'Forbidden' );
|
||||
|
||||
/**
|
||||
* @since 2.4.10
|
||||
*/
|
||||
abstract class FW_Type {
|
||||
/**
|
||||
* @return string Unique type
|
||||
*/
|
||||
abstract public function get_type();
|
||||
}
|
||||
Reference in New Issue
Block a user