Advertisement
Guest User

template-builder.class.php?

a guest
Mar 20th, 2018
70
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 56.18 KB | None | 0 0
  1. <?php
  2. /**
  3. * Central Template builder class
  4. */
  5.  
  6. // Don't load directly
  7. if ( !defined('ABSPATH') ) { die('-1'); }
  8.  
  9. if ( !class_exists( 'AviaBuilder' ) ) {
  10.  
  11. class AviaBuilder
  12. {
  13. const VERSION = '0.9.5';
  14.  
  15. /**
  16. * Holds the instance of this class
  17. *
  18. * @since 4.2.1
  19. * @var AviaBuilder
  20. */
  21. static private $_instance = null;
  22.  
  23. /**
  24. *
  25. * @var string 'safe' | 'debug'
  26. */
  27. public static $mode = "";
  28.  
  29. public static $path = array();
  30. public static $resources_to_load = array();
  31. public static $default_iconfont = "";
  32. public static $full_el = array();
  33. public static $full_el_no_section = array();
  34.  
  35. /**
  36. *
  37. * @var array
  38. */
  39. public $paths;
  40.  
  41. /**
  42. * [Class name] => class
  43. *
  44. * @var array
  45. */
  46. public $shortcode_class;
  47.  
  48. /**
  49. * Back reference to class name of shortcode
  50. * [shortcode] => ClassName
  51. *
  52. * @since 4.2.1
  53. * @var array
  54. */
  55. public $shortcode;
  56.  
  57. /**
  58. * Back reference to shortcode for children (nested or layout_children)
  59. * The shortcode class must not exist. Needed to identify and repair the element structure
  60. *
  61. * child_shortcode => array( parent_shortcode, .... )
  62. *
  63. * @since 4.2.1
  64. * @var array
  65. */
  66. public $shortcode_parents;
  67.  
  68. /**
  69. *
  70. * @since 4.2.1
  71. * @var ShortcodeParser
  72. */
  73. protected $shortcode_parser;
  74.  
  75. /**
  76. * State of the selectbox in admin area for the post/page/...
  77. *
  78. * @since 4.2.1
  79. * @var string 'disabled' | 'check_only' | 'auto_repair'
  80. */
  81. protected $posts_shortcode_parser_state;
  82.  
  83.  
  84. /**
  85. * Tabs in backend for categorizing shortcode buttons in ALB
  86. *
  87. * @var array
  88. */
  89. public $tabs;
  90.  
  91.  
  92. /**
  93. * Backend ALB shortcode buttons
  94. *
  95. * @var array
  96. */
  97. public $shortcode_buttons;
  98.  
  99.  
  100. /**
  101. *
  102. * @var AviaSaveBuilderTemplate
  103. */
  104. public $builderTemplate;
  105.  
  106. /**
  107. *
  108. * @var boolean
  109. */
  110. public $disable_drag_drop;
  111.  
  112.  
  113. /**
  114. * Holds the status of the ALB for the current post
  115. *
  116. * @since 4.2.1
  117. * @var string 'active' | ''
  118. */
  119. protected $alb_builder_status;
  120.  
  121. /**
  122. * Stores the balanced post content of a non ALB post to allow building the shortcode tree
  123. *
  124. * @since 4.2.1
  125. * @var string
  126. */
  127. public $post_content;
  128.  
  129. /**
  130. * Revision post id to save our postmeta fields
  131. *
  132. * @since 4.2.1
  133. * @var int
  134. */
  135. protected $revision_id;
  136.  
  137.  
  138. /**
  139. * Flag if the ALB magic wand button had been added to tinyMCE buttons
  140. *
  141. * @since 4.2.4
  142. * @var boolean
  143. */
  144. protected $alb_magic_wand_button;
  145.  
  146.  
  147. /**
  148. * Flag to add the nonce input field on non alb supported pages that provide the ALB magic wand shortcode button
  149. *
  150. * @since 4.2.4
  151. * @var boolean
  152. */
  153. protected $alb_nonce_added;
  154.  
  155.  
  156. /**
  157. * Return the instance of this class
  158. *
  159. * @since 4.2.1
  160. * @return AviaBuilder
  161. */
  162. static public function instance()
  163. {
  164. if( is_null( AviaBuilder::$_instance ) )
  165. {
  166. AviaBuilder::$_instance = new AviaBuilder();
  167. }
  168.  
  169. return AviaBuilder::$_instance;
  170. }
  171.  
  172.  
  173. /**
  174. * Initializes plugin variables and sets up WordPress hooks/actions.
  175. *
  176. * @return void
  177. */
  178. protected function __construct()
  179. {
  180. $this->paths = array();
  181. $this->shortcode_class = array();
  182. $this->shortcode = array();
  183. $this->shortcode_parents = array();
  184. $this->shortcode_parser = null;
  185. $this->posts_shortcode_parser_state = '';
  186. $this->tabs = array();
  187. $this->shortcode_buttons = array();
  188. $this->builderTemplate = null;
  189. $this->disable_drag_drop = false;
  190. $this->alb_builder_status = 'unknown';
  191. $this->post_content = '';
  192. $this->revision_id = 0;
  193. $this->alb_magic_wand_button = false;
  194. $this->alb_nonce_added = false;
  195.  
  196. $this->paths['pluginPath'] = trailingslashit( dirname( dirname(__FILE__) ) );
  197. $this->paths['pluginDir'] = trailingslashit( basename( $this->paths['pluginPath'] ) );
  198. $this->paths['pluginUrlRoot'] = apply_filters('avia_builder_plugins_url', plugins_url().'/'.$this->paths['pluginDir']);
  199. $this->paths['pluginUrl'] = $this->paths['pluginUrlRoot'] . "avia-template-builder/";
  200. $this->paths['assetsURL'] = trailingslashit( $this->paths['pluginUrl'] ) . 'assets/';
  201. $this->paths['assetsPath'] = trailingslashit( $this->paths['pluginPath'] ) . 'assets/';
  202. $this->paths['imagesURL'] = trailingslashit( $this->paths['pluginUrl'] ) . 'images/';
  203. $this->paths['configPath'] = apply_filters('avia_builder_config_path', $this->paths['pluginPath'] .'config/');
  204.  
  205. AviaBuilder::$path = $this->paths;
  206. AviaBuilder::$default_iconfont = apply_filters('avf_default_iconfont', array( 'entypo-fontello' =>
  207. array(
  208. 'append' => '?v=3',
  209. 'include' => $this->paths['assetsPath'].'fonts',
  210. 'folder' => $this->paths['assetsURL'].'fonts',
  211. 'config' => 'charmap.php',
  212. 'compat' => 'charmap-compat.php', //needed to make the theme compatible with the old version of the font
  213. 'full_path' => 'true' //tells the script to not prepend the wp_upload dir path to these urls
  214. )
  215. ));
  216.  
  217. add_action('load-post.php', array(&$this, 'admin_init') , 5 );
  218. add_action('load-post-new.php', array(&$this, 'admin_init') , 5 );
  219.  
  220. add_action('init', array(&$this, 'loadLibraries') , 5 );
  221. add_action('init', array(&$this, 'init') , 10 );
  222.  
  223. //save and restore meta information if user restores a revision
  224. add_action('wp_creating_autosave', array( $this, 'avia_builder_creating_autosave'), 10, 1 );
  225. add_action('_wp_put_post_revision', array( $this, 'avia_builder_put_revision'), 10, 1 );
  226. add_action('wp_restore_post_revision', array(&$this, 'avia_builder_restore_revision'), 10, 2);
  227.  
  228. add_filter( 'avia_builder_metabox_filter', array( $this, 'handler_alb_metabox_filter'), 10, 1 );
  229.  
  230.  
  231. add_action('dbx_post_sidebar', array( $this, 'handler_wp_dbx_post_sidebar'), 10, 1 );
  232.  
  233. }
  234.  
  235. /**
  236. *
  237. * @since 4.2.1
  238. */
  239. public function __destruct()
  240. {
  241. unset( $this->paths );
  242. unset( $this->shortcode_class );
  243. unset( $this->shortcode );
  244. unset( $this->shortcode_parents );
  245. unset( $this->shortcode_parser );
  246. unset( $this->tabs );
  247. unset( $this->shortcode_buttons );
  248. unset( $this->builderTemplate );
  249. }
  250.  
  251.  
  252. /**
  253. * After all metaboxes have been added we check if hidden input field avia_nonce_loader had been set.
  254. * If not we have to add it. If user adds a shortcode (like tabs) with magic wand that need to call backend
  255. * check_ajax_referrer cannot proceed in backend because this value is missing
  256. *
  257. * @added_by Günter
  258. * @since 4.2.4
  259. * @param WP_Post $post
  260. */
  261. public function handler_wp_dbx_post_sidebar( WP_Post $post )
  262. {
  263. if( ! $this->alb_magic_wand_button )
  264. {
  265. return;
  266. }
  267.  
  268. if( ! $this->alb_nonce_added )
  269. {
  270. $nonce = wp_create_nonce ('avia_nonce_loader');
  271. echo '<input type="hidden" name="avia-loader-nonce" id="avia-loader-nonce" value="' . $nonce . '" />';
  272.  
  273. $this->alb_nonce_added = true;
  274. }
  275. }
  276.  
  277.  
  278. /**
  279. *Load all functions that are needed for both front and backend
  280. **/
  281. public function init()
  282. {
  283. if(isset($_GET['avia_mode']))
  284. {
  285. AviaBuilder::$mode = esc_attr($_GET['avia_mode']);
  286. }
  287.  
  288. $this->createShortcode();
  289.  
  290. $this->addActions();
  291. AviaStoragePost::generate_post_type();
  292.  
  293. //hook into the media uploader. we always need to call this for several hooks to be active
  294. new AviaMedia();
  295.  
  296. //on ajax call load the functions that are usually only loaded on new post and edit post screen
  297. if(AviaHelper::is_ajax())
  298. {
  299. if(empty( $_POST['avia_request'] )) return;
  300. $this->admin_init();
  301. }
  302.  
  303. //activate asset manager
  304. $this->asset_manager();
  305.  
  306. }
  307.  
  308.  
  309. /**
  310. *Load functions that are only needed on add/edit post screen
  311. **/
  312. public function admin_init()
  313. {
  314. $this->addAdminFilters();
  315. $this->addAdminActions();
  316. $this->loadTextDomain();
  317. $this->call_classes();
  318. $this->apply_editor_wrap();
  319. }
  320.  
  321. /**
  322. *Load all the required library files.
  323. **/
  324. public function loadLibraries()
  325. {
  326. require_once( $this->paths['pluginPath'].'php/pointer.class.php' );
  327. require_once( $this->paths['pluginPath'].'php/shortcode-helper.class.php' );
  328. require_once( $this->paths['pluginPath'].'php/shortcode-parser.class.php' );
  329. require_once( $this->paths['pluginPath'].'php/generic-helper.class.php' );
  330. require_once( $this->paths['pluginPath'].'php/html-helper.class.php' );
  331. require_once( $this->paths['pluginPath'].'php/meta-box.class.php' );
  332. require_once( $this->paths['pluginPath'].'php/shortcode-template.class.php' );
  333. require_once( $this->paths['pluginPath'].'php/media.class.php' );
  334. require_once( $this->paths['pluginPath'].'php/tiny-button.class.php' );
  335. require_once( $this->paths['pluginPath'].'php/save-buildertemplate.class.php' );
  336. require_once( $this->paths['pluginPath'].'php/storage-post.class.php' );
  337. require_once( $this->paths['pluginPath'].'php/font-manager.class.php' );
  338. require_once( $this->paths['pluginPath'].'php/asset-manager.class.php' );
  339.  
  340.  
  341. //autoload files in shortcodes folder and any other folders that were added by filter
  342. $folders = apply_filters('avia_load_shortcodes', array($this->paths['pluginPath'].'php/shortcodes/'));
  343. $this->autoloadLibraries($folders);
  344. }
  345.  
  346. /**
  347. * PHP include all files from a number of folders which are passed as an array
  348. * This auoloads all the shortcodes located in php/shortcodes and any other folders that were added by filter
  349. **/
  350. protected function autoloadLibraries($paths)
  351. {
  352. foreach ($paths as $path)
  353. {
  354. //include single files
  355. foreach(glob($path.'*.php') as $file)
  356. {
  357. require_once( $file );
  358. }
  359.  
  360. //include modules (eg files within folders with the same name)
  361. foreach(glob($path.'*', GLOB_ONLYDIR) as $folder)
  362. {
  363. $php_file = trailingslashit($folder) . basename($folder) . ".php";
  364.  
  365. if(file_exists( $php_file ))
  366. {
  367. include( $php_file );
  368. }
  369. }
  370. }
  371. }
  372.  
  373.  
  374. /**
  375. *Add filters to various wordpress filter hooks
  376. **/
  377. protected function addAdminFilters()
  378. {
  379. //lock drag and drop?
  380. $this->disable_drag_drop = apply_filters('avf_allow_drag_drop', false);
  381.  
  382. // add_filter('tiny_mce_before_init', array($this, 'tiny_mce_helper')); // remove span tags from tinymce - currently disabled, doesnt seem to be necessary
  383. add_filter( 'admin_body_class', array( $this, 'admin_body_class' ) );
  384. }
  385.  
  386. /**
  387. *Add Admin Actions to some wordpress action hooks
  388. **/
  389. protected function addAdminActions() {
  390.  
  391. add_action( 'admin_enqueue_scripts', array( $this, 'admin_scripts_styles' ) );
  392. add_action( 'admin_print_scripts', array($this,'load_shortcode_assets'), 2000);
  393. add_action( 'print_media_templates', array($this, 'js_template_editor_elements' )); //create js templates for AviaBuilder Canvas Elements
  394. add_action( 'avia_save_post_meta_box', array($this, 'meta_box_save' )); //hook into meta box saving and store the status of the template builder and the shortcodes that are used
  395.  
  396. add_filter( 'avf_before_save_alb_post_data', array( $this, 'handler_before_save_alb_post_data' ), 10, 2 ); // hook to balance shortcode for non ALB pages
  397.  
  398. //custom ajax actions
  399. add_action('wp_ajax_avia_ajax_text_to_interface', array($this,'text_to_interface'));
  400. add_action('wp_ajax_avia_ajax_text_to_preview', array($this,'text_to_preview'));
  401.  
  402. }
  403.  
  404.  
  405. /**
  406. *Add Actions for the frontend
  407. **/
  408. protected function addActions() {
  409.  
  410. // Enable shortcodes in widget areas
  411. add_filter('widget_text', 'do_shortcode');
  412.  
  413. //default wordpress hooking
  414. add_action('wp_head', array($this,'load_shortcode_assets'), 2000);
  415. add_filter( 'template_include' , array($this, 'template_include'), 2000);
  416. }
  417.  
  418. /**
  419. *Automatically load assests like fonts into your frontend
  420. **/
  421. public function load_shortcode_assets()
  422. {
  423. $output = "";
  424. $output .= avia_font_manager::load_font();
  425.  
  426. /* if the builder is decoupled from the theme then make sure to only load iconfonts if they are actually necessary. in enfolds case it is
  427.  
  428. foreach(AviaBuilder::$resources_to_load as $element)
  429. {
  430. if($element['type'] == 'iconfont')
  431. {
  432. $output .= avia_font_manager::load_font();
  433. }
  434. }
  435. */
  436.  
  437. echo $output;
  438.  
  439. //output preview css paths
  440. if(is_admin()) echo $this->load_preview_css( $output );
  441. }
  442.  
  443.  
  444. /**
  445. *load css and js files when in editable mode
  446. **/
  447. public function admin_scripts_styles()
  448. {
  449. $ver = AviaBuilder::VERSION;
  450.  
  451. #js
  452. wp_enqueue_script('avia_builder_js', $this->paths['assetsURL'].'js/avia-builder.js', array('jquery','jquery-ui-core', 'jquery-ui-sortable', 'jquery-ui-droppable','jquery-ui-datepicker','wp-color-picker','media-editor','post'), $ver, TRUE );
  453. wp_enqueue_script('avia_element_js' , $this->paths['assetsURL'].'js/avia-element-behavior.js' , array('avia_builder_js'), $ver, TRUE );
  454. wp_enqueue_script('avia_modal_js' , $this->paths['assetsURL'].'js/avia-modal.js' , array('jquery', 'avia_element_js', 'wp-color-picker'), $ver, TRUE );
  455. wp_enqueue_script('avia_history_js' , $this->paths['assetsURL'].'js/avia-history.js' , array('avia_element_js'), $ver, TRUE );
  456. wp_enqueue_script('avia_tooltip_js' , $this->paths['assetsURL'].'js/avia-tooltip.js' , array('avia_element_js'), $ver, TRUE );
  457.  
  458.  
  459. #css
  460. wp_enqueue_style( 'avia-modal-style' , $this->paths['assetsURL'].'css/avia-modal.css');
  461. wp_enqueue_style( 'avia-builder-style' , $this->paths['assetsURL'].'css/avia-builder.css');
  462. wp_enqueue_style( 'wp-color-picker' );
  463.  
  464. /**
  465. * @since 4.2.3 we support columns in rtl order (before they were ltr only). To be backward comp. with old sites use this filter.
  466. */
  467. if( is_rtl() && ( 'yes' == apply_filters( 'avf_rtl_column_support', 'yes' ) ) )
  468. {
  469. wp_enqueue_style( 'avia-builder-rtl-style' , $this->paths['assetsURL'].'css/avia-builder-rtl.css');
  470. }
  471.  
  472. #localize strings for javascript
  473. include_once($this->paths['configPath']."javascript_strings.php");
  474.  
  475. if(!empty($strings))
  476. {
  477. foreach($strings as $key => $string)
  478. {
  479. wp_localize_script( $key, str_replace('_js', '_L10n', $key), $string );
  480. }
  481. }
  482.  
  483.  
  484. }
  485.  
  486.  
  487. public function load_preview_css( $icon_font = "", $css = "" )
  488. {
  489. $output = "";
  490. $template_url = get_template_directory_uri();
  491. $child_theme_url = get_stylesheet_directory_uri();
  492. $avia_dyn_stylesheet_url = false;
  493. $ver = AviaBuilder::VERSION;
  494.  
  495. global $avia;
  496. $safe_name = avia_backend_safe_string($avia->base_data['prefix']);
  497. $safe_name = apply_filters('avf_dynamic_stylesheet_filename', $safe_name);
  498.  
  499. if( get_option('avia_stylesheet_exists'.$safe_name) == 'true' )
  500. {
  501. $avia_upload_dir = wp_upload_dir();
  502. if(is_ssl()) $avia_upload_dir['baseurl'] = str_replace("http://", "https://", $avia_upload_dir['baseurl']);
  503.  
  504. $avia_dyn_stylesheet_url = $avia_upload_dir['baseurl'] . '/dynamic_avia/'.$safe_name.'.css';
  505. }
  506.  
  507. $google_fonts = array(avia_get_option('google_webfont'), avia_get_option('default_font'));
  508.  
  509. foreach($google_fonts as $font)
  510. {
  511. $font_weight = "";
  512.  
  513. if(strpos($font, ":") !== false)
  514. {
  515. $data = explode(':',$font);
  516. $font = $data[0];
  517. $font_weight = $data[1];
  518. }
  519.  
  520. if(strpos($font, 'websave') === false)
  521. {
  522. $avia->style->add_google_font($font, $font_weight);
  523. }
  524. }
  525.  
  526. //if no user defined css is available load all the default frontend css
  527. if(empty($css))
  528. {
  529. $css = array(
  530.  
  531. includes_url('/js/mediaelement/mediaelementplayer-legacy.min.css') => 1,
  532. includes_url('/js/mediaelement/wp-mediaelement.css?ver=4.9.4') => 1,
  533.  
  534. $template_url."/css/grid.css" => 1,
  535. $template_url."/css/base.css" => 1,
  536. $template_url."/css/layout.css" => 1,
  537. $template_url."/css/shortcodes.css" => 1,
  538. $template_url."/js/aviapopup/magnific-popup.css" => 1,
  539. $template_url."/css/rtl.css" => is_rtl(),
  540. $child_theme_url."/style.css" => $template_url != $child_theme_url,
  541. );
  542.  
  543. // iterate over template builder modules and load the default css in there as well.
  544. // hakish approach that might need refinement if we improve the backend preview
  545. $path = trailingslashit (dirname( $this->paths['pluginPath'])) . "avia-shortcodes/";
  546.  
  547. foreach(glob($path.'*', GLOB_ONLYDIR) as $folder)
  548. {
  549. $css_file = trailingslashit($folder) . basename($folder) . ".css";
  550. $css_url = trailingslashit($this->paths['pluginUrlRoot']) . "avia-shortcodes/" . basename($folder) ."/". basename($folder) . ".css";
  551.  
  552. if(file_exists( $css_file ))
  553. {
  554. $css[ $css_url ] = 1;
  555. }
  556. }
  557.  
  558.  
  559. //custom user css, overwriting our styles
  560. $css[$template_url."/css/custom.css"] = 1;
  561. $css[$avia_dyn_stylesheet_url] = $avia_dyn_stylesheet_url;
  562. $css[$template_url."/css/admin-preview.css"] = 1;
  563.  
  564. $css = apply_filters('avf_preview_window_css_files' , $css );
  565. }
  566.  
  567. //module css
  568. if(is_array($css))
  569. {
  570. foreach($css as $url => $load)
  571. {
  572. if($load) $output .= "<link rel='stylesheet' href='".$url."?ver=".$ver."' type='text/css' media='all' />";
  573. }
  574. }
  575.  
  576. $output .= "<script type='text/javascript' src='".includes_url('/js/jquery/jquery.js')."?ver=".$ver."'></script>";
  577. $output .= "<script type='text/javascript' src='".$template_url."/js/avia-admin-preview.js?ver=".$ver."'></script>";
  578. $output .= $avia->style->link_google_font();
  579.  
  580.  
  581. $error = __('It seems you are currently adding some HTML markup or other special characters. Once all HTML tags are closed the preview will be available again. If this message persists please check your input for special characters and try to remove them.','avia_framework');
  582. $html = "<script type='text/javascript'>var avia_preview = " . json_encode( array( "error" => $error, "paths" => $output.$icon_font, 'title' => __('Element Preview','avia_framework') , 'background' => __('Set preview background:','avia_framework')) ) . "; \n";
  583. $html .= "</script>";
  584.  
  585. return $html;
  586. }
  587.  
  588. /**
  589. *multilanguage activation
  590. **/
  591. public function loadTextDomain()
  592. {
  593. load_plugin_textdomain( 'avia_framework', false, $this->paths['pluginDir'] . 'lang/');
  594. }
  595.  
  596. /**
  597. *safe mode or debugging
  598. **/
  599. public function setMode($status = "")
  600. {
  601. AviaBuilder::$mode = apply_filters('avia_builder_mode', $status);
  602. }
  603.  
  604.  
  605. /**
  606. * Returns the instance of ShortcodeParser
  607. *
  608. * @since 4.2.1
  609. * @return ShortcodeParser
  610. */
  611. public function get_shortcode_parser()
  612. {
  613. if( is_null( $this->shortcode_parser ) )
  614. {
  615. $this->shortcode_parser = new ShortcodeParser( $this->get_posts_shortcode_parser_state() );
  616. }
  617.  
  618. return $this->shortcode_parser;
  619. }
  620.  
  621. /**
  622. * Returns the state for the shortcode parser for the current or given post
  623. *
  624. * @since 4.2.1
  625. * @param int|null $post_id
  626. * @param string $default
  627. * @return string 'disabled' | 'check_only' | 'auto_repair'
  628. */
  629. public function get_posts_shortcode_parser_state( $post_id = null, $default = 'disabled' )
  630. {
  631.  
  632. if( is_null( $post_id ) || ! is_numeric( $post_id ) )
  633. {
  634. if( ! empty( $this->posts_shortcode_parser_state ) )
  635. {
  636. return $this->posts_shortcode_parser_state;
  637. }
  638.  
  639. $post_id = isset( $_POST['post_ID'] ) ? (int)$_POST['post_ID'] : get_the_ID();
  640. }
  641.  
  642. if( ! in_array( $default, array( 'disabled', 'check_only', 'auto_repair' ) ) )
  643. {
  644. $default = 'disabled';
  645. }
  646.  
  647. if( false !== $post_id )
  648. {
  649. $this->posts_shortcode_parser_state = get_post_meta( $post_id, '_avia_sc_parser_state', true );
  650. }
  651.  
  652. if( empty( $this->posts_shortcode_parser_state ) )
  653. {
  654. $this->posts_shortcode_parser_state = $default;
  655. }
  656.  
  657. return $this->posts_shortcode_parser_state;
  658. }
  659.  
  660.  
  661. /**
  662. * Updates the state for the shortcode parser for the current or given post and
  663. * returns the actual value stored in DB
  664. *
  665. * @since 4.2.1
  666. * @param string $state 'disabled' | 'check_only' | 'auto_repair'
  667. * @param int|null $post_id
  668. * @return string
  669. */
  670. public function set_posts_shortcode_parser_state( $state = '', $post_id = null )
  671. {
  672. if( ! in_array( $state, array( 'disabled', 'check_only', 'auto_repair' ) ) )
  673. {
  674. $state = 'check_only';
  675. }
  676.  
  677. $this->posts_shortcode_parser_state = $state;
  678.  
  679. if( is_null( $post_id ) || ! is_numeric( $post_id ) )
  680. {
  681. $post_id = isset( $_POST['post_ID'] ) ? (int)$_POST['post_ID'] : get_the_ID();
  682. }
  683.  
  684. if( false !== $post_id )
  685. {
  686. update_post_meta( $post_id, '_avia_sc_parser_state', $this->posts_shortcode_parser_state );
  687. }
  688.  
  689. return $this->posts_shortcode_parser_state;
  690. }
  691.  
  692. /**
  693. * Returns the state of the ALB for a given post id.
  694. * If null, checks for $_POST['aviaLayoutBuilder_active'] or the current post id.
  695. *
  696. * @since 4.2.1
  697. * @param int|null $post_id
  698. * @param string $default 'active' | ''
  699. * @return string
  700. */
  701. public function get_alb_builder_status( $post_id = null, $default = '' )
  702. {
  703. if( is_null( $post_id ) )
  704. {
  705. /**
  706. * Check if we are on an edit page
  707. */
  708. if( isset( $_POST['aviaLayoutBuilder_active'] ) )
  709. {
  710. $builder_status = $_POST['aviaLayoutBuilder_active'];
  711. if( ! in_array( $builder_status, array( 'active', '' ) ) )
  712. {
  713. $builder_status = $default;
  714. }
  715.  
  716. return $builder_status;
  717. }
  718.  
  719. /**
  720. * If set, return the saved value
  721. */
  722. if( 'unknown' != $this->alb_builder_status )
  723. {
  724. return $this->alb_builder_status;
  725. }
  726. }
  727.  
  728. $id = ! is_null( $post_id ) ? $post_id : get_the_ID();
  729.  
  730. if( false === $id )
  731. {
  732. return $default;
  733. }
  734.  
  735. $status = get_post_meta( $id, '_aviaLayoutBuilder_active', true );
  736.  
  737. /**
  738. * Allows to filter the status
  739. *
  740. * @used_by enfold\config-woocommerce\config.php 10
  741. */
  742. $status = apply_filters( 'avf_builder_active', $status, $id );
  743.  
  744. return $status;
  745. }
  746.  
  747. /**
  748. * Set the builder status for the current or a given post id
  749. *
  750. * @since 4.2.1
  751. * @param string $status 'active' | ''
  752. * @param int|null $post_id
  753. * @param string $default 'active' | ''
  754. * @return boolean
  755. */
  756. public function set_alb_builder_status( $status = '', $post_id = null, $default = '' )
  757. {
  758. if( ! in_array( $status, array( 'active', '' ) ) )
  759. {
  760. $status = $default;
  761. }
  762.  
  763. $id = ! is_null( $post_id ) ? $post_id : get_the_ID();
  764.  
  765. if( is_null( $post_id ) )
  766. {
  767. $this->alb_builder_status = $status;
  768. }
  769.  
  770. if( false === $id )
  771. {
  772. return false;
  773. }
  774.  
  775. update_post_meta( $id, '_aviaLayoutBuilder_active', $status );
  776.  
  777. return true;
  778. }
  779.  
  780. /**
  781. *set fullwidth elements that need to interact with section shortcode
  782. **/
  783. public function setFullwidthElements($elements = array())
  784. {
  785. $elements = apply_filters('avf_fwd_elements', $elements);
  786.  
  787. AviaBuilder::$full_el_no_section = $elements;
  788. AviaBuilder::$full_el = array_merge(array('av_section'), $elements);
  789. }
  790.  
  791.  
  792.  
  793. /**
  794. *calls external classes that are needed for the script to operate
  795. **/
  796. public function call_classes()
  797. {
  798. //create the meta boxes
  799. new MetaBoxBuilder($this->paths['configPath']);
  800.  
  801. // save button
  802. $this->builderTemplate = new AviaSaveBuilderTemplate($this);
  803.  
  804. //activate helper function hooks
  805. AviaHelper::backend();
  806.  
  807. //create tiny mce button
  808. $tiny = array(
  809. 'id' => 'avia_builder_button',
  810. 'title' => __('Insert Theme Shortcode','avia_framework' ),
  811. 'image' => $this->paths['imagesURL'].'tiny-button.png',
  812. 'js_plugin_file' => $this->paths['assetsURL'].'js/avia-tinymce-buttons.js',
  813. 'shortcodes' => array_map(array($this, 'fetch_configs'), $this->shortcode_class)
  814. );
  815.  
  816. //if we are using tinymce 4 or higher change the javascript file
  817. global $tinymce_version;
  818.  
  819. if(version_compare($tinymce_version[0], 4, ">="))
  820. {
  821. $tiny['js_plugin_file'] = $this->paths['assetsURL'].'js/avia-tinymce-buttons-4.js';
  822. }
  823.  
  824. new avia_tinyMCE_button($tiny);
  825. $this->alb_magic_wand_button = true;
  826.  
  827. //activate iconfont manager
  828. new avia_font_manager();
  829.  
  830. //fetch all Wordpress pointers that help the user to use the builder
  831. include($this->paths['configPath']."pointers.php");
  832. $myPointers = new AviaPointer($pointers);
  833. }
  834.  
  835.  
  836. public function asset_manager()
  837. {
  838. if(empty($this->asset_manager_class))
  839. {
  840. //activate asset_manager
  841. $this->asset_manager_class = new aviaAssetManager( $this );
  842. }
  843.  
  844. return $this->asset_manager_class;
  845. }
  846.  
  847.  
  848. /**
  849. *array mapping helper that returns the config arrays of a shortcode
  850. **/
  851.  
  852. public function fetch_configs($array)
  853. {
  854. return $array->config;
  855. }
  856.  
  857. /**
  858. *class that adds an extra class to the body if the builder is active
  859. **/
  860. public function admin_body_class($classes)
  861. {
  862. global $post_ID;
  863.  
  864. if(!empty($post_ID) && $this->get_alb_builder_status($post_ID))
  865. {
  866. $classes .= ' avia-advanced-editor-enabled ';
  867. }
  868.  
  869. if($this->disable_drag_drop == true)
  870. {
  871. $classes .= ' av-no-drag-drop ';
  872. }
  873.  
  874. /**
  875. * @since 4.2.3 we support columns in rtl order (before they were ltr only). To be backward comp. with old sites use this filter.
  876. */
  877. if( is_rtl() && ( 'yes' == apply_filters( 'avf_rtl_column_support', 'yes' ) ) )
  878. {
  879. $classes .= ' rtl ';
  880. }
  881.  
  882. return $classes;
  883. }
  884.  
  885.  
  886.  
  887. /**
  888. *automatically load all child classes of the aviaShortcodeTemplate class and create an instance
  889. **/
  890. public function createShortcode()
  891. {
  892. $children = array();
  893. foreach(get_declared_classes() as $class)
  894. {
  895. if(is_subclass_of($class, 'aviaShortcodeTemplate'))
  896. {
  897. $allow = false;
  898. $children[] = $class;
  899. $this->shortcode_class[$class] = new $class($this);
  900. $shortcode = $this->shortcode_class[$class]->config['shortcode'];
  901.  
  902. //check if the shortcode is allowed. if so init the shortcode, otherwise unset the item
  903. if( empty(ShortcodeHelper::$manually_allowed_shortcodes) && empty(ShortcodeHelper::$manually_disallowed_shortcodes) ) $allow = true;
  904. if( !$allow && !empty(ShortcodeHelper::$manually_allowed_shortcodes) && in_array($shortcode, ShortcodeHelper::$manually_allowed_shortcodes)) $allow = true;
  905. if( !$allow && !empty(ShortcodeHelper::$manually_disallowed_shortcodes) && !in_array($shortcode, ShortcodeHelper::$manually_disallowed_shortcodes)) $allow = true;
  906.  
  907.  
  908. if($allow)
  909. {
  910. $this->shortcode_class[$class]->init();
  911. $this->shortcode[$this->shortcode_class[$class]->config['shortcode']] = $class;
  912.  
  913. //save shortcode as allowed by default. if we only want to display the shortcode in tinymce remove it from the list but keep the class instance alive
  914. if(empty($this->shortcode_class[$class]->config['tinyMCE']['tiny_only']))
  915. {
  916. ShortcodeHelper::$allowed_shortcodes[] = $this->shortcode_class[$class]->config['shortcode'];
  917. }
  918.  
  919. //save nested shortcodes if they exist
  920. if(isset($this->shortcode_class[$class]->config['shortcode_nested']))
  921. {
  922. ShortcodeHelper::$nested_shortcodes = array_merge(ShortcodeHelper::$nested_shortcodes, $this->shortcode_class[$class]->config['shortcode_nested']);
  923. }
  924. }
  925. else
  926. {
  927. unset($this->shortcode_class[$class]);
  928. }
  929. }
  930. }
  931.  
  932. /**
  933. * Initialise reference to parent and children shortcode(s) so we know the default structure of the elements.
  934. * Nested shortcodes are merged with layout_children.
  935. */
  936. foreach( $this->shortcode_class as $class => &$sc )
  937. {
  938. $nested = isset( $sc->config['shortcode_nested'] ) && is_array( $sc->config['shortcode_nested'] ) ? $sc->config['shortcode_nested'] : array();
  939. $sc->config['layout_children'] = array_unique( array_merge( $nested, $sc->config['layout_children'] ) );
  940.  
  941. foreach( $sc->config['layout_children'] as $child_sc )
  942. {
  943. if( ! isset( $this->shortcode_parents[ $child_sc ] ) )
  944. {
  945. $this->shortcode_parents[ $child_sc ] = array();
  946. }
  947. $this->shortcode_parents[ $child_sc ][] = $sc->config['shortcode'];
  948. }
  949. }
  950.  
  951. unset( $sc );
  952. }
  953.  
  954. /**
  955. * Gets an opening or closing tag or a start fragment and returns the shortcode
  956. *
  957. * @since 4.2.1
  958. * @param type $tag
  959. * @return false|string
  960. */
  961. public function extract_shortcode_from_tag( $tag = '' )
  962. {
  963. if( empty( $tag) || ! is_string( $tag ) )
  964. {
  965. return false;
  966. }
  967.  
  968. $match = array();
  969.  
  970. $regex = '\[\/?([\w|-]+)'; // gets opening and closing tag till first space after tag
  971. preg_match_all( "/" . $regex . "/s", $tag, $match, PREG_OFFSET_CAPTURE );
  972.  
  973. if( empty( $match ) )
  974. {
  975. return false;
  976. }
  977.  
  978. return $match[1][0][0];
  979. }
  980.  
  981.  
  982. /**
  983. * Gets an opening or closing shortcode tag (or the beginning part of it, extracts the shortcode and returns the shortcode class
  984. *
  985. * @since 4.2.1
  986. * @param string $tag a valid shortcode tag
  987. * @return aviaShortcodeTemplate|false
  988. */
  989. public function get_sc_class_from_tag( $tag = '' )
  990. {
  991. $sc_name = $this->extract_shortcode_from_tag( $tag );
  992. if( false === $sc_name )
  993. {
  994. return false;
  995. }
  996.  
  997. return $this->get_shortcode_class( $sc_name );
  998. }
  999.  
  1000.  
  1001. /**
  1002. * Returns the shortcode class
  1003. *
  1004. * @since 4.2.1
  1005. * @param string $sc_name
  1006. * @return aviaShortcodeTemplate|false
  1007. */
  1008. public function get_shortcode_class( $sc_name )
  1009. {
  1010. return ( isset( $this->shortcode[ $sc_name ] ) && isset( $this->shortcode_class[ $this->shortcode[ $sc_name ] ] ) ) ? $this->shortcode_class[ $this->shortcode[ $sc_name ] ] : false;
  1011. }
  1012.  
  1013.  
  1014. /**
  1015. * Returns the array with the parents shortcodes
  1016. *
  1017. * @since 4.2.1
  1018. * @param string $tag
  1019. * @return array
  1020. */
  1021. public function get_sc_parents_from_tag( $tag = '' )
  1022. {
  1023. $sc_name = $this->extract_shortcode_from_tag( $tag );
  1024. if( false === $sc_name )
  1025. {
  1026. return array();
  1027. }
  1028.  
  1029. return ( isset( $this->shortcode_parents[ $sc_name ] ) ) ? $this->shortcode_parents[ $sc_name ] : array();
  1030. }
  1031.  
  1032.  
  1033. /**
  1034. *create JS templates
  1035. **/
  1036. public function js_template_editor_elements()
  1037. {
  1038. foreach($this->shortcode_class as $shortcode)
  1039. {
  1040. $class = $shortcode->config['php_class'];
  1041. $template = $this->shortcode_class[$class]->prepare_editor_element();
  1042.  
  1043. if(is_array($template)) continue;
  1044.  
  1045. echo "\n<script type='text/html' id='avia-tmpl-{$class}'>\n";
  1046. echo $template;
  1047. echo "\n</script>\n\n";
  1048. }
  1049.  
  1050. }
  1051.  
  1052.  
  1053. /**
  1054. * Balance the shortcode in the post content of a non ALB page
  1055. *
  1056. * @since 4.2.1
  1057. * @param array $data
  1058. * @param array $postarr
  1059. * @return array
  1060. */
  1061. public function handler_before_save_alb_post_data( array $data, array $postarr )
  1062. {
  1063. /**
  1064. * Get current ALB values and save to post meta
  1065. */
  1066. $builder_stat = $this->get_alb_builder_status();
  1067. $this->set_alb_builder_status( $builder_stat );
  1068.  
  1069. $parser_state = isset( $_POST['_avia_sc_parser_state'] ) ? $_POST['_avia_sc_parser_state'] : '';
  1070. $parser_state = $this->set_posts_shortcode_parser_state( $parser_state );
  1071.  
  1072.  
  1073. if( 'active' == $builder_stat )
  1074. {
  1075. return $data;
  1076. }
  1077.  
  1078. /**
  1079. * Normal pages we only balance the shortcodes but do not modify the otber content to keep all user stylings
  1080. */
  1081. $this->post_content = isset( $data['post_content'] ) ? trim( $data['post_content'] ) : '';
  1082. $this->get_shortcode_parser()->set_builder_save_location( 'content' );
  1083. $this->post_content = ShortcodeHelper::clean_up_shortcode( $this->post_content, 'balance_only' );
  1084. $data['post_content'] = $this->post_content;
  1085.  
  1086. return $data;
  1087. }
  1088.  
  1089. /**
  1090. * Remove Boxes not needed, e.g. Enfold Parser Metabox
  1091. *
  1092. * @since 4.2.1
  1093. * @param array $boxes
  1094. * @return array
  1095. */
  1096. public function handler_alb_metabox_filter( array $boxes )
  1097. {
  1098. $s = AviaBuilder::$mode;
  1099.  
  1100. if( 'debug' == AviaBuilder::$mode )
  1101. {
  1102. return $boxes;
  1103. }
  1104.  
  1105. foreach ( $boxes as $key => $box )
  1106. {
  1107. if( 'avia_sc_parser' == $box['id'] )
  1108. {
  1109. unset( $boxes[ $key ] );
  1110. }
  1111. }
  1112.  
  1113. $boxes = array_merge( $boxes );
  1114. return $boxes;
  1115. }
  1116.  
  1117. /**
  1118. * Save builder relevant data of the post in backend - $_POST['content'] has already been saved at this point.
  1119. *
  1120. * - Save status of builder (open/closed)
  1121. * - Save and balance shortcodes in _aviaLayoutBuilderCleanData
  1122. * - Create the shortcode tree
  1123. **/
  1124. public function meta_box_save()
  1125. {
  1126.  
  1127. if( isset( $_POST['post_ID'] ) )
  1128. {
  1129. /**
  1130. * New states have been saved already in handler_before_save_alb_post_data
  1131. */
  1132. $builder_stat = $this->get_alb_builder_status();
  1133. $parser_state = $this->get_posts_shortcode_parser_state();
  1134.  
  1135. /**
  1136. * Copy balanced shortcodes to content field so the shortcode tree can be built
  1137. *
  1138. */
  1139. if( 'active' == $builder_stat )
  1140. {
  1141. $this->get_shortcode_parser()->set_builder_save_location( 'content' );
  1142. if( isset( $_POST['_aviaLayoutBuilderCleanData'] ) )
  1143. {
  1144. $_POST['content'] = ShortcodeHelper::clean_up_shortcode( $_POST['_aviaLayoutBuilderCleanData'], 'content' );
  1145. }
  1146. else
  1147. {
  1148. /**
  1149. * _aviaLayoutBuilderCleanData should be set by default, so this is only a fallback
  1150. */
  1151. $_POST['content'] = ShortcodeHelper::clean_up_shortcode( $_POST['content'], 'content' );
  1152. }
  1153. }
  1154. else
  1155. {
  1156. $_POST['content'] = $this->post_content;
  1157. }
  1158.  
  1159. /**
  1160. * Save the hidden container and balance the shortcodes
  1161. */
  1162. if(isset($_POST['_aviaLayoutBuilderCleanData']))
  1163. {
  1164. $this->get_shortcode_parser()->set_builder_save_location( 'clean_data' );
  1165. update_post_meta( (int)$_POST['post_ID'], '_aviaLayoutBuilderCleanData', ShortcodeHelper::clean_up_shortcode( $_POST['_aviaLayoutBuilderCleanData'], 'balance_only' ) );
  1166. }
  1167.  
  1168.  
  1169. //extract all ALB shortcodes from the post array and store them so we know what we are dealing with when the user opens a page.
  1170. //usesfull for special elements that we might need to render outside of the default loop like fullscreen slideshows
  1171. // $matches = array();
  1172. // preg_match_all("/".ShortcodeHelper::get_fake_pattern()."/s", $_POST['content'], $matches, PREG_OFFSET_CAPTURE );
  1173.  
  1174.  
  1175. /**
  1176. * Extract all ALB shortcodes from the post array and store them so we know what we are dealing with when the user opens a page.
  1177. * Usesfull for special elements that we might need to render outside of the default loop like fullscreen slideshows.
  1178. *
  1179. * We always save this tree so we can be sure to have the correct state of the page when we load this post meta.
  1180. */
  1181. $tree = ShortcodeHelper::build_shortcode_tree( $_POST['content'] );
  1182. update_post_meta( (int) $_POST['post_ID'], '_avia_builder_shortcode_tree', $tree );
  1183.  
  1184. /**
  1185. * Now we can save the postmeta data to revision post
  1186. */
  1187. $this->save_alb_revision_data();
  1188. }
  1189. }
  1190.  
  1191.  
  1192.  
  1193. /**
  1194. *function that checks if a dynamic template exists and uses that template instead of the default page template
  1195. **/
  1196. public function template_include( $original_template )
  1197. {
  1198. global $avia_config;
  1199.  
  1200. $post_id = @get_the_ID();
  1201.  
  1202. if(is_feed()) return;
  1203.  
  1204. if(($post_id && is_singular()) || isset($avia_config['builder_redirect_id']))
  1205. {
  1206. if(!empty($avia_config['builder_redirect_id'])) $post_id = $avia_config['builder_redirect_id'];
  1207.  
  1208. ShortcodeHelper::$tree = get_post_meta($post_id, '_avia_builder_shortcode_tree', true);
  1209.  
  1210. $builder_template = locate_template( 'template-builder.php', false );
  1211.  
  1212. /**
  1213. * Redirect to default ALB template if we need to show parser debug info (implemented with default shortcode content)
  1214. */
  1215. if( isset( $_REQUEST['avia_alb_parser'] ) && ( 'show' == $_REQUEST['avia_alb_parser'] ) && ( '' != $builder_template ) )
  1216. {
  1217. $avia_config['conditionals']['is_builder'] = true;
  1218. $avia_config['conditionals']['is_builder_template'] = true;
  1219. return $builder_template;
  1220. }
  1221.  
  1222. if( ( 'active' == $this->get_alb_builder_status( $post_id ) ) && ( '' != $builder_template ) )
  1223. {
  1224. $avia_config['conditionals']['is_builder'] = true;
  1225.  
  1226. //only redirect if no custom template is set
  1227. $template_file = get_post_meta( $post_id, '_wp_page_template', true );
  1228.  
  1229. if( "default" == $template_file || empty( $template_file ) )
  1230. {
  1231. $avia_config['conditionals']['is_builder_template'] = true;
  1232. return $builder_template;
  1233. }
  1234. }
  1235. else
  1236. {
  1237. /**
  1238. * In case we are in preview mode we have to rebuild the shortcode tree so the user can see the real result of the page
  1239. */
  1240. if( is_preview() )
  1241. {
  1242. global $post;
  1243.  
  1244. /**
  1245. * If user views a preview we must use the content because WordPress doesn't update the post meta field
  1246. */
  1247. setup_postdata( $post );
  1248. $content = apply_filters( 'avia_builder_precompile', get_the_content() );
  1249.  
  1250. /**
  1251. * In preview we must update the shortcode tree to reflect the current page structure.
  1252. * Prior make sure that shortcodes are balanced and save this in post_content so we have
  1253. * the updated content when displaying the page.
  1254. */
  1255. $this->get_shortcode_parser()->set_builder_save_location( 'preview' );
  1256. $post->post_content = ShortcodeHelper::clean_up_shortcode( $content, 'balance_only' );
  1257. ShortcodeHelper::$tree = ShortcodeHelper::build_shortcode_tree( $post->post_content );
  1258. }
  1259. }
  1260.  
  1261. //if a custom page was passed and the template builder is not active redirect to the default page template
  1262. if(isset($avia_config['builder_redirect_id']))
  1263. {
  1264. if($template = locate_template('page.php', false))
  1265. {
  1266. return $template;
  1267. }
  1268. }
  1269. }
  1270.  
  1271. return $original_template;
  1272. }
  1273.  
  1274. public function apply_editor_wrap()
  1275. {
  1276. //fetch the config array
  1277. include($this->paths['configPath']."meta.php");
  1278.  
  1279. $slug = "";
  1280. $pages = array();
  1281. //check to which pages the avia builder is applied
  1282. foreach($elements as $element)
  1283. {
  1284. if(is_array($element['type']) && $element['type'][1] == 'visual_editor')
  1285. {
  1286. $slug = $element['slug']; break;
  1287. }
  1288. }
  1289.  
  1290. foreach($boxes as $box)
  1291. {
  1292. if($box['id'] == $slug)
  1293. {
  1294. $pages = $box['page'];
  1295. }
  1296. }
  1297. global $typenow;
  1298.  
  1299. if(!empty($pages) && in_array($typenow, $pages))
  1300. {
  1301. //html modification of the admin area: wrap
  1302. add_action( 'edit_form_after_title', array($this, 'wrap_default_editor' ), 100000);
  1303. add_action( 'edit_form_after_editor', array($this, 'close_default_editor_wrap' ), 1);
  1304. }
  1305. }
  1306.  
  1307.  
  1308. public function wrap_default_editor()
  1309. {
  1310. global $post_ID;
  1311.  
  1312. $status = $this->get_alb_builder_status( $post_ID );
  1313. $params = apply_filters('avf_builder_button_params',
  1314. array( 'disabled' =>false,
  1315. 'note' => "",
  1316. 'noteclass' => "",
  1317. 'button_class' =>'',
  1318. 'visual_label' => __( 'Advanced Layout Editor', 'avia_framework' ),
  1319. 'default_label' => __( 'Default Editor', 'avia_framework' )
  1320. )
  1321. );
  1322.  
  1323.  
  1324. if($params['disabled']) { $status = false; }
  1325. $active_builder = $status == "active" ? $params['default_label'] : $params['visual_label'];
  1326. $editor_class = $status == "active" ? "class='avia-hidden-editor'" : "";
  1327. $button_class = $status == "active" ? "avia-builder-active" : "";
  1328.  
  1329.  
  1330.  
  1331. echo "<div id='postdivrich_wrap' {$editor_class}>";
  1332.  
  1333. if($this->disable_drag_drop == false)
  1334. {
  1335. echo '<a id="avia-builder-button" href="#" class="avia-builder-button button-primary '.$button_class.' '.$params['button_class'].'" data-active-button="'.$params['default_label'].'" data-inactive-button="'.$params['visual_label'].'">'.$active_builder.'</a>';
  1336. }
  1337. if($params['note']) echo "<div class='av-builder-note ".$params['noteclass']."'>".$params['note']."</div>";
  1338. }
  1339.  
  1340. public function close_default_editor_wrap()
  1341. {
  1342. echo "</div>";
  1343. }
  1344.  
  1345.  
  1346. /**
  1347. * function called by the metabox class that creates the interface in your wordpress backend
  1348. **/
  1349. public function visual_editor($element)
  1350. {
  1351. $output = "";
  1352. $title = "";
  1353. $i = 0;
  1354.  
  1355. $this->shortcode_buttons = apply_filters('avia_show_shortcode_button', array());
  1356.  
  1357.  
  1358. if(!empty($this->shortcode_buttons) && $this->disable_drag_drop == false)
  1359. {
  1360. $this->tabs = isset($element['tab_order']) ? array_flip($element['tab_order']) : array();
  1361. foreach($this->tabs as &$empty_tabs) $empty_tabs = array();
  1362.  
  1363.  
  1364. foreach ($this->shortcode_buttons as $shortcode)
  1365. {
  1366. if(empty($shortcode['tinyMCE']['tiny_only']))
  1367. {
  1368. if(!isset($shortcode['tab'])) $shortcode['tab'] = __("Custom Elements",'avia_framework' );
  1369.  
  1370. $this->tabs[$shortcode['tab']][] = $shortcode;
  1371. }
  1372. }
  1373.  
  1374. foreach($this->tabs as $key => $tab)
  1375. {
  1376. if(empty($tab)) continue;
  1377.  
  1378. usort($tab,array($this, 'sortByOrder'));
  1379.  
  1380. $i ++;
  1381. $title .= "<a href='#avia-tab-$i'>".$key."</a>";
  1382.  
  1383. $output .= "<div class='avia-tab avia-tab-$i'>";
  1384.  
  1385. foreach ($tab as $shortcode)
  1386. {
  1387. if(empty($shortcode['invisible']))
  1388. {
  1389. $output .= $this->create_shortcode_button($shortcode);
  1390. }
  1391. }
  1392.  
  1393. $output .= "</div>";
  1394. }
  1395. }
  1396.  
  1397. global $post_ID;
  1398. $active_builder = $this->get_alb_builder_status( $post_ID );
  1399.  
  1400.  
  1401. $extra = AviaBuilder::$mode != true ? "" : "avia_mode_".AviaBuilder::$mode;
  1402. $hotekey_info = htmlentities($element['desc'], ENT_QUOTES, get_bloginfo( 'charset' ));
  1403.  
  1404. $output = '<div class="shortcode_button_wrap avia-tab-container"><div class="avia-tab-title-container">'.$title.'</div>'.$output.'</div>';
  1405. $output .= '<input type="hidden" value="'.$active_builder.'" name="aviaLayoutBuilder_active" id="aviaLayoutBuilder_active" />';
  1406.  
  1407. if($this->disable_drag_drop == false)
  1408. {
  1409. $output .= '<a href="#info" class="avia-hotkey-info" data-avia-help-tooltip="'.$hotekey_info.'">'.__('Information', 'avia_framework' ).'</a>';
  1410. $output .= $this->builderTemplate->create_save_button();
  1411. }
  1412.  
  1413. $output .= "<div class='layout-builder-wrap {$extra}'>";
  1414.  
  1415. if($this->disable_drag_drop == false)
  1416. {
  1417. $output .= " <div class='avia-controll-bar'></div>";
  1418. }
  1419.  
  1420. $output .= " <div id='aviaLayoutBuilder' class='avia-style avia_layout_builder avia_connect_sort preloading av_drop' data-dragdrop-level='0'>";
  1421. $output .= " </div>";
  1422.  
  1423.  
  1424. $clean_data = get_post_meta($post_ID, '_aviaLayoutBuilderCleanData', true);
  1425. // $clean_data = htmlentities($clean_data, ENT_QUOTES, get_bloginfo( 'charset' )); //entity-test: added htmlentities
  1426.  
  1427.  
  1428. $output .= " <textarea id='_aviaLayoutBuilderCleanData' name='_aviaLayoutBuilderCleanData'>".$clean_data."</textarea>";
  1429. $nonce = wp_create_nonce ('avia_nonce_loader');
  1430. $output .= ' <input type="hidden" name="avia-loader-nonce" id="avia-loader-nonce" value="'.$nonce.'" />';
  1431. $output .= "</div>";
  1432.  
  1433. $this->alb_nonce_added = true;
  1434.  
  1435. return $output;
  1436. }
  1437.  
  1438. /**
  1439. * Function called by the metabox class that creates the interface in your wordpress backend -
  1440. * Output the Shordcode Parser Select and Info Panel below the normal Texteditor and above the ALB Editor
  1441. *
  1442. * @since 4.2.1
  1443. * @param array $element
  1444. * @return string
  1445. */
  1446. public function parser_select_panel( $element )
  1447. {
  1448. global $post_ID;
  1449.  
  1450. $parser_state = $this->get_posts_shortcode_parser_state();
  1451. $link = get_permalink( $post_ID );
  1452.  
  1453. $args = array( 'avia_alb_parser' => 'show' );
  1454. $link = add_query_arg( $args, $link );
  1455.  
  1456.  
  1457. $out = '';
  1458. $out .= '<div class="avia-builder-parser-section">';
  1459. // $out .= '<div class="avia-builder-parser-label">';
  1460. // $out .= '<label for="av_select_sc_parser">';
  1461. // $out .= __( 'Enfold Shortcode Parser:', 'avia_framework' );
  1462. // $out .= '</label>';
  1463. // $out .= '</div>';
  1464. $out .= '<div class="avia-builder-parser-select avia-form-element avia-style">';
  1465. $out .= '<select id="av_select_sc_parser" name="_avia_sc_parser_state" class="avia-style">';
  1466. $out .= '<option value="disabled" ' . selected( 'disabled', $parser_state, false ) . '>' . __( 'Disabled - No checks are done on update', 'avia_framework' ) . '</option>';
  1467. $out .= '<option value="check_only" ' . selected( 'check_only', $parser_state, false ) . '>' . __( 'Check enabled on update - checks the structure only', 'avia_framework' ) . '</option>';
  1468. $out .= '<option value="auto_repair" ' . selected( 'auto_repair', $parser_state, false ) . '>' . __( 'Auto Repair Function enabled - Repairs errors in shortcode structure during update', 'avia_framework' ) . '</option>';
  1469. $out .= '</select>';
  1470. $out .= '</div>';
  1471. $out .= '<div class="avia-builder-parser-info-button">';
  1472. $out .= '<a href="' . $link . '" class="button-primary" target="_blank">' . __( 'Show Parser Info', 'avia_framework') . '</a>';
  1473. $out .= '</div>';
  1474. $out .= '<div class="avia-builder-parser-message">';
  1475. $out .= $this->get_shortcode_parser()->display_dashboard_info();
  1476. $out .= '</div>';
  1477. $out .= '</div>';
  1478.  
  1479. return $out;
  1480. }
  1481.  
  1482.  
  1483. /*create a shortcode button*/
  1484. protected function create_shortcode_button($shortcode)
  1485. {
  1486. $class = "";
  1487.  
  1488. if(!empty($shortcode['posttype']) && $shortcode['posttype'][0] != AviaHelper::backend_post_type())
  1489. {
  1490. $shortcode['tooltip'] = $shortcode['posttype'][1];
  1491. $class .= "av-shortcode-disabled ";
  1492. }
  1493.  
  1494.  
  1495. $icon = isset($shortcode['icon']) ? '<img src="'.$shortcode['icon'].'" alt="'.$shortcode['name'].'" />' : "";
  1496. $data = !empty($shortcode['tooltip']) ? " data-avia-tooltip='".$shortcode['tooltip']."' " : "";
  1497. $data .= !empty($shortcode['drag-level']) ? " data-dragdrop-level='".$shortcode['drag-level']."' " : "";
  1498. $class .= isset($shortcode['class']) ? $shortcode['class'] : "";
  1499. $class .= !empty($shortcode['target']) ? " ".$shortcode['target'] : "";
  1500.  
  1501.  
  1502.  
  1503.  
  1504.  
  1505. $link = "";
  1506. $link .= "<a {$data} href='#".$shortcode['php_class']."' class='shortcode_insert_button ".$class."' >".$icon.'<span>'.$shortcode['name']."</span></a>";
  1507.  
  1508. return $link;
  1509. }
  1510.  
  1511.  
  1512. /*helper function to sort the shortcode buttons*/
  1513. protected function sortByOrder($a, $b)
  1514. {
  1515. if(empty($a['order'])) $a['order'] = 10;
  1516. if(empty($b['order'])) $b['order'] = 10;
  1517.  
  1518. return $b['order'] >= $a['order'];
  1519. }
  1520.  
  1521.  
  1522.  
  1523.  
  1524. public function text_to_interface($text = NULL)
  1525. {
  1526. if(!current_user_can('edit_posts')) die();
  1527. if(isset($_REQUEST['params']['_ajax_nonce'])) $_REQUEST['_ajax_nonce'] = $_REQUEST['params']['_ajax_nonce'];
  1528.  
  1529. check_ajax_referer('avia_nonce_loader', '_ajax_nonce' );
  1530.  
  1531. global $shortcode_tags;
  1532.  
  1533. $allowed = false;
  1534.  
  1535. if(isset($_POST['text'])) $text = $_POST['text']; //isset when avia_ajax_text_to_interface is executed (avia_builder.js)
  1536. if(isset($_POST['params']) && isset($_POST['params']['allowed'])) $allowed = explode(',',$_POST['params']['allowed']); //only build pattern with a subset of shortcodes
  1537.  
  1538. //build the shortcode pattern to check if the text that we want to check uses any of the builder shortcodes
  1539. ShortcodeHelper::build_pattern($allowed);
  1540. $text_nodes = preg_split("/".ShortcodeHelper::$pattern."/s", $text);
  1541.  
  1542.  
  1543. foreach( $text_nodes as $node )
  1544. {
  1545. if( strlen( trim( $node ) ) == 0 || strlen( trim( strip_tags( $node) ) ) == 0)
  1546. {
  1547. //$text = preg_replace("/(".preg_quote($node, '/')."(?!\[\/))/", '', $text);
  1548. }
  1549. else
  1550. {
  1551. $text = preg_replace("/(".preg_quote($node, '/')."(?!\[\/))/", '[av_textblock]$1[/av_textblock]', $text);
  1552. }
  1553. }
  1554.  
  1555. $text = $this->do_shortcode_backend($text);
  1556.  
  1557. if(isset($_POST['text']))
  1558. {
  1559. echo $text;
  1560. exit();
  1561. }
  1562. else
  1563. {
  1564. return $text;
  1565. }
  1566. }
  1567.  
  1568. public function text_to_preview($text = NULL)
  1569. {
  1570. if(!current_user_can('edit_posts')) die();
  1571. check_ajax_referer('avia_nonce_loader', '_ajax_nonce' );
  1572.  
  1573. $text = "";
  1574. if(isset($_POST['text'])) $text = stripslashes( $_POST['text'] );
  1575.  
  1576. $text = do_shortcode($text);
  1577. echo $text;
  1578. exit();
  1579.  
  1580. }
  1581.  
  1582.  
  1583.  
  1584. public function do_shortcode_backend($text)
  1585. {
  1586. return preg_replace_callback( "/".ShortcodeHelper::$pattern."/s", array($this, 'do_shortcode_tag'), $text );
  1587. }
  1588.  
  1589.  
  1590. public function do_shortcode_tag( $m )
  1591. {
  1592. global $shortcode_tags;
  1593.  
  1594. // allow [[foo]] syntax for escaping a tag
  1595. if ( $m[1] == '[' && $m[6] == ']' ) {
  1596. return substr($m[0], 1, -1);
  1597. }
  1598.  
  1599. //check for enclosing tag or self closing
  1600. $values['closing'] = strpos($m[0], '[/'.$m[2].']');
  1601. $values['content'] = $values['closing'] !== false ? $m[5] : NULL;
  1602. $values['tag'] = $m[2];
  1603. $values['attr'] = shortcode_parse_atts( stripslashes($m[3]) );
  1604.  
  1605.  
  1606.  
  1607.  
  1608. if(is_array($values['attr']))
  1609. {
  1610. $charset = get_bloginfo( 'charset' );
  1611. foreach($values['attr'] as &$attr)
  1612. {
  1613. $attr = htmlentities($attr, ENT_QUOTES, $charset);
  1614. }
  1615. }
  1616. else
  1617. {
  1618. $values['attr'] = array();
  1619. }
  1620.  
  1621.  
  1622.  
  1623. if(isset($_POST['params']['extract']))
  1624. {
  1625. //if we open a modal window also check for nested shortcodes
  1626. if($values['content']) $values['content'] = $this->do_shortcode_backend($values['content']);
  1627.  
  1628. $_POST['extracted_shortcode'][] = $values;
  1629.  
  1630. return $m[0];
  1631. }
  1632.  
  1633. if(in_array($values['tag'], ShortcodeHelper::$allowed_shortcodes))
  1634. {
  1635. return $this->shortcode_class[$this->shortcode[$values['tag']]]->prepare_editor_element( $values['content'], $values['attr'] );
  1636. }
  1637. else
  1638. {
  1639. return $m[0];
  1640. }
  1641. }
  1642.  
  1643.  
  1644.  
  1645. /**
  1646. * this helper function tells the tiny_mce_editor to remove any span tags that dont have a classname (list insert on ajax tinymce tend do add them)
  1647. * see more: http://martinsikora.com/how-to-make-tinymce-to-output-clean-html
  1648. */
  1649.  
  1650. public function tiny_mce_helper($mceInit)
  1651. {
  1652. $mceInit['extended_valid_elements'] = empty($mceInit['extended_valid_elements']) ? "" : $mceInit['extended_valid_elements'] .",";
  1653. $mceInit['extended_valid_elements'] = "span[!class]";
  1654. return $mceInit;
  1655. }
  1656.  
  1657. /**
  1658. * Return the postmeta metakey names
  1659. *
  1660. * @since 4.2.1
  1661. * @return array
  1662. */
  1663. public function get_alb_meta_key_names()
  1664. {
  1665. $meta_keys = array(
  1666. '_aviaLayoutBuilder_active',
  1667. '_aviaLayoutBuilderCleanData',
  1668. '_avia_builder_shortcode_tree',
  1669. '_alb_shortcode_status_content',
  1670. '_alb_shortcode_status_clean_data',
  1671. '_alb_shortcode_status_preview'
  1672. );
  1673.  
  1674. /**
  1675. * @used_by currently unused
  1676. *
  1677. * @since 4.2.1
  1678. */
  1679. $meta_keys = apply_filters( 'avf_alb_meta_field_names', $meta_keys );
  1680.  
  1681. if( ! is_array( $meta_keys) )
  1682. {
  1683. $meta_keys = array();
  1684. }
  1685.  
  1686. return $meta_keys;
  1687. }
  1688.  
  1689.  
  1690. /**
  1691. * Helper function that restores the post meta if user restores a revision
  1692. * see: https://lud.icro.us/post-meta-revisions-wordpress
  1693. */
  1694. public function avia_builder_restore_revision( $post_id, $revision_id )
  1695. {
  1696.  
  1697. $meta_fields = $this->get_alb_meta_key_names();
  1698.  
  1699. foreach( $meta_fields as $meta_field )
  1700. {
  1701. $builder_meta_data = get_metadata( 'post', $revision_id, $meta_field, true );
  1702.  
  1703. if ( ! empty( $builder_meta_data ) )
  1704. {
  1705. update_post_meta( $post_id, $meta_field, $builder_meta_data );
  1706. }
  1707. else
  1708. {
  1709. delete_post_meta( $post_id, $meta_field );
  1710. }
  1711. }
  1712. }
  1713.  
  1714.  
  1715. /**
  1716. * An autosave post is being updated
  1717. *
  1718. * @since 4.2.5
  1719. * @added_by Günter
  1720. * @param array $post
  1721. */
  1722. public function avia_builder_creating_autosave( array $post )
  1723. {
  1724. if( ! isset( $_REQUEST['aviaLayoutBuilder_active'] ) )
  1725. {
  1726. return;
  1727. }
  1728.  
  1729. $this->revision_id = $post['ID'];
  1730.  
  1731. $this->do_alb_autosave( stripslashes( $post['post_content'] ) );
  1732. }
  1733.  
  1734. /**
  1735. * A revision or a new autosave is created
  1736. *
  1737. * @since 4.2.1
  1738. * @added_by Günter
  1739. * @param int $revision_id
  1740. */
  1741. public function avia_builder_put_revision( $revision_id )
  1742. {
  1743. if( ! isset( $_REQUEST['aviaLayoutBuilder_active'] ) )
  1744. {
  1745. return;
  1746. }
  1747.  
  1748. $this->revision_id = $revision_id;
  1749.  
  1750. if( isset( $_POST['content'] ) )
  1751. {
  1752. $this->do_alb_autosave( $_POST['content'] );
  1753. }
  1754. }
  1755.  
  1756. /**
  1757. * Create default revision entries for autosave or preview
  1758. *
  1759. * @since 4.2.5
  1760. * @added_by Günter
  1761. * @param string $content
  1762. */
  1763. protected function do_alb_autosave( $content )
  1764. {
  1765. /**
  1766. * Copy all metadata from original post
  1767. */
  1768. $this->save_alb_revision_data();
  1769.  
  1770.  
  1771. /**
  1772. * Now we need to update the internal data to reflect new situation as we are in an autosave
  1773. * or preview (which saves the content to the only autosave post)
  1774. */
  1775. $tree = ShortcodeHelper::build_shortcode_tree( $content );
  1776.  
  1777. update_metadata( 'post', $this->revision_id, '_aviaLayoutBuilder_active', $_REQUEST['aviaLayoutBuilder_active'] );
  1778. update_metadata( 'post', $this->revision_id, '_aviaLayoutBuilderCleanData', $content );
  1779. update_metadata( 'post', $this->revision_id, '_avia_builder_shortcode_tree', $tree );
  1780. }
  1781.  
  1782.  
  1783.  
  1784. /**
  1785. * A revision had been saved and we have updated our internal data -
  1786. * now save our meta data to restore when user reverts to a revision
  1787. *
  1788. * @since 4.2.1
  1789. */
  1790. protected function save_alb_revision_data()
  1791. {
  1792. if( $this->revision_id <= 0 )
  1793. {
  1794. return;
  1795. }
  1796.  
  1797. $post_id = get_the_ID();
  1798.  
  1799. if( false === $post_id )
  1800. {
  1801. return;
  1802. }
  1803.  
  1804. $meta_fields = $this->get_alb_meta_key_names();
  1805.  
  1806. foreach( $meta_fields as $meta_field )
  1807. {
  1808. $builder_meta_data = get_post_meta( $post_id, $meta_field, true );
  1809.  
  1810. if ( ! empty( $builder_meta_data ) )
  1811. {
  1812. update_metadata( 'post', $this->revision_id, $meta_field, $builder_meta_data );
  1813. }
  1814. }
  1815. }
  1816.  
  1817. } // end class
  1818.  
  1819. /**
  1820. * Returns the main instance of Avia_Support to prevent the need to use globals
  1821. *
  1822. * @since 4.2.1
  1823. * @return AviaBuilder
  1824. */
  1825. function Avia_Builder()
  1826. {
  1827. return AviaBuilder::instance();
  1828. }
  1829.  
  1830. } // end if !class_exists
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement