ajax – Woocommerce custom webhook -> action woocommerce_before_calculate_totals

I want to create a custom webhook in woocommerce. I have done something like this before, but can’t remember the syntax and am having trouble finding it in the docs.

I have a custom plugin with the following code

function add_new_webhook_topics( $topics ) {
    // New topic array to add to the list, must match hooks being created.
    $new_topics = array( 
        'order.gift_card' => __( 'Order Gift Card', 'woocommerce' ),
        );
    return array_merge( $topics, $new_topics );
 }
 add_filter( 'woocommerce_webhook_topics', 'add_new_webhook_topics' );

I want to replace the Order Gift Card Section with a redeem gift card, now I assume the ‘order.gift_card’ is my topic which is supposed to fire on submission of payment. What I am actually wanting to do is fire a ajax function before submitting the payment which updates the checkout price with woocommerce_before_calculate_totals function.

Now I am debating if I am supposed to create a custom webhook which fires on a new form on the checkout page, which updates the total price before paying based on my returning payload from the webhook. Or I just do a Ajax request without tying into woocomerce webhooks since it is not an event based on woocommerce which fires the request I am trying to make.

Feel free to ask questions for clarification.

This is a previous post for context, with what landed me here
Is it possible to update the total price on the checkout page in woocommerce from a custom field

woocommerce deposit Form with AJAX and shortcode won’t update but add to previous output

I am trying to create a product page where selecting a field defines a product and this triggers an AJAX call to display the woocommerce deposit form and add to cart submit button that correspond to the relevant product id.

The form that contains the deposit selection fields and submit button is displayed by using a shortcode which is called on page load with the default product.

Then, zhen clicking on the field that corresponds to the product you want to change to, I use an AJAX request to execute that shortcode again. I then try to replace the old form by the new form with innerhtml in Javascript, however for some reason the new form is always added after the old one. I can’t seem to replace that innerhtml content. Here is the code:

This is contained on the page:

//div to be filled with product deposit and add to cart form
<div id="adddepositsection">(add_product id="17364")</div>

//AJAX call on field click to execute the shortcode and replace the innerhtml
jQuery('#product2').on('click', function(){
document.getElementById("product1").className = "unselectedbox";
document.getElementById("product2").className = "selectedbox";
document.getElementById("product3").className = "unselectedbox";

jQuery.ajax({
        type: "POST",
        url: "/wp-admin/admin-ajax.php",
        data: {
            action: 'addfunctionshortcode',
            // add your parameters here
            productid: "17372"
        },
        success: function (output) {
document.getElementById("adddepositsection").innerHTML = output; 
}
        });


});

Shortcode function to display the deposit and add to cart button as well as function to execute that shortcode via AJAX in functions.php:

 //Display deposit choice and add to cart shortcode
    function add_product_display( $atts ) {
      $atts = shortcode_atts( array(
            'id' => null,
        ), $atts, 'bartag' );
    
        
            if( intval( $atts('id') ) > 0 && function_exists( 'wc_get_product' ) ){
             $product = wc_get_product( $atts('id') );
        ?>
    
        <form class="cart" action="<?php echo esc_url( apply_filters( 'woocommerce_add_to_cart_form_action', $product->get_permalink() ) ); ?>" method="post" enctype='multipart/form-data'>
            
            <div class="wc-deposits-wrapper <?php echo WC_Deposits_Product_Manager::deposits_forced( $product->get_id() ) ? 'wc-deposits-forced' : 'wc-deposits-optional'; ?>">
        <?php if ( ! WC_Deposits_Product_Manager::deposits_forced( $product->get_id() ) ) : ?>
            <ul class="wc-deposits-option">
                <li>
                    <input type="radio" name="wc_deposit_option" value="yes" id="wc-option-pay-deposit" <?php checked( $default_selected_type, 'deposit' ); ?> />
                    <label for="wc-option-pay-deposit">
                        <?php esc_html_e( 'Pay Deposit', 'woocommerce-deposits' ); ?>
                    </label>
                </li>
                <li>
                    <input type="radio" name="wc_deposit_option" value="no" id="wc-option-pay-full" <?php checked( $default_selected_type, 'full' ); ?> />
                    <label for="wc-option-pay-full">
                        <?php esc_html_e( 'Pay in Full', 'woocommerce-deposits' ); ?>
                    </label>
                </li>
            </ul>
        <?php endif; ?>
    </div>
            <div class="addcartcontainer">
                
    <?php if ( $product->is_in_stock() ) {  
             if (pll_current_language() == "en"   ) { ?>
                    <button type="submit" name="add-to-cart" value="<?php echo esc_attr( $product->get_id() ); ?>" class="addtocartsubmit">BUY NOW</button> <?php
                     }
                    elseif (pll_current_language() == "fr"){ ?>
                        <button type="submit" name="add-to-cart" value="<?php echo esc_attr( $product->get_id() ); ?>" class="addtocartsubmit">ACHETER MAINTENANT</button> <?php
                    }
                    elseif (pll_current_language() == "it"){ ?>
                        <button type="submit" name="add-to-cart" value="<?php echo esc_attr( $product->get_id() ); ?>" class="addtocartsubmit">ACQUISTA ORA</button> <?php
                    }
             }
                else { 
     if (pll_current_language() == "en"   ) { ?>
                    <button type="submit" name="add-to-cart" value="<?php echo esc_attr( $product->get_id() ); ?>" class="addtocartsubmit">SOLD OUT</button> <?php
                     }
                    elseif (pll_current_language() == "fr"){ ?>
                        <button type="submit" name="add-to-cart" value="<?php echo esc_attr( $product->get_id() ); ?>" class="addtocartsubmit">EPUISE</button> <?php
                    }
                    elseif (pll_current_language() == "it"){ ?>
                        <button type="submit" name="add-to-cart" value="<?php echo esc_attr( $product->get_id() ); ?>" class="addtocartsubmit">SOLD OUT</button> <?php
                    }
                 } ?>
            </div>
    
        </form>
    
    
    <?php
    
    }
    }
    add_shortcode( 'add_product', 'add_product_display' );

//Function called by AJAX to execute shortcode
// register the ajax action for authenticated users
add_action('wp_ajax_addfunctionshortcode', 'addfunctionshortcode');

// register the ajax action for unauthenticated users
add_action('wp_ajax_nopriv_addfunctionshortcode', 'addfunctionshortcode');

// handle the ajax request
function addfunctionshortcode() {
    $atts('id') = $_REQUEST('productid');
            echo  add_product_display( $atts );
die();
}

ajax – How to ajaxify wordpress theme

I want to Ajaxify my theme.
this is my index.php:

<?php get_header(); ?>
<body>

<div id="loading">
<img id="loading-image" src="https://wordpress.stackexchange.com/wp-content/themes/radioghesehV3.4/images/ajax-loader.gif" alt="Loading..." />
</div>

<div class="Content">

<?php get_footer(); ?>

and this is my ajax.js file to ajaxify my theme:

jQuery(document).ready(function($) {
    $('#loading').hide();
    $('a').on( 'click', function() {
        event.preventDefault();
        var pageToLoad = $(this).attr("href");
        //alert (pageToLoad);
        $.ajax({
            url: pageToLoad,
            success: function( data ) {
            var pagecontent = $(data);
            $('.mainContent').replaceWith(pagecontent);
            //$('.Content').html(pagecontent);
            }
        });
    });
});

In my website I’ve homepage and one custom post type. this is my custom post type:

<div class="Content">
</div>

now when I open homepage everything is ok. when I click on content thats open my custom post type it opens that without problem. but when I go back to my home page I get a lots of errors in console. because ajax get header and footer again and if I go to another post and open my homepage again I will have more than one time <Doctype html> and header and footer section and it will be create lots of errors.
Please tell me what should I do to avoid loading header and footer more than one time.
Thanks

Woocommerce error on admin ajax search product: Unknown column ” in ‘where clause’

When I want to add products to a manual order in Woocommerce, the product search returns “no matches found”. I looked at the logs and I found this error seems to be culprit. I searched the error but every case I found, the unknown column name is defined in the log. Here it’s blank: Unknown column '' How can I investigate what’s causing it? I’m trying with TwentyTwenty and only WC activated…

Full error:
(proxy_fcgi:error) (pid 3178592) (client *:60140) AH01071: Got error 'PHP message: WordPress database error Unknown column '' in 'where clause' for query SELECT DISTINCT posts.ID as product_id, posts.post_parent as parent_id FROM wp_posts postsnttt LEFT JOIN wp_wc_product_meta_lookup wc_product_meta_lookup ON posts.ID = wc_product_meta_lookup.product_idnttt LEFT JOIN wp_wc_product_meta_lookup parent_wc_product_meta_lookupnttt ON posts.post_type = 'product_variation' AND parent_wc_product_meta_lookup.product_id = posts.post_parent ntttWHERE posts.post_type IN ('product','product_variation')nttt AND ( ( ( posts.post_title LIKE '%chorizo%') OR ( posts.post_excerpt LIKE '%chorizo%') OR ( posts.post_content LIKE '%chorizo%' ) OR ( wc_product_meta_lookup.sku LIKE '%chorizo%' ) OR ( wc_product_meta_lookup.sku = "" AND parent_wc_product_meta_lookup.sku LIKE '%chorizo%' ) )) nttt AND posts.post_status IN ('private','publish') ntttntttORDER BY posts.post_parent ASC, posts.post_title ASCnttt LIMIT 30 nttt made by do_action('wp_ajax_woocommerce_json_search_products_and_varia...',

actions – do_action won’t work in ajax callback

I want to perform some actions when ajax tasks done successfully. For instance, if the item added to the cart, I want to send an email. Also may perform a few more actions.

Setting up do_action('prefix_item_added_to_cart', $args); doesn’t recognized and so add_action doesn’t perform a task, in my case sending email.

If I write code procedural code to send an email, that works fine but using do_action.

Does not work

// ajax callback function
function my_ajax_callback() {

    ...
    // add item to cart
    $cart =. new Cart();
    $cart_id = $cart->add_item($params);

    // if item added successfully
    if($cart_id){
        // perform action
        do_action('prefix_item_added_to_cart', $args);
    }
    ...

}

// action callback
function send_email_to_user($args) {

    // send email notification
    wp_mail('set params for email');

}

// action
add_action('prefix_item_added_to_cart', $args);

Works

function my_ajax_callback() {

    ...
    // add item to cart
    $cart =. new Cart();
    $cart_id = $cart->add_item($params);

    // if item added successfully
    if($cart_id){
        // send email notification
        wp_mail('set params for email');
    }
    ...

}

8 – How to recenter a geolocation google common map in views after an ajax boundary filter execution?

On Drupal 8.97 with all updated modules, I have a View that uses a Geolocation Google Common Map as an attachment. The map acts a boundary filter, but after the filter executes Drupal.ajax(ajaxSettings).execute() via /modules/contrib/geolocation/modules/geolocation_google_maps/js/geolocation-common-map-google.js, I am unable to re-center the map to ANY coordinates, including the user’s location.

Before the ajax call, map.getCenter() works, and so does manually inputting coordinates, like map.getCenter({ lat: -34.397, lng: 150.644 }), but afterwards, no dice. The custom re-center buttons I created still register clicks, and if console.log the map object afterwards, I can’t see any changes to the map object…and indeed some of my other custom map controls (like zoom in and out) still work after the ajax execution. I’m baffled.

I have looked at the ajaxSettings object too, and have attempted to change some of those center related properties before executing the Drupal.ajax(ajaxSettings).execute() command as above, but I still can’t get the map center to change (though I don’t quite know if I’m looking at the right properties…there’s hundreds of them). The map can still be panned around with a mouse of course, but I ultimately would like for users to be able to re-center to their location…and I would like to programmatically recenter and execute a search using the center of city locations without having to reload the page, so it’s kind of critical that I get this sorted.

Thank you in advance for your help.

magento2.2 – Magento 2.2.4 – checkout/cart get shipping rates via AJAX

Version 2.2.4 seems to have a buggy form post on checkout/cart to update shipping rates.

I have other stores using 2.3.* that work fine.

I am trying to run defaultProcessor.getRates() on a JavaScript but when I change, I get an error message saying that it needs an address object and I cannot find one because I am still on checkout/cart and did not provide a full address.

Help !!

Thank you !!

8 – Creating a route that returns an AJAX Response that opens a modal

​I have this route that is suppose to render a block and two view blocks and then display them in a modal.

Originally, I had this route created in the Pages section of Structure, but then decided to create it in my module using this tutorial

However, when I construct it in my module, now it won’t open in a modal. It attempts to, but then just fails with no errors in the console or in Drupal, so I can’t debug the issue because I can’t even find out what the issue is… If I go to the route directly in the browser instead of through a link, it just prints out an array of command objects

Here’s my code:

my_module.routing.yml

my_module.my.results:
  path: "/user/results"
  defaults:
    _title: "My Results"
    _controller: 'Drupalmy_moduleControllerme3Controller::myResults'
  requirements:
    _user_is_logged_in: "TRUE"
    _is_ajax_request: 'TRUE'

myController.php

class myController extends ControllerBase {
  function myResults() {
    $renderer = Drupal::service('renderer');

    $top_careers_view = views_embed_view('top_careers', 'block_top_careers');
    $top_careers = $renderer->render($top_careers_view);
    $matched_degrees_view = views_embed_view('matched_degrees', 'block_matched_degrees');
    $matched_degrees = $renderer->render($matched_degrees_view);

    $content = $top_careers . $matched_degrees;

    $title = "Title";
    $options = (
      'dialogClass' => 'my_modal'
    );
    $response = new AjaxResponse();
    $response->addCommand(new OpenModalDialogCommand($title, $content, $options));

    return $response;
  }
}

my-template.html.twig

<a 
  class="use-ajax"
  data-dialog-type="modal" 
  data-dialog-options='{
    "dialogClass": "my-modal"
  }'
  href="/{{ language }}/my/results">{{ 'Match More Careers'|t }}
</a>

At one point I had /my/results_test created in Pages that I would open up in a modal via the html link:

<a 
  class="ytp-magenta-button use-ajax"
  data-dialog-type="modal" 
  data-dialog-options='{
    "dialogClass": "ytp-dashboard-me3-modal"
  }'
  href="/{{ language }}/my/results_test">{{ 'Match More Careers'|t }}
</a>

I also had the /my/results route still created in my module and if I created a modal-link (defined above) to it from one of the blocks in /my/result_test, then the /my/results route would open in a modal as expected.

So essentially, with what I have, I can open my modal route from another modal, but I can’t open it directly from a regular page…

themes – Ajax Call not Working in Plugin

I’ve been developing a website using WP and to display some database information in the front-end of the site i’ve created a plugin. Right now i want to include a filtering function for that same information using the plugin, but it does not work.

This is the file where i’ve created the filters, called **showcomidas

<div class="container">
    <div class="row">
        <br />
        <div class="col-md-3">                              
            <div class="list-group">
                <h6>Modo de Confeção</h6>
                <div style="height: 180px; overflow-y: auto; overflow-x: hidden;">
                <?php

                $query =  "SELECT * FROM win_gab_modo_confecao ORDER BY designacaoModoConfecao";
                $result = $wpdb->get_results($query);
                foreach($result as $row)
                {
                ?>
                <div class="list-group-item checkbox" style="font-size: 14;">
                    <label><input type="checkbox" class="common_selector modoconf" value="<?php echo $row->idModoConfecao ?>"  > <?php echo $row->designacaoModoConfecao ?></label>
                </div>
                <?php
                }

                ?>
                </div>
            </div><br>

            <div class="list-group">
            <h6>Modo de Serviço</h6>
                <div style="overflow-y: auto; overflow-x: hidden;">
                <?php

                $query2 =  "SELECT * FROM win_gab_modo_servico ORDER BY designacaoModoServico";
                $result2 = $wpdb->get_results($query2);
                foreach($result2 as $row2)
                {
                ?>
                <div class="list-group-item checkbox" style="font-size: 14;">
                    <label><input type="checkbox" class="common_selector modoserv" value="<?php echo $row2->idModoServico ?>"  > <?php echo $row2->designacaoModoServico ?></label>
                </div>
                <?php
                }

                ?>
                </div>

            </div><br>
            
            <div class="list-group">
            <h6>Sub Categoria 1</h6>
                <div style="height: 180px; overflow-y: auto; overflow-x: hidden;">
                <?php

                $query3 =  "SELECT * FROM win_gab_sub_categorias WHERE subCategoria1 = '1' ORDER BY designacaoSubCategoria";
                $result3 = $wpdb->get_results($query3);
                foreach($result3 as $row3)
                {
                ?>
                <div class="list-group-item checkbox"  style="font-size: 14;">
                    <label><input type="checkbox" class="common_selector sub1" value="<?php echo $row3->idSubCategoria ?>"  > <?php echo $row3->designacaoSubCategoria ?></label>
                </div>
                <?php
                }
                ?>  
                </div>

            </div><br>

        
            <div class="list-group">
            <h6>Sub Categoria 2</h6>
                <div style="height: 180px; overflow-y: auto; overflow-x: hidden;">
                <?php

                $query3 =  "SELECT * FROM win_gab_sub_categorias WHERE subCategoria2 = '1' ORDER BY designacaoSubCategoria";
                $result3 = $wpdb->get_results($query3);
                foreach($result3 as $row3)
                {
                ?>
                <div class="list-group-item checkbox"  style="font-size: 14;">
                    <label><input type="checkbox" class="common_selector sub2" value="<?php echo $row3->idSubCategoria ?>"  > <?php echo $row3->designacaoSubCategoria ?></label>
                </div>
                <?php
                }
                ?>  
            </div>
        </div>

        <div class="col-md-9">
            <br />
            <div class="row filter_data">
            </div>
        </div>
    </div>
</div>

Right after this is where the problem is i believe. We begin the JS instructions that will call a file in the plugin’s directory called fetch_data.php.

    $(document).ready(function(){

filter_data();

function filter_data()
{
    $('.filter_data').html('<div id="loading" style="" ></div>');
    var action = 'fetch_data';
    var minimum_price = $('#hidden_minimum_price').val();
    var maximum_price = $('#hidden_maximum_price').val();
    var modoconf = get_filter('modoconf');
    var modoserv = get_filter('modoserv');
    var sub1 = get_filter('sub1');
    var sub2 = get_filter('sub2');


    $.ajax({
        url:"fetch_data.php",
        method:"POST",
        data:{action:action, minimum_price:minimum_price, maximum_price:maximum_price, modoconf:modoconf, modoserv:modoserv, sub1:sub1, sub2:sub2},
        success:function(data){
            $('.filter_data').html(data);
        }
    });
}

function get_filter(class_name)
{
    var filter = ();
    $('.'+class_name+':checked').each(function(){
        filter.push($(this).val());
    });
    return filter;
}

$('.common_selector').click(function(){
    filter_data();
});

$('#price_range').slider({
    range:true,
    min:1000,
    max:65000,
    values:(1000, 65000),
    step:500,
    stop:function(event, ui)
    {
        $('#price_show').html(ui.values(0) + ' - ' + ui.values(1));
        $('#hidden_minimum_price').val(ui.values(0));
        $('#hidden_maximum_price').val(ui.values(1));
        filter_data();
    }
}); 

});

Following this code, it calls the fetch_data.php like i mentioned above:

global $wpdb;

if(isset($_POST("action")))
{
    $query = "
        SELECT * FROM win_gab_ficha_tecnica WHERE idFichaTecnica != '0' 
    ";
    if(isset($_POST("modoconf")))
    {
        $conf_filter = implode("','", $_POST("modoconf"));
        $query .= "
         AND modoConfecaoFichaTecnica IN('".$conf_filter."')
        ";
    }
   
    if(isset($_POST("modoserv")))
    {
        $serv_filter = implode("','", $_POST("modoserv"));
        $query .= "
         AND modoServicoFichaTecnica IN('".$serv_filter."')
        ";
    }
    
    if(isset($_POST("subcat1")))
    {
        $subcat1_filter = implode("','", $_POST("subcat1"));
        $query .= "
         AND subCategoria1 IN('".$subcat1_filter."')
        ";
    }
    
    if(isset($_POST("subcat2")))
    {
        $subcat2_filter = implode("','", $_POST("subcat2"));
        $query .= "
        AND subCategoria2 IN('".$subcat2_filter."')
        ";
    }
    
$result = $wpdb->get_results($query);
$total_row = $wpdb->rowCount();
    $output = '';
    if($total_row > 0)
    {
        foreach($result as $row)
        {
            

    $output .= '
                <div class="col-sm-4 col-lg-3 col-md-3">
                    <div style="border:1px solid #ccc; border-radius:5px; padding:16px; margin-bottom:16px; height:450px;">
                        <img src="https://wordpress.stackexchange.com/image/". $row('fotografiaFichaTecnica') .'" alt="" class="img-responsive" >
                        <p align="center"><strong><a href="#">'. $row('nomeFichaTecnica') .'</a></strong></p>
                        <p>Modo Confeção: '. $row('modoConfecaoFichaTecnica').' MP<br />
                        Modo Serviço: '. $row('modoServicoFichaTecnica') .' <br />
                        Sub-Categoria 1: '. $row('subCategoria1') .' GB<br />
                        Sub-Categoria 2: '. $row('subCategoria2') .' GB </p>
                    </div>
    
                </div>
                ';
            }
        }
        else
        {
            $output = '<h3>No Data Found</h3>';
        }
        echo $output;
    }

We’ve all the right calls in our plugin file for enqueuing scripts and all that stuff.
When we load the wordpress page where this info is supposed to be displayed, the filtering simply does not work, and we get this console error:

jquery-1.10.2.min.js?ver=1.0:4 POST http://itamgabalgarve.pt/page-comidas/fetch_data.php 404 (Not Found)

Also, like i previosuly mentioned this is a plugin that displays the info in our custom-made theme. The page (in the theme) contains a function that calls the plugin and displays our info:

if (function_exists(get_comidas()))

web application – XSS via Ajax request?

I’m currently honing in on my web exploitation skills and came across this JavaScript function here:

 Event.observe(window, 'load', function() {
    new Ajax.Request('/dir/dir', {
      method: 'post',
      parameters: 'actionx3DrefreshAjaxModulex26ampx3BmodIdx3D_1895_1x26ampx3BgroupIdx3D_1_1x26ampx3Bgroup_idx3Dx26ltx3BXSS',', 
      onSuccess: function(transport) {
        try {
          var res = transport.responseXML.getElementsByTagName('x')(0).textContent;
          $('div_1').innerHTML = res.stripScripts();
          page.globalEvalScripts(res,true);
        } catch (e) { 
          $('div_1').innerHTML = 'Failed';
        }
      },
      onFailure: function(transport) {
        $('div_1').innerHTML = 'Fail';
      }
    });
  });

My understanding of the script is that when the page loads, an Ajax POST request will be sent, and if it’s successful, it’ll call the function and try do something but I’m not entirely sure what it’s doing…

I feel like this might be an attack vector, as you can inject values into the parameters field via the URL, except things like <script> are filtered and switched out with <xxxx>. <body onload`=alert(1)> seems to get through unfiltered, but it requires the back tick, which makes the alert not work.

I’m just wondering what other possible payloads there could potentially be, if any? When I inject <XSS (like in the code above) it falls through to the catch statement so I’m not sure if there’s something I can do to make it not cause an exception and pass things through as valid input.