File: D:/HostingSpaces/HBergman/delifestyle.nl/wwwroot/wp-content/plugins/maxbuttons/classes/button.php
<?php
defined('ABSPATH') or die('No direct access permitted');
/* Datamodel and base functionality for a button
*/
use MaxButtons\maxBlocks as maxBlocks;
use MaxButtons\maxField as maxField;
class maxButton
{
protected $id = 0;
protected $document_id = 0; // an id that's not duplicated when there are multiple buttons on the same page. Preferably reliable as well.
protected $name = '';
protected $status = '';
protected $description = '';
protected $cache = '';
protected $button_loaded = false;
protected $data = array();
protected $blocks; //= array('basic', 'text' , 'border', 'color', 'gradient', 'container', 'advanced', 'responsive'); // Blocks
protected $templates = array(); // .tpl files
protected $button_css = array('normal' => array() ,':hover' => array() ,':visited' => array(), "responsive" => array());
protected $button_js = array();
// output conditions
protected $load_css = 'footer'; // [ footer, inline, external, element ]
protected $load_js = 'footer';
protected $cssParser = false;
protected $parsed_css = '';
/* Class constructor
Get als loads the various blocks of which a button is built up. Blocks can be added and removed using the mb-init-blocks filter
*/
function __construct()
{
maxUtils::addTime("Button construct");
// the parser
// get all files from blocks map
// get all blocks via apply filters, do init. Init should not load anything big.
$block_paths = apply_filters('mb-block-paths', array(MB()->get_plugin_path() . "blocks/") );
global $blockClass; // load requires only once
if ($blockClass == '' || count($blockClass) == 0)
{
$newBlocks = array();
foreach($block_paths as $block_path)
{
$dir_iterator = new RecursiveDirectoryIterator($block_path, FilesystemIterator::SKIP_DOTS);
$iterator = new RecursiveIteratorIterator($dir_iterator, RecursiveIteratorIterator::SELF_FIRST);
foreach ($iterator as $fileinfo)
{
$path = $fileinfo->getRealPath();
// THIS IS PHP > 5.3.6
//$extension = $fileinfo->getExtension();
$extension = pathinfo($path, PATHINFO_EXTENSION);
if ($fileinfo->isFile() )
{
if ($extension == 'php')
{
require_once($path);
}
elseif($extension == 'tpl')
{
$filename = $fileinfo->getBasename('.tpl');
$this->templates[$filename] = array('path' => $path);
}
}
}
}
ksort($blockOrder);
foreach($blockOrder as $prio => $blockArray)
{
foreach($blockArray as $block)
{
if (isset($blockClass[$block]))
$newBlocks[$block] = $blockClass[$block];
}
}
$blockClass = $newBlocks;
if (is_admin())
{
maxField::setTemplates($this->templates);
maxBlocks::init();
}
$this->loadBlockClasses($blockClass);
}
$this->blocks = array_keys($blockClass);
}
/* Makes overriding block features possible by subclass
*/
private function loadBlockClasses($classes)
{
// set blocks to the 'block name' that survived.
maxUtils::addTime("Load Block classes");
$classes = apply_filters("mb_blockclassesload", $classes);
foreach($classes as $block => $class)
{
$block = new $class();
if (is_admin())
maxBlocks::add($block); // block collection.
}
do_action("mb_blockclassesloaded", $classes);
}
/** Simple function to retrieve loaded blocks - * Questionable if in use */
public function getDefinedBlocks()
{
return $this->blocks;
}
/** Get Data from Database and set variables
*
* You can pass either id or name to this function
*
* @return Boolean Returns false when no data was found using either ID or name
*/
function set($id = 0, $name = '', $status = 'publish')
{
maxUtils::addTime("Button set $id");
$id = intval($id);
$name = sanitize_text_field($name);
$status = sanitize_text_field($status);
global $wpdb;
$this->clear(); // clear the internals of any previous work
// check to see if the value passed is NOT numeric. If it is, use title, else assume numeric
if($id == 0 && $name != '') {
$row = $wpdb->get_row($wpdb->prepare("SELECT * FROM " . maxUtils::get_buttons_table_name() . " WHERE name = '%s' and status ='%s'", trim($name), $status ), ARRAY_A);
} else {
$row = $wpdb->get_row($wpdb->prepare("SELECT * FROM " . maxUtils::get_buttons_table_name() . " WHERE id = %d and status ='%s'", $id, $status), ARRAY_A);
}
if (count($row) == 0)
{
return false;
}
/* Take the id from the query, otherwise ( when button shortcode called by name ) id might not be present properly' */
$button_id = $row["id"];
maxButtons::buttonLoad(array("button_id" => $button_id)); // central registration
return $this->setupData($row);
}
/** Clear button settings
*
* This function prevent that generated values from previous set actions will still be present.
*/
function clear()
{
unset($this->data);
unset($this->button_css);
$this->id = 0; // clear id
$this->button_css = '';
$this->button_js = array();
$this->data = array();
$this->data = $this->save(array(),false);
$this->cache = '';
$this->button_loaded = false;
}
function setupData($data)
{
maxUtils::addTime("Button: Setup data");
foreach($this->blocks as $block)
{
if (array_key_exists($block, $data)) // strangely isset doesn't work
{
$this->data[$block] = maybe_unserialize($data[$block]); // allow to feed unserialized stuff not from dbase
if (! is_array($this->data[$block]))
{
$this->data[$block] = json_decode($data[$block], true);
}
}
else
{
// else block does not exist in this dataset - ignoring.
//exit("Fatal: Something wrong with provider on $block ");
}
}
$this->id = $data["id"];
$this->document_id = maxButtons::getDocumentID(array("button_id" => $this->id));
$this->cache = isset($data["cache"]) ? trim($data["cache"]) : ''; // not set at button packs / non-dbase buttons!
$this->data["id"] = $this->id; // needed for certain blocks, to be button aware.
$this->data["document_id"] = $this->document_id; // bound to JS and others.
$this->name = $data["name"];
$this->status = $data["status"];
$this->description = $this->data["basic"]["description"];
do_action('mb-data-load', $this->data);
return true;
}
function get( )
{
return $this->data;
}
function getID()
{
return $this->id;
}
function getDocumentID()
{
return $this->document_id;
}
function getName()
{
return $this->name;
}
function getDescription()
{
return $this->description;
}
function getStatus()
{
return $this->status;
}
function getParsedCSS()
{
return $this->parsed_css;
}
function getCSSArray()
{
return $this->button_css;
}
function getCSSParser()
{
if (! $this->cssParser)
$this->cssParser = new maxCSSParser();
return $this->cssParser;
}
// get the cache
function getCache()
{
return $this->cache;
}
// modify the cache at own risk
function setCache($cache)
{
$this->cache = $cache;
}
function setData($blockname, $data )
{
foreach($data as $key => $value)
{
$this->data[$blockname][$key] = $value;
}
}
/* Tell all blocks to reload the daa
This function will tell all loaded blocks to reload it's data. This is needed when data is changed after the initial button load.
*/
function reloadData()
{
do_action('mb-data-load', $this->data);
}
/* Parse CSS from the elements
@param string $mode [normal,preview,editor] - The view needed.
@param string $forceCompile Recompile the CSS in any case
*/
function parse_css($mode = "normal", $forceCompile = false )
{
$css = $this->button_css;
if (isset($this->cache) && $this->cache != '' && ! $forceCompile)
{
$css = $this->cache;
// kill media queries from cache
if ($mode != 'normal')
{
$pattern = "/@media.*}/is";
preg_match($pattern, $css, $matches);
$css = preg_replace($pattern, '', $css);
}
maxUtils::addTime("Button: Cache loaded");
}
else
{
/* Internal filter, please don't use */
$css = apply_filters('mb-css-blocks', $css, $mode);
/* Filter the raw CSS array before compile
This filters passes an array with all CSS element before compile time. This should be CSS elements that van be understood by the CSS parser.
@since 4.20
@param $css CSS Array - split by element and pseudo (normal/hover)
*/
$css = apply_filters('mb/button/rawcss', $css, $mode);
$this->button_css = $css;
$css = $this->getCSSParser()->parse($this->button_css);
if ($mode == 'normal') // only in general mode, otherwise things go amiss.
$this->update_cache($css);
}
$this->parsed_css = $css;
return $css;
}
/* Call blocks for javascript
Function will call for all block element to crunch the required javascript for output ( if any )
@param string $mode [normal, preview, editor]
*/
function parse_js($mode = "normal")
{
maxUtils::addTime("Button :: parse JS");
$js = $this->button_js;
$js = apply_filters('mb-js-blocks', $js, $mode);
$this->button_js = $js;
}
/* Parse the actual button
Function adds the basic button components, creates the DOM object for the button and asks all block elements to parse their additions.
@param string $mode [normal, preview, editor]
@return Object DomObj presentation of the button
*/
function parse_button($mode = 'normal')
{
$name = $this->name;
// non-latin breaks CSS / ID's - so move to latin.
$name = maxUtils::translit($name);
$name = sanitize_title($name);
$classes = array("maxbutton-" . $this->id,
"maxbutton");
if ($name != '')
$classes[] = "maxbutton-" . $name;
$classes = apply_filters('mb-mainclasses', $classes);
$classes = implode(' ', $classes);
$domObj = new simple_html_dom();
$domObj->load('<a class="' . $classes . '"></a>');
$domObj = apply_filters('mb-parse-button', $domObj, $mode, $this->id);
$domObj->load($domObj->save());
$cssParser = $this->getCSSParser();
$cssParser->loadDom($domObj);
return $domObj;
}
/* Display all data and html to allow users to edit button settings */
public function admin_fields()
{
do_action('mb-admin-fields' );
}
/* Display the button */
public function display($args = array() )
{
maxUtils::startTime('button-display-'. $this->id);
$defaults = array(
"mode" => 'normal',
"preview_part" => "full",
"echo" => true,
"load_css" => "footer", // control how css is loaded.
"compile" => false, // possibility to force recompile if needed.
);
$output = ''; // init output;
$args = wp_parse_args($args, $defaults);
$cssParser = $this->getCSSParser(); // init parser
$this->load_css = $args["load_css"];
if ($this->id == 0) // if button doesn't exists don't display unless in editor
{
if (! $args["mode"] == 'editor' )
return;
$data = apply_filters("mb-save-fields", array(), array() ); // load defaults
$data["id"] = 0;
do_action('mb-data-load', $data);
}
$mode = (isset($args["mode"])) ? $args["mode"] : "normal";
switch($mode)
{
case "preview":
$preview = true;
$compile = false;
break;
case "editor":
$preview = true;
$compile = true;
// editor is both compile and preview.
break;
break;
case "normal":
$preview = false;
$compile = false;
break;
}
if ( $this->load_css == "element" || $args["preview_part"] != "full" || $args["compile"] == true) { // if css output is on element, for to compile - otherwise inline styles will not be loaded.
$compile = true;
}
else
$compile = false;
$domObj = $this->parse_button($mode);
maxUtils::startTime('button-parse-css-'. $this->id);
$this->parse_css($mode, $compile);
maxUtils::endTime('button-parse-css-'. $this->id);
if (! $preview) // no js on previews
$this->parse_js($mode);
if ($preview) // mark it preview
{
$domObj->find('a',0)->class .= ' maxbutton-preview';
}
if ($preview && $args["preview_part"] != 'full')
{
if ($args["preview_part"] != 'normal')
{
$domObj->find('a',0)->class .= ' hover';
$domObj = $cssParser->outputInline($domObj,'hover');
}
else
{
$domObj->find('a',0)->class .= ' normal';
$domObj = $cssParser->outputInline($domObj);
}
}
elseif ($this->load_css == 'footer')
{
$css = $this->display_css(false, false);
do_action('mb-footer',$this->id, $css);
if (! $preview)
{
$js = $this->display_js(false, true);
do_action('mb-footer', $this->document_id, $js, 'js');
}
} elseif ($this->load_css == 'inline')
{
if ($args["echo"])
$this->display_css();
else
$output .= $this->display_css(false);
}
elseif ($this->load_css == 'element') // not possible to load both normal and hover to an element.
{
$domObj->find('a',0)->class .= ' normal';
$domObj = $this->cssParser->outputInline($domObj);
//$this->get_element_css($domObj, 'normal');
}
$output .= $domObj->save();
$output = apply_filters('mb-before-button-output', $output);
maxButtons::buttonDone(array("button_id" => $this->id, "document_id" => $this->document_id) );
maxUtils::endTime('button-display-'. $this->id);
if ($args["echo"])
echo $output;
else
return $output;
}
/* Function used to map field id's to display for Frontend Javascript
This function bundles all defined fields into a json encoded variable. This is used for the frontend javascript functions in the
administrator area like colorpickers and real-time updating of the button preview
*/
public function display_field_map()
{
$map = array();
$map = apply_filters("mb-field-map",$map);
echo "<script language='javascript'>";
echo "var buttonFieldMap = '" . json_encode($map) . "';" ;
echo "</script>";
}
/* Write parsed CSS to output.
@param echo Default true. When true, outputs directly, otherwise returns output string
@param style_tag Default true. When true, outputs a html <style> tags around the output.
*/
public function display_css($echo = true, $style_tag = true)
{
$output = '';
if ($style_tag)
$output .= "<style type='text/css'>";
$output .= $this->parsed_css;
if ($style_tag)
$output .= "</style>";
if ($echo) echo $output;
else return $output;
}
/* Output Parsed Javascripting */
public function display_js($echo = true, $tag = true)
{
$output = '';
if (count($this->button_js) == 0)
return; // no output, holiday
if ($tag)
{
$output .= "<script type='text/javascript'> ";
$output .= " if (typeof maxButton" . $this->document_id . " == 'undefined') { ";
$output .= " function maxButton" . $this->document_id . "() { ";
}
foreach($this->button_js as $index => $code)
{
$output .= $code;
}
if ($tag)
{
$output .= " }
}
window.onload = maxButton" . $this->document_id . "();
</script> ";
}
if ($echo) echo $output;
else return $output;
}
/* Makes a copy of the current buttons.
The button to be copied -must- be loaded and set
*/
function copy()
{
$this->id = 0;
$data = $this->data;
$data["name"] = $this->name;
return $this->update($data);
}
/* Change the publication status of the button.
*/
function setStatus($status = "publish")
{
$data = $this->data;
$data["status"] = sanitize_text_field($status);
return $this->update($data);
}
/* Remove the button from database */
public function delete($id)
{
global $wpdb;
$wpdb->query($wpdb->prepare("DELETE FROM " . maxUtils::get_table_name() . " WHERE id = %d", $id));
}
/* Save changes to the button
Updates or saves the button. Existing buttons must load their data and be set -first- or lose all not-passed data.
@param post Post data in field - value format (flat $_POST array)
@param boolean savedb if false do not save to database
*/
public function save($post, $savedb = true)
{
$post = stripslashes_deep($post); // don't multiply slashes please.
$data = apply_filters('mb-save-fields',$this->data, $post);
// echo "<PRE>"; print_R($post); echo "---"; print_R($data); echo "</PRE>";
//exit("");
if (! $savedb ) return $data;
return $this->update($data); // save to db.
}
/* Updates the button data to the database. Adds a button if it doesn't exist */
public function update($data)
{
global $wpdb;
$return = false;
$fields = array();
foreach($this->blocks as $block)
{
if (isset($data[$block]))
{
$blockData = $data[$block];
$fields[$block] = json_encode($blockData);
}
}
if (isset($data["name"])) { // other fields.
$fields["name"] = $data["name"];
}
if (isset($data["status"])) {
$fields["status"] = $data["status"];
}
$where = array('id' => $this->id );
if ($this->id > 0)
{
$where = array('id' => $this->id);
$where_format = array('%d');
$result = $wpdb->update(maxUtils::get_table_name(), $fields, $where, null, $where_format);
$return = true;
}
else
{
$result = $wpdb->insert(maxUtils::get_table_name(), $fields);
$id = $wpdb->insert_id;
$this->id = $id;
$return = $id;
}
if ($result === 0)
{
$error = "Database error " . $wpdb->last_error;
MB()->add_notice('error', $error);
}
// update the cache
$this->cache = ''; // empty cache
$result = $this->set($this->id); // set the newest values
if (! $result ) return false;
$this->display(array("echo" => false, "load_css" => "element")); // do display routing to compile.
$css = $this->parsed_css;
$this->update_cache($css);
return $return;
}
/* Updates the CSS cache. */
public function update_cache($css)
{
$return = false;
global $wpdb;
if ($this->id > 0)
{
$fields = array("cache" => $css);
$where = array('id' => $this->id);
$where_format = array('%d');
$wpdb->update(maxUtils::get_table_name(), $fields, $where, null, $where_format);
$return = true;
}
return $return;
}
// Resets all of the button caches.
public function reset_cache()
{
global $wpdb;
$fields = array("cache" => null);
$where = array(1 => 1);
//$where_format = array('%d');
$sql = "UPDATE " . maxUtils::get_table_name() . " SET cache = NULL ";
$wpdb->query($sql);
}
/* Display button via shortcode
Function that accepts WP shortcode arguments and displays or returns a button
@param $atts array Shortcode Atts
@return string HTML presentation of button
*/
public function shortcode($atts)
{
extract(shortcode_atts(array(
'id' => '',
'name' => '',
'text' => '',
'url' => '',
'window' => '',
'nofollow' => '',
'nocache' => false,
'style' => 'footer',
'exclude' => ''
), $atts));
$button_id = $id;
$button_name = $name;
if ($button_id > 0)
$result = $this->set($button_id);
elseif ($button_name != '')
$result = $this->set(0, $button_name);
else return; // no button
/* Shortcode cache control
If true the button CSS will be recompiled again. If false the plugin will check the cache for CSS declarations. Set to true if anything is interrupting the caching mechanism. Please note, recompiling causes some load times!
@param boolean $nocache True / False
*/
$compile = apply_filters("mb/shortcode/nocache", $nocache);
if (! $result)
return; // shortcode doesn't exist
// If we're not in the admin and the button is in the trash, just return nothing
if (!is_admin() && $this->status == 'trash') {
return '';
}
// Check to handle excludes
if ("{$exclude}" != '') {
global $post;
// Don't render the button if excluded from the current post/page
$exclude = explode(',', "{$exclude}");
if (in_array($post->ID, $exclude)) {
return '';
}
}
// Override shortcode options comparing to default button data.
$overrides = false;
if ($text != '')
{
$this->data["text"]["text"] = $text;
$overrides = true;
}
if ($url != '')
{
$this->data["basic"]["url"] = $url;
//$compile = true; // css change forces recompile
$overrides = true;
}
if ($window != '' && $window =='new')
{
$this->data["basic"]["new_window"] = 1;
$overrides = true;
}
if ($nofollow != '' && $nofollow == 'true')
{
$this->data["basic"]["nofollow"] = 1;
$overrides = true;
}
switch($style)
{
case "inline":
$load_css = 'inline';
break;
default:
$load_css = 'footer';
break;
}
// allow for more flexible changes and data manipulation.
$data = $this->data;
$this->data = $this->shortcode_overrides($this->data, $atts);
$this->data = apply_filters('mb/shortcode/data', $this->data, $atts);
if ($data !== $this->data)
{
$overrides = true;
}
if ($overrides)
{
do_action('mb-data-load', $this->data);
}
// if there are no reasons not to display; display
$args = array("echo" => false,
"load_css" => $load_css,
"compile" => $compile,
);
$args = apply_filters('mb_shortcode_display_args', $args);
$output = $this->display($args);
return $output;
}
public function shortcode_overrides($data, $atts)
{
return $data;
}
}