JezK
Edit File: class-cartflows-bricks-dynamic-data.php
<?php /** * Cartflows Bricks Dynamic Data. * * @package Cartflows */ if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly. } /** * This class handles bricks dynamic data functionality. */ class Cartflows_Bricks_Dynamic_Data { /** * Member Variable * * @var object instance */ private static $instance; /** * Initiator * * @return object instance */ public static function get_instance() { if ( ! isset( self::$instance ) ) { self::$instance = new self(); } return self::$instance; } /** * Setup actions and filters. * * @since 1.6.13 */ private function __construct() { add_filter( 'bricks/dynamic_tags_list', array( $this, 'dynamic_tags' ), 10 ); add_filter( 'bricks/dynamic_data/render_tag', array( $this, 'get_the_tag_value' ), 10, 3 ); add_filter( 'bricks/frontend/render_data', array( $this, 'render' ), 10, 3 ); add_filter( 'bricks/dynamic_data/render_content', array( $this, 'render' ), 10, 3 ); } /** * Register Tags. * * @param array $tags Existing tags. * * @return array */ public function dynamic_tags( $tags = array() ) { $cartflows_tags = apply_filters( 'cartflows_bricks_dynamic_tags_list', array( array( 'slug' => 'wcf_next_step', 'name' => '{wcf_next_step}', 'label' => esc_html__( 'Next Step', 'cartflows' ), 'group' => esc_html__( 'CartFlows', 'cartflows' ), ), ) ); return array_merge( $tags, $cartflows_tags ); } /** * Parse tag * * @param string $name Tag name. * @param object $post Post object. * @return string */ public function parse_tag( $name, $post ) { switch ( $name ) { case 'wcf_next_step': return '?class=wcf-next-step'; } $name = apply_filters( 'cartflows_bricks_dynamic_data_render_tag', $name, $post ); return $name; } /** * Dynamic tag exists in $content: Replaces dynamic tag with requested data. * * @param string $content Content. * @param WP_Post $post Post object. * @param string $context Context. * * @return string */ public function render( $content, $post, $context = 'text' ) { if ( ! wcf()->utils->is_step_post_type() ) { return $content; } /** * \w: Matches any word character (alphanumeric & underscore). * Equivalent to [A-Za-z0-9_] * "À-ÖØ-öø-ÿ" Add the accented characters * "-" Needed because some post types handles are like "my-post-type" * ":" Needed for extra arguments to dynamic data tags (e.g. post_excerpt:20 or wp_user_meta:my_meta_key) * "|" and "," needed for the post terms like {post_terms_post_tag:sep} where sep could be a pipe or comma * "(", ")" and "'" for the function arguments of the dynamic tag {echo} * "@" to support email addresses as arguments of the dynamic tag {echo} #3kazphp * * @since 1.9.4: "u" modifier: Pattern strings are treated as UTF-8 to support Cyrillic, Arabic, etc. * @since 1.10: "$", "+", "%", "#", "!", "=", "<", ">", "&", "~", "[", "]", ";" as arguments of the dynamic tag {echo} * * @see https://regexr.com/ */ $pattern = '/{([\wÀ-ÖØ-öø-ÿ\-\s\.\/:\(\)\'@|,$%#!+=<>&~\[\];]+)}/u'; /** * Matches the echo tag pattern (#86bwebj6m) * * @since 1.9.8 */ $echo_pattern = '/echo:([a-zA-Z0-9_]+)/'; // Get a list of tags to exclude from the Dynamic Data logic. $exclude_tags = apply_filters( 'bricks/dynamic_data/exclude_tags', array() ); // phpcs:ignore /** * STEP: Determine how many times we need to run the DD parser * * Previously we ran the parser by counting the number of open curly braces in the content. (@since 1.8) * But this is not reliable because the content could contain curly braces in the code elements or any shortcodes. * Causing the website to load extremely slow. * * @since 1.8.2 (#862jyyryg) */ // Get all registered tags except the excluded ones. // Example: [0 => "post_title", 1 => "woo_product_price", 2 => "echo"]. $registered_tags = array_filter( array_column( $this->dynamic_tags(), 'slug' ), function ( $tag ) use ( $exclude_tags ) { return ! in_array( $tag, $exclude_tags, true ); } ); $dd_tags_in_content = array(); $dd_tags_found = array(); $echo_tags_found = array(); // Find all dynamic data tags in the content. preg_match_all( $pattern, $content, $dd_tags_in_content ); $dd_tags_in_content = ! empty( $dd_tags_in_content[1] ) ? $dd_tags_in_content[1] : array(); // Find all echo tags in the content. preg_match_all( $echo_pattern, $content, $echo_tags_found ); // Combine the dynamic data tags from the content and the echo tags. if ( ! empty( $echo_tags_found[0] ) ) { $dd_tags_in_content = array_merge( $dd_tags_in_content, $echo_tags_found[0] ); } if ( ! empty( $dd_tags_in_content ) ) { /** * $dd_tags_in_content only matches the pattern, but some codes from Code element could match the pattern too. * Example: function test() { return 'Hello World'; } will match the pattern, but it's not a dynamic data tag. * * Find all dynamic data tags in the content which starts with dynamic data tag from $registered_tags * Cannot use array_in or array_intersect because $registered_tags only contains the tag name, somemore tags could have filters like {echo:my_function( 'Hello World' ) * * Example: $registered_tags = [0 => "post_title", 1 => "woo_product_price", 2 => "echo"] * Example: $dd_tags_in_content = [0 => "post_title", 1 => "woo_product_price:value", 2 => "echo:my_function('Hello World')"] */ $dd_tags_found = array_filter( $dd_tags_in_content, function ( $tag ) use ( $registered_tags ) { foreach ( $registered_tags as $all_tag ) { /** * Skip not our tags. */ if ( strpos( $tag, 'wcf_' ) === 0 ) { return true; } if ( strpos( $tag, $all_tag ) === 0 ) { return true; } } return false; } ); } // Get the count of found dynamic data tags. $dd_tag_count = count( $dd_tags_found ); // STEP: Run the parser based on the count of found dynamic data tags. for ( $i = 0; $i < $dd_tag_count; $i++ ) { preg_match_all( $pattern, $content, $matches ); if ( empty( $matches[0] ) ) { return $content; } foreach ( $matches[1] as $key => $match ) { $tag = $matches[0][ $key ]; if ( in_array( $match, $exclude_tags, true ) ) { continue; } $value = $this->get_the_tag_value( $match, $post, $content ); $content = str_replace( $tag, $value, $content ); } ++$dd_tag_count; } return $content; } /** * Main function to render the tag value for WooCommerce provider * * @param string $tag Tag name. * @param object $post Post object. * @param string $context The Tag context. * * @return string */ public function get_the_tag_value( $tag, $post, $context ) { if ( ! wcf()->utils->is_step_post_type() ) { return $tag; } // Get all the registered tags and check if the tag exists. $registered_tags = $this->dynamic_tags(); $tag_slug = strtok( $tag, ':' ); if ( ! in_array( $tag_slug, array_column( $registered_tags, 'slug' ), true ) ) { return $tag; } // Return the parsed tag value. return $this->parse_tag( $tag, $post ); } } /** * Initiate the class. */ Cartflows_Bricks_Dynamic_Data::get_instance();