/**
 * Parse shortcodes in the page content
 * @param string page content to be evaluated for internal shortcodes
 */
function wpv_parse_content_shortcodes($content) {
	global $WPV_settings;
    
    $views_shortcodes_regex = wpv_inner_shortcodes_list_regex();
    
	$inner_expressions = array();
	$inner_expressions[] = "/\\[types.*?\\].*?\\[\\/types\\]/i";    
	$inner_expressions[] = "/\\[(". $views_shortcodes_regex .").*?\\]/i";
	// support for custom inner shortcodes via settings page
	// since 1.4
	$custom_inner_shortcodes = array();
	if ( isset( $WPV_settings->wpv_custom_inner_shortcodes ) && is_array( $WPV_settings->wpv_custom_inner_shortcodes ) ) {
		$custom_inner_shortcodes = $WPV_settings->wpv_custom_inner_shortcodes;
	}
	// wpv_custom_inner_shortcodes filter
	// since 1.4
	// takes an array of shortcodes and returns an array of shortcodes
	$custom_inner_shortcodes = apply_filters( 'wpv_custom_inner_shortcodes', $custom_inner_shortcodes );
	// remove duplicates
	$custom_inner_shortcodes = array_unique( $custom_inner_shortcodes );
	// add the custom inner shortcodes, whether they are self-closing or not
	if ( sizeof( $custom_inner_shortcodes ) > 0 ) {
		foreach ( $custom_inner_shortcodes as $custom_inner_shortcode ) {
			$inner_expressions[] = "/\\[" . $custom_inner_shortcode . ".*?\\].*?\\[\\/" . $custom_inner_shortcode . "\\]/i";
		}
		$inner_expressions[] = "/\\[(" . implode( '|', $custom_inner_shortcodes ) . ").*?\\]/i";
	}
	// search for shortcodes
	$matches = array();
	$counts = _find_outer_brackets($content, $matches);
	
	// iterate 0-level shortcode elements
	if($counts > 0) {
		foreach($matches as $match) {
			
			foreach ($inner_expressions as $inner_expression) {
				$inner_counts = preg_match_all($inner_expression, $match, $inner_matches);
				
				// replace all 1-level inner shortcode matches
				if($inner_counts > 0) {
					foreach($inner_matches[0] as &$inner_match) {
						// execute shortcode content and replace
						$resolved_match = wpv_preprocess_shortcodes_in_html_elements($inner_match);
						$filter_state = new WPV_WP_filter_state( 'the_content' );
						$resolved_match = do_shortcode( $resolved_match );
						$filter_state->restore();
						$content = str_replace($inner_match, $resolved_match, $content);
						$match = str_replace($inner_match, $resolved_match, $match);
					}
				}
			}
		}
	}
	
	return $content;
}
/**
* wpv_preprocess_shortcodes_in_html_elements
*
* Processes Views shortcodes inside HTML attributes, fixing a compatibility issue with WordPress 4.2.3 and beyond.
* Heavily inspired in do_shortcodes_in_html_tags.
*
* @since 1.9.1
*/

function wpv_preprocess_shortcodes_in_html_elements( $content ) {
	global $WPV_settings;
	$views_shortcodes_regex = wpv_inner_shortcodes_list_regex();
	$inner_expressions = array();
	$inner_expressions[] = array(
								 'regex'       => "/\\[types.*?\\]\\[\\/types\\]/i",
								 'has_content' => false
								);
	$inner_expressions[] = array(
								 'regex'       => "/\\[types.*?\\](.*?)\\[\\/types\\]/i",
								 'has_content' => true
								);
	$inner_expressions[] = array(
								 'regex'       => "/\\[(". $views_shortcodes_regex .").*?\\]/i",
								 'has_content' => false
								);
	
	// support for custom inner shortcodes via settings page
	// since 1.4
	$custom_inner_shortcodes = array();
	if ( isset( $WPV_settings->wpv_custom_inner_shortcodes ) && is_array( $WPV_settings->wpv_custom_inner_shortcodes ) ) {
		$custom_inner_shortcodes = $WPV_settings->wpv_custom_inner_shortcodes;
	}
	// wpv_custom_inner_shortcodes filter
	// since 1.4
	// takes an array of shortcodes and returns an array of shortcodes
	$custom_inner_shortcodes = apply_filters( 'wpv_custom_inner_shortcodes', $custom_inner_shortcodes );
	// remove duplicates
	$custom_inner_shortcodes = array_unique( $custom_inner_shortcodes );
	// add the custom inner shortcodes, whether they are self-closing or not
	if ( sizeof( $custom_inner_shortcodes ) > 0 ) {
		foreach ( $custom_inner_shortcodes as $custom_inner_shortcode ) {
			$inner_expressions[] = array(
										 'regex'       => "/\\[" . $custom_inner_shortcode . ".*?\\](.*?)\\[\\/" . $custom_inner_shortcode . "\\]/is",
										 'has_content' => true
										);
		}
		$inner_expressions[] = array(
									 'regex' => "/\\[(" . implode( '|', $custom_inner_shortcodes ) . ").*?\\]/i",
									 'has_content' => false
									);
	}
			
			
	// Normalize entities in unfiltered HTML before adding placeholders.
	$trans = array( '[' => '[', ']' => ']' );
	$content = strtr( $content, $trans );
	
	$textarr = wpv_html_split( $content );

	foreach ( $textarr as &$element ) {
		if ( '' == $element || '<' !== $element[0] ) {
			continue;
		}

		$noopen = false === strpos( $element, '[' );
		$noclose = false === strpos( $element, ']' );
		if ( $noopen || $noclose ) {
			// This element does not contain shortcodes.
			continue;
		}

		if ( '<!--' === substr( $element, 0, 4 ) || '<![CDATA[' === substr( $element, 0, 9 ) ) {
			continue;
		}
		
		foreach ( $inner_expressions as $shortcode ) {
			$counts = preg_match_all( $shortcode[ 'regex' ], $element, $matches );
			
			if ( $counts > 0 ) {
				foreach ( $matches[0] as $index => &$match ) {
					
					// We need to exclude wpv-post-body here otherwise
					// wpautop can be applied to it too soon.
					
					if ( strpos( $match, '[wpv-post-body' ) !== 0 ) {
						$string_to_replace = $match;
						
						// execute shortcode content and replace
						
						if ( $shortcode[ 'has_content' ] ) {
							$inner_content = $matches[1][ $index ];
							if ( $inner_content ) {
								$new_inner_content = wpv_preprocess_shortcodes_in_html_elements( $inner_content );
								$match = str_replace( $inner_content, $new_inner_content, $match );
							}
						}
						$filter_state = new WPV_WP_filter_state( 'the_content' );
						$replacement = do_shortcode( $match );
						$filter_state->restore();
						$resolved_match = $replacement;
						$element = str_replace( $string_to_replace, $resolved_match, $element );
					}
				}
			}
		}
		
	}
	
	$content = implode( '', $textarr );
	
	return $content;
}
/**
 * Views-Shortcode: wpv-post-body
 *
 * Description: Display the content of the current post
 *
 * Parameters:
 * 'view_template' => The name of a Content template to use when displaying the post content.
 * 'suppress_filters' => Returns the post body with just the natural WordPress filters applied
 * 'output' => [ normal | raw | inherit ] The format of the output when view_template="None": with wpautop, without wpautop or inherited from the parent Template when aplicable
 *
 * Example usage:
 * [wpv-post-body view_template="None"]
 *
 * Link:
 *
 * Note:
 *
 */
function wpv_shortcode_wpv_post_body($atts)
{
    $post_id_atts = new WPV_wpcf_switch_post_from_attr_id($atts);
    extract(shortcode_atts(array('view_template' => 'None', 'output' => 'normal'), $atts));
    $old_override = null;
    $out = '';
    global $post;
    if (!is_object($post) || empty($post)) {
        return $out;
    }
    if (post_password_required($post)) {
        $post_protected_password_form = get_the_password_form($post);
        /**
         * Filter wpv_filter_post_protected_body
         *
         * @param (string) $post_protected_password_form The default WordPress password form
         * @param (object) $post The post object to which this shortcode is related to
         * @param (array) $atts The array of attributes passed to this shortcode
         *
         * @return (string)
         *
         * @since 1.7.0
         */
        return apply_filters('wpv_filter_post_protected_body', $post_protected_password_form, $post, $atts);
    }
    global $WPV_templates, $WPVDebug;
    static $stop_infinite_loop_keys;
    if (isset($atts['suppress_filters']) && $atts['suppress_filters'] == 'true') {
        $suppress_filters = true;
    } else {
        $suppress_filters = false;
    }
    $id = '';
    if (isset($atts['view_template'])) {
        if (isset($post->view_template_override) && $post->view_template_override != '') {
            $old_override = $post->view_template_override;
        }
        $post->view_template_override = $atts['view_template'];
        $id = $post->view_template_override;
    }
    if (strtolower($id) == 'none') {
        $ct_id = $id;
        $output_mode = $output;
    } else {
        $ct_id = $WPV_templates->get_template_id($id);
        $output_mode = 'normal';
    }
    $WPVDebug->wpv_debug_start($ct_id, $atts, 'content-template');
    $WPVDebug->set_index();
    if ($WPVDebug->user_can_debug()) {
        global $WP_Views;
        $current_item_type = 'posts';
        $view_settings = $WP_Views->get_view_settings();
        if (isset($view_settings['view-query-mode']) && $view_settings['view-query-mode'] == 'normal' && isset($view_settings['query_type']) && isset($view_settings['query_type'][0]) && $view_settings['query_type'][0] != 'posts') {
            $current_item_type = $view_settings['query_type'][0];
            // taxonomy or users
        }
        switch ($current_item_type) {
            case 'posts':
                $WPVDebug->add_log('content-template', $post);
                break;
            case 'taxonomy':
                $WPVDebug->add_log('content-template', $WP_Views->taxonomy_data['term']);
                break;
            case 'users':
                $WPVDebug->add_log('content-template', $WP_Views->users_data['term']);
                break;
        }
    }
    if (!empty($post) && isset($post->post_type) && $post->post_type != 'view' && $post->post_type != 'view-template') {
        // Set the output mode for this shortcode (based on the "output" attribute if the "view_template" attribute is set to None, the selected Template output mode will override this otherwise)
        // normal (default) - restore wpautop, only needed if has been previously removed
        // raw - remove wpautop and set the $wpautop_was_active to true
        // inherit - when used inside a Content Template, inherit its wpautop setting; when used outside a Template, inherit from the post itself (so add format, just like "normal")
        // NOTE BUG: we need to first remove_wpautop because for some reason not doing so switches the global $post to the top_current_page one
        $wpautop_was_removed = $WPV_templates->is_wpautop_removed();
        $wpautop_was_active = false;
        $WPV_templates->remove_wpautop();
        if ($wpautop_was_removed) {
            // if we had disabled wpautop, we only need to enable it again for mode "normal" in view_template="None" (will be overriden by Template settings if needed)
            if ($output_mode == 'normal') {
                $WPV_templates->restore_wpautop('');
            }
        } else {
            // if wpautop was not disabled, we need to revert its state, but just for modes "normal" and "inherit"; we will enable it globally again after the main procedure
            $wpautop_was_active = true;
            if ($output_mode == 'normal' || $output_mode == 'inherit') {
                $WPV_templates->restore_wpautop('');
            }
        }
        // Remove the icl language switcher to stop WPML from add the
        // "This post is avaiable in XXXX" twice.
        // Keep this: we need to know that this needs to be restored by the flag $icl_filter_removed
        global $icl_language_switcher;
        $icl_filter_removed = false;
        if (isset($icl_language_switcher)) {
            $icl_filter_removed = remove_filter('the_content', array($icl_language_switcher, 'post_availability'), 100);
        }
        // Check for infinite loops where a View template contains a
        // wpv-post-body shortcode without a View template specified
        // or a View template refers to itself directly or indirectly.
        $key = (string) $post->ID;
        if (isset($post->view_template_override)) {
            $key .= $post->view_template_override;
        }
        if (!isset($stop_infinite_loop_keys[$key])) {
            $stop_infinite_loop_keys[$key] = 1;
            if ($suppress_filters) {
                /**
                 * wpv_filter_wpv_the_content_suppressed
                 *
                 * Mimics the the_content filter on wpv-post-body shortcodes with attribute suppress_filters="true"
                 * Check WPV_template::init()
                 *
                 * Since 1.8.0
                 */
                $out .= apply_filters('wpv_filter_wpv_the_content_suppressed', $post->post_content);
            } else {
                $filter_state = new WPV_WP_filter_state('the_content');
                $out .= apply_filters('the_content', $post->post_content);
                $filter_state->restore();
            }
            unset($stop_infinite_loop_keys[$key]);
        } else {
            $out .= $post->post_content;
        }
        if ($icl_filter_removed) {
            // TODO this might not be needed anymore as we are restoring all the filters below
            add_filter('the_content', array($icl_language_switcher, 'post_availability'), 100);
        }
        // Restore the wpautop configuration only if is has been changed
        if ($wpautop_was_removed) {
            $WPV_templates->remove_wpautop();
        } else {
            if ($wpautop_was_active) {
                $WPV_templates->restore_wpautop('');
            }
        }
    }
    if (isset($post->view_template_override)) {
        if ($old_override) {
            $post->view_template_override = $old_override;
        } else {
            unset($post->view_template_override);
        }
    }
    $WPVDebug->add_log_item('output', $out);
    $WPVDebug->wpv_debug_end();
    apply_filters('wpv_shortcode_debug', 'wpv-post-body', json_encode($atts), '', 'Output shown in the Nested elements section');
    return $out;
}