Nonce has not been verifed - Woocommerce problem - php

I have problem with nonce,
I have ajax calls that download cost and dates from API, recently I made change to posts, they are not wordpress posts that "pretend" to be a products, they are now products from woocommerce.
Old posts have no problems with veryfing nonce, new ones can't verify nonces. I really didn't change anything besides making Woocommerce.php that use my product.twig instead of making products using gutenberg.
Here's my jsData:
declare const jsData: { ajaxUrl: string; nonce: string; post_id: number; google_api_key: string; theme_uri: string }
Here's ajax call:
async addToCart(dateStart: DateTime, dateEnd: DateTime) {
const formData = new FormData()
formData.append('nonce', jsData.nonce)
formData.append('action', 'addToCart')
formData.append('product_id', `${jsData.post_id}`)
formData.append('booked_date_start', dateStart.format('YYYY-MM-DD'))
formData.append('booked_date_end', dateEnd.format('YYYY-MM-DD'))
return callAjax({
method: 'POST',
body: formData,
}).then(res => res.json())
}
This is my assets.php where I create nonce and i transfer it to js bundle
$nonce = wp_create_nonce('ajax');
// type in jsData.d.ts
$transferDatas = [
'ajaxUrl' => admin_url('admin-ajax.php?data-nonce="' . $nonce . '"'),
'nonce' => $nonce,
'post_id' => get_the_ID(),
'theme_uri' => get_stylesheet_directory_uri(),
'google_api_key' => get_field('google_api_key', 'options'),
];
wp_localize_script('bundle-js', 'jsData', $transferDatas);
And this is how I try to verify nonce
if (wp_verify_nonce($_POST['nonce'], 'ajax')) ...
I tried to change post to REQUEST, and I added action which register session on init like below in my functions.php
function register_my_session()
{
if( !session_id() )
{
session_start();
}
}
Do you have any ideas what can I change to make those nonces verifed like on old posts (that are still up and work - new ones doesnt work)?

Related

WooCommerce: how to check user authorization via REST API

In my store there is an iframe in which products are placed. Iframe has the ability to save the selected product configuration, but only authorized users can do this.Thus, need to check whether the token has entered under login or not. Wordpress provides the function is_user_logged_in () but it does not suit me.My question is this: is there a way to do the same through the REST API?
https://developer.wordpress.org/rest-api/using-the-rest-api/authentication/
The WP REST ajax call itself by default doesn't carry over the cookie. You can follow the above ref, using this way:
In PHP:
<?php
wp_localize_script( 'wp-api', 'wpApiSettings', array(
'root' => esc_url_raw( rest_url() ),
'nonce' => wp_create_nonce( 'wp_rest' )
) );
In JS:
$.ajax( {
url: wpApiSettings.root + 'wp/v2/posts/1',
method: 'POST',
beforeSend: function ( xhr ) {
xhr.setRequestHeader( 'X-WP-Nonce', wpApiSettings.nonce );
},
data:{
'title' : 'Hello Moon'
}
} ).done( function ( response ) {
console.log( response );
} );
WP will automatically setup the user in REST with that. And you can use is_user_logged_in() now.

After passing jQuery Ajax to PHP in Wordpress, how to update global variable prior to use in other function (without using async=false)?

First time posting to StackOverflow. (upvotes appreciated to help me get included in the community)
Despite being new to coding in general, I've been able to work out the following steps in Wordpress thanks to Zac Gordon's very helpful video https://youtu.be/Z0Jw226QKAM?t=216 and demo files https://github.com/zgordon/wordpress-ajax following the steps he outlines:
Pass Nonce and AJAX URL via wp_localize_script
Make AJAX call with Nonce and URL in JavaScript
Hook PHP AJAX Function into Wordpress AJAX Hooks
Use JavaScript to Handle AJAX Response
Although I am able to return the expected result with the AJAX response (which I can print to console) and I am now able to retrieve a value to pass to another function, I am unable to update the value in advance of passing it to other functions.
Based on other StackOverflow conversations (JQuery - Storing ajax response into global variable) I am thinking this is probably an issue with Asynchronous vs Synchronous AJAX calling. However I've further read that setting "async: false" should be avoided at all costs and seems to be deprecated at this point (and didn't help when I tried) so I'm trying to find the proper way to pass this variable from one function to another. Answers I read were not specific to Wordpress which left me at a loss for solving on my own.
The goal is fairly straightforward: get the $(window).height() using AJAX, store as a variable, pass variable into another function in PHP which transforms that variable and adjusts the height of a map Plugin (hook: storymap_heights ).
For starters: I'm currently just trying to get this to work with initial page load, but I would also be curious if it's possible to rerun the functions every time the browser window is resized?
The following code gets me close: I have to refresh twice for the global variable $heights {and/or "get_option( 'jsforwp_heights' )" } to update and properly set the "new" browser window size (so it seems to be storing the variable but not until after it runs through at least once before). The code is currently stored in a Wordpress Snippets plugin, but should work the same as being placed in Functions.php:
<?PHP
global $heights;
if ( null == $heights ) {
add_option( 'jsforwp_heights', 100 );
}
$heights = get_option( 'jsforwp_heights' );
function my_theme_scripts() {
wp_enqueue_script( 'my-great-script', get_template_directory_uri() . '/assets/js/my-great-script.js', array( 'jquery' ), '1.12.4', true );
wp_localize_script(
'my-great-script',
'jsforwp_globals',
[
'ajax_url' => admin_url('admin-ajax.php'),
'total_heights' => get_option('jsforwp_heights'),
'nonce' => wp_create_nonce('nonce_name')
]
);
}
add_action( 'wp_enqueue_scripts', 'my_theme_scripts' );
function screen_height_is(){
check_ajax_referer('nonce_name');
global $heights;
$heights = $_POST['height'];
update_option('jsforwp_heights',$heights);
// set_map_height($heights); //test
$response['success'] = true;
$response['height'] = $heights;
$response = json_encode($response);
echo $response;
wp_die();
}
add_action('wp_ajax_screen_height_is','screen_height_is',1);
add_action( 'wp_ajax_nopriv_screen_height_is', 'screen_height_is',1 );
function set_map_height(){
global $heights;
$testA = get_option('jsforwp_heights');
$testB = "px";
$height = $testA. $testB;
echo $height;
return $height;
}
add_filter('storymaps_heights','set_map_height',10);
//tests for function above
//function set_map_height($heights){
//$testA = '300'; //static option
//$testA = $heights; //works with same loading delay problem
//$testA = $response['height']; //doesn't work even if $response set as global
I have tried nesting the functions without success and calling the set_map_height($heights) from within the screen_height_is() function without success. I also have tried setting #Priority within add_action and add_filter (1 for add_action, 10 for add_filter) to try to get them to wait to run but this also does not seem correct.
The following code is stored in my js file: my-great-script.js:
jQuery(document).ready(function($){
var myResponse;
$.ajax({
type: 'post',
dataType: 'json',
url: jsforwp_globals.ajax_url,
async: false,
data: {
action : 'screen_height_is',
_ajax_nonce : jsforwp_globals.nonce,
width : $(window).width(),
height : $(window).height(),
screen_width : screen.width,
screen_height: screen.height
},
success: function( response ) {
// if( 'success' == response) {
if( response['success'] == true) {
alert("Something went right");
}
else {
alert("Something went wrong");
}
}
})
.done(function(response) {
console.log(response);
})
.fail(function(error) {
alert(error);
})
.always(function() {
console.log("complete");
});
});
Console log prints:
{height: "598", success: true}
complete
I am a little unclear if/how I should be modifying the Success callback to reach my overall goal? Or if the wp_enqueue_script() dependencies need to be modified?
In case this helps, the following filter in PHP hooks into the storymaps-core.php file:
add_filter('storymaps_heights','set_map_height',10);
Where the following wp_enqueue_script resides:
function storymap_external_resources() {
wp_enqueue_style( 'storymap-stylesheet', 'https://cdn.knightlab.com/libs/storymapjs/latest/css/storymap.css' );
wp_enqueue_script( 'storymap-javascript', 'https://cdn.knightlab.com/libs/storymapjs/latest/js/storymap-min.js', array(), '1.0.0', false );
}
add_action( 'wp_enqueue_scripts', 'storymap_external_resources' );
Any help on what to try next is much appreciated!

WooCommerce Session returns blank

I am developing mobile application from my existing WooCommerce store. I have added custom APIs to maintain everything through user session. I don't know how session is being managed on WooCommerce. But when I call wp_get_session_token() method from mobile app, it returns blank string and from postman when I call the same API, it returns proper string of session.
My main object is to add product to cart and retrieve from cart for particular session of user. By using custom APIs, I am able to do everything as per user session. Product is being added to current logged in user's cart via logged in session. But from mobile app, I am not able to add product to cart for particular user via its session. I am getting proper response for custom add to cart API from mobile app but it can't define for which user's cart that product is added. Also after adding product to cart, I call get cart items API which also return 0 items which means product is not being added there. All these APIs working fine from Postman.
To figure out this issue, I tried calling wp_get_session_token() method in login API. This method returns proper session id when it is called from Postman. But when I call this from mobile app, it returns only blank string.
It seems to me that problem is with session from mobile app but I don't know how to manage it from Mobile App to WooCommerce store.
Here is my login API where I return session id for now to debug:
function register_api_hooks() {
register_rest_route(
'custom-plugin', '/login/',
array(
'methods' => ['GET'],
'callback' => 'login',
)
);
function login($request) {
$creds = array();
$creds['user_login'] = $request["username"];
$creds['user_password'] = $request["password"];
$creds['remember'] = true;
$user = wp_signon( $creds, false );
$session = (object) wp_get_session_token();
write_log($user);
write_log($session);
return $session;
// return $user;
}
}
write_log also have blank entry for session when it is called from Mobile App.
Code for add to cart:
add_action( 'rest_api_init', 'register_cart_hooks' );
// API custom endpoints for WP-REST API
function register_cart_hooks() {
register_rest_route(
'custom-plugin', '/addToCart/',
array(
'methods' => ['GET'],
'callback' => 'addToCart',
)
);
function addToCart($request) {
global $woocommerce;
$woocommerce>cart>add_to_cart($request["product_id"],$request["quantity"]);
return "Success...";
}
}
Please let me know where I am going wrong or what other implementation I have to make.
EDIT
Here is the code I am using from React Native Mobile App:
fetch(url1, {
method: methodName,
async: true,
crossDomain: true,
headers: new Headers({
"Content-Type": "application/json",
"cache-control": "no-cache",
}),
body:data1
}).then((response) => {
const statusCode = response.status;
console.log("fetchData StatusCode : "+statusCode);
console.log("fetchData response1 : " + JSON.stringify(response));
console.log("fetchData response2 : " + response);
return response.json();
}).then((responseJson) => {
// var firstResponse = responseJson.split(',');
// console.log("fetchData responseJson 111 : "+firstResponse);
console.log("fetchData responseJson : "+responseJson);
var response = JSON.stringify(responseJson);
console.log("fetchData responseJson stringify : " + response);
response = JSON.parse(response);
console.log("fetchData responseJson stringify 1 : " + response);
console.log("fetchData responseJson stringify 2 : " + JSON.stringify(response));
if (callBack != null) {
callBack("", response);
}
}).catch((error) => {
console.log("fetchData Api error : "+error);
if (callBack != null) {
console.log("fetchData Api error callBack != null 2");
callBack("Error", "");
}
});

WordPress Ajax is successful but function doesn't appear to run

I've been googling this for a while and have tried a number of things (for example nesting my formName and formData in the 'data:' attribute, but that resulted in parseerrors, so I'm guessing I'm pretty close to having this working! I've also removed those attributes and hard coded the items in my function, but the problem remains the same.
Everything appears to be OK and I get by success alert, but when I check my database the usermeta hasn't been updated. I don't know the best way to debug the PHP function either so any tips on that would be handy for the future!!
This is my ajax function which get's fired on blur:
function storeData(data) {
$.ajax({
type: 'POST',
formData: data,
formName: 'Testform',
action: 'storeApplicationData',
success:function( data ) {
console.log('stored form');
},
error: function(xml, error) {
console.log(error);
}
});
return false;
}
This is my PHP code in my functions file, I've hard-coded the values I'm passing in to update_user_meta for now, just to ensure that isn't the issue:
function storeApplicationData(){
update_user_meta('15', 'Testform', '12345678');
}
add_action('wp_ajax_storeApplicationData', 'storeApplicationData');
add_action('wp_ajax_nopriv_storeApplicationData', 'storeApplicationData');
I'm checking the database directly, the meta field doesn't get updated...
Any help would be appreciated!
I figured this out, I was missing the proper enqueing for my ajax url:
function theme_enqueue() {
$theme_url = get_template_directory_uri(); // Used to keep our Template Directory URL
$ajax_url = admin_url( 'admin-ajax.php' ); // Localized AJAX URL
// Register Our Script for Localization
wp_register_script( 'applications', "{$theme_url}/applicationform.js", array( 'jquery' ),'1.0', true);
// Localize Our Script so we can use `ajax_url`
wp_localize_script('applications','ajax_url',$ajax_url);
// Finally enqueue our script
wp_enqueue_script( 'applications' );
}
add_action( 'wp_enqueue_scripts', 'theme_enqueue' );
I also added:
url: ajax_url,
to my ajax!

Onclick Link POST to REST

I'm making sure I am going about this the right way because WooCommerce kinda complicates things. First I'll explain what I am looking for. I'm wanting it so when an admin clicks a custom button I created in the WooCommerce orders page that it shows them the tracking number for a specific order. I have that up and running just fine. Now what I would also like to do is to make a call to my api with their username and post it to my log with the admin username along with the tracking number they accessed. However I'm running into a couple issues, some of which I haven't encountered yet, but feel as though they could be a problem. So I have the link in one function that loops through each order to display the tracking button, and the css/ajax in another function for being posted in the head section. So here are some issues:
1.) How can I make it so that I only need one instance of jQuery? I don't want it to flood the source code with multiple instances.
2.) I thought maybe just posting it once in the head section would be fine, but if it's not in the link button function then how will the jQuery get the correct value if the variable is different for each order id since it would no longer be looping through each instance with the jQuery?
3.) How could I accomplish this call from another host so I do not need to upload my API to each domain?
Here is the code I have so far, please tell me if there is a better way to go about this task. Thank you in advance.
add_action( 'woocommerce_admin_order_actions_end', 'add_custom_order_actions_button', 100, 1 );
function add_custom_order_actions_button( $order ) {
// Username
$user_info = get_userdata($order->user_id);
// Tracking
$tracking_number = get_post_meta( $order->get_id(), '_disquy_tracking_number', true );
if( empty($tracking_number) ) return;
// Prepare the button data
$url = esc_url('https://track.disquy.com/'.$tracking_number.'?');
$name = esc_attr( __('Tracking', 'woocommerce' ) );
$class = esc_attr( 'tracking' );
printf( '<a class="button wc-action-button wc-action-button-%s %s" href="%s" title="%s" id="apicall">%s</a>', $class, $class, $url, $name, $name );
}
add_action( 'admin_head', 'add_custom_order_actions_button_css' );
function add_custom_order_actions_button_css() {
echo '<script type="text/javascript">
$("#apicall").click(function(event){
event.preventDefault();
$.post("adminlog.php", {username : ' . $user_info . ', tracking : ' . $tracking_number . '}, function(response){
alert(response);
});
});
</script>
<style>.wc-action-button-tracking::after { font-family: woocommerce !important; content: "\e01a" !important; }</style>
}
Actually, you don't need jQuery at all! It's been awhile since I've worked with PHP based CMS's, but here's an alternative example to what you could do. Just check the PHP syntax to make sure it's correct. No jQuery. Pure vanilla JS. Uses native Fetch API to handle AJAX request.
add_action( 'woocommerce_admin_order_actions_end', 'add_custom_order_actions_button', 100, 1 );
function add_custom_order_actions_button( $order ) {
// UserID
$user_id = get_userdata($order->user_id);
// Tracking Data
$tracking_data = get_post_meta($order->get_id(), '_disquy_tracking_number', true );
if(empty($tracking_data)) return;
$base_url = 'https://track.disquy.com';
$url = esc_url(.$base_url.'/'.$tracking_data.'?');
$name = esc_attr( __('Tracking', 'woocommerce' ) );
$class = esc_attr( 'tracking' );
printf('<a class="button wc-action-button wc-action-button-
%s %s" href="%s" title="%s" id="apicall">%s</a>',
$class, $class, $url, $name, $name );
}
add_action( 'admin_head', 'add_custom_order_actions_button_css' );
function add_custom_order_actions_button_css() {
echo '<script type="text/javascript">
const elem = document.getElementById('#apicall')
elem.addEventListener('click', postUserTransaction)
const postUserTransaction = (e) => {
e.preventDefault();
const postData (e) => {
event.preventDefault();
const tittle = elem.title;
const body = document.body.value;
return fetch('adminlog.php', {
method: 'POST',
headers : new Headers({
"username":".$user_id.",
"tracking":".$tracking_data.'
})
})
.then(res => res.json())
.then(data => data)
.then(data => {
console.log(data)
alert(data)
return data
})
.catch(err => new Error(err))
}
}
</script>
<style>.wc-action-button-tracking::after { font-family: woocommerce !important; content: "\e01a" !important; }</style>
}
By using the addEventListener method instead of defining the onclick method inline your HTML. You should be able to write all your JS scripts in a separate folder, then import them using hooks. Again, it's been awhile though. If you're looking for dynamic rendering of DOM variables, jQuery wont work. It only works with a rendered DOM. Vanilla JS can take care of this for you, but you'll need aditional configs. I honestly think there has to be hooks included using PHP for inject DOM elements on update. Then simple write eventListeners for changes in the DOM, then make necessary updates.
As mentioned before, include your scripts files elsewhere, then hook them into the page via PHP and your WooCommerce API for doing so.
Cheers!
EDIT:
You need to modify the fetch and promise chain to POST you PHP script, then edit the then block containing the alert to add the response data to the DB. Here is another example using fetch to POST with PHP. I don't know what vars and hooks you have to work with to make the final DB update using your Res data. That's something you should have.
fetch("http://www.example.org/submit.php", {
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded"
},
body: "key=val&key2=val2"
})
.then(res => res.json()),
.then(res => {
if (res.ok) {
alert("Perfect! Your settings are saved.");
} else if (res.status == 401) {
alert("Oops! You are not authorized.");
}
}, (e) => {
alert("Error submitting form!");
});

Categories