/**
  * Core function to render a View based on a set of arguments
  *
  * @access public
  * @static
  * @param array $passed_args {
  *
  *      Settings for rendering the View
  *
  *      @type int $id View id
  *      @type int $page_size Number of entries to show per page
  *      @type string $sort_field Form field id to sort
  *      @type string $sort_direction Sorting direction ('ASC' or 'DESC')
  *      @type string $start_date - Ymd
  *      @type string $end_date - Ymd
  *      @type string $class - assign a html class to the view
  *      @type string $offset (optional) - This is the start point in the current data set (0 index based).
  * }
  *
  * @return string|null HTML output of a View, NULL if View isn't found
  */
 public function render_view($passed_args)
 {
     // validate attributes
     if (empty($passed_args['id'])) {
         do_action('gravityview_log_error', '[render_view] Returning; no ID defined.', $passed_args);
         return null;
     }
     // Solve problem when loading content via admin-ajax.php
     // @hack
     if (!$this->getGvOutputData()) {
         do_action('gravityview_log_error', '[render_view] gv_output_data not defined; parsing content.', $passed_args);
         $this->parse_content();
     }
     // Make 100% sure that we're dealing with a properly called situation
     if (!is_object($this->getGvOutputData()) || !is_callable(array($this->getGvOutputData(), 'get_view'))) {
         do_action('gravityview_log_error', '[render_view] gv_output_data not an object or get_view not callable.', $this->getGvOutputData());
         return null;
     }
     $view_id = $passed_args['id'];
     $view_data = $this->getGvOutputData()->get_view($view_id, $passed_args);
     do_action('gravityview_log_debug', '[render_view] View Data: ', $view_data);
     do_action('gravityview_log_debug', '[render_view] Init View. Arguments: ', $passed_args);
     // The passed args were always winning, even if they were NULL.
     // This prevents that. Filters NULL, FALSE, and empty strings.
     $passed_args = array_filter($passed_args, 'strlen');
     //Override shortcode args over View template settings
     $atts = wp_parse_args($passed_args, $view_data['atts']);
     do_action('gravityview_log_debug', '[render_view] Arguments after merging with View settings: ', $atts);
     // It's password protected and you need to log in.
     if (post_password_required($view_id)) {
         do_action('gravityview_log_error', sprintf('[render_view] Returning: View %d is password protected.', $view_id));
         // If we're in an embed or on an archive page, show the password form
         if (get_the_ID() !== $view_id) {
             return get_the_password_form();
         }
         // Otherwise, just get outta here
         return null;
     }
     /**
      * Don't render View if user isn't allowed to see it
      * @since 1.15
      */
     if (is_user_logged_in() && false === GVCommon::has_cap('read_gravityview', $view_id)) {
         return null;
     }
     if ($this->isGravityviewPostType()) {
         /**
          * @filter `gravityview_direct_access` Should Views be directly accessible, or only visible using the shortcode?
          * @see https://codex.wordpress.org/Function_Reference/register_post_type#public
          * @see GravityView_Post_Types::init_post_types
          * @since 1.15.2
          * @param[in,out] boolean `true`: allow Views to be accessible directly. `false`: Only allow Views to be embedded via shortcode. Default: `true`
          * @param int $view_id The ID of the View currently being requested. `0` for general setting
          */
         $direct_access = apply_filters('gravityview_direct_access', true, $view_id);
         $embed_only = !empty($atts['embed_only']);
         if (!$direct_access || $embed_only && !GVCommon::has_cap('read_private_gravityviews')) {
             return __('You are not allowed to view this content.', 'gravityview');
         }
     }
     ob_start();
     /**
      * Set globals for templating
      * @deprecated 1.6.2
      */
     global $gravityview_view;
     $gravityview_view = new GravityView_View($view_data);
     $post_id = !empty($atts['post_id']) ? intval($atts['post_id']) : $this->getPostId();
     $gravityview_view->setPostId($post_id);
     if (!$this->getSingleEntry()) {
         // user requested Directory View
         do_action('gravityview_log_debug', '[render_view] Executing Directory View');
         //fetch template and slug
         $view_slug = apply_filters('gravityview_template_slug_' . $view_data['template_id'], 'table', 'directory');
         do_action('gravityview_log_debug', '[render_view] View template slug: ', $view_slug);
         /**
          * Disable fetching initial entries for views that don't need it (DataTables)
          */
         $get_entries = apply_filters('gravityview_get_view_entries_' . $view_slug, true);
         /**
          * Hide View data until search is performed
          * @since 1.5.4
          */
         if (!empty($atts['hide_until_searched']) && !$this->isSearch()) {
             $gravityview_view->setHideUntilSearched(true);
             $get_entries = false;
         }
         if ($get_entries) {
             if (!empty($atts['sort_columns'])) {
                 // add filter to enable column sorting
                 add_filter('gravityview/template/field_label', array($this, 'add_columns_sort_links'), 100, 3);
             }
             $view_entries = self::get_view_entries($atts, $view_data['form_id']);
             do_action('gravityview_log_debug', sprintf('[render_view] Get Entries. Found %s entries total, showing %d entries', $view_entries['count'], sizeof($view_entries['entries'])));
         } else {
             $view_entries = array('count' => null, 'entries' => null, 'paging' => null);
             do_action('gravityview_log_debug', '[render_view] Not fetching entries because `gravityview_get_view_entries_' . $view_slug . '` is false');
         }
         $gravityview_view->setPaging($view_entries['paging']);
         $gravityview_view->setContext('directory');
         $sections = array('header', 'body', 'footer');
     } else {
         // user requested Single Entry View
         do_action('gravityview_log_debug', '[render_view] Executing Single View');
         do_action('gravityview_render_entry_' . $view_data['id']);
         $entry = $this->getEntry();
         // You are not permitted to view this entry.
         if (empty($entry) || !self::is_entry_approved($entry, $atts)) {
             do_action('gravityview_log_debug', '[render_view] Entry does not exist. This may be because of View filters limiting access.');
             /**
              * @since 1.6
              */
             echo esc_attr(apply_filters('gravityview/render/entry/not_visible', __('You have attempted to view an entry that is not visible or may not exist.', 'gravityview')));
             return null;
         }
         // We're in single view, but the view being processed is not the same view the single entry belongs to.
         // important: do not remove this as it prevents fake attempts of displaying entries from other views/forms
         if ($this->getGvOutputData()->has_multiple_views() && $view_id != $this->get_context_view_id()) {
             do_action('gravityview_log_debug', '[render_view] In single entry view, but the entry does not belong to this View. Perhaps there are multiple views on the page. View ID: ' . $view_id);
             return null;
         }
         //fetch template and slug
         $view_slug = apply_filters('gravityview_template_slug_' . $view_data['template_id'], 'table', 'single');
         do_action('gravityview_log_debug', '[render_view] View single template slug: ', $view_slug);
         //fetch entry detail
         $view_entries['count'] = 1;
         $view_entries['entries'][] = $entry;
         do_action('gravityview_log_debug', '[render_view] Get single entry: ', $view_entries['entries']);
         $back_link_label = isset($atts['back_link_label']) ? $atts['back_link_label'] : null;
         // set back link label
         $gravityview_view->setBackLinkLabel($back_link_label);
         $gravityview_view->setContext('single');
         $sections = array('single');
     }
     // add template style
     self::add_style($view_data['template_id']);
     // Prepare to render view and set vars
     $gravityview_view->setEntries($view_entries['entries']);
     $gravityview_view->setTotalEntries($view_entries['count']);
     // If Edit
     if ('edit' === gravityview_get_context()) {
         do_action('gravityview_log_debug', '[render_view] Edit Entry ');
         do_action('gravityview_edit_entry', $this->getGvOutputData());
         return ob_get_clean();
     } else {
         // finaly we'll render some html
         $sections = apply_filters('gravityview_render_view_sections', $sections, $view_data['template_id']);
         do_action('gravityview_log_debug', '[render_view] Sections to render: ', $sections);
         foreach ($sections as $section) {
             do_action('gravityview_log_debug', '[render_view] Rendering ' . $section . ' section.');
             $gravityview_view->render($view_slug, $section, false);
         }
     }
     //@todo: check why we need the IF statement vs. print the view id always.
     if ($this->isGravityviewPostType() || $this->isPostHasShortcode()) {
         // Print the View ID to enable proper cookie pagination
         echo '<input type="hidden" class="gravityview-view-id" value="' . esc_attr($view_id) . '">';
     }
     $output = ob_get_clean();
     return $output;
 }