Plugin Directory

Changeset 3462938


Ignore:
Timestamp:
02/16/2026 10:10:44 PM (4 weeks ago)
Author:
vectoron
Message:

Fix: Replace broken shortcode-based detection with class marker detection for .vectoron-content wrapper

The [vectoron_article] shortcode was stripped by do_shortcode (priority 11) before
vectoron_wrap_content (priority 99) could detect it — so detection never actually worked.
The wrapper only appeared on builder sites because integrations hardcode it in save_post hooks.

Three-layer fix:

  • Storage-time: vectoron-api.php wraps content in create_post() and update_post() when am-article class detected
  • Render-time: shortcodes.php wraps as fallback for existing posts (detected by .am-article class, not shortcode)
  • Double-wrap guard: All 4 builder integrations (Elementor, Beaver Builder, DIVI, WP Bakery) check before wrapping
  • Shortcode registration kept for backward compat (existing posts won't show raw [vectoron_article] text)
Location:
vectoron/trunk
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • vectoron/trunk/includes/shortcodes.php

    r3448212 r3462938  
    11<?php
    22/**
    3  * Vectoron Shortcodes and Asset Loading
     3 * Vectoron Content Detection and Asset Loading
    44 *
    5  * Provides [vectoron_article] shortcode functionality:
    6  * - Disables wpautop for shortcode content
    7  * - Wraps content in .vectoron-content container
     5 * Detects Vectoron-generated content by .vectoron-content wrapper or .am-article class:
     6 * - Disables wpautop for Vectoron content
     7 * - Wraps content in .vectoron-content container (render-time fallback for existing posts)
    88 * - Enqueues CSS/JS for FAQ accordion
    99 * - Injects universal GA4 tracking script
     10 * - Keeps [vectoron_article] shortcode registered for backward compatibility only
    1011 *
    1112 * @package Vectoron
     
    1819
    1920/**
    20  * Check if the vectoron shortcode is present in post content or ACF field.
     21 * Check if post contains Vectoron-generated content.
     22 *
     23 * Detects the .vectoron-content wrapper (added by vectoron-api.php on publish)
     24 * or the .am-article class (from json_to_html.py) for existing posts published
     25 * before the wrapper was added at save time.
    2126 *
    2227 * @param int|WP_Post|null $post Optional. Post ID or post object. Defaults to global $post.
    23  * @return bool True if shortcode is found in post_content or configured ACF field.
     28 * @return bool True if Vectoron content is found in post_content or configured ACF field.
    2429 */
    2530function vectoron_has_shortcode( $post = null ) {
     
    2934    }
    3035
    31     // Check main post_content first.
    32     if ( has_shortcode( $post->post_content, 'vectoron_article' )
    33         || has_shortcode( $post->post_content, 'marketing_visionary_article' ) ) {
     36    // Check for Vectoron content wrapper (added by vectoron-api.php on publish).
     37    if ( strpos( $post->post_content, 'vectoron-content' ) !== false ) {
     38        return true;
     39    }
     40
     41    // Check for Vectoron-generated HTML (am-article class from json_to_html.py).
     42    // Catches existing posts published before the wrapper was added at save time.
     43    if ( strpos( $post->post_content, 'class="am-article"' ) !== false ) {
    3444        return true;
    3545    }
     
    4050        $acf_content = get_field( $acf_field, $post->ID );
    4151        if ( is_string( $acf_content ) && (
    42             has_shortcode( $acf_content, 'vectoron_article' )
    43             || has_shortcode( $acf_content, 'marketing_visionary_article' )
     52            strpos( $acf_content, 'vectoron-content' ) !== false
     53            || strpos( $acf_content, 'class="am-article"' ) !== false
    4454        ) ) {
    4555            return true;
     
    5161
    5262/**
    53  * Disable wpautop if the shortcode is present
     63 * Disable wpautop if Vectoron content is present.
    5464 */
    5565function vectoron_disable_wpautop( $content ) {
    56     if ( has_shortcode( $content, 'vectoron_article' )
    57         || has_shortcode( $content, 'marketing_visionary_article' ) ) {
     66    if ( strpos( $content, 'vectoron-content' ) !== false
     67        || strpos( $content, 'class="am-article"' ) !== false ) {
    5868        remove_filter( 'the_content', 'wpautop' );
    5969    }
     
    6373
    6474/**
    65  * Wrap content in .vectoron-content container when shortcode is present.
     75 * Wrap content in .vectoron-content container at render time (fallback for existing posts).
    6676 */
    6777function vectoron_wrap_content( $content ) {
    68     if ( has_shortcode( $content, 'vectoron_article' )
    69         || has_shortcode( $content, 'marketing_visionary_article' ) ) {
     78    // Already wrapped — skip.
     79    if ( strpos( $content, 'vectoron-content' ) !== false ) {
     80        return $content;
     81    }
     82    // Wrap existing posts that have Vectoron HTML but no wrapper.
     83    if ( strpos( $content, 'class="am-article"' ) !== false ) {
    7084        $content = '<div class="vectoron-content">' . $content . '</div>';
    7185    }
     
    310324
    311325/**
    312  * Shortcode handler - no visible output, just triggers asset loading
     326 * Shortcode handler — kept so existing posts with [vectoron_article] don't render raw bracket text.
     327 * Detection no longer depends on this shortcode; it uses .vectoron-content / .am-article class instead.
    313328 */
    314329function vectoron_shortcode_handler( $atts, $content = null ) {
     
    316331}
    317332add_shortcode( 'vectoron_article', 'vectoron_shortcode_handler' );
    318 // Note: 'marketing_visionary_article' shortcode removed - use 'vectoron_article' instead
  • vectoron/trunk/integrations/beaver-builder.php

    r3448969 r3462938  
    108108    // Rich-text module node with the HTML content.
    109109    // Wrap content in .vectoron-content div so CSS styles (FAQ accordions, headings, etc.) work.
     110    // Guard against double-wrapping — content from vectoron-api.php may already have the wrapper.
     111    $wrapped_text = ( strpos( $html_content, 'vectoron-content' ) !== false )
     112        ? $html_content
     113        : '<div class="vectoron-content">' . $html_content . '</div>';
     114
    110115    $module_node = array(
    111116        'node'     => $module_id,
     
    115120        'settings' => (object) array(
    116121            'type' => 'rich-text',
    117             'text' => '<div class="vectoron-content">' . $html_content . '</div>',
     122            'text' => $wrapped_text,
    118123        ),
    119124    );
  • vectoron/trunk/integrations/divi.php

    r3448969 r3462938  
    128128    // Sanitize HTML content to prevent XSS while allowing safe HTML tags.
    129129    // Wrap content in .vectoron-content div so CSS styles (FAQ accordions, headings, etc.) work.
     130    // Guard against double-wrapping — content from vectoron-api.php may already have the wrapper.
     131    $wrapped_content = ( strpos( $html_content, 'vectoron-content' ) !== false )
     132        ? wp_kses_post( $html_content )
     133        : '<div class="vectoron-content">' . wp_kses_post( $html_content ) . '</div>';
     134
    130135    $shortcode_content = sprintf(
    131136        '[et_pb_section fb_built="1" _builder_version="%1$s" global_colors_info="{}"]' .
     
    133138        '[et_pb_column type="4_4" _builder_version="%1$s" custom_padding="|||" global_colors_info="" custom_padding__hover="|||"]' .
    134139        '[et_pb_text _builder_version="%1$s" background_size="initial" background_position="top_left" background_repeat="repeat" global_colors_info="{}"]' .
    135         '<div class="vectoron-content">%2$s</div>' .
     140        '%2$s' .
    136141        '[/et_pb_text]' .
    137142        '[/et_pb_column]' .
     
    139144        '[/et_pb_section]',
    140145        esc_attr( $builder_version ),
    141         wp_kses_post( $html_content )
     146        $wrapped_content
    142147    );
    143148
  • vectoron/trunk/integrations/elementor.php

    r3451062 r3462938  
    9393    // Check if containers are enabled on this site using centralized helper.
    9494    $use_containers = vectoron_is_elementor_containers_enabled();
     95
     96    // Wrap content in .vectoron-content div so CSS styles (FAQ accordions, headings, etc.) work.
     97    // Guard against double-wrapping — content from vectoron-api.php may already have the wrapper.
     98    $wrapped_content = ( strpos( $html_content, 'vectoron-content' ) !== false )
     99        ? $html_content
     100        : '<div class="vectoron-content">' . $html_content . '</div>';
    95101
    96102    if ( $use_containers ) {
     
    116122                        'isInner'    => false,
    117123                        'settings'   => array(
    118                             // Wrap content in .vectoron-content div so CSS styles (FAQ accordions, headings, etc.) work.
    119                             'editor' => '<div class="vectoron-content">' . $html_content . '</div>',
     124                            'editor' => $wrapped_content,
    120125                        ),
    121126                        'elements'   => array(),
     
    155160                            'isInner'    => false,
    156161                            'settings'   => array(
    157                                 // Wrap content in .vectoron-content div so CSS styles (FAQ accordions, headings, etc.) work.
    158                                 'editor' => '<div class="vectoron-content">' . $html_content . '</div>',
     162                                'editor' => $wrapped_content,
    159163                            ),
    160164                            'elements'   => array(),
  • vectoron/trunk/integrations/wp-bakery.php

    r3448969 r3462938  
    127127    // Sanitize HTML content to prevent XSS while allowing safe HTML tags.
    128128    // Wrap content in .vectoron-content div so CSS styles (FAQ accordions, headings, etc.) work.
     129    // Guard against double-wrapping — content from vectoron-api.php may already have the wrapper.
     130    $wrapped_content = ( strpos( $html_content, 'vectoron-content' ) !== false )
     131        ? wp_kses_post( $html_content )
     132        : '<div class="vectoron-content">' . wp_kses_post( $html_content ) . '</div>';
     133
    129134    $shortcode_content = sprintf(
    130         '[vc_row][vc_column][vc_column_text]<div class="vectoron-content">%s</div>[/vc_column_text][/vc_column][/vc_row]',
    131         wp_kses_post( $html_content )
     135        '[vc_row][vc_column][vc_column_text]%s[/vc_column_text][/vc_column][/vc_row]',
     136        $wrapped_content
    132137    );
    133138
  • vectoron/trunk/vectoron-api.php

    r3459361 r3462938  
    435435        $content = sanitize_post_field('post_content', $request->get_param('content'), 0, 'db');
    436436
     437        // Wrap Vectoron content in .vectoron-content div for CSS scoping.
     438        // Detects content from json_to_html.py by the am-article class marker.
     439        if ( strpos( $content, 'class="am-article"' ) !== false
     440            && strpos( $content, 'vectoron-content' ) === false ) {
     441            $content = '<div class="vectoron-content">' . $content . '</div>';
     442        }
     443
    437444        // Validate and sanitize post status
    438445        $status_input = sanitize_text_field($request->get_param('status')) ?: 'draft';
     
    607614        // Use sanitize_post for content to preserve shortcodes
    608615        $content = sanitize_post_field('post_content', $request->get_param('content'), $post_id, 'db');
     616
     617        // Wrap Vectoron content in .vectoron-content div for CSS scoping.
     618        if ( ! empty( $content )
     619            && strpos( $content, 'class="am-article"' ) !== false
     620            && strpos( $content, 'vectoron-content' ) === false ) {
     621            $content = '<div class="vectoron-content">' . $content . '</div>';
     622        }
    609623
    610624        // Validate and sanitize post status
Note: See TracChangeset for help on using the changeset viewer.