Advertisement
Guest User

Untitled

a guest
Jul 6th, 2018
30
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
PHP 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