elegantthemes / create-divi-extension

MIT License
185 stars 58 forks source link

VB :: React: Divi builder shortcodes don't exist in AJAX calls #128

Open jcdotnet opened 6 years ago

jcdotnet commented 6 years ago

Problem Description

Hello, I'm trying to get data generated from the Divi Builder via AJAX but I'm having issues when trying to call a Divi Builder shortcode, this is my AJAX call:

componentDidUpdate() {  
     $.ajax({
        url : window.ETBuilderBackend.ajaxUrl,
        type : 'post',
        data : {
          action : 'ddtest_handle_divi_section_shortcode',
          test_id : 3 // I'm hardcoding the value for this example
        },
        success : function( response ) {
          console.log(response);
            $('.test-selector').html( response );
        }
      });
}

And this is my PHP code:

function ddtest_handle_divi_section_shortcode() {

    if (function_exists('et_pb_section')) 
        echo 'et_pb_section exists ';
    else 
     echo 'et_pb_section DOES NOT exist '; // this is echoed  
    if (function_exists('do_shortcode')) 
        echo 'do_shortcode exists '; // this is echoed
    else 
     echo 'do_shortcode  DOES NOT exist ';

    echo do_shortcode( '[et_pb_section global_module="' . $_POST['test_id'] . '"][/et_pb_section]' );
    wp_die();
}
add_action( 'wp_ajax_nopriv_ddtest_handle_divi_section_shortcode', 'ddtest_handle_divi_section_shortcode' );
add_action( 'wp_ajax_ddtest_handle_divi_section_shortcode', 'ddtest_handle_divi_section_shortcode' );

The function do_shortcode works and I can render other plugins shortcodes, this only happens with Divi when making AJAX calls.

Steps To Reproduce

  1. Created a PHP function that returns a module content using the WP built-in do_shortcode function
  2. Called this function via AJAX in componentDidUpdate()
  3. The response is the string of the shortcode. The function do_shortcode works but fails when trying to extract the shortcode content, no matter the layout: if fails for sections, modules and for all the Divi shortcode functions. It works fine when using other plugins shortcodes.
jcdotnet commented 6 years ago

What I want to do is load a layout from the Divi Library from React. In order to achieve that I would like to either follow the implementation above (get the shortcode rendered) or try something like this (builder.js, where we get the shorcode and then we render it):

$.ajax( {
    type: "POST",
    url: et_pb_options.ajaxurl,
    data:
    {
       action : 'et_pb_load_layout',
       et_admin_load_nonce : et_pb_options.et_admin_load_nonce,
       et_layout_id : $layout.data( 'layout_id' )   
        },
        success: function( data ){
           ET_PageBuilder_App.createNewLayout( data, 'load_layout' );
    }
} );

I would call to my ddtest_handle_divi_section_shortcode which now would return the post content (I forgot to add the nonces, I just wanted to focus on the shortcode issue). I could even call to the Divi built-in PHP et_pb_load_layout function which do the same in this second scenario.

How could I do this from React? I'm kind of stuck here.

There is another issue related. Hope we can get support and help each other. Thank you in advance.

lots0logs commented 6 years ago

Hi, you can ensure the builder modules are loaded for your ajax callback by using the et_builder_load_actions filter to add your ajax action to the array of allowed actions:

function ddtest_et_builder_load_actions( $actions ) {
    $actions[] = 'ddtest_handle_divi_section_shortcode';

    return $actions;
}

add_filter( 'et_builder_load_actions', 'ddtest_et_builder_load_actions' );
jcdotnet commented 6 years ago

Thank YOU @lots0logs! Solved!

jcdotnet commented 6 years ago

Hi again @lots0logs. How can we ensure that the modules CSS are loaded too?

For example, let's suppose that we are loading a module with this style:

.et_pb_row_3 {
    background-color: #beb4ac;
}

When using do_shortcode( '[et_pb_section global_module="' . $test_id . '"][/et_pb_section]' ) we get the CSS loaded here:

<style id="et-builder-module-design-cached-inline-styles">.et_pb_row_3{background-color:#beb4ac;</style>

However, when using do_shortcode( '[et_pb_section global_module="' . $_POST['test_id'] . '"][/et_pb_section]' ) in the AJAX call no styles are either rendered or applied, so we have the default color for that row which is white if I recall correctly.

To sum up, we can load layouts in the Visual Builder so far thanks to the filter you mentioned but the styles are not applied. How could we load the styles too? Thank you!

lots0logs commented 6 years ago

You can retrieve the styles using ET_Builder_Element::get_style() after calling do_shortcode()

jcdotnet commented 6 years ago

Thanks @lots0logs

I just noticed that do_shortcode does not render the module inline styles and the animation classes and ET_Builder_Element::get_style() does not retrieve them so while we are almost there we are not getting the desired module output yet.

lots0logs commented 6 years ago

Could you share all of your code related to this so we can take a look?

jcdotnet commented 6 years ago

Sure! This is the code related to this issue:

JSX:

    const _this = this; 
    $.ajax({
      url : window.ETBuilderBackend.ajaxUrl,
      type : 'post',
      data : {
            action : 'ddmenus_handle_divi_section_shortcode',
            et_admin_load_nonce : window.et_fb_options.et_admin_load_nonce,
            divi_layout : this.props.divi_layout
      },
      success : function( response ) {
           $('.dd-menu-item-modal').html( response );
      }
    });

PHP:

function ddmenus_et_builder_load_actions( $actions ) {
    $actions[] = 'ddmenus_handle_divi_section_shortcode';
    return $actions;
}
add_filter( 'et_builder_load_actions', 'ddmenus_et_builder_load_actions' );
function ddmenus_handle_divi_section_shortcode() {

    if ( ! wp_verify_nonce( $_POST['et_admin_load_nonce'], 'et_admin_load_nonce' ) ) {
        wp_die();
    }  

    echo do_shortcode( '[et_pb_section global_module="' . $_POST['divi_layout'] . '"][/et_pb_section]' );

    $style =  ET_Builder_Element::get_style();

    echo '<style class="dd-menu-item-modal-styles"> ' . $style . ' </style>';
    wp_die();
}

This the result:

<div class="dd-menu-item-modal">
  <div class="et_pb_with_border et_pb_section et_pb_section_1 et_pb_with_background et_section_regular">

  <div class="et_pb_with_border et_pb_row et_pb_row_0 vertical-align et_pb_gutters1">
    <div class="et_pb_column et_pb_column_1_2 et_pb_column_0 et_pb_css_mix_blend_mode_passthrough">

  <div class="et_pb_with_border et_pb_module et_pb_image et_pb_image_0 et-waypoint et_always_center_on_mobile">

    <span class="et_pb_image_wrap"><img src="http://localhost:86/divipruebas/wp-content/uploads/2018/07/HAYES.png" alt=""></span>
    </div>
    </div> <!-- .et_pb_column -->

<div class="et_pb_column et_pb_column_1_2 et_pb_column_1    et_pb_css_mix_blend_mode_passthrough et-last-child">

    <div class="et_pb_with_border et_pb_module et_pb_cta_0 et_pb_promo et_pb_bg_layout_dark  et_pb_text_align_center et_pb_no_bg">

    <div class="et_pb_promo_description">
        <h2 class="et_pb_module_header">Hayes</h2>
        <h3>75€</h3>
    </div>
    <div class="et_pb_button_wrapper"><a class="et_pb_button et_pb_promo_button" href="#">BUY</a></div>
    </div>
    </div> <!-- .et_pb_column -->

   </div> <!-- .et_pb_row -->                               
 </div> <!-- .et_pb_section -->

<style class="dd-menu-item-modal-styles"> .dd-menu-item-modal 
.et_pb_section_1 { border-color:#f8f9fb; } .dd-menu-item-modal 
.et_pb_section_1.et_pb_section { background-color:rgba(248,249,251,0) !important; } .dd-menu-item-modal 
.et_pb_row_0 { background-color: #beb4ac; border-radius: 30px 30px 30px 30px;overflow: hidden; border-color:#f8f9fb; } .dd-menu-item-modal 
.et_pb_image_0 .et_pb_image_wrap { border-radius: 20px 20px 20px 20px;overflow: hidden; border-color:#f8f9fb; } .dd-menu-item-modal 
.et_pb_image_0 { margin-left: 30px !important; text-align: center; } .dd-menu-item-modal 
.et_pb_cta_0.et_pb_promo h2, .et_pb_cta_0.et_pb_promo h1.et_pb_module_header, .et_pb_cta_0.et_pb_promo h3.et_pb_module_header, .et_pb_cta_0.et_pb_promo h4.et_pb_module_header, .et_pb_cta_0.et_pb_promo h5.et_pb_module_header, .et_pb_cta_0.et_pb_promo h6.et_pb_module_header { font-size: 40px !important; } .dd-menu-item-modal 
.et_pb_cta_0.et_pb_promo { color: #f8f9fb !important; border-radius: 0px 20px 20px 0px;overflow: hidden; border-color:#f8f9fb; }  
body #page-container .et_pb_cta_0.et_pb_promo .et_pb_button { 
                    border-radius:50px; }  
body #page-container .et_pb_cta_0.et_pb_promo .et_pb_button:hover { 
                    border-radius:50px; } .dd-menu-item-modal 
.et_pb_row_0.et_pb_row { margin-left: auto !important; margin-right: auto !important; } .dd-menu-item-modal }  
</style>
</div>

And this should be the result:

<div class="dd-menu-item-modal">
  <div class="et_pb_with_border et_pb_section et_pb_section_1 et_pb_with_background et_section_regular">

  <div class="et_pb_with_border et_pb_row et_pb_row_0 vertical-align et_pb_gutters1">

         <!-- THIS CLASSES (et_animated, slide) AND THE INLINE STYLES ARE NOT LOADED WHEN USING AJAX -->        
        <div class="et_pb_with_border et_pb_module et_pb_image et_pb_image_0 et_animated et-waypoint et_always_center_on_mobile slide et-animated" 
          style="animation-duration: 1000ms; animation-delay: 0ms; opacity: 0; animation-timing-function: ease-in-out; transform: scale3d(0.5, 0.5, 0.5)">

  <div class="et_pb_with_border et_pb_module et_pb_image et_pb_image_0 et-waypoint et_always_center_on_mobile">

    <span class="et_pb_image_wrap"><img src="http://localhost:86/divipruebas/wp-content/uploads/2018/07/HAYES.png" alt=""></span>
    </div>
    </div> <!-- .et_pb_column -->

<div class="et_pb_column et_pb_column_1_2 et_pb_column_1    et_pb_css_mix_blend_mode_passthrough et-last-child">

    <div class="et_pb_with_border et_pb_module et_pb_cta_0 et_pb_promo et_pb_bg_layout_dark  et_pb_text_align_center et_pb_no_bg">

    <div class="et_pb_promo_description">
        <h2 class="et_pb_module_header">Hayes</h2>
        <h3>75€</h3>
    </div>
    <div class="et_pb_button_wrapper"><a class="et_pb_button et_pb_promo_button" href="#">BUY</a></div>
    </div>
    </div> <!-- .et_pb_column -->

   </div> <!-- .et_pb_row -->                               
 </div> <!-- .et_pb_section -->

<style class="dd-menu-item-modal-styles"> .dd-menu-item-modal 
.et_pb_section_1 { border-color:#f8f9fb; } .dd-menu-item-modal 
.et_pb_section_1.et_pb_section { background-color:rgba(248,249,251,0) !important; } .dd-menu-item-modal 
.et_pb_row_0 { background-color: #beb4ac; border-radius: 30px 30px 30px 30px;overflow: hidden; border-color:#f8f9fb; } .dd-menu-item-modal 
.et_pb_image_0 .et_pb_image_wrap { border-radius: 20px 20px 20px 20px;overflow: hidden; border-color:#f8f9fb; } .dd-menu-item-modal 
.et_pb_image_0 { margin-left: 30px !important; text-align: center; } .dd-menu-item-modal 
.et_pb_cta_0.et_pb_promo h2, .et_pb_cta_0.et_pb_promo h1.et_pb_module_header, .et_pb_cta_0.et_pb_promo h3.et_pb_module_header, .et_pb_cta_0.et_pb_promo h4.et_pb_module_header, .et_pb_cta_0.et_pb_promo h5.et_pb_module_header, .et_pb_cta_0.et_pb_promo h6.et_pb_module_header { font-size: 40px !important; } .dd-menu-item-modal 
.et_pb_cta_0.et_pb_promo { color: #f8f9fb !important; border-radius: 0px 20px 20px 0px;overflow: hidden; border-color:#f8f9fb; } 
body #page-container .et_pb_cta_0.et_pb_promo .et_pb_button { 
                    border-radius:50px; }  
body #page-container .et_pb_cta_0.et_pb_promo .et_pb_button:hover { 
                    border-radius:50px; } .dd-menu-item-modal 
.et_pb_row_0.et_pb_row { margin-left: auto !important; margin-right: auto !important; }   
</style>
</div>

ET_Builder_Element::get_style() works as expected, I have added the .dd-menu-item-modal selector to the output (see above but don't take these changes into account) so those styles are applied only in the layout.

Basically this is the code, $_POST['divi_layout'] is the layout ID.

Thank you.

lots0logs commented 6 years ago

I see. Those classes don't come from PHP. They are added by javascript when the page loads. You'll have to handle that yourself in this case I'm afraid.

jcdotnet commented 6 years ago

Handling that is a very difficult task. Is there another way to fully load a layout from the Divi Library in the Visual Builder? Thank you,

lots0logs commented 6 years ago

No, I'm afraid not at this time. A proper way to do it via the builder API is on the roadmap though there is no ETA I can provide at this time. Sorry!

khushdoms commented 5 years ago

As per applied add_filter( 'et_builder_load_actions', 'ddmenus_et_builder_load_actions' ); it is not working when fetch post data via ajax. see below code have add that code on ajax. $post_content = wpautop(do_shortcode($single->post_content));

This is fetch post content on ajax call. see how it is display on frontend builder enabled https://prnt.sc/lrc9zv

aficiomaquinas commented 5 years ago

You can retrieve the styles using ET_Builder_Element::get_style() after calling do_shortcode()

Could you explain a bit more on how to achieve this? So far I've been able to add the filter to the AJAX call but the css does not work. What should I do?

aficiomaquinas commented 5 years ago

No, I'm afraid not at this time. A proper way to do it via the builder API is on the roadmap though there is no ETA I can provide at this time. Sorry!

Is the mentioned API already available?

wassy83 commented 5 years ago

Hi to all, I'm trying to inject the layouts from the divi library into my php pages like single-mycustompost.php with this simple code <?php echo do_shortcode('[et_pb_section global_module="MODULE_ID"][/et_pb_section]');?> everything is ok in the frontend but in the visual builder the styles are not rendered for 2 reasons, the first one is that into