using wp_set_auth_cookie with out any hook - php

Wordpress version 4.7.5
I am signing up new users from Instagram, I am successfully able signup the new user. after signup I am trying to logged in the user.
I can use hook, but would like better solution than the dirty one, I
have posted as that will be totally unuseful .
if( $user_created ) {
$new_user = get_user_by( 'id', $user_created );
//$loggedin = programmatic_login( $new_user->user_login );
//ob_start();
if ( !is_user_logged_in() ) {
wp_clear_auth_cookie();
wp_set_current_user( $user_created, $new_user->user_login );
wp_set_auth_cookie( $user_created, true );
do_action( 'wp_login', $new_user->user_login );
// wp_safe_redirect(site_url() . '/profile/');
// exit;
// $redirect_to=user_admin_url();
// wp_safe_redirect($redirect_to);
// exit();
}
//ob_end_clean();
} ?>
<script>jQuery(document).ready(function(){ window.location.href = "<?php echo site_url() . '/profile/'; ?>";});</script> <?php
also tried with a custom programmatic_login function from another post.
if I am trying to var_dump wp_get_current_user() and $_COOKIE below this, I am getting user object for wp_get_current_user() and array(1) { ["wordpress_test_cookie"]=> string(15) "WP Cookie check" } for $_COOKIE .
Important Edit
The code is inside a function, which is hooked to a hook, that is called in side a page that is after header is getting displayed, so we could not use init here. any other way of doing it and also because of this wp_safe_redirect() or header('Location: ') also not working .
Important Update with what I have just tried
A dirty work around
when I created the user from Instagram login, After successful creation I redirected the user to a page with get parameter something like ?user_id=$inserted_id and on wp hook, I tried to get the GET['user_id'] and logged it and it worked, trying to find a proper solution.
if ( $wpdb->insert_id ){ //that is registration with instagram
?>
<script>jQuery(document).ready(function(){ window.location.href = "<?php echo get_bloginfo('url') . '/profile/?id=' . $wpdb->insert_id; ?>";});</script>
<?php
}
and then
add_action( 'wp', 'login_current_user' );
function login_current_user(){
if ( is_page() && get_the_id() == 863 ){
if ( isset( $_GET['id'] ) ){
if ( !is_user_logged_in() ) {
$user_id = $_GET['id'];
$user = get_user_by( 'id', $user_id );
wp_clear_auth_cookie();
wp_set_current_user( $user_id, $user->user_login );
wp_set_auth_cookie( $user_id, true );
do_action( 'wp_login', $user->user_login );
if ( is_user_logged_in() ){
$redirect_to=site_url() . '/profile';
wp_safe_redirect($redirect_to);
exit();
}
}
}
}
}
Proble with dirty trick. If the id we are passing as get parameter
exists in wp_users table then with no verification that will be logged
in .
Update
I created a user_meta before redirecting to profile page and after verification login the user and removed the usermeta, just like an OTP . Trying to make it better if possible.
Below the code:-
if ( $wpdb->insert_id ){ //that is registration with instagram
$temporary_token = sha1(rand());
update_user_meta( $wpdb->insert_id, 'temporary_token', $temporary_token);
?>
<script>jQuery(document).ready(function(){ window.location.href = "<?php echo get_bloginfo('url') . '/profile/?id=' . $wpdb->insert_id . '&token=' . $temporary_token; ?>";});</script>
<?php
}
and then
add_action( 'wp', 'login_current_user' );
function login_current_user(){
if ( is_page() && get_the_id() == 863 ){
if ( isset( $_GET['id'] ) ){
if ( !is_user_logged_in() ) {
$user_id = $_GET['id'];
$user = get_user_by( 'id', $user_id );
if ( $_GET['token'] == get_user_meta( $user_id, 'temporary_token', true ) ){
delete_user_meta( $user_id, 'temporary_token', $_GET['token'] );
wp_clear_auth_cookie();
wp_set_current_user( $user_id, $user->user_login );
wp_set_auth_cookie( $user_id, true );
do_action( 'wp_login', $user->user_login );
if ( is_user_logged_in() ){
$redirect_to=site_url() . '/profile';
wp_safe_redirect($redirect_to);
exit();
}
}
}
}
}
}

If headers have been sent before wp_clear_auth_cookie() or wp_set_auth_cookie() are called then neither will work as both rely on PHP's setcookie function. The after_setup_theme action will occur before headers have been sent so hooking that and setting the cookies there should fix the issue.
function myPlugin_createUser(){
// Probably need to put code that creates user here too otherwise $user_created will never return true
if( $user_created ) {
$new_user = get_user_by( 'id', $user_created );
if ( !is_user_logged_in() ) {
wp_clear_auth_cookie();
wp_set_current_user( $user_created, $new_user->user_login );
wp_set_auth_cookie( $user_created, true );
do_action( 'wp_login', $new_user->user_login );
}
}
}
add_action( 'after_setup_theme', 'myPlugin_createUser' );
Update:
If you're outputting view elements before triggering your createUser function it won't work so we need to make sure they run completely independent of each other. Below I've put together a simple example of how to achieve this - to the view we output a link which passes a GET parameter, this parameter is picked up by the plugin and runs the action before anything is rendered allowing us to set the cookie.
my-plugin.php
// Note: you'll need to include a completed version of myPlugin_createUser() function as above for these examples to work
add_shortcode( 'my-plugin', function() {
// I've used a GET request for simplicity- a form + POST request may be more practical for your purposes and will prevent caching issues.
echo "<a href='?my_plugin_login_user=1'>Login</a>";
});
// Check for our GET parameter
if( isset( $_GET['my_plugin_login_user'] ) ) {
// Nothing should be rendered yet as plugin template hasn't even started loading yet so cookies should set fine
add_action( 'plugins_loaded', 'myPlugin_createUser' );
}
page-my-template.php
<div> ...
<?php
do_shortcode( 'my-plugin' );
?>
</div>
Update 2:
If using Instagrams Authentication API the explicit flow outlined https://www.instagram.com/developer/authentication/ (most of the examples used below are taken from there) is probably the best approach. Below I'll give a brief rundown of how you could implement it. Much of it is taken from there with notes added.
Send the user off to https://api.instagram.com/oauth/authorize/?client_id=CLIENT-ID&redirect_uri=REDIRECT-URI&response_type=code
You could include the WordPress user ID as a parameter on the callback URL or if the user hasn't yet been created and you need to maintain state then you'll need to generate a temporary token that you can use later that's been associated with said data or store that data client side if it's not sensitive which is probably easier and better as it doesn't require a user to be logged in to function.
The user will then login
Not much to say about this step - if an error occurs they'll be redirected to http://your-redirect-uri?error=access_denied&error_reason=user_denied&error_description=The+user+denied+your+request
If login is successful the user will be redirected to http://your-redirect-uri?code=CODE
The CODE passed back on the redirect URL we can redeem for an access token.
So from here there's a multitude of ways we can handle it but essentially what we need is an endpoint for the redirect that we have sufficient control over to send HTTP headers before any of the HTTP response body is sent.
Methods of approaching this (not an exhaustive list):
Conditionally hooking on pages Instagram auths are allowed (as in your examples). This has the advantage of not requiring an additional redirect.
Custom page template
External script that manually bootstraps WordPress does what we need, then redirects back in
So now once we've got an endpoint setup we need to redeem the CODEfor an access token. Adapted this snippet from https://gist.github.com/arturmamedov/7f5a90b85a20e06e344ebb88dc898d25
$uri = 'https://api.instagram.com/oauth/access_token';
$data = [
'client_id' => '213esdaedasdasd12...YOUR_CLIENT_ID',
'client_secret' => 'a8b4aaf06c0da310...YOUR_CLIENT_SECRET',
'grant_type' => 'authorization_code',
'redirect_uri' => 'http://www.YOUR_REDIRECT_URL.it', // The exact redirect URL as used previously
'code' => $_GET['code']
];
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $uri); // uri
curl_setopt($ch, CURLOPT_POST, true); // POST
curl_setopt($ch, CURLOPT_POSTFIELDS, $data); // POST DATA
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); // RETURN RESULT true
curl_setopt($ch, CURLOPT_HEADER, 0); // RETURN HEADER false
curl_setopt($ch, CURLOPT_NOBODY, 0); // NO RETURN BODY false / we need the body to return
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0); // VERIFY SSL HOST false
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0); // VERIFY SSL PEER false
$result = json_decode(curl_exec($ch));
$result will be an object representation of the JSON response:
{
"access_token": "fb2e77d.47a0479900504cb3ab4a1f626d174d2d",
"user": {
"id": "1574083",
"username": "snoopdogg",
"full_name": "Snoop Dogg",
"profile_picture": "..."
}
}
From here we just create our user/authenticate with WordPress and redirect to the desired page/render the template (no need to redirect if handled via conditional hooks) and restore the page state if needed.

Related

Schedule php wordpress script to run in background

I hope I am not expecting too much. Any help would be extremely useful for me, because I am stuck for days now.
I created a relatively simple wordpress plugin in php.
What is the plugin supposed to do ?
-The plugin is supposed to communicate with external api and import product data in json file.
Import is started by pressing "start import" button that is created by pluin in the wordpress menu - import products.
Example request:
curl -X GET
-H 'X-Api-Key: [api-key]'
https://example.com/products/[PRODUCT ID]
[PRODUCT ID] is supposed to range from 1 to 10000
Plugin receives json file with product feed for every single request - every single [PRODUCT ID]
Plugin creates a woocommerce product and attaches imported information.
Does the plugin work ?
Yes and no, It imports first 100 products (in about 1min) correctly and then it just stops, sometimes resulting in error related to the request taking too much time to finish.
I know that the plugin doesn't work because the import script is executed in the browser and gets timed out.
I also know that I should do this process in the background, split it into batches and queue execution. The thing is I tried many ways to do so but failed miserably.
I have composer and action scheduler installed.
Unfortunately everytime I try to split this into batches, use action scheduler It just doesn't work or imports first product and stops.
I know that I'm dealing with large amount of products, I don't have error handling, checking if imported product exists etc, but I really have to run this import once
so there is no need to make this plugin very refined. This has to run, import products and I can get rid of it.
I do have wp debug on, so my attepmts on using action scheduler didn't create any errors or fatal errors, but it just didn't work properly.
I have 1500MB Ram available, this is shared hosting server, I/O 1MB, 60 available processes, 88000/600000 Inodes used, 5/200GB disc space used.
I increased php maxExecutionTime to 3000, memorylimit 1536M, maxInputTime 3000, but that didn't change anything.
I'm attaching my working code below. This is the version without my poor attemts on using action scheduler, splitting it into batches and running it in the backgroud.
I feel like this is going to be easier to read.
This code below runs in the web browser and works, but gets timed out.
I will be extremely grateful for any help with running it in the background.
Is it possible to just run this script from SSH linux terminal so it doesn't get timed out ?
`
<?php
/**
* Plugin Name: Product Importer
* Description: Imports products from an external API
* Version: 1.0
* Author: me
* Author URI: http://www.example.com
*/
// Include the Autoscheduler library
require_once '/home/user/vendor/woocommerce/action-scheduler/action-scheduler.php';
add_action('admin_menu', 'add_import_button');
function add_import_button() {
add_menu_page('Import Products', 'Import Products', 'manage_options', 'import_products', 'import_products_page');
}
function import_products_page() {
echo '<h1>Import Products</h1>';
echo '<form method="post">';
echo '<input type="submit" name="start_import" value="Start Import">';
echo '</form>';
if (isset($_POST['start_import'])) {
import_function();
}
}
function import_function() {
$product_id = 1;
while($product_id < 10000){
$product_id++;
$api_key = 'my-api-key';
$headers = array(
'X-Api-Key: ' . $api_key,
);
$url = 'https://example.com/products/';
$product_url = $url . $product_id;
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $product_url);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
$product_data = json_decode($response, true);
// post array etc
// Set other product data as required.
}
}
}
`
One of the ways to solve this issue is using recursion where the code can run in the background. Take a look at the example below
require_once '/home/user/vendor/woocommerce/action-scheduler/action-scheduler.php';
add_action('admin_menu', 'add_import_button');
function add_import_button() {
add_menu_page('Import Products', 'Import Products', 'manage_options', 'import_products', 'import_products_page');
}
function import_products_page() {
echo '<h1>Import Products</h1>';
echo '<form method="post">';
echo '<input type="hidden" name="product_id" value="1">'; // optional
echo '<input type="submit" name="start_import" value="Start Import">';
echo '</form>';
if (isset($_POST['start_import'])) {
import_function();
}
}
// AJAX function
add_action( 'wp_ajax_nopriv_import_function', 'import_function' );
add_action( 'wp_ajax_import_function', 'import_function' );
function import_function() {
$product_id = ( ! empty( $_POST['product_id'] ) ) ? $_POST['product_id'] : 1;
$url = 'https://example.com/products/';
$args = array(
'headers' => array(
'Content-Type' => 'application/json',
'X-Api-Key' => 'apikey12345'
)
);
// this call the function and return the body
$results = wp_remote_retrieve_body(wp_remote_get($url . $product_id, $args));
// convert to array
$results = json_decode( $results );
// Stop the code execution on this conditions
if( ! is_array( $results ) || empty( $results ) ){
return false;
}
// Do your product creation here...
$product_id++; // increase $product_id
wp_remote_post( admin_url('admin-ajax.php?action=import_function'), [
'blocking' => false, // needed for the script to continue running on the background
'sslverify' => false, // needed if working on localhost.
'body' => [
'product_id' => $product_id
]
] );
}
OK, I managed to get it to work. I assume that it's dumb way to do this, but since it works it's fine for me. The only thing that is problematic now is the fact that the code for image import that I used previously (when code ran in browser) now makes the plugin stuck. Without it it works great and fast. Here is my current code:
<?php
/**
* Plugin Name: Product Importer
* Description: Imports products from an external API
* Version: 3.0
* Author: me
* Author URI: http://www.example.com
*/
register_activation_hook( __FILE__, 'schedule_import' ); //plugin starts when activated, fine for me
function schedule_import() {
wp_schedule_single_event( time(), 'import_products' );
}
add_action( 'import_products', 'import_function' );
function import_function() {
$batch_size = 50; //when split into batches it worked faster than one products after another, so ok
$batch_delay = 60; //give it some time to finish batch, to avoid problems
$last_imported_product_id = get_option( 'last_imported_product_id', 1 ); //need it for incrementation and rescheduling
$api_key = 'apikey123456789';
$headers = array(
'X-Api-Key: ' . $api_key,
);
$url = 'https://example.com/products/';
for ( $i = 0; $i < $batch_size; $i++ ) {
$product_id = $last_imported_product_id + $i;
$product_url = $url . $product_id;
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $product_url);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
$product_data = json_decode($response, true);
$post = array(
'post_title' => $product_data['name'],
'post_content' => $product_data['description'],
'post_status' => 'publish',
'post_type' => 'product',
'meta_input' => array(
'_virtual' => 'yes',
'_regular_price' => $product_data['price'],
),
);
$post_id = wp_insert_post($post);
update_post_meta($post_id, '_sku', $product_data['Id']);
wp_set_object_terms($post_id, 'external', 'product_type');
$external_url = 'https://example.external.url';
update_post_meta( $post_id, '_product_url', $external_url );
update_option( 'last_imported_product_id', $product_id + 1 ); //incrementation of product_id for rescheduling
wp_schedule_single_event( time() + $batch_delay, 'import_products' ); //rescheduling
}
}
This above works well. However when I add my old code for image imports it imports nothing or 1 product (without image lol) and becomes stuck. After a minute it imports the same product over and over again. Old code for image import:
// Get the product images
$images = $product_data['images']['screenshots'];
$image_ids = [];
foreach ($images as $image) {
// Download the image
$image_url = $image['url'];
$response = wp_remote_get($image_url);
if (is_array($response)) {
$image_data = $response['body'];
$filename = basename($image_url);
$file_array = array(
'name' => $filename,
'tmp_name' => download_url($image_url),
);
// Insert the image into the media library
$attach_id = media_handle_sideload($file_array, $post_id);
if (!is_wp_error($attach_id)) {
array_push($image_ids, $attach_id);
}
}
// Set the product image gallery
update_post_meta($post_id, '_product_image_gallery', implode(',', $image_ids));
// Set the product featured image
update_post_meta($post_id, '_thumbnail_id', $image_ids[0]);
And no, I don't put it after rescheduling, but after $post array.
Honestly no idea why it would crash, tried smaller batches, longer wait between batches etc. I assume the code for images import is just very poorly written. Any solutions for this problem are going to be very appreciated ! :)
PS: I am totally fine with importing the first image available (there is around 6) and setting it up as thumbnail for product. I can give up on the gallery since It's going to slow down the process anyway.
EDIT: here is the fragment of json file received from api. (for better context of importing images):
"images":{
"screenshots":[
{
"url":"https://example.jpg",
"thumbnail":"https://example.jpg"
},
{
"url":"https://example.jpg",
"thumbnail":"https://example.jpg"
},
{
"url":"https://example.jpg",
"thumbnail":"https://example.jpg"
etc....

Is it correct to put wordpress php shortcode hook inside an if statement in which the if statement is the response of a post method?

This is the WordPress php code I am planning to implement. The code is a plugin that post a form data to external Api. The plan is I want the success response to be displayed on WordPress Front-end using shortcodes. Currently i don't have an external api to test it but i am also not if this the right way to get what i want so is it? Thanks in advance.
add_action('wpforms_process_complete', 'wpairform_api_sender', 10, 4);
function wpairform_api_sender($fields, $entry, $form_data, $entry_id)
{
//if form ID is 1
if ($form_data['id'] == 10240) {
$api_url = 'https://hook.integromat.com/tzeseygrctyxjbsxfp7psbbkt40j8tc2';
$body = array(
'text' => $fields['1']['value'],
);
$response = wp_remote_post($api_url, array('body' => $body));
if( is_wp_error( $response )){
$error_message = $response->get_error_message();
return "Something went wrong: $error_message";
}
if( 200 !== wp_remote_retrieve_response_code( $response )){
return;
}
if (200 === wp_remote_retrieve_response_code( $response )) {
//$response_body = wp_remote_retrieve_body( $response );
//var_dump($response_body->message);
function github_issues_func($atts)
{
return wp_remote_retrieve_body($response);
}
add_shortcode("github_issues", "github_issues_func");
}
}
}
If all you want to do is to get that response from the API and show it on your Front End, you can save that in a transient instead of generating a shortcode each time the form runs, you can read more about transients here

Calculated distance shipping cart fee via Google API in WooCommerce

So, I have written a piece of code after getting some help from SO and internet. I want to add a fees to the cart by calculating the distance between the vendor's location (billing_city) and customer's area via Google Maps API Distance-Matrix. Here, I use a dropdown after billing form to get the area of customer.
I am having problem of getting the value from cookies and pass the variable to next function. FYKI, I have inserted this code into my child theme functions.
add_action( 'wp_footer', 'calculate_distance_between_two_locations' );
function calculate_distance_between_two_locations($dist) {
// I am getting first item of the cart
foreach( WC()->cart->get_cart() as $cart_item ){
$product_id = $cart_item['product_id'];
break;
}
//Now I am fetching vendor's id and location of the item
$vendor_id = get_post_field( 'post_author', $product_id );
$vendor_location = get_user_meta($vendor_id, 'billing_city', true);
//Here I'm fetching the value from customer location
//I am using a dropdown/select named billing_myfield5
if (is_checkout()) {?>
<script type="text/javascript">
jQuery( document ).ready(function( $ ) {
$('#billing_myfield5').change(function(){
jQuery('body').trigger('update_checkout');
var location = $('#billing_myfield5 option:selected').text();
document.cookie="cusarea="+location;
});
});
</script>
<?php
}
//Encoding the customer's location for Google API
//and putting it into a variable
$customer_area = rawurlencode($_COOKIE ['cusarea']);
//I am setting Google API
$shippingurl = "https://maps.googleapis.com/maps/api/distancematrix/json?origins=".$vendor_location."&destinations=".$customer_area."&key=MY_API_KEY";
//Now fetching json response from googleapis.com:
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $shippingurl);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$response = json_decode(curl_exec($ch), true);
//If google responds with a status of OK
//Extract the distance text:
if($response['status'] == "OK"){
$dist = $response['rows'][0]['elements'][0]['distance']['text'];
}
//Getting the integers from the string
$dist_ance = preg_replace("/[^0-9\.]/", '', $dist);
//Finally putting the value in session
session_start();
$_SESSION['dist'] = $dist_ance;
}
So, now I should have a value in $_SESSION['dist']and I should be able to pass it to another function in same page. Here's the code I am using to calculate the cart fees.
add_action( 'woocommerce_cart_calculate_fees', 'woo_add_cart_fee' );
function woo_add_cart_fee( $cart ){
if ( ! $_POST || ( is_admin() && ! is_ajax() ) ) {
return;
}
if($_SESSION['dist']){
$customshipcost = $dist_ance;
if ( is_admin() && ! defined ( 'DOING_AJAX' ))
WC()->cart->add_fee('Distance Delivery Charge', $customshipcost , true);
}
}
Well, I am having two problems actually. Any help would be really appreciated.
Sometimes I get the value from cookie, sometimes I don't. I use echo
to check whether it's giving me the value or not.
The session is not responding. I get a '0' as fees in my cart.
FYKI, I am just trying to show only numerical distance as fees in cart right now.
Here is the correct way to get the selected location value in the woocommerce_cart_calculate_fees action hook. I have moved all php code in this hooked function.
In a custom function hooked in woocommerce_after_checkout_form action hook, I have added your revised jQuery code.
I have test everything (but not the google API part and the distance calculation fee) and it works live: Each time a value is selected, it is updated in the fee function.
Here is the code:
add_action( 'woocommerce_after_checkout_form', 'custom_checkout_jquery_script', 10 );
function custom_checkout_jquery_script() {
// Setting the country in customer data and session
$country_code = 'BD'; // For Bangladesh
WC()->session->set( 'country', $country_code );
WC()->session->set( 'billing_country', $country_code );
WC()->session->set( 'shipping_country', $country_code );
WC()->customer->set_billing_country( $country_code );
WC()->customer->set_shipping_country( $country_code );
// The jQuery code
?>
<script type="text/javascript">
(function($){
// Initializing (get the default value)
var location = $('#billing_myfield5 option:selected').html();
document.cookie="cusarea="+location;
// To test the default location output in browser console dev tools
console.log('Selected Area: '+location);
// Get the live value when selected
$( 'form.checkout' ).on( 'change', '#billing_myfield5', function(){
location = $('#billing_myfield5 option:selected').html();
document.cookie="cusarea="+location;
$('body').trigger('update_checkout');
// To test the selected location output in browser console dev tools
console.log('Selected Area: '+location);
});
})(jQuery);
</script>
<?php
}
add_action( 'woocommerce_cart_calculate_fees', 'distance_shipping_fee', 10, 1 );
function distance_shipping_fee( $wc_cart ){
if ( is_admin() && ! defined( 'DOING_AJAX' ) ) return;
if( empty($_COOKIE ['cusarea']) ) return; // Waiting for the selected area (cookie)
else $cookie = $_COOKIE ['cusarea'];
// Encoding the customer's location for Google API
$customer_area = rawurlencode( $cookie );
// I am getting first item of the cart
foreach( $wc_cart->get_cart() as $cart_item ){
$product_id = $cart_item['product_id'];
break;
}
// Get the vendor's id and location
$vendor_id = get_post_field( 'post_author', $product_id );
$vendor_location = get_user_meta($vendor_id, 'billing_city', true);
// Setting Google API URL ##
$gapi_key = "MY_API_KEY"; // Set HERE your google api key
$shippingurl = "https://maps.googleapis.com/maps/api/distancematrix/json?origins=$vendor_location";
$shippingurl .= "&destinations=$customer_area&key=$gapi_key";
// Now fetching json response from googleapis:
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $shippingurl);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$response = json_decode(curl_exec($ch), true);
// If google responds with a status of OK: Extract the distance text:
if($response['status'] == "OK")
$dist = $response['rows'][0]['elements'][0]['distance']['text'];
// Getting the integers from the string
$distance = preg_replace("/[^0-9\.]/", '', $dist);
if( $distance > 0 ){
$customshipcost = $distance;
// Displaying the selected location in the fee label
$wc_cart->add_fee( "Distance Delivery fee ($cookie)", $customshipcost , true);
}
}
Code goes in function.php file of your active child theme (or theme) or also in any plugin file.
All code is tested on Woocommerce 3+ and works.
This will solve your coockie and session problem

Wordpress shortcode fires api call when editing post

I created a wordpress plugin with a add_shortcode filter that sends an api call to our system and retrieves documents from the server. However, I noticed that it fires even in the Admin area while I am editing a post or a page. So as I type the value inside the shortcode, it continuously communicates with the server.
How do I stop the shortcode from firing the api call function unless it was published in the post/page?
Edit- Adding more info
The comments below are putting me on the right track, so I want to add more info for you guys.
I am using the WordPress Boilerplate. I added the add_shortcode filter to the plugin library and I register the add_shortcode in the define_public_hook:
$this->loader->add_shortcode( 'my_plugin', $plugin_public, 'my_shortcode', 10, 2 );
then in my-plugin-public-display.php I add the functions (I'll abbreviate it...):
public function api_get_as_json( $controller, $slug, $action, $params, $endpoint ) {
if ( null == $params ) {
$params = array();
}
// Create URL with params
$url = $endpoint . $controller . $slug . $action . '?' . http_build_query($params);
// echo $url;
// Use curl to make the query
$ch = curl_init();
curl_setopt_array(
$ch, array(
CURLOPT_URL => $url,
CURLOPT_RETURNTRANSFER => true
)
);
$output = curl_exec($ch);
// Decode output into an array
$json_data = json_decode( $output, true );
curl_close( $ch );
return $json_data;
}
/**
* Shortcodes
*
* #since 1.0.0
*/
public function my_shortcode( $atts ) {
//turn on output buffering to capture script output
ob_start();
// Get attributes from shortcode
$attributes = shortcode_atts( array(
...
), $atts, 'my_plugin' );
$my_array = //getting the array attributes here...
/* Send API calls to WhoTeaches, get profile and Packages */
$result = $this->api_get_as_json('controller/', null, 'action', $my_array, $host . "domain.com/api/v1/");
// Load the view
include (plugin_dir_path( dirname( __FILE__ ) ) . 'public/partials/my-plugin-public-display.php');
// Get content from buffer and return it
$output = ob_get_clean();
return $output;
// Clear the buffer
ob_end_flush();
}
Do I need to add or edit something here?

Twitter Get User Status values using API and is there a limit?

All,
I have the following code to grab a twitter status and display it back to the user:
if( ! $tweet ) {
//$format = 'json';
//$contents = file_get_contents( "http://api.twitter.com/1/statuses/user_timeline/{$username}.{$format}", 0, $context );
//$contents = file_get_contents(" https://api.twitter.com/1/statuses/user_timeline.json?screen_name={$username}&count={$how_many}", 0, $context );
$url = "http://api.twitter.com/1/statuses/user_timeline.json?screen_name={$username}&count={$how_many}";
$curl = curl_init();
curl_setopt( $curl, CURLOPT_URL, $url );
curl_setopt( $curl, CURLOPT_RETURNTRANSFER, 1 );
$contents = curl_exec( $curl );
curl_close( $curl );
if ( ! empty( $contents ) ) {
// Decode it.
$tweet = json_decode( $contents );
// Cache it for next time.
//set_transient( $id.'-'.$username, $tweet, 60*60*3 ); // 3 hour cache
}
}
// Check to make sure we have a tweet and display it.
if ( is_array($tweet) && isset($tweet[0]->id_str)) {
do_action( 'themeblvd_twitter_slider', $tweet, $options, $username, $slider_id );
} else {
$output = '<span class="tweet-icon '.$options['icon'].'"></span>';
$output .= 'We experienced an error with Twitter! Please check back soon for our reviews!';
}
return $output;
So basically I'm trying to determine if I've already fetched some tweets and if not go fetch them and then pass them back to the loop below to display them to the user.
<?php
foreach($tweet as $t){
?>
<li class="slide tight <?php echo $classes; ?>">
<div class="slide-body">
<div class="grid-protection">
<?php
echo '<span class="tweet-icon '.$options['icon'].'"></span>';
echo '<a href="http://twitter.com/'.$username.'/status/'.$t->id_str.'" target="_blank">';
echo $t->text;
echo '</a>';
?>
</div><!-- .grid-protection (end) -->
</div><!-- .slide-body (end) -->
</li>
<?php
}
?>
For some reason I'm getting the error message saying that they can't be displayed. If I keep the limit to like 10 it displays fairly consistently without an error. If I increase the limit to like 50 or 85 I get the error message saying that twitter is having a problem. Has the API changed recently? Do they have new limits? Any ideas on why I can't display the 85 tweets?
Thanks in advace!
I found out that you can actually determine if you've reached your limit yet or not but calling the following URL:
https://api.twitter.com//1/account/rate_limit_status.json
What I did was check the response in this before actually trying to call the user status API. My code to check the rate limit looks like the following:
$url_check_limit = "https://api.twitter.com//1/account/rate_limit_status.json";
$curl_limit = curl_init();
curl_setopt( $curl_limit, CURLOPT_URL, $url_check_limit );
curl_setopt( $curl_limit, CURLOPT_RETURNTRANSFER, 1 );
$contents_limit = curl_exec( $curl_limit );
curl_close( $curl_limit );
if ( ! empty( $contents_limit ) ) {
// Decode it.
$tweet_limit = json_decode( $contents_limit );
}
if ( $tweet_limit->remaining_hits == "0" ){
$no_tweets = true;
echo "We've reached out rate limit";
}else{
//Execute the Twitter user_status API from my original question
}
This allows me to avoid keep calling the twitter API if I hit my limit already. If I didn't hit my limit I call the code in my original question and display the tweets to the user. Hope this helps someone!

Categories