/** * 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; }