File: /var/www/hcv/wp-content/plugins/timber-library/lib/Helper.php
<?php
namespace Timber;
use Timber\FunctionWrapper;
use Timber\URLHelper;
/**
* As the name suggests these are helpers for Timber (and you!) when developing. You can find additional (mainly internally-focused helpers) in TimberURLHelper
*/
class Helper {
/**
* A utility for a one-stop shop for Transients
* @api
* @example
* ```php
* $context = Timber::context();
* $context['favorites'] = Timber\Helper::transient('user-' .$uid. '-favorites', function() use ($uid) {
* //some expensive query here that's doing something you want to store to a transient
* return $favorites;
* }, 600);
* Timber::render('single.twig', $context);
* ```
*
* @param string $slug Unique identifier for transient
* @param callable $callback Callback that generates the data that's to be cached
* @param integer $transient_time (optional) Expiration of transients in seconds
* @param integer $lock_timeout (optional) How long (in seconds) to lock the transient to prevent race conditions
* @param boolean $force (optional) Force callback to be executed when transient is locked
* @return mixed
*/
public static function transient( $slug, $callback, $transient_time = 0, $lock_timeout = 5, $force = false ) {
$slug = apply_filters('timber/transient/slug', $slug);
$enable_transients = ($transient_time === false || (defined('WP_DISABLE_TRANSIENTS') && WP_DISABLE_TRANSIENTS)) ? false : true;
$data = $enable_transients ? get_transient($slug) : false;
if ( false === $data ) {
$data = self::handle_transient_locking($slug, $callback, $transient_time, $lock_timeout, $force, $enable_transients);
}
return $data;
}
/**
* Does the dirty work of locking the transient, running the callback and unlocking
* @param string $slug
* @param callable $callback
* @param integer $transient_time Expiration of transients in seconds
* @param integer $lock_timeout How long (in seconds) to lock the transient to prevent race conditions
* @param boolean $force Force callback to be executed when transient is locked
* @param boolean $enable_transients Force callback to be executed when transient is locked
*/
protected static function handle_transient_locking( $slug, $callback, $transient_time, $lock_timeout, $force, $enable_transients ) {
if ( $enable_transients && self::_is_transient_locked($slug) ) {
$force = apply_filters('timber_force_transients', $force);
$force = apply_filters('timber_force_transient_'.$slug, $force);
if ( !$force ) {
//the server is currently executing the process.
//We're just gonna dump these users. Sorry!
return false;
}
$enable_transients = false;
}
// lock timeout shouldn't be higher than 5 seconds, unless
// remote calls with high timeouts are made here
if ( $enable_transients ) {
self::_lock_transient($slug, $lock_timeout);
}
$data = $callback();
if ( $enable_transients ) {
set_transient($slug, $data, $transient_time);
self::_unlock_transient($slug);
}
return $data;
}
/**
* @internal
* @param string $slug
* @param integer $lock_timeout
*/
public static function _lock_transient( $slug, $lock_timeout ) {
set_transient($slug.'_lock', true, $lock_timeout);
}
/**
* @internal
* @param string $slug
*/
public static function _unlock_transient( $slug ) {
delete_transient($slug.'_lock', true);
}
/**
* @internal
* @param string $slug
*/
public static function _is_transient_locked( $slug ) {
return (bool) get_transient($slug.'_lock');
}
/* These are for measuring page render time */
/**
* For measuring time, this will start a timer
* @api
* @return float
*/
public static function start_timer() {
$time = microtime();
$time = explode(' ', $time);
$time = $time[1] + $time[0];
return $time;
}
/**
* For stopping time and getting the data
* @example
* ```php
* $start = TimberHelper::start_timer();
* // do some stuff that takes awhile
* echo TimberHelper::stop_timer( $start );
* ```
* @param int $start
* @return string
*/
public static function stop_timer( $start ) {
$time = microtime();
$time = explode(' ', $time);
$time = $time[1] + $time[0];
$finish = $time;
$total_time = round(($finish - $start), 4);
return $total_time.' seconds.';
}
/* Function Utilities
======================== */
/**
* Calls a function with an output buffer. This is useful if you have a function that outputs text that you want to capture and use within a twig template.
* @example
* ```php
* function the_form() {
* echo '<form action="form.php"><input type="text" /><input type="submit /></form>';
* }
*
* $context = Timber::context();
* $context['post'] = new Timber\Post();
* $context['my_form'] = TimberHelper::ob_function('the_form');
* Timber::render('single-form.twig', $context);
* ```
* ```twig
* <h1>{{ post.title }}</h1>
* {{ my_form }}
* ```
* ```html
* <h1>Apply to my contest!</h1>
* <form action="form.php"><input type="text" /><input type="submit /></form>
* ```
* @api
* @param callback $function
* @param array $args
* @return string
*/
public static function ob_function( $function, $args = array(null) ) {
ob_start();
call_user_func_array($function, $args);
$data = ob_get_contents();
ob_end_clean();
return $data;
}
/**
* @codeCoverageIgnore
* @deprecated since 1.3.0
*
* @param mixed $function_name String or array( $class( string|object ), $function_name ).
* @param array $defaults Optional.
* @param bool $return_output_buffer Optional. Return function output instead of return value. Default false.
* @return FunctionWrapper|mixed
*/
public static function function_wrapper( $function_name, $defaults = array(), $return_output_buffer = false ) {
Helper::warn( 'function_wrapper is deprecated and will be removed in 1.4. Use {{ function( \'function_to_call\' ) }} instead or use FunctionWrapper directly. For more information refer to https://timber.github.io/docs/guides/functions/' );
return new FunctionWrapper( $function_name, $defaults, $return_output_buffer );
}
/**
*
*
* @param mixed $arg that you want to error_log
* @return void
*/
public static function error_log( $error ) {
global $timber_disable_error_log;
if ( !WP_DEBUG || $timber_disable_error_log ) {
return;
}
if ( is_object($error) || is_array($error) ) {
$error = print_r($error, true);
}
return error_log('[ Timber ] '.$error);
}
/**
* @param string $message that you want to output
* @return boolean
*/
public static function warn( $message ) {
return trigger_error($message, E_USER_WARNING);
}
/**
*
*
* @param string $separator
* @param string $seplocation
* @return string
*/
public static function get_wp_title( $separator = ' ', $seplocation = 'left' ) {
$separator = apply_filters('timber_wp_title_seperator', $separator);
return trim(wp_title($separator, false, $seplocation));
}
/* Text Utitilites */
/* Object Utilities
======================== */
/**
* @codeCoverageIgnore
* @deprecated since 1.2.0
* @see TextHelper::trim_words
* @param string $text
* @param int $num_words
* @param string|null|false $more text to appear in "Read more...". Null to use default, false to hide
* @param string $allowed_tags
* @return string
*/
public static function trim_words( $text, $num_words = 55, $more = null, $allowed_tags = 'p a span b i br blockquote' ) {
return TextHelper::trim_words($text, $num_words, $more, $allowed_tags);
}
/**
* @deprecated since 1.2.0
* @see TextHelper::close_tags
* @param string $html
* @return string
*/
public static function close_tags( $html ) {
return TextHelper::close_tags($html);
}
/**
*
*
* @param array $array
* @param string $prop
* @return void
*/
public static function osort( &$array, $prop ) {
usort($array, function( $a, $b ) use ($prop) {
return $a->$prop > $b->$prop ? 1 : -1;
} );
}
/**
*
*
* @param array $arr
* @return bool
*/
public static function is_array_assoc( $arr ) {
if ( !is_array($arr) ) {
return false;
}
return (bool) count(array_filter(array_keys($arr), 'is_string'));
}
/**
*
*
* @param array $array
* @return \stdClass
*/
public static function array_to_object( $array ) {
$obj = new \stdClass;
foreach ( $array as $k => $v ) {
if ( is_array($v) ) {
$obj->{$k} = self::array_to_object($v); //RECURSION
} else {
$obj->{$k} = $v;
}
}
return $obj;
}
/**
*
*
* @param array $array
* @param string $key
* @param mixed $value
* @return bool|int
*/
public static function get_object_index_by_property( $array, $key, $value ) {
if ( is_array($array) ) {
$i = 0;
foreach ( $array as $arr ) {
if ( is_array($arr) ) {
if ( $arr[$key] == $value ) {
return $i;
}
} else {
if ( $arr->$key == $value ) {
return $i;
}
}
$i++;
}
}
return false;
}
/**
*
*
* @param array $array
* @param string $key
* @param mixed $value
* @return array|null
* @throws Exception
*/
public static function get_object_by_property( $array, $key, $value ) {
if ( is_array($array) ) {
foreach ( $array as $arr ) {
if ( $arr->$key == $value ) {
return $arr;
}
}
return false;
}
throw new \InvalidArgumentException('$array is not an array, got:');
Helper::error_log($array);
}
/**
*
*
* @param array $array
* @param int $len
* @return array
*/
public static function array_truncate( $array, $len ) {
if ( sizeof($array) > $len ) {
$array = array_splice($array, 0, $len);
}
return $array;
}
/* Bool Utilities
======================== */
/**
*
*
* @param mixed $value
* @return bool
*/
public static function is_true( $value ) {
if ( isset($value) ) {
if ( is_string($value) ) {
$value = strtolower($value);
}
if ( ($value == 'true' || $value === 1 || $value === '1' || $value == true) && $value !== false && $value !== 'false' ) {
return true;
}
}
return false;
}
/**
*
*
* @param int $i
* @return bool
*/
public static function iseven( $i ) {
return ($i % 2) == 0;
}
/**
*
*
* @param int $i
* @return bool
*/
public static function isodd( $i ) {
return ($i % 2) != 0;
}
/**
* Plucks the values of a certain key from an array of objects
* @param array $array
* @param string $key
*/
public static function pluck( $array, $key ) {
$return = array();
foreach ( $array as $obj ) {
if ( is_object($obj) && method_exists($obj, $key) ) {
$return[] = $obj->$key();
} elseif ( is_object($obj) && property_exists($obj, $key) ) {
$return[] = $obj->$key;
} elseif ( is_array($obj) && isset($obj[$key]) ) {
$return[] = $obj[$key];
}
}
return $return;
}
/**
* Filters a list of objects, based on a set of key => value arguments.
* Uses native Twig Filter.
*
* @since 1.14.0
* @deprecated since 1.17 (to be removed in 2.0). Use array_filter or Helper::wp_list_filter instead
* @todo remove this in 2.x
* @param array $list to filter.
* @param callback|string|array $arrow function used for filtering,
* string or array for backward compatibility.
* @param string $operator to use (AND, NOT, OR). For backward compatibility.
* @return array
*/
public static function filter_array( $list, $arrow, $operator = 'AND' ) {
if ( ! is_callable( $arrow ) ) {
self::warn( 'This filter is using Twig\'s filter by default. If you want to use wp_list_filter use {{ my_array|wp_list_filter }}.' );
return self::wp_list_filter( $list, $arrow, $operator );
}
if ( is_array( $list ) ) {
return array_filter( $list, $arrow, \ARRAY_FILTER_USE_BOTH );
}
// the IteratorIterator wrapping is needed as some internal PHP classes are \Traversable but do not implement \Iterator
return new \CallbackFilterIterator( new \IteratorIterator( $list ), $arrow );
}
/**
* Filters a list of objects, based on a set of key => value arguments.
* Uses WordPress WP_List_Util's filter.
*
* @since 1.5.3
* @ticket #1594
* @param array $list to filter.
* @param string|array $args to search for.
* @param string $operator to use (AND, NOT, OR).
* @return array
*/
public static function wp_list_filter( $list, $args, $operator = 'AND' ) {
if ( ! is_array( $args ) ) {
$args = array( 'slug' => $args );
}
if ( ! is_array( $list ) && ! is_a( $list, 'Traversable' ) ) {
return array();
}
$util = new \WP_List_Util( $list );
return $util->filter( $args, $operator );
}
/* Links, Forms, Etc. Utilities
======================== */
/**
*
* Gets the comment form for use on a single article page
* @deprecated 0.21.8 use `{{ function('comment_form') }}` instead
* @param int $post_id which post_id should the form be tied to?
* @param array The $args thing is a mess, [fix at some point](http://codex.wordpress.org/Function_Reference/comment_form)
* @return string
*/
public static function get_comment_form( $post_id = null, $args = array() ) {
global $post;
$post = get_post($post_id);
return self::ob_function('comment_form', array($args, $post_id));
}
/**
* @codeCoverageIgnore
* @deprecated since 1.1.2
* @param array $args
* @return array
*/
public static function paginate_links( $args = array() ) {
Helper::warn('Helper/paginate_links has been moved to Pagination/paginate_links');
return Pagination::paginate_links($args);
}
/**
* @codeCoverageIgnore
* @return string
*/
public function get_current_url() {
Helper::warn('TimberHelper::get_current_url() is deprecated and will be removed in future versions, use Timber\URLHelper::get_current_url()');
return URLHelper::get_current_url();
}
/**
* Converts a WP object (WP_Post, WP_Term) into his
* equivalent Timber class (Timber\Post, Timber\Term).
*
* If no match is found the function will return the inital argument.
*
* @param mix $obj WP Object
* @return mix Instance of equivalent Timber object, or the argument if no match is found
*/
public static function convert_wp_object( $obj ) {
if ( $obj instanceof \WP_Post ) {
$class = \Timber\PostGetter::get_post_class($obj->post_type);
return new $class($obj->ID);
} elseif ( $obj instanceof \WP_Term ) {
return new \Timber\Term($obj->term_id);
} elseif ( $obj instanceof \WP_User ) {
return new \Timber\User($obj->ID);
}
return $obj;
}
}