/**
  * Process view $settings array, return HTML output
  *
  * @param string $id       The current view id
  * @param array  $settings The settings array
  * @param array  $pargs    The pagination settings array
  *
  * @return string HTML output of Content View
  */
 static function view_process_settings($id, $settings, $pargs = array())
 {
     if (empty($settings)) {
         return __('Empty settings', PT_CV_DOMAIN);
     }
     global $pt_cv_glb, $pt_cv_id;
     $view_id = !empty($id) ? $id : PT_CV_Functions::string_random();
     // Init arrays
     if (!isset($pt_cv_glb[$view_id])) {
         $pt_cv_glb[$view_id] = array();
     }
     if (!isset($pt_cv_glb['processed_view'])) {
         $pt_cv_glb['processed_view'] = array();
     }
     /**
      * 1. Get View settings
      */
     $view_settings = array();
     foreach ($settings as $key => $value) {
         $view_settings[$key] = esc_sql($value);
     }
     $pt_cv_glb[$view_id]['view_settings'] = $view_settings;
     // Check duplicated View
     // (Same View ID but different shortcode parameters => consider as 2 different Views)
     if (empty($pargs) && apply_filters(PT_CV_PREFIX_ . 'check_duplicate', 0, $view_id, $view_settings)) {
         $sc_params = isset($pt_cv_glb[$view_id]['shortcode_params']) ? $pt_cv_glb[$view_id]['shortcode_params'] : PT_CV_Functions::string_random();
         $vid = $view_id . '-' . md5(serialize($sc_params));
         if (!empty($pt_cv_glb['processed_view'][$vid])) {
             return '';
         } else {
             $pt_cv_glb['processed_view'][$vid] = 1;
         }
     }
     // Get content type
     $content_type = apply_filters(PT_CV_PREFIX_ . 'content_type', PT_CV_Functions::setting_value(PT_CV_PREFIX . 'content-type', $view_settings), $id);
     $pt_cv_glb[$view_id]['content_type'] = $content_type;
     // Get view type
     $view_type = PT_CV_Functions::setting_value(PT_CV_PREFIX . 'view-type', $view_settings);
     $pt_cv_glb[$view_id]['view_type'] = $view_type;
     // If is pagination request
     $session_id = $pargs && isset($pargs['session_id']) ? $pargs['session_id'] : 0;
     // Store main View ID
     // If parent View is not finished
     if (!isset($pt_cv_glb[$pt_cv_id]['finished'])) {
         $pt_cv_main_id = !empty($pt_cv_id) ? $pt_cv_id : $view_id;
     } else {
         $pt_cv_main_id = $view_id;
     }
     if ($session_id) {
         if (empty($pt_cv_id)) {
             $pt_cv_id = $session_id;
         }
         $session_data = array_merge(array('$args' => '', '$dargs' => ''), false === ($saved_settings = get_transient(PT_CV_PREFIX . 'view-data-' . $session_id)) ? array() : $saved_settings);
         $args = $session_data['$args'];
         $dargs = $session_data['$dargs'];
     } else {
         // Assign view id as current View
         $pt_cv_id = $session_id = $view_id;
         // Store settings
         set_transient(PT_CV_PREFIX . 'view-settings-' . $session_id, $settings, 7 * DAY_IN_SECONDS);
     }
     // Extract Query & Display settings from settings array
     if (empty($args) || empty($dargs)) {
         $dargs = apply_filters(PT_CV_PREFIX_ . 'all_display_settings', PT_CV_Functions::view_display_settings($view_type, $dargs));
         $args = apply_filters(PT_CV_PREFIX_ . 'query_parameters', PT_CV_Functions::view_filter_settings($content_type, $view_settings));
         // Store view data
         set_transient(PT_CV_PREFIX . 'view-data-' . $session_id, array('$args' => $args, '$dargs' => $dargs), 7 * DAY_IN_SECONDS);
     }
     // Pagination settings
     PT_CV_Functions::view_get_pagination_settings($dargs, $args, $pargs);
     // Update global query parameters variable
     $pt_cv_glb[$view_id]['dargs'] = $dargs;
     $pt_cv_glb[$view_id]['args'] = $args;
     do_action(PT_CV_PREFIX_ . 'add_global_variables');
     // Validate settings, if some required parameters are missing, show error and exit
     $error = apply_filters(PT_CV_PREFIX_ . 'validate_settings', array(), $args);
     // Return error message
     if ($error) {
         return implode('</p><p>', $error);
     }
     /**
      * 2. Output Items
      */
     $pt_query = array();
     // What kind of content to display
     $pt_cv_glb[$view_id]['display_what'] = apply_filters(PT_CV_PREFIX_ . 'display_what', 'post');
     if ($pt_cv_glb[$view_id]['display_what'] === 'post') {
         // Display posts
         // Get $content_items & $pt_query
         extract(self::get_posts_list($args, $view_type));
     } else {
         // Display categories...
         $content_items = apply_filters(PT_CV_PREFIX_ . 'view_content', array());
     }
     // Restore main View id
     $pt_cv_id = $pt_cv_main_id;
     /**
      * 3. Output Pagination
      */
     $current_page = self::get_current_page($pargs);
     $html = PT_CV_Html::content_items_wrap($content_items, $current_page, $args['posts_per_page'], $view_id);
     // Append Pagination HTML if this is first page, or not Ajax calling
     if ($pt_query && $args['posts_per_page'] > 0 && PT_CV_Functions::is_pagination($dargs, $current_page)) {
         // Total post founds
         $found_posts = apply_filters(PT_CV_PREFIX_ . 'found_posts', $pt_query->found_posts);
         // Total number of items
         $total_items = $args['limit'] > 0 && $found_posts > $args['limit'] ? $args['limit'] : $found_posts;
         // Total number of pages
         $max_num_pages = ceil($total_items / $args['posts_per_page']);
         // Output pagination
         $html .= "\n" . PT_CV_Html::pagination_output($max_num_pages, $current_page, $session_id);
     }
     // Reset View ID
     $pt_cv_glb[$pt_cv_id]['finished'] = 1;
     return $html;
 }
 /**
  * Wrap content of all items
  *
  * @param array $content_items The array of Raw HTML output (is not wrapped) of each item
  * @param int   $current_page  The current page
  * @param int   $post_per_page The number of posts per page
  * @param int   $id            ID of View
  *
  * @return string Full HTML output for Content View
  */
 static function content_items_wrap($content_items, $current_page, $post_per_page, $id)
 {
     global $pt_cv_glb, $pt_cv_id;
     $dargs = PT_CV_Functions::get_global_variable('dargs');
     if (empty($content_items)) {
         return 'empty content_items';
     }
     // Assign as global variable
     $pt_cv_glb[$pt_cv_id]['content_items'] = $content_items;
     $display = PT_CV_Functions::is_pagination($dargs, $current_page);
     // 1. Before output
     $before_output = $display ? apply_filters(PT_CV_PREFIX_ . 'before_output_html', '') : '';
     // 2. Output content
     $content = array();
     $view_type = $dargs['view-type'];
     // Separate items by row, column
     switch ($view_type) {
         // Grid
         case 'grid':
             PT_CV_Html_ViewType::grid_wrapper($content_items, $content);
             break;
             // Collapsible List
         // Collapsible List
         case 'collapsible':
             PT_CV_Html_ViewType::collapsible_wrapper($content_items, $content);
             break;
             // Scrollable List
         // Scrollable List
         case 'scrollable':
             PT_CV_Html_ViewType::scrollable_wrapper($content_items, $content);
             break;
         default:
             foreach ($content_items as $post_id => $content_item) {
                 // Wrap content of item
                 $content[] = PT_CV_Html::content_item_wrap($content_item, '', $post_id);
             }
             $content = apply_filters(PT_CV_PREFIX_ . 'content_items_wrap', $content, $content_items, $current_page, $post_per_page);
             break;
     }
     // Join content
     $content_list = balanceTags(implode("\n", $content));
     // Custom attribute of a page
     $page_attr_ = apply_filters(PT_CV_PREFIX_ . 'page_attr', '', $view_type, $content_items);
     $page_attr = strip_tags($page_attr_);
     // Wrap items in 'page' wrapper
     $wrap_in_page = apply_filters(PT_CV_PREFIX_ . 'wrap_in_page', true);
     if ($wrap_in_page) {
         // Wrap in page wrapper
         $html = sprintf('<div id="%s" class="%s" %s>%s</div>', esc_attr(PT_CV_PREFIX . 'page' . '-' . $current_page), esc_attr(PT_CV_PREFIX . 'page'), $page_attr, $content_list);
         // Remove page attribute value
         $page_attr = '';
     } else {
         $html = $content_list;
     }
     if ($display) {
         // Get wrapper class of a view
         $view_class = apply_filters(PT_CV_PREFIX_ . 'view_class', array(PT_CV_PREFIX . 'view', PT_CV_PREFIX . $view_type));
         // ID for the wrapper
         $view_id = PT_CV_PREFIX . 'view-' . $id;
         $output = sprintf('<div class="%s" id="%s" %s>%s</div>', esc_attr(implode(' ', array_filter($view_class))), esc_attr($view_id), $page_attr, $html);
         do_action(PT_CV_PREFIX_ . 'store_view_data', $view_id);
     } else {
         $output = $html;
     }
     return balanceTags($before_output) . balanceTags($output);
 }