core/Utils/Utilities.php
<?php
namespace Kontentblocks\Utils;
use Kontentblocks\Backend\Environment\EnvironmentInterface;
use Kontentblocks\Backend\Environment\PostEnvironment;
use Kontentblocks\Backend\Environment\TermEnvironment;
use Kontentblocks\Backend\Environment\UserEnvironment;
use Kontentblocks\Fields\Definitions\NullField;
use Kontentblocks\Fields\Definitions\ReturnObjects\StandardFieldReturn;
use Kontentblocks\Kontentblocks;
use phpDocumentor\Reflection\Types\Self_;
use Symfony\Component\HttpFoundation\Request;
use XHProfRuns_Default;
/**
* Class Utilities
* @package Kontentblocks\Utils
*/
class Utilities
{
protected static $postEnvironments = array();
protected static $termEnvironments = array();
protected static $userEnvironments = array();
protected static $request;
/**
* @param null $storageId
* @param null $actualPostId
* @return PostEnvironment
* @deprecated use getPostEnvironment instead
*/
public static function getEnvironment($storageId = null, $actualPostId = null)
{
return self::getPostEnvironment($storageId, $actualPostId);
}
/**
* Get environment
*
* $storageId is most likely the ID of the current post
* but can vary if a different storage logic applies.
* $actualPostId may be equal to storageId in most cases and should be a valid post ID
*
* @param mixed $storageId
* @param null $actualPostId
* @return PostEnvironment
* @since 0.1.0
*/
public static function getPostEnvironment($storageId = null, $actualPostId = null)
{
$cacheKey = get_current_blog_id() . ':' . $storageId;
if ($storageId && is_numeric($storageId) && $storageId !== -1) {
if (isset(self::$postEnvironments[$cacheKey])) {
_K::info("cached PostEnvironment found for post ID {$cacheKey}");
return self::$postEnvironments[$cacheKey];
} else {
$realId = (is_null($actualPostId)) ? $storageId : $actualPostId;
$postObj = get_post($realId);
if (!is_null($postObj)) {
_K::info("new PostEnvironment built for post ID {$cacheKey}");
return self::$postEnvironments[$cacheKey] = new PostEnvironment($storageId, $postObj);
}
return null;
}
}
return null;
}
/**
* @param $termId
* @param null $taxonomy
* @return TermEnvironment
*/
public static function getTermEnvironment($termId, $taxonomy = null)
{
if ($termId && is_numeric($termId) && $termId !== -1) {
if (isset(self::$termEnvironments[$termId])) {
_K::info("cached TermEnvironment found for post ID {$termId}");
return self::$termEnvironments[$termId];
} else {
$termObj = get_term($termId, $taxonomy);
_K::info("new TermEnvironment built for post ID {$termId}");
return self::$termEnvironments[$termId] = new TermEnvironment($termId, $termObj);
}
}
}
/**
* @param $userId
* @param \WP_User $user
* @return UserEnvironment
*/
public static function getUserEnvironment($userId, \WP_User $user)
{
if ($userId && is_numeric($userId) && $userId !== 0) {
if (isset(self::$userEnvironments[$userId])) {
return self::$userEnvironments[$userId];
} else {
return self::$userEnvironments[$userId] = new UserEnvironment($userId, $user);
}
}
}
/**
* a hidden editor instance to make sure that wp related tinymce
* js environment and files are correctly setup
*/
public static function hiddenEditor()
{
global $kbHiddenEditorCalled;
if (!$kbHiddenEditorCalled) {
wp_enqueue_editor();
/** @var JSONTransport $jsonTransport */
$jsonTransport = Kontentblocks()->getService('utility.jsontransport');
$jsonTransport->registerData('tinymce', 'settings', self::editorDefaultSettings());
echo "<div style='display: none;'>";
self::editor('ghost', '', 'ghost', true, array('tinymce' => array('wp_skip_init' => false)));
echo '</div>';
}
// make sure to no call this twice
$kbHiddenEditorCalled = true;
}
public static function editorDefaultSettings()
{
global $wp_version;
// introduced in 4.3
// necessary for wp_editor which expects $wp_styles to be setup ( state: 4.3alpha )
if (function_exists('wp_styles')) {
wp_styles();
}
$plugins = array_unique(
apply_filters(
'tiny_mce_plugins',
array(
'charmap',
'hr',
'media',
'paste',
'tabfocus',
'textcolor',
'fullscreen',
'wordpress',
'wpeditimage',
'wpgallery',
'wplink',
'wpdialogs',
'wpview'
)
)
);
/*
* autoresize behaviour is new from version 4
*/
if (version_compare($wp_version, '4.0', '>=')) {
$plugins[] = 'wpautoresize';
}
if (version_compare($wp_version, '4.0', '<=')) {
$plugins[] = 'wpfullscreen';
}
if (version_compare($wp_version, '4.2', '>=')) {
$plugins[] = 'wptextpattern';
$plugins[] = 'wpemoji';
}
if (version_compare($wp_version, '4.8', '>=')) {
$plugins[] = 'lists';
}
$settings = array(
'wpautop' => true,
// use wpautop?
'media_buttons' => false,
// show insert/upload button(s)
// 'textarea_name' => $name,
// set the textarea name to something different, square brackets [] can be used here
'tabindex' => '',
'editor_css' => '',
'drag_drop_upload' => true,
'editor_class' => 'kb_editor_textarea',
// add extra class(es) to the editor textarea
'teeny' => false,
// output the minimal editor config used in Press This
'dfw' => false,
// replace the default fullscreen with DFW (needs specific DOM elements and css)
'tinymce' => array(
'height' => '350px',
'editor_height' => '350',
'autoresize_min_height' => '200',
'autoresize_max_height' => '600',
'resize' => 'vertical',
'paste_remove_styles' => true,
'menubar' => false,
'preview_styles' => 'font-family font-size font-weight font-style text-decoration text-transform',
'plugins' => implode(',', $plugins),
'wp_autoresize_on' => true,
'wp_skip_init' => false,
),
// load TinyMCE, can be used to pass settings directly to TinyMCE using an array()
'quicktags' => true
);
$settings = apply_filters('kb.tinymce.global.settings', $settings);
return $settings;
}
/**
* @param string $id editors unique id
* @param string $data | initial content of the editor
* @param null $name
* @param bool $media | whether to render media buttons or not
* @param array $args | additional args
*/
static public function editor($id, $data, $name = null, $media = false, $args = array())
{
$settings = self::editorDefaultSettings();
$settings['textarea_name'] = $name;
$settings['media_buttons'] = $media;
if (!empty($args)) {
$settings = Utilities::arrayMergeRecursive($args, $settings);
}
wp_editor($data, $id . 'editor', $settings);
}
/**
* Recursivly merge associative arrays
* Keys which are excplicit set to null get removed from the result
* Keys not present in $new, but available in $old will be taken from $old
*
* @param array $new
* @param array $old
* @return array
*/
public static function arrayMergeRecursive($new, $old)
{
$merged = $new;
if (!is_array($merged)) {
return $old;
}
if (is_array($old)) {
foreach ($old as $key => $val) {
if (is_array($old[$key])) {
if (array_key_exists($key, $merged) && isset($merged[$key]) && $merged[$key] !== null) {
// key exists and is not null, dig further into the array until actual values are reached
$merged[$key] = self::arrayMergeRecursive($merged[$key], $old[$key]);
} elseif (array_key_exists($key, $merged) && $merged[$key] === null) {
unset($merged[$key]);
} else {
// preserve the old value
$merged[$key] = self::arrayMergeRecursive($old[$key], $old[$key]);
}
} else {
if (array_key_exists($key, $merged) && $merged[$key] === null) {
// key was set to null on purpose, and gets removed finally
unset($merged[$key]);
} elseif (!isset($merged[$key])) {
// there is something missing in current(new) data, add it
$merged[$key] = $val;
}
}
}
}
return $merged;
}
/**
* @param $index
*
* @return string
*/
public static function getBaseIdField($index)
{
// prepare base id for new blocks
if (!empty($index)) {
$base_id = self::getHighestId($index);
} else {
$base_id = 0;
}
// add a hidden field to the meta box, javascript will use this
return '<input type="hidden" id="kb_all_blocks" value="' . $base_id . '" />';
}
/**
* @param $index
*
* @return mixed
*/
public static function getHighestId($index)
{
$collect = [];
if (!empty($index)) {
foreach ($index as $module) {
$module = maybe_unserialize($module);
$count = strrchr($module['mid'], "_");
$id = str_replace('_', '', $count);
$collect[] = $id;
}
}
if (empty($collect)) {
return absint(1);
} else {
return absint(max($collect));
}
}
/**
* Wrapper to wp get_post_types
* returns all public post types as object
* @return array
*/
public static function getPostTypes()
{
$postTypes = get_post_types(array('public' => true), 'objects', 'and');
$collection = array();
foreach ($postTypes as $pt) {
$collect = array(
'name' => $pt->labels->name,
'value' => $pt->name
);
$collection[] = $collect;
}
return $collection;
}
/**
* Wrapper to wp get_page_templates
* Internal use only
* @return array
*/
public static function getPageTemplates()
{
$page_templates = get_page_templates();
$page_templates['Default (page.php)'] = 'default';
$collection = array();
foreach ($page_templates as $template => $filename) {
$collect = array(
'name' => $template,
'value' => $filename
);
$collection[] = $collect;
}
return $collection;
}
/**
* Evaluate the current template file if possible
* read template as file in the wp template hierachy
* @return string
* @since 0.1.0
*/
public static function getTemplateFile()
{
global $template;
if (!empty($template) && is_string($template)) {
return str_replace('.php', '', basename($template));
} else {
return 'generic';
}
}
/**
* Check if a top level admin menu exists
* (not reliable in all situations)
* @param string $id menu identifier
* @return bool
*/
public static function adminMenuExists($id)
{
global $menu;
foreach ($menu as $item) {
if (strtolower($item[0]) == strtolower($id)) {
return true;
}
}
return false;
}
/**
* Test if an array is indexed or associative
* @param array $array
* @return bool
*/
public static function isAssocArray($array)
{
$array = array_keys($array);
return ($array !== array_keys($array));
}
/**
* Internal debugging shortcut helper for Xhprof
*/
public static function enableXhprof()
{
if (function_exists('xhprof_enable')) {
if (filter_input(INPUT_GET, 'xhprof', FILTER_SANITIZE_STRING)) {
include '/usr/share/php/xhprof_lib/utils/xhprof_lib.php';
include '/usr/share/php/xhprof_lib/utils/xhprof_runs.php';
xhprof_enable(XHPROF_FLAGS_NO_BUILTINS + XHPROF_FLAGS_MEMORY);
}
}
}
/**
* Internal debugging shortcut helper for Xhprof
* @param string $app Xhprof group id
*/
public static function disableXhprf($app = 'Kontentblocks')
{
if (function_exists('xhprof_disable')) {
if (filter_input(INPUT_GET, 'xhprof', FILTER_SANITIZE_STRING)) {
$XHProfData = xhprof_disable();
$XHProfRuns = new XHProfRuns_Default();
$XHProfRuns->save_run($XHProfData, $app);
}
}
}
/**
* Call the ghost to visit the url in concat mode
* @param null $postId
* @param bool $blocking
* @param null $host
* @param array $args
* @return null|void
*/
public static function remoteConcatGet($postId = null, $blocking = false, $host = null, $args = array())
{
if (apply_filters('kb.remote.concat.get.disable', false)) {
return null;
}
if (is_null($postId)) {
return;
}
$postType = get_post_type($postId);
$blacklist = apply_filters('kb.remote.concat.posttypes', array());
if (in_array($postType, $blacklist)) {
return null;
}
if (post_type_supports($postType, 'editor')) {
if (!apply_filters('kb.remote.concat.ignore.editor', '__return_false')) {
return null;
}
}
$base = get_permalink($postId);
if (!is_null($host)) {
$parsed = parse_url($base);
$base = str_replace($parsed['host'], $host, $base);
}
$url = add_query_arg('concat', 'true', $base);
$url = add_query_arg('contime', time(), $url);
if ($url !== false) {
$args = wp_parse_args($args, array('timeout' => 5, 'blocking' => $blocking));
$args = apply_filters('kb.remote.concat.args', $args, $url);
$response = wp_remote_get($url, $args);
return $response;
}
}
/**
* @param $array
* @return mixed
*/
public static function validateBoolRecursive($array)
{
foreach ($array as $k => $v) {
if (is_array($v)) {
$array[$k] = self::validateBoolRecursive($v);
}
if ($v === 'true' || $v === 'false') {
$array[$k] = filter_var($v, FILTER_VALIDATE_BOOLEAN);
}
}
return $array;
}
/**
* Filterable array of allowed cats
* uses @filter kb_menu_cats
* @return array $cats
*/
public static function setupCats()
{
// defaults
$cats = array(
'standard' => __('Standard', 'Kontentblocks'),
);
$cats = apply_filters('kb.module.cats', $cats);
$cats['media'] = __('Media', 'Kontentblocks');
$cats['special'] = __('Spezial', 'Kontentblocks');
$cats['core'] = __('System', 'Kontentblocks');
$cats['gmodule'] = __('Global Modules', 'Kontentblocks');
ksort($cats);
Kontentblocks::getService('utility.jsontransport')->registerData('ModuleCategories', null, $cats);
return $cats;
}
/**
* @param $haystack
* @param $needle
* @param int $offset
* @return bool
*/
public static function strposa($haystack, $needle, $offset = 0)
{
if (!is_array($needle)) {
$needle = array($needle);
}
foreach ($needle as $query) {
if (is_array($haystack)) {
foreach ($haystack as $hay) {
if (strpos($hay, $query, $offset) !== false) {
return true;
} // stop on first true result
}
} else {
if (strpos($haystack, $query, $offset) !== false) {
return true;
} // stop on first true result
}
}
return false;
}
/**
* @param $arr
* @param $path
* @param $value
*/
public static function assignArrayByPath(&$arr, $path, $value)
{
$keys = explode('.', $path);
while ($key = array_shift($keys)) {
$arr = &$arr[$key];
}
$arr = $value;
}
/**
* @param $key
* @param EnvironmentInterface|null $environment
* @return string
*/
public static function buildContextKey($key, EnvironmentInterface $environment = null)
{
if (!is_null($environment)) {
if ($environment->getId() !== get_the_ID()) {
return $key;
}
}
if (self::isPreview()) {
$key = '_preview_' . $key;
}
return $key;
}
/**
* @return bool
*/
public static function isPreview()
{
$request = self::getRequest();
if (is_admin()) {
return ($request->request->get('wp-preview', '') === 'dopreview');
} else {
return is_preview();
}
}
/**
* @return Request
*/
public static function getRequest()
{
if (is_null(self::$request)) {
self::$request = Request::createFromGlobals();
}
return self::$request;
}
public static function filterPostId($postId)
{
$postId = absint($postId);
if (!is_numeric($postId)) {
return $postId;
}
}
/**
* @return string
*/
public static function getCacheGroup()
{
$parts = array();
$parts[] = 'kontentblocks';
if (defined('ICL_LANGUAGE_CODE')) {
$parts[] = ICL_LANGUAGE_CODE;
}
return implode('_', $parts);
}
public static function trackSize($size)
{
$kbimagesizes = get_option('kbimagesizes');
if (!is_array($kbimagesizes)) {
$kbimagesizes = [];
}
$kbimagesizes[$size] = $size;
update_option('kbimagesizes', $kbimagesizes, false);
}
/**
* @param array $args
* @return Null
*/
public static function getNullField($args = [])
{
return new NullField('nullfield', null, 'nullkey', $args);
}
public static function extractFieldValue($val)
{
if (is_a($val, StandardFieldReturn::class)) {
return $val->value;
}
return $val;
}
}