Advertisement
Guest User

Untitled

a guest
Aug 16th, 2018
23
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 31.04 KB | None | 0 0
  1. <?php
  2. /**
  3. * The ALB Element Manager class handles information about usage of elements in posts and other additional info needed about the elements.
  4. *
  5. * In a first step it handles shortcodes in ALB and non ALB pages, but will also handle oncoming implementations of ALB elements.
  6. *
  7. * @author Günter
  8. * @since 4.3
  9. */
  10.  
  11. if ( ! defined( 'ABSPATH' ) ) { exit; } // Exit if accessed directly
  12.  
  13.  
  14. if( ! class_exists( 'aviaElementManager' ) )
  15. {
  16.  
  17. class aviaElementManager
  18. {
  19. const VERSION = '1.0.1'; // Main version - needed to check for main global updates
  20. const USAGE_VERSION = '1.0'; // Stored data structure version - change for minor updates only
  21. const USAGE_PREFIX = 'av_alb_usage_';
  22. const ELEMENT_UID = 'av_uid'; // unique ID attribute key used in shortcode (or jsoin datastructure later)
  23.  
  24. /**
  25. * Accumulate added id's used as prefix
  26. *
  27. * @since 4.3
  28. * @var int
  29. */
  30. static private $added_uid = 1;
  31.  
  32.  
  33. /**
  34. *
  35. * @since 4.3
  36. * @var array
  37. */
  38. protected $registered_alb_elements;
  39.  
  40. /**
  41. * Single page info - currently only containing count info
  42. *
  43. * $shortcode => array ( 'count' => $count,
  44. * 'version' => $version
  45. * )
  46. * @since 4.3
  47. * @var array
  48. */
  49. protected $usage_info;
  50.  
  51.  
  52. /**
  53. * Is filled by default in get_header action with the ALB elements of the current post
  54. * false, if an error occured generating the elements, null if could not be filled (needs function get_the_ID()
  55. *
  56. * [$shortcode_name] => array(
  57. * 'element' => $shortcode_name
  58. * 'count => $nr_of_occurrence
  59. * )
  60. * @since 4.3
  61. * @var array|false|null
  62. */
  63. protected $current_post_elements;
  64.  
  65.  
  66. /**
  67. *
  68. * @since 4.3
  69. * @var array|false $post_id => array( $element => true|false )
  70. */
  71. protected $post_elements_state;
  72.  
  73.  
  74. /**
  75. *
  76. * @since 4.3
  77. * @var array|false $element => true|false
  78. */
  79. protected $blog_elements_state;
  80.  
  81.  
  82. /**
  83. *
  84. * @since 4.3
  85. * @var array $element => 'checked' | 'new' | 'initialising'
  86. */
  87. protected $checked_elements;
  88.  
  89.  
  90. /**
  91. *
  92. * @since 4.3
  93. */
  94. public function __construct()
  95. {
  96. $this->registered_alb_elements = null;
  97. $this->usage_info = array();
  98. $this->current_post_elements = null;
  99. $this->blog_elements_state = array();
  100. $this->post_elements_state = array();
  101. $this->checked_elements = null;
  102.  
  103. add_action( 'get_header', array( $this, 'handler_wp_get_header' ), 10, 1 );
  104.  
  105. if( is_admin() )
  106. {
  107. add_action( 'admin_init', array( $this, 'handler_check_for_version_updates' ), 10 );
  108. add_action( 'trashed_post', array( $this, 'handler_wp_trashed_post' ), 10, 1 );
  109. add_action( 'untrash_post', array( $this, 'handler_wp_untrash_post' ), 10, 1 );
  110.  
  111. add_action( 'ava_after_import_demo_settings', array( $this, 'handler_after_import_demo' ), 10 );
  112. }
  113.  
  114. return $this;
  115. }
  116.  
  117. /**
  118. *
  119. * @since 4.3
  120. */
  121. public function __destruct()
  122. {
  123. unset( $this->registered_alb_elements );
  124. unset( $this->usage_info );
  125. unset( $this->current_post_elements );
  126. unset( $this->blog_elements_state );
  127. unset( $this->post_elements_state );
  128. unset( $this->checked_elements );
  129. }
  130.  
  131.  
  132. /**
  133. * Returns all registered ALB element names (currently this is a wrapper for the shortcode names)
  134. *
  135. * @since 4.3
  136. * @return array
  137. */
  138. public function registered_elements()
  139. {
  140. if( is_null( $this->registered_alb_elements ) )
  141. {
  142. $this->registered_alb_elements = apply_filters( 'avf_get_all_alb_element_names', array_merge( ShortcodeHelper::$allowed_shortcodes, ShortcodeHelper::$nested_shortcodes ) );
  143. $this->registered_alb_elements = array_merge( array_unique( $this->registered_alb_elements ) );
  144. }
  145.  
  146. return $this->registered_alb_elements;
  147. }
  148.  
  149.  
  150. /**
  151. * Returns an array of elements and the check status
  152. *
  153. * @since 4.3
  154. * @return array
  155. */
  156. public function get_checked_elements()
  157. {
  158. if( is_null( $this->checked_elements ) )
  159. {
  160. $this->checked_elements = get_option( 'av_alb_element_check_stat', array() );
  161. }
  162.  
  163. return $this->checked_elements;
  164. }
  165.  
  166.  
  167. /**
  168. * Update the checked elements array in DB
  169. *
  170. * @since 4.3
  171. * @param array $elements
  172. */
  173. public function update_checked_elements( array $elements )
  174. {
  175. if( serialize( $elements ) == serialize( $this->checked_elements ) )
  176. {
  177. return true;
  178. }
  179.  
  180. $this->checked_elements = $elements;
  181.  
  182. return update_option( 'av_alb_element_check_stat', $elements );
  183. }
  184.  
  185. /**
  186. * Compares the registered elements with the already existing checked element list.
  187. * Adds new elements to the list (marked 'new').
  188. * Checks, if all elements have been marked 'checked'
  189. *
  190. * We assume new elements as checked, if we find one post that uses that element. Under normal working conditions we catch the first
  191. * use on the post update and add it to the element usage info.
  192. * As long as user does not manipulate post content outside normal WP workflow or uses the shortcode before registering the element
  193. * this assumption will work.
  194. *
  195. * If we only have new elements (= pageload
  196. *
  197. * @since 4.3
  198. * @param string $initialise '' | 'initialise'
  199. * @return array 'new' | 'initialising' | 'only_new' | empty array
  200. */
  201. public function all_elements_checked( $initialise = '' )
  202. {
  203. static $checked = null;
  204.  
  205. if( ! is_null( $checked ) && ( 'initialise' != $initialise ) )
  206. {
  207. return $checked;
  208. }
  209.  
  210. $chk = $this->get_checked_elements();
  211.  
  212. /**
  213. * Only check for new elements in backend
  214. */
  215. if( is_admin() || ( 'initialise' == $initialise ) )
  216. {
  217. $update = false;
  218. $els = $this->registered_elements();
  219.  
  220. foreach ( $els as $el )
  221. {
  222. if( ! array_key_exists( $el, $chk ) )
  223. {
  224. $chk[ $el ] = 'new';
  225. $update = true;
  226. }
  227. }
  228.  
  229. foreach( $chk as $elem => $value )
  230. {
  231. if( 'new' == $value )
  232. {
  233. $key = aviaElementManager::USAGE_PREFIX . $elem;
  234. $entry = get_option( $key, array() );
  235. /**
  236. * set to checked if used at least once and assume checked
  237. */
  238. if( ! empty( $entry ) )
  239. {
  240. $chk[ $elem ] = 'checked';
  241. $update = true;
  242. }
  243. }
  244. }
  245.  
  246. if( $update )
  247. {
  248. $this->update_checked_elements( $chk );
  249. }
  250. }
  251.  
  252. $checked = array_values( array_unique( $chk ) );
  253.  
  254. if( ( 1 == count( $checked ) ) && ( 'new' == $checked[0] ) )
  255. {
  256. $checked = array( 'only_new' );
  257. }
  258. else
  259. {
  260. $checked = array_diff( $checked, array( 'checked' ) );
  261. }
  262.  
  263. return $checked;
  264. }
  265.  
  266. /**
  267. * Returns the array with infos about elements used for the current post
  268. * Needs the function get_the_ID() to fill the array
  269. *
  270. * @since 4.3
  271. * @return array|false|null
  272. */
  273. public function get_current_post_elements()
  274. {
  275. if( is_null( $this->current_post_elements ) && ( false !== get_the_ID() ) )
  276. {
  277. $this->current_post_elements = $this->get_posts_detail_element_info( get_the_ID() );
  278. }
  279.  
  280. return $this->current_post_elements;
  281. }
  282.  
  283.  
  284. /**
  285. * Returns an array with all registered ALB elements as key and info true|false
  286. * To speed up frontend we save infos in options/postmeta once we have the info.
  287. * From backend on update post we force a writing to DB.
  288. *
  289. * @since 4.3
  290. * @param string $source 'post' | 'blog'
  291. * @param int $post_id defaults to the value of get_the_ID();
  292. * @param string $initialise '' | 'initialise'
  293. * @return array|false
  294. */
  295. public function get_elements_state( $source = 'post', $post_id = 0, $initialise = '' )
  296. {
  297. if( ( 'post' == $source ) && ( 0 == $post_id ) )
  298. {
  299. $post_id = get_the_ID();
  300. if( false === $post_id )
  301. {
  302. return false;
  303. }
  304. }
  305.  
  306. $intersect = array_intersect( array( 'initialising', 'only_new' ), $this->all_elements_checked( $initialise ) );
  307.  
  308. if( ! empty( $intersect ) )
  309. {
  310. if( 'initialise' != $initialise )
  311. {
  312. return false;
  313. }
  314. }
  315.  
  316. $elements = $this->registered_elements();
  317.  
  318. /**
  319. * In frontend try to get cached values
  320. */
  321. if( ! is_admin() )
  322. {
  323. if( 'post' == $source )
  324. {
  325. if( isset( $this->post_elements_state[ $post_id ] ) )
  326. {
  327. return $this->post_elements_state[ $post_id ];
  328. }
  329.  
  330. /**
  331. * To save memory we only saved used elements - we need to fill up the whole array
  332. */
  333. $stored = get_post_meta( $post_id, '_av_alb_posts_elements_state', true );
  334.  
  335. if( ! empty( $stored ) && is_array( $stored ) )
  336. {
  337. $all_elements = array_flip( $elements );
  338. foreach( $all_elements as $e => $value )
  339. {
  340. $all_elements[ $e ] = ( isset( $stored[ $e ] ) && ( true === $stored[ $e ] ) ) ? true : false;
  341. }
  342.  
  343. $this->post_elements_state[ $post_id ] = $all_elements;
  344. return $all_elements;
  345. }
  346. }
  347.  
  348. else
  349. {
  350. if( ! empty( $this->blog_elements_state ) )
  351. {
  352. return $this->blog_elements_state;
  353. }
  354.  
  355. $stored = get_option( 'av_alb_blog_elements_state', array() );
  356. if( ! empty( $stored ) )
  357. {
  358. $this->blog_elements_state = $stored;
  359. return $this->blog_elements_state;
  360. }
  361. }
  362. }
  363.  
  364. $states = array();
  365.  
  366. foreach ( $elements as $element )
  367. {
  368. $key = aviaElementManager::USAGE_PREFIX . $element;
  369. $entry = get_option( $key, array() );
  370.  
  371. if( 'post' == $source )
  372. {
  373. if( ! isset( $entry[ $post_id ] ) )
  374. {
  375. $states[ $element ] = false;
  376. }
  377. else
  378. {
  379. $states[ $element ] = ( $entry[ $post_id ]['count'] > 0 );
  380. }
  381. continue;
  382. }
  383.  
  384. $states[ $element ] = false;
  385.  
  386. if( ! empty( $entry ) )
  387. {
  388. foreach ( $entry as $key => $value )
  389. {
  390. if( $value['count'] > 0 )
  391. {
  392. $states[ $element ] = true;
  393. break;
  394. }
  395. }
  396. }
  397. }
  398.  
  399. if( 'post' == $source )
  400. {
  401. /**
  402. * To save storage we remove elements that are not used in the post
  403. */
  404. $save_states = array();
  405. foreach( $states as $e => $used )
  406. {
  407. if( true === $used )
  408. {
  409. $save_states[ $e ] = true;
  410. }
  411. }
  412.  
  413. update_post_meta( $post_id, '_av_alb_posts_elements_state', $save_states );
  414. $this->post_elements_state[ $post_id ] = $states;
  415. }
  416. else
  417. {
  418. update_option( 'av_alb_blog_elements_state', $states );
  419. $this->blog_elements_state = $states;
  420. }
  421.  
  422. return $states;
  423. }
  424.  
  425. /**
  426. *
  427. * @since 4.3
  428. * @param string $template
  429. */
  430. public function handler_wp_get_header( $template = null )
  431. {
  432. if( is_null( $this->current_post_elements ) )
  433. {
  434. $this->current_post_elements = $this->get_posts_detail_element_info( get_the_ID() );
  435. }
  436.  
  437. do_action( 'ava_current_post_element_info_available', $this );
  438. }
  439.  
  440.  
  441. /**
  442. * After import of demos we need to force an update of elements settings
  443. *
  444. * @since 4.3
  445. */
  446. public function handler_after_import_demo()
  447. {
  448. update_option( 'av_alb_element_mgr', '' );
  449. update_option( 'av_alb_element_mgr_update', '' );
  450.  
  451. $this->exec_version_update();
  452. }
  453.  
  454. /**
  455. * Check if we need to update our class internal data
  456. *
  457. * @since 4.3
  458. */
  459. public function handler_check_for_version_updates()
  460. {
  461. $version = get_option( 'av_alb_element_mgr', '' );
  462. $update_state = get_option( 'av_alb_element_mgr_update', '' );
  463.  
  464. if( ( aviaElementManager::VERSION == $version ) && ( '' == $update_state ) )
  465. {
  466. return;
  467. }
  468.  
  469. if ( defined( 'DOING_AJAX' ) && DOING_AJAX )
  470. {
  471. return;
  472. }
  473.  
  474. // allow user to login/logout
  475. if( is_admin() && ( ! is_user_logged_in() ) )
  476. {
  477. return;
  478. }
  479.  
  480. /**
  481. * Allow to filter function for a custom login page.
  482. * Return true or false (boolean value) if you used a custom page, else any numeric value for standard WP login page.
  483. *
  484. * @used_by: currently unused
  485. *
  486. * @since 4.3
  487. */
  488. $result = apply_filters( 'avf_is_custom_admin_login_page', -1 );
  489.  
  490. if( is_bool( $result ) )
  491. {
  492. return;
  493. }
  494.  
  495. if( false !== stripos( $_SERVER["SCRIPT_NAME"], strrchr( wp_login_url(), '/') ) )
  496. {
  497. return;
  498. }
  499.  
  500. $this->exec_version_update();
  501. }
  502.  
  503.  
  504. /**
  505. * Simple update function.
  506. *
  507. * As most user applications only have a few hundred pages/posts we do the update on the fly.
  508. * For larger databases we add state flags that recognise unfinished post updates and skip already
  509. * finished.
  510. *
  511. * Might be extended to a background process in future releases.
  512. *
  513. * IMPORTANT:
  514. * ==========
  515. *
  516. * It is possible to filter the predefined post types and status.
  517. * If this is done you have to change the version number (by adding .a ) to force a rebuild of the internal index.
  518. * We will always increment the version number using x.x only, so setting it to x.x.a is a save method to be
  519. * able to follow future updates without any further intervention.
  520. *
  521. * @since 4.3
  522. */
  523. protected function exec_version_update()
  524. {
  525.  
  526. $update_state = get_option( 'av_alb_element_mgr_update', '' );
  527.  
  528. $query_args = array(
  529. 'post_type' => apply_filters( 'avf_alb_supported_post_types_elmgr', Avia_Builder()->get_supported_post_types() ),
  530. 'post_status' => apply_filters( 'avf_alb_supported_post_status_elmgr', Avia_Builder()->get_supported_post_status() ),
  531. 'nopaging' => true,
  532. 'fields' => 'ids'
  533. );
  534.  
  535. if( '' != $update_state )
  536. {
  537. /**
  538. * Filter not updated posts
  539. */
  540. $query_args['meta_query'] = array(
  541. array(
  542. 'key' => '_av_alb_element_mgr_version',
  543. 'value' => aviaElementManager::VERSION,
  544. 'compare' => '!=',
  545. ),
  546. );
  547. }
  548.  
  549. $query = new WP_Query( $query_args );
  550.  
  551. if( '' == $update_state )
  552. {
  553. /**
  554. * Reset all internal data
  555. */
  556. $chk = $this->get_checked_elements();
  557.  
  558. foreach( $chk as $el => $value )
  559. {
  560. $chk[ $el ] = 'initialising';
  561. }
  562.  
  563. $this->update_checked_elements( $chk );
  564.  
  565. $this->usage_info = array();
  566. $this->update_option_usage_info();
  567.  
  568. $this->blog_elements_state = array();
  569. update_option( 'av_alb_blog_elements_state', $this->blog_elements_state );
  570.  
  571. $this->post_elements_state = array();
  572. }
  573.  
  574. update_option( 'av_alb_element_mgr_update', 'in_update' );
  575.  
  576.  
  577. foreach ( $query->posts as $post_id )
  578. {
  579. set_time_limit( 0 );
  580.  
  581. /**
  582. * Check if an update had been interrupted - skip already updated posts
  583. */
  584. $updated = get_post_meta( $post_id, '_av_alb_element_mgr_version', true );
  585. if( ( $updated == aviaElementManager::VERSION ) && ( '' != $update_state ) )
  586. {
  587. continue;
  588. }
  589.  
  590. update_post_meta( $post_id, '_av_alb_posts_elements_state', array() );
  591.  
  592. $content = Avia_Builder()->get_post_content( $post_id );
  593.  
  594. $content_new = $this->set_element_ids_in_content( $content, $post_id, 'no_escape' );
  595. aviaElementManager::$added_uid = 1;
  596.  
  597. if( $content != $content_new )
  598. {
  599. Avia_Builder()->update_post_content( $post_id, $content_new );
  600. }
  601.  
  602. $this->update_usage_from_post_content( $content_new, $post_id, 'initialise' );
  603.  
  604. update_post_meta( $post_id, '_av_alb_element_mgr_version', aviaElementManager::VERSION );
  605.  
  606. /**
  607. * Reset no longer needed elements - free memory
  608. */
  609. $this->post_elements_state = array();
  610. }
  611.  
  612. unset( $query );
  613.  
  614. $chk = $this->get_checked_elements();
  615.  
  616. foreach ( $chk as $el => $value )
  617. {
  618. $chk[ $el ] = 'checked';
  619. }
  620.  
  621. $this->update_checked_elements( $chk );
  622.  
  623. $this->blog_elements_state = array();
  624. $this->get_elements_state( 'blog', 0, 'initialise' );
  625.  
  626. update_option( 'av_alb_element_mgr', aviaElementManager::VERSION );
  627. update_option( 'av_alb_element_mgr_update', '' );
  628. }
  629.  
  630.  
  631. /**
  632. * Remove all element info for this post from options
  633. *
  634. * @since 4.3
  635. * @param int $post_id
  636. */
  637. public function handler_wp_trashed_post( $post_id )
  638. {
  639. global $post;
  640.  
  641. if( $post->ID != $post_id )
  642. {
  643. return;
  644. }
  645.  
  646. /**
  647. * Remove all index entries by rendering an empty content
  648. */
  649. $this->updated_post_content( '', $post_id, 'trash' );
  650. }
  651.  
  652.  
  653. /**
  654. * Restore all element info for this post from options
  655. *
  656. * @since 4.4.1
  657. * @param int $post_id
  658. */
  659. public function handler_wp_untrash_post( $post_id )
  660. {
  661. global $post;
  662.  
  663. if( $post->ID != $post_id )
  664. {
  665. return;
  666. }
  667.  
  668. /**
  669. * Restore all index entries by rendering content
  670. */
  671. $this->updated_post_content( $post->post_content, $post_id, 'untrash' );
  672. }
  673.  
  674.  
  675. /**
  676. * Returns an array of all used ALB shortcodes in given post:
  677. *
  678. * [$shortcode_name] => array(
  679. * 'element' => $shortcode_name
  680. * 'count => $nr_of_occurrence
  681. * )
  682. *
  683. * @since 4.3
  684. * @param int $post_id
  685. * @return array|false false, if we could not get a valid result for the post( = updateing the options is DB failed / not a valid post object )
  686. */
  687. public function get_posts_detail_element_info( $post_id )
  688. {
  689. $state = get_post_meta( $post_id, '_av_el_mgr_version', true );
  690.  
  691. /**
  692. * We access a non checked post or last check failed
  693. * ( this is a fallback only under normal workflow )
  694. */
  695. if( $state != aviaElementManager::USAGE_VERSION )
  696. {
  697. $content = Avia_Builder()->get_post_content( $post_id );
  698.  
  699. if( false === $content )
  700. {
  701. return false;
  702. }
  703.  
  704. if( false === $this->update_usage_from_post_content( $content, $post_id ) )
  705. {
  706. return false;
  707. }
  708. }
  709.  
  710. $elements = $this->registered_elements();
  711.  
  712. $used = array();
  713.  
  714. foreach ( $elements as $element )
  715. {
  716. $key = aviaElementManager::USAGE_PREFIX . $element;
  717. $entry = get_option( $key, array() );
  718.  
  719. if( ! isset( $entry[ $post_id ] ) )
  720. {
  721. continue;
  722. }
  723.  
  724. $used[ $element ] = array(
  725. 'element' => $element,
  726. 'count' => $entry[ $post_id ]['count']
  727. );
  728. }
  729.  
  730. return $used;
  731. }
  732.  
  733.  
  734. /**
  735. * Called when a new post is added or content is updated. Checks if we have a post we need to deal with.
  736. *
  737. * @since 4.4.1
  738. * @param string $content
  739. * @param int $post_id
  740. * @param string $action 'update' | 'trash' | 'untrash'
  741. * @return boolean
  742. */
  743. public function updated_post_content( $content, $post_id, $action = 'update' )
  744. {
  745. global $post;
  746.  
  747. /**
  748. * See comment for function exec_version_update
  749. */
  750. $post_types = apply_filters( 'avf_alb_supported_post_types_elmgr', Avia_Builder()->get_supported_post_types() );
  751. $post_status = apply_filters( 'avf_alb_supported_post_status_elmgr', Avia_Builder()->get_supported_post_status() );
  752.  
  753. if( ! in_array( $post->post_type, $post_types ) )
  754. {
  755. return;
  756. }
  757.  
  758. $check_status = $post->post_status;
  759.  
  760. switch( $action )
  761. {
  762. case 'trash':
  763. /**
  764. * Post status is still original statut - WP does not update $post
  765. */
  766. $content = '';
  767. break;
  768. case 'untrash':
  769. /**
  770. * Post status is trash - WP does not update $post (not even on a later hook)
  771. */
  772. $check_status = get_post_meta( $post_id, '_wp_trash_meta_status', true );
  773. break;
  774. case 'update':
  775. default:
  776. break;
  777. }
  778.  
  779. if( ! in_array( $check_status, $post_status ) )
  780. {
  781. return;
  782. }
  783.  
  784. return $this->update_usage_from_post_content( $content, $post_id );
  785. }
  786.  
  787. /**
  788. * Updates the usage info for ALB elements from the post content.
  789. * Also sets a postmeta that we know we updated the usage info and with wich version it was updated
  790. *
  791. * @since 4.3
  792. * @param string $content
  793. * @param int $post_id
  794. * @param string $initialise '' | 'initialise'
  795. * @return boolean
  796. */
  797. public function update_usage_from_post_content( $content, $post_id, $initialise = '' )
  798. {
  799.  
  800. $this->usage_info = array();
  801.  
  802. $matches = array();
  803.  
  804. preg_match_all( "/" . ShortcodeHelper::get_fake_pattern( true, $this->registered_elements(), 'fake' ) . "/s", $content, $matches );
  805. if( is_array( $matches ) && is_array( $matches[0] ) && ( ! empty( $matches[0] ) ) )
  806. {
  807. $elements = explode( ',', str_replace( array( '[', ']' ), '', implode( ',', $matches[0] ) ) );
  808. }
  809. else
  810. {
  811. $elements = array();
  812. }
  813.  
  814. $this->add_usage_info( $elements, $post_id );
  815.  
  816. $success = $this->update_option_usage_info( $post_id );
  817.  
  818. $pm = $success ? aviaElementManager::USAGE_VERSION : 'failed';
  819. update_post_meta( $post_id, '_av_el_mgr_version', $pm );
  820.  
  821. /**
  822. * Force update of cache data
  823. */
  824. unset( $this->post_elements_state[ $post_id ] );
  825. $this->get_elements_state( 'post', $post_id, $initialise );
  826.  
  827. if( 'initialise' != $initialise )
  828. {
  829. $this->blog_elements_state = array();
  830. $this->get_elements_state( 'blog' );
  831. }
  832.  
  833. return $success;
  834. }
  835.  
  836.  
  837. /**
  838. * Updates the array $this->usage_info
  839. *
  840. * @since 4.3
  841. * @param array $elements
  842. */
  843. protected function add_usage_info( array $elements )
  844. {
  845. if( empty( $elements ) )
  846. {
  847. return;
  848. }
  849.  
  850. /**
  851. * If an element is marked as new and we find it in the post we assume that this is the first and only occurence and we can
  852. * mark this element as checked
  853. */
  854. $new = array();
  855. $found = array();
  856. $check = $this->all_elements_checked();
  857.  
  858. if( ! empty( $check ) )
  859. {
  860. $new = array_intersect( $this->get_checked_elements(), array( 'new' ) );
  861. }
  862.  
  863. foreach ( $elements as $element )
  864. {
  865. $element = trim( $element );
  866.  
  867. /**
  868. * Don't count closing tags
  869. */
  870. if( strpos( $element, '/' ) !== false )
  871. {
  872. continue;
  873. }
  874.  
  875. if( array_key_exists( $element, $new ) )
  876. {
  877. $found[] = $element;
  878. unset( $new[ $element ] );
  879. }
  880.  
  881. if( array_key_exists( $element, $this->usage_info ) )
  882. {
  883. $this->usage_info[ $element ]['count']++;
  884. }
  885. else
  886. {
  887. $this->usage_info[ $element ] = array(
  888. 'version' => aviaElementManager::USAGE_VERSION,
  889. 'count' => 1
  890. );
  891. }
  892. }
  893.  
  894. if( empty( $found ) )
  895. {
  896. return;
  897. }
  898.  
  899. $chk = $this->get_checked_elements();
  900.  
  901. foreach( $found as $el )
  902. {
  903. $chk[ $el ] = 'checked';
  904. }
  905.  
  906. $this->update_checked_elements( $chk );
  907. }
  908.  
  909.  
  910. /**
  911. * Update the element usage entries in options.
  912. * Tries to update all options (also if an error occurs)
  913. *
  914. * @since 4.3
  915. * @param int $post_id 0 to clear all entries
  916. * @return boolean false, if the update failed and we have an inconsistent info
  917. */
  918. protected function update_option_usage_info( $post_id = 0 )
  919. {
  920. $all_elements = array_flip( $this->registered_elements() );
  921.  
  922. $success = true;
  923.  
  924. foreach( $this->usage_info as $element => $info )
  925. {
  926. $key = aviaElementManager::USAGE_PREFIX . $element;
  927. $entry = get_option( $key, array() );
  928.  
  929. /**
  930. * As we also get false when values are not changed we have to check manually before update
  931. */
  932. $need_update = true;
  933. if( isset( $entry[ $post_id ] ) )
  934. {
  935. $diff1 = array_diff_assoc( $entry[ $post_id ], $info );
  936. $diff2 = array_diff_assoc( $info, $entry[ $post_id ] );
  937.  
  938. $need_update = ! ( empty( $diff1 ) && empty( $diff2 ) );
  939. }
  940.  
  941. if( $need_update )
  942. {
  943. $entry[ $post_id ] = $info;
  944. if( ! update_option( $key, $entry ) )
  945. {
  946. $success = false;
  947. }
  948. }
  949.  
  950. unset( $all_elements[ $element ] );
  951. }
  952.  
  953. /**
  954. * Remove entries that were removed
  955. */
  956. foreach( $all_elements as $element => $dummy )
  957. {
  958. $key = aviaElementManager::USAGE_PREFIX . $element;
  959. $entry = get_option( $key, array() );
  960.  
  961. if( array_key_exists( $post_id, $entry ) || ( 0 == $post_id ) )
  962. {
  963. if( 0 == $post_id )
  964. {
  965. $entry = array();
  966. }
  967. else
  968. {
  969. unset( $entry[ $post_id ] );
  970. }
  971.  
  972. if( ! update_option( $key, $entry ) )
  973. {
  974. $success = false;
  975. }
  976. }
  977. }
  978.  
  979. return $success;
  980. }
  981.  
  982. /**
  983. * Scans all ALB shortcodes and checks, if they have a unique id.
  984. *
  985. * @since 4.3
  986. * @param string $content
  987. * @param int $post_id
  988. * @param string $escspe 'escape' | 'no_escape'
  989. * @return string
  990. */
  991. public function set_element_ids_in_content( $content, $post_id, $escspe = 'escape' )
  992. {
  993. $all_elements = $this->registered_elements();
  994.  
  995. $elements = array();
  996. preg_match_all( "/" . get_shortcode_regex( $all_elements ) . "/s", $content, $elements, PREG_OFFSET_CAPTURE );
  997. if( empty( $elements ) || ! is_array( $elements ) || empty( $elements[0] ) )
  998. {
  999. return $content;
  1000. }
  1001.  
  1002. $count = count( $elements[0] );
  1003.  
  1004. for( $i = $count - 1; $i >= 0; $i-- )
  1005. {
  1006. /**
  1007. * Check for nested shortcodes
  1008. */
  1009. if( ! empty( $elements[5][ $i ][0] ) )
  1010. {
  1011. $new_content = $this->set_element_ids_in_content( $elements[5][ $i ][0], $post_id, $escspe );
  1012. if( $elements[5][ $i ][0] != $new_content )
  1013. {
  1014. $content = substr_replace( $content, $new_content, $elements[5][ $i ][1], strlen( $elements[5][ $i ][0] ) );
  1015. }
  1016. }
  1017.  
  1018. $atts = shortcode_parse_atts( stripslashes( $elements[3][ $i ][0] ) );
  1019. if( ! is_array( $atts ) )
  1020. {
  1021. $atts = array();
  1022. }
  1023.  
  1024. if( array_key_exists( aviaElementManager::ELEMENT_UID, $atts ) && ( '' != trim( $atts[ aviaElementManager::ELEMENT_UID ] ) ) )
  1025. {
  1026. continue;
  1027. }
  1028.  
  1029. $atts[ aviaElementManager::ELEMENT_UID ] = 'av-' . base_convert( aviaElementManager::$added_uid . mt_rand( 10, 9999 ) . $post_id , 10, 36 );
  1030. aviaElementManager::$added_uid ++;
  1031.  
  1032. $new_atts = '';
  1033. foreach( $atts as $att => $value)
  1034. {
  1035. $new_atts .= ( is_numeric( $att ) ) ? " {$value}" : " {$att}='{$value}'";
  1036. }
  1037.  
  1038. if( 'escape' == $escspe )
  1039. {
  1040. $new_atts = addslashes( $new_atts );
  1041. }
  1042.  
  1043. $content = substr_replace( $content, $new_atts, $elements[3][ $i ][1], strlen( $elements[3][ $i ][0]) );
  1044. }
  1045.  
  1046. return $content;
  1047. }
  1048.  
  1049. /**
  1050. * Add debug info to shortcode parser debug page
  1051. *
  1052. * @since 4.3
  1053. * @return string
  1054. */
  1055. public function debug_element_usage_info()
  1056. {
  1057.  
  1058. $blog = $this->get_elements_state( 'blog' );
  1059. if( ! is_array( $blog ) )
  1060. {
  1061. $blog = __( 'Blog status of elements is currently not available', 'avia_framework' );
  1062. }
  1063. else
  1064. {
  1065. ksort( $blog );
  1066. $blog = $this->esc_boolean( $blog );
  1067. }
  1068.  
  1069. $post = $this->get_elements_state( 'post' );
  1070. if( ! is_array( $post ) )
  1071. {
  1072. $post = __( 'Post status of elements is currently not available', 'avia_framework' );
  1073. }
  1074. else
  1075. {
  1076. ksort( $post );
  1077.  
  1078. foreach( $post as $element => $value )
  1079. {
  1080. if( false === $value )
  1081. {
  1082. unset( $post[ $element ] );
  1083. }
  1084. }
  1085.  
  1086. $post = $this->esc_boolean( $post );
  1087. }
  1088.  
  1089. $chk = $this->get_checked_elements();
  1090.  
  1091. $detail = array();
  1092.  
  1093. $reg_elements = $this->registered_elements();
  1094. sort( $reg_elements );
  1095.  
  1096. foreach( $reg_elements as $element )
  1097. {
  1098. $key = aviaElementManager::USAGE_PREFIX . $element;
  1099.  
  1100. $value = get_option( $key, array() );
  1101. ksort( $value );
  1102. $detail[ $element ] = $value;
  1103. }
  1104.  
  1105. $update_state = get_option( 'av_alb_element_mgr_update', '' );
  1106. $update_state = ( '' != $update_state ) ? __( 'currently updating database', 'avia_framework' ) : __( 'is up to date', 'avia_framework' );
  1107.  
  1108. $out = '';
  1109.  
  1110. $out .= "[av_tab title='" . __( 'Shortcode Usage Overview', 'avia_framework' ) . "' icon_select='yes' icon='ue823' font='entypo-fontello']";
  1111.  
  1112. $out .= "[av_toggle_container initial='0' mode='toggle' sort='true' styling='' colors='' font_color='' background_color='' border_color='' custom_class='']";
  1113.  
  1114. $out .= "[av_toggle title='" . __( 'General Element Manager Info', 'avia_framework' ) . "' tags='blog']";
  1115.  
  1116. $out .= '<p class="av-el-mgr-info av-version">' . __( 'Element Manager Version: ', 'avia_framework' ) . aviaElementManager::VERSION . '</p>';
  1117. $out .= '<p class="av-el-mgr-info av-update">' . __( 'Element Manager Update State: ', 'avia_framework' ) . $update_state . '</p>';
  1118.  
  1119. $out .= "[/av_toggle]";
  1120.  
  1121. $out .= "[av_toggle title='" . __( 'Blog Usage - which elements are used in the blog', 'avia_framework' ) . "' tags='blog']";
  1122.  
  1123. $out .= '<pre><code>';
  1124. $out .= $this->esc_shortcode( print_r( $blog, true ) );
  1125. $out .= '</code></pre>';
  1126.  
  1127. $out .= "[/av_toggle]";
  1128.  
  1129. $out .= "[av_toggle title='" . __( 'Post Usage - which elements are used in this post', 'avia_framework' ) . "' tags='post']";
  1130.  
  1131. $out .= '<pre><code>';
  1132. $out .= $this->esc_shortcode( print_r( $post, true ) );
  1133. $out .= '</code></pre>';
  1134.  
  1135. $out .= "[/av_toggle]";
  1136.  
  1137. $out .= "[av_toggle title='" . __( 'Check State - shows, which elements are recognised or new or in update', 'avia_framework' ) . "' tags='check']";
  1138.  
  1139. $out .= '<pre><code>';
  1140. $out .= $this->esc_shortcode( print_r( $chk, true ) );
  1141. $out .= '</code></pre>';
  1142.  
  1143. $out .= "[/av_toggle]";
  1144.  
  1145. $out .= "[/av_toggle_container]";
  1146.  
  1147. $out .= "[/av_tab]";
  1148.  
  1149.  
  1150. $out .= "[av_tab title='" . __( 'Detailed Shortcode Usage', 'avia_framework' ) . "' icon_select='yes' icon='ue826' font='entypo-fontello']";
  1151.  
  1152. $out .= "[av_toggle_container initial='0' mode='toggle' sort='true' styling='' colors='' font_color='' background_color='' border_color='' custom_class='']";
  1153.  
  1154. foreach( $detail as $element => $usage )
  1155. {
  1156. $element_desc = $element . ' ( ' . count( $usage ) . ' )';
  1157. $out .= "[av_toggle title='{$element_desc}' tags='{$element_desc}']";
  1158.  
  1159. $out .= '<pre><code>';
  1160. $out .= $this->esc_shortcode( print_r( $usage, true ) );
  1161. $out .= '</code></pre>';
  1162.  
  1163. $out .= "[/av_toggle]";
  1164. }
  1165.  
  1166. $out .= "[/av_toggle_container]";
  1167.  
  1168. $out .= "[/av_tab]";
  1169.  
  1170. return $out;
  1171. }
  1172.  
  1173. /**
  1174. * Remove [ and ]
  1175. *
  1176. * @since 4.3
  1177. * @param string $text
  1178. * @return string
  1179. */
  1180. private function esc_shortcode( $text )
  1181. {
  1182. return str_replace( array( '[', ']' ), '"', $text );
  1183. }
  1184.  
  1185.  
  1186. /**
  1187. * Replace a boolean value by string
  1188. *
  1189. * @since 4.3
  1190. * @param array $values
  1191. * @return array
  1192. */
  1193. private function esc_boolean( array $values )
  1194. {
  1195. foreach( $values as $key => $value )
  1196. {
  1197. if( is_bool( $value ) )
  1198. {
  1199. $values[ $key ] = $value ? 'true' : 'false';
  1200. }
  1201. }
  1202.  
  1203. return $values;
  1204. }
  1205.  
  1206. }
  1207.  
  1208. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement