PluginProbe
MaxButtons – Create buttons / 6.3
MaxButtons – Create buttons v6.3
6.23 6.24 6.25 6.26 6.26.1 6.27 6.28 6.3 6.4 6.5 6.6 6.7 6.8 6.9 7.0 7.1 7.1.1 7.1.2 7.1.3 7.10 7.11 7.13 7.13.1 7.13.2 7.13.3 All 100 releases
maxbuttons / classes / button.php

button.php in MaxButtons – Create buttons 6.3, at classes/button.php

894 lines 21.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 defined('ABSPATH') or die('No direct access permitted');
4
5 /* Datamodel and base functionality for a button
6
7 */
8
9 use MaxButtons\maxBlocks as maxBlocks;
10 use MaxButtons\maxField as maxField;
11
12 class maxButton
13 {
14 protected $id = 0;
15 protected $document_id = 0; // an id that's not duplicated when there are multiple buttons on the same page. Preferably reliable as well.
16 protected $name = '';
17 protected $status = '';
18 protected $description = '';
19 protected $cache = '';
20
21 protected $button_loaded = false;
22
23 protected $data = array();
24 protected $blocks; //= array('basic', 'text' , 'border', 'color', 'gradient', 'container', 'advanced', 'responsive'); // Blocks
25 protected $templates = array(); // .tpl files
26
27 protected $button_css = array('normal' => array() ,':hover' => array() ,':visited' => array(), "responsive" => array());
28 protected $button_js = array();
29
30 // output conditions
31 protected $load_css = 'footer'; // [ footer, inline, external, element ]
32 protected $load_js = 'footer';
33
34 protected $cssParser = false;
35 protected $parsed_css = '';
36
37
38 /* Class constructor
39
40 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
41 */
42 function __construct()
43 {
44 maxUtils::addTime("Button construct");
45
46 // the parser
47
48 // get all files from blocks map
49
50 // get all blocks via apply filters, do init. Init should not load anything big.
51
52
53 $block_paths = apply_filters('mb-block-paths', array(MB()->get_plugin_path() . "blocks/") );
54
55 global $blockClass; // load requires only once
56
57 if ($blockClass == '' || count($blockClass) == 0)
58 {
59
60 $newBlocks = array();
61
62 foreach($block_paths as $block_path)
63 {
64 $dir_iterator = new RecursiveDirectoryIterator($block_path, FilesystemIterator::SKIP_DOTS);
65 $iterator = new RecursiveIteratorIterator($dir_iterator, RecursiveIteratorIterator::SELF_FIRST);
66
67 foreach ($iterator as $fileinfo)
68 {
69
70 $path = $fileinfo->getRealPath();
71 // THIS IS PHP > 5.3.6
72 //$extension = $fileinfo->getExtension();
73 $extension = pathinfo($path, PATHINFO_EXTENSION);
74
75 if ($fileinfo->isFile() )
76 {
77 if ($extension == 'php')
78 {
79 require_once($path);
80 }
81 elseif($extension == 'tpl')
82 {
83 $filename = $fileinfo->getBasename('.tpl');
84 $this->templates[$filename] = array('path' => $path);
85 }
86 }
87 }
88
89 }
90 ksort($blockOrder);
91 foreach($blockOrder as $prio => $blockArray)
92 {
93 foreach($blockArray as $block)
94 {
95 if (isset($blockClass[$block]))
96 $newBlocks[$block] = $blockClass[$block];
97
98 }
99 }
100 $blockClass = $newBlocks;
101 if (is_admin())
102 {
103 maxField::setTemplates($this->templates);
104 maxBlocks::init();
105 }
106 $this->loadBlockClasses($blockClass);
107
108
109
110 }
111
112 $this->blocks = array_keys($blockClass);
113 }
114
115 /* Makes overriding block features possible by subclass
116
117 */
118 private function loadBlockClasses($classes)
119 {
120 // set blocks to the 'block name' that survived.
121 maxUtils::addTime("Load Block classes");
122
123 $classes = apply_filters("mb_blockclassesload", $classes);
124
125
126 foreach($classes as $block => $class)
127 {
128 $block = new $class();
129 if (is_admin())
130 maxBlocks::add($block); // block collection.
131 }
132
133 do_action("mb_blockclassesloaded", $classes);
134
135 }
136
137 /** Simple function to retrieve loaded blocks - * Questionable if in use */
138 public function getDefinedBlocks()
139 {
140 return $this->blocks;
141 }
142
143 /** Get Data from Database and set variables
144 *
145 * You can pass either id or name to this function
146 *
147 * @return Boolean Returns false when no data was found using either ID or name
148 */
149 function set($id = 0, $name = '', $status = 'publish')
150 {
151 maxUtils::addTime("Button set $id");
152
153 $id = intval($id);
154 $name = sanitize_text_field($name);
155 $status = sanitize_text_field($status);
156
157 global $wpdb;
158 $this->clear(); // clear the internals of any previous work
159
160 // check to see if the value passed is NOT numeric. If it is, use title, else assume numeric
161 if($id == 0 && $name != '') {
162 $row = $wpdb->get_row($wpdb->prepare("SELECT * FROM " . maxUtils::get_table_name() . " WHERE name = '%s' and status ='%s'", trim($name), $status ), ARRAY_A);
163
164 } else {
165 $row = $wpdb->get_row($wpdb->prepare("SELECT * FROM " . maxUtils::get_table_name() . " WHERE id = %d and status ='%s'", $id, $status), ARRAY_A);
166 }
167
168 if (count($row) == 0)
169 {
170 return false;
171 }
172
173 /* Take the id from the query, otherwise ( when button shortcode called by name ) id might not be present properly' */
174 $button_id = $row["id"];
175 maxButtons::buttonLoad(array("button_id" => $button_id)); // central registration
176
177 return $this->setupData($row);
178
179 }
180 /** Clear button settings
181 *
182 * This function prevent that generated values from previous set actions will still be present.
183 */
184 function clear()
185 {
186 unset($this->data);
187 unset($this->button_css);
188 $this->id = 0; // clear id
189 $this->button_css = '';
190 $this->button_js = array();
191 $this->data = array();
192 $this->data = $this->save(array(),false);
193 $this->cache = '';
194 $this->button_loaded = false;
195 $this->reloadData();
196 }
197
198 function setupData($data)
199 {
200 maxUtils::addTime("Button: Setup data");
201 foreach($this->blocks as $block)
202 {
203
204 if (array_key_exists($block, $data)) // strangely isset doesn't work
205 {
206 $this->data[$block] = maybe_unserialize($data[$block]); // allow to feed unserialized stuff not from dbase
207 if (! is_array($this->data[$block]))
208 {
209 $this->data[$block] = json_decode($data[$block], true);
210 }
211
212 }
213 else
214 {
215 // else block does not exist in this dataset - ignoring.
216 //exit("Fatal: Something wrong with provider on $block ");
217 }
218 }
219
220 $this->id = $data["id"];
221 $this->document_id = maxButtons::getDocumentID(array("button_id" => $this->id));
222 $this->cache = isset($data["cache"]) ? trim($data["cache"]) : ''; // not set at button packs / non-dbase buttons!
223 $this->data["id"] = $this->id; // needed for certain blocks, to be button aware.
224 $this->data["document_id"] = $this->document_id; // bound to JS and others.
225 $this->name = $data["name"];
226 $this->status = $data["status"];
227 $this->description = $this->data["basic"]["description"];
228
229 do_action('mb-data-load', $this->data);
230
231 return true;
232
233 }
234
235 function get( )
236 {
237 return $this->data;
238
239 }
240
241 function getID()
242 {
243 return $this->id;
244 }
245 function getDocumentID()
246 {
247 return $this->document_id;
248 }
249 function getName()
250 {
251 return $this->name;
252 }
253 function getDescription()
254 {
255 return $this->description;
256 }
257
258 function getStatus()
259 {
260 return $this->status;
261 }
262
263 function getParsedCSS()
264 {
265 return $this->parsed_css;
266 }
267
268 function getCSSArray()
269 {
270
271 return $this->button_css;
272 }
273
274 function getCSSParser()
275 {
276 if (! $this->cssParser)
277 $this->cssParser = new maxCSSParser();
278
279 return $this->cssParser;
280 }
281 // get the cache
282 function getCache()
283 {
284 return $this->cache;
285 }
286
287 // modify the cache at own risk
288 function setCache($cache)
289 {
290 $this->cache = $cache;
291 }
292
293 function setData($blockname, $data )
294 {
295 foreach($data as $key => $value)
296 {
297 $this->data[$blockname][$key] = $value;
298
299 }
300 }
301
302 /* Tell all blocks to reload the daa
303
304 This function will tell all loaded blocks to reload it's data. This is needed when data is changed after the initial button load.
305
306 */
307 function reloadData()
308 {
309 do_action('mb-data-load', $this->data);
310
311 }
312
313 /* Parse CSS from the elements
314
315 @param string $mode [normal,preview,editor] - The view needed.
316 @param string $forceCompile Recompile the CSS in any case
317 */
318 function parse_css($mode = "normal", $forceCompile = false )
319 {
320 $css = $this->button_css;
321
322 if (isset($this->cache) && $this->cache != '' && ! $forceCompile)
323 {
324
325 $css = $this->cache;
326 // kill media queries from cache
327 if ($mode != 'normal')
328 {
329 $pattern = "/@media.*}/is";
330 preg_match($pattern, $css, $matches);
331 $css = preg_replace($pattern, '', $css);
332 }
333
334 maxUtils::addTime("Button: Cache loaded");
335 }
336 else
337 {
338 /* Internal filter, please don't use */
339 $css = apply_filters('mb-css-blocks', $css, $mode);
340
341 /* Filter the raw CSS array before compile
342
343 This filters passes an array with all CSS element before compile time. This should be CSS elements that can be understood by the CSS parser.
344 @since 4.20
345 @param $css CSS Array - split by element and pseudo (normal/hover)
346
347 */
348 $css = apply_filters('mb/button/rawcss', $css, $mode);
349
350 $this->button_css = $css;
351
352 $css = $this->getCSSParser()->parse($this->button_css);
353 $css = apply_filters('mb/button/compiledcss', $css, $mode); // the final result.
354
355 if ($mode == 'normal') // only in general mode, otherwise things go amiss.
356 $this->update_cache($css);
357
358 }
359
360 $this->parsed_css = $css;
361
362
363 return $css;
364 }
365
366 /* Call blocks for javascript
367
368 Function will call for all block element to crunch the required javascript for output ( if any )
369 @param string $mode [normal, preview, editor]
370
371 */
372 function parse_js($mode = "normal")
373 {
374 maxUtils::addTime("Button :: parse JS");
375 $js = $this->button_js;
376 $js = apply_filters('mb-js-blocks', $js, $mode);
377 $this->button_js = $js;
378 }
379
380 /* Parse the actual button
381
382 Function adds the basic button components, creates the DOM object for the button and asks all block elements to parse their additions.
383
384 @param string $mode [normal, preview, editor]
385 @return Object DomObj presentation of the button
386 */
387 function parse_button($mode = 'normal')
388 {
389 $name = $this->name;
390 // non-latin breaks CSS / ID's - so move to latin.
391 $name = maxUtils::translit($name);
392 $name = sanitize_title($name);
393
394 $classes = array("maxbutton-" . $this->id,
395 "maxbutton");
396 if ($name != '')
397 $classes[] = "maxbutton-" . $name;
398
399 $classes = apply_filters('mb-mainclasses', $classes);
400 $classes = implode(' ', $classes);
401
402 $domObj = new simple_html_dom();
403 $domObj->load('<a class="' . $classes . '"></a>');
404
405 $domObj = apply_filters('mb-parse-button', $domObj, $mode, $this->id);
406
407 $domObj->load($domObj->save());
408
409 $cssParser = $this->getCSSParser();
410 $cssParser->loadDom($domObj);
411
412 return $domObj;
413 }
414
415 /* Display all data and html to allow users to edit button settings */
416 public function admin_fields()
417 {
418 do_action('mb-admin-fields' );
419
420 }
421
422 /* Display the button */
423 public function display($args = array() )
424 {
425 maxUtils::startTime('button-display-'. $this->id);
426 $defaults = array(
427 "mode" => 'normal',
428 "preview_part" => "full",
429 "echo" => true,
430 "load_css" => "footer", // control how css is loaded.
431 "compile" => false, // possibility to force recompile if needed.
432 );
433 $output = ''; // init output;
434
435 $args = wp_parse_args($args, $defaults);
436
437 $cssParser = $this->getCSSParser(); // init parser
438
439 $this->load_css = $args["load_css"];
440
441 if ($this->id == 0) // if button doesn't exists don't display unless in editor
442 {
443 if (! $args["mode"] == 'editor' )
444 return;
445
446 $data = apply_filters("mb-save-fields", array(), array() ); // load defaults
447 $data["id"] = 0;
448 do_action('mb-data-load', $data);
449 }
450
451 $mode = (isset($args["mode"])) ? $args["mode"] : "normal";
452 switch($mode)
453 {
454 case "preview":
455 $preview = true;
456 $compile = false;
457 break;
458 case "editor":
459 $preview = true;
460 $compile = true;
461 // editor is both compile and preview.
462 break;
463 break;
464 case "normal":
465 $preview = false;
466 $compile = false;
467 break;
468 }
469
470
471 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.
472 $compile = true;
473
474 }
475 else
476 $compile = false;
477
478
479 $domObj = $this->parse_button($mode);
480
481 maxUtils::startTime('button-parse-css-'. $this->id);
482 $this->parse_css($mode, $compile);
483 maxUtils::endTime('button-parse-css-'. $this->id);
484
485 if (! $preview) // no js on previews
486 $this->parse_js($mode);
487
488 if ($preview) // mark it preview
489 {
490
491 $domObj->find('a',0)->class .= ' maxbutton-preview';
492 }
493
494 if ($preview && $args["preview_part"] != 'full')
495 {
496
497 if ($args["preview_part"] != 'normal')
498 {
499 $domObj->find('a',0)->class .= ' hover';
500 $domObj = $cssParser->outputInline($domObj,'hover');
501
502 }
503 else
504 {
505 $domObj->find('a',0)->class .= ' normal';
506 $domObj = $cssParser->outputInline($domObj);
507 }
508
509 }
510 elseif ($this->load_css == 'footer')
511 {
512 $css = $this->display_css(false, false);
513 do_action('mb-footer',$this->id, $css);
514
515 if (! $preview)
516 {
517 $js = $this->display_js(false, true);
518 do_action('mb-footer', $this->document_id, $js, 'js');
519 }
520 } elseif ($this->load_css == 'inline')
521 {
522 if ($args["echo"])
523 $this->display_css();
524 else
525 $output .= $this->display_css(false);
526 }
527 elseif ($this->load_css == 'element') // not possible to load both normal and hover to an element.
528 {
529 $domObj->find('a',0)->class .= ' normal';
530 $domObj = $this->cssParser->outputInline($domObj);
531 //$this->get_element_css($domObj, 'normal');
532 }
533
534
535 $output .= $domObj->save();
536
537 $output = apply_filters('mb-before-button-output', $output);
538 maxButtons::buttonDone(array("button_id" => $this->id, "document_id" => $this->document_id) );
539
540 maxUtils::endTime('button-display-'. $this->id);
541
542 if ($args["echo"])
543 echo $output;
544 else
545 return $output;
546
547 }
548 /* Function used to map field id's to display for Frontend Javascript
549
550 This function bundles all defined fields into a json encoded variable. This is used for the frontend javascript functions in the
551 administrator area like colorpickers and real-time updating of the button preview
552 */
553 public function display_field_map()
554 {
555 $map = array();
556 $map = apply_filters("mb-field-map",$map);
557
558
559 echo "<script language='javascript'>";
560 echo "var buttonFieldMap = '" . json_encode($map) . "';" ;
561 echo "</script>";
562
563 }
564
565 /* Write parsed CSS to output.
566 @param echo Default true. When true, outputs directly, otherwise returns output string
567 @param style_tag Default true. When true, outputs a html <style> tags around the output.
568 */
569 public function display_css($echo = true, $style_tag = true)
570 {
571 $output = '';
572
573 if ($style_tag)
574 $output .= "<style type='text/css'>";
575
576 $output .= $this->parsed_css;
577
578 if ($style_tag)
579 $output .= "</style>";
580
581
582 if ($echo) echo $output;
583 else return $output;
584
585 }
586
587 /* Output Parsed Javascripting */
588 public function display_js($echo = true, $tag = true)
589 {
590 $output = '';
591
592 if (count($this->button_js) == 0)
593 return; // no output, holiday
594
595 if ($tag)
596 {
597 $output .= "<script type='text/javascript'> ";
598 $output .= " if (typeof maxButton" . $this->document_id . " == 'undefined') { ";
599 $output .= " function maxButton" . $this->document_id . "() { ";
600 }
601
602 foreach($this->button_js as $index => $code)
603 {
604 $output .= $code;
605
606 }
607
608 if ($tag)
609 {
610 $output .= " }
611 }
612 window.onload = maxButton" . $this->document_id . "();
613 </script> ";
614 }
615
616 if ($echo) echo $output;
617 else return $output;
618 }
619
620
621 /* Makes a copy of the current buttons.
622
623 The button to be copied -must- be loaded and set
624 */
625 function copy()
626 {
627 $this->id = 0;
628 $data = $this->data;
629 $data["name"] = $this->name;
630
631 return $this->update($data);
632 }
633 /* Change the publication status of the button.
634
635 */
636 function setStatus($status = "publish")
637 {
638 $data = $this->data;
639 $data["status"] = sanitize_text_field($status);
640
641 return $this->update($data);
642
643 }
644 /* Remove the button from database */
645 public function delete($id)
646 {
647 global $wpdb;
648 $wpdb->query($wpdb->prepare("DELETE FROM " . maxUtils::get_table_name() . " WHERE id = %d", $id));
649 }
650
651 /* Save changes to the button
652
653 Updates or saves the button. Existing buttons must load their data and be set -first- or lose all not-passed data.
654
655 @param post Post data in field - value format (flat $_POST array)
656 @param boolean savedb if false do not save to database
657 */
658 public function save($post, $savedb = true)
659 {
660 $post = stripslashes_deep($post); // don't multiply slashes please.
661 $data = apply_filters('mb-save-fields',$this->data, $post);
662
663 if (! $savedb ) return $data;
664 return $this->update($data); // save to db.
665
666 }
667
668 /* Updates the button data to the database. Adds a button if it doesn't exist */
669 public function update($data)
670 {
671 global $wpdb;
672 $return = false;
673
674 $fields = array();
675 foreach($this->blocks as $block)
676 {
677 if (isset($data[$block]))
678 {
679 $blockData = $data[$block];
680 $fields[$block] = json_encode($blockData);
681 }
682 }
683 if (isset($data["name"])) { // other fields.
684 $fields["name"] = $data["name"];
685 }
686 if (isset($data["status"])) {
687 $fields["status"] = $data["status"];
688 }
689
690
691 $where = array('id' => $this->id );
692 if ($this->id > 0)
693 {
694 $where = array('id' => $this->id);
695 $where_format = array('%d');
696 $result = $wpdb->update(maxUtils::get_table_name(), $fields, $where, null, $where_format);
697 $return = true;
698 }
699 else
700 {
701 $fields['created'] = current_time('mysql',1);
702
703 $result = $wpdb->insert(maxUtils::get_table_name(), $fields);
704 $id = $wpdb->insert_id;
705
706 $this->id = $id;
707 $return = $id;
708
709 }
710
711
712 if ($result === false)
713 {
714 $error = "Database error " . $wpdb->last_error;
715 MB()->add_notice('error', $error);
716 $install = MB()->getClass("install");
717 $install::create_database_table(); // run dbdelta to try and fix.
718
719 }
720
721 // update the cache
722 $this->cache = ''; // empty cache
723 $result = $this->set($this->id); // set the newest values
724
725 if (! $result ) return false;
726
727 $this->display(array("echo" => false, "load_css" => "element")); // do display routing to compile.
728 $css = $this->parsed_css;
729 $this->update_cache($css);
730
731 return $return;
732 }
733
734 /* Updates the CSS cache. */
735 public function update_cache($css)
736 {
737 $return = false;
738 global $wpdb;
739
740 if ($this->id > 0)
741 {
742 $fields = array("cache" => $css);
743 $where = array('id' => $this->id);
744 $where_format = array('%d');
745 $wpdb->update(maxUtils::get_table_name(), $fields, $where, null, $where_format);
746 $return = true;
747
748 }
749 return $return;
750 }
751
752 // Resets all of the button caches.
753 public function reset_cache()
754 {
755 global $wpdb;
756 $fields = array("cache" => null);
757 $where = array(1 => 1);
758 //$where_format = array('%d');
759 $sql = "UPDATE " . maxUtils::get_table_name() . " SET cache = NULL ";
760 $wpdb->query($sql);
761
762 }
763
764
765 /* Display button via shortcode
766
767 Function that accepts WP shortcode arguments and displays or returns a button
768
769 @param $atts array Shortcode Atts
770 @return string HTML presentation of button
771
772 */
773 public function shortcode($atts)
774 {
775 extract(shortcode_atts(array(
776 'id' => '',
777 'name' => '',
778 'text' => '',
779 'url' => '',
780 'window' => '',
781 'nofollow' => '',
782 'nocache' => false,
783 'style' => 'footer',
784 'exclude' => ''
785
786 ), $atts));
787
788 $button_id = $id;
789 $button_name = $name;
790
791 if ($button_id > 0)
792 $result = $this->set($button_id);
793 elseif ($button_name != '')
794 $result = $this->set(0, $button_name);
795 else return; // no button id / name
796
797 /* Shortcode cache control
798
799 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!
800
801 @param boolean $nocache True / False
802 */
803 $compile = apply_filters("mb/shortcode/nocache", $nocache);
804
805 if (! $result)
806 return; // shortcode doesn't exist
807
808 // If we're not in the admin and the button is in the trash, just return nothing
809 if (!is_admin() && $this->status == 'trash') {
810 return '';
811 }
812 // Check to handle excludes
813 if ("{$exclude}" != '') {
814 global $post;
815
816 // Don't render the button if excluded from the current post/page
817 $exclude = explode(',', "{$exclude}");
818 if (in_array($post->ID, $exclude)) {
819 return '';
820 }
821 }
822
823 // Override shortcode options comparing to default button data.
824 $overrides = false;
825 if ($text != '')
826 {
827 $this->data["text"]["text"] = $text;
828 $overrides = true;
829 }
830 if ($url != '')
831 {
832
833 $this->data["basic"]["url"] = $url;
834 //$compile = true; // css change forces recompile
835 $overrides = true;
836 }
837 if ($window != '' && $window =='new')
838 {
839 $this->data["basic"]["new_window"] = 1;
840 $overrides = true;
841 }
842 if ($nofollow != '' && $nofollow == 'true')
843 {
844 $this->data["basic"]["nofollow"] = 1;
845 $overrides = true;
846 }
847
848 switch($style)
849 {
850 case "inline":
851 $load_css = 'inline';
852 break;
853 default:
854 $load_css = 'footer';
855 break;
856 }
857
858 // allow for more flexible changes and data manipulation.
859 $data = $this->data;
860 $this->data = $this->shortcode_overrides($this->data, $atts);
861 $this->data = apply_filters('mb/shortcode/data', $this->data, $atts);
862
863 if ($data !== $this->data)
864 {
865 $overrides = true;
866 }
867
868 if ($overrides)
869 {
870 do_action('mb-data-load', $this->data);
871 }
872 // if there are no reasons not to display; display
873 $args = array("echo" => false,
874 "load_css" => $load_css,
875 "compile" => $compile,
876 );
877 $args = apply_filters('mb_shortcode_display_args', $args);
878
879
880 $output = $this->display($args);
881
882 return $output;
883
884 }
885
886
887 public function shortcode_overrides($data, $atts)
888 {
889 return $data;
890 }
891
892 } // class
893
894