I have a problem that I will never be able to solve on my own, I hope someone will help me here, thank you for any answers and I appreciate any help.
Basically I have two functions, one sets the date of the last login and current login, while the other gets the login set by the first function. With simple shortcodes I can then display the date of the last login and current login. This works well, but in addition to the dates I also want to show the location from which the login was made and which browser was used.
Geolocation Function
So to do this I wrote a geolocation function that returns lat and long value, with reverse geocoding I then get the readable address. This also works well.
Get Browser Function
Then I wrote another little function that gets the browser used by the user with user agent, this also works wonderfully.
Main Problem
The problem with geolocation and get browser is that functions always return current values. But that's not what I want.
What I want to do is store locations and browsers at login (just like I do with dates) and then view them. In this way, if you log in at point A at 00:00, this will remain the same. Currently it does not do this because it is only hovering where you are at the moment and not where you were at 00:00.
So how can I memorize locations and browsers just like I am doing with dates? I specify that I am working on my website with wordpress.
Date function
// Function that get last login
function get_last_login($user_id, $prev = null) {
$last_login = get_user_meta($user_id);
$time = current_time( 'timestamp' );
if(isset($last_login['_last_login_prev'][0]) && $prev) {
$last_login = get_user_meta($user_id, '_last_login_prev', 'true' );
}
else if(isset($last_login['_last_login'][0])) {
$last_login = get_user_meta($user_id, '_last_login', 'true' );
}
else {
update_user_meta( $user_id, '_last_login', $time );
$last_login = $last_login['_last_login'][0];
} return $last_login;
}
// Shortcode (1) - Last Login Date
function last_login_date() {
global $current_user;
echo '<div class="lastlogin"> '.date("j/m/Y - H:i", get_last_login($current_user->ID, true)).' </div>';
} add_shortcode('lastlogin', 'last_login_date');
// Shortcode (2) - Current Login Date
function current_login_date() {
global $current_user;
echo '<p>Current: Login date: '. date("j M Y - H:i", get_last_login($current_user->ID)). '</p>';
} add_shortcode('currentlogin', 'current_login_date');
Geolocation function
//enqueue my-script
wp_enqueue_script( 'my-script', trailingslashit( get_stylesheet_directory_uri() ) . 'woocommerce/myaccount/assets/my-script.js', array( 'jquery-min' ), wp_get_theme()->version, true );
//pass ajax and a nonce to my-script
wp_localize_script( 'my-script', 'localize', array(
'_ajax_url' => admin_url( 'admin-ajax.php' ),
'_ajax_nonce' => wp_create_nonce( '_ajax_nonce' ),
));
add_action( 'wp_ajax__wpso_73934145', function () {
if ( check_ajax_referer( '_ajax_nonce' ) ) {
$user_id = get_current_user_id();
$latitude = $_POST['latitude'];
$longitude = $_POST['longitude'];
$openStreetMapObject = $_POST['openStreetMapObject'];
$meta_key = '_user_position';
$meta_value = array(
'latitude' => $latitude,
'longitude' => $longitude,
'openStreetMapObject' => $openStreetMapObject,
);
update_user_meta( $user_id, $meta_key, $meta_value );
wp_send_json_success( $meta_value );
} else {
wp_send_json_error();
};
wp_die();
});
my-script.js (for geolocation function)
console.log( 'my-script.js has been successfully loaded' );
if ( navigator.geolocation ) {
window.navigator.geolocation.getCurrentPosition( function( position ) {
let lat = position.coords.latitude;
let lon = position.coords.longitude;
//https://nominatim.org/release-docs/latest/api/Reverse/
$.getJSON(`https://nominatim.openstreetmap.org/reverse?format=json&lat=${lat}&lon=${lon}`, function( object ) {
let adress = object.address;
$.ajax( {
type: 'POST',
url: localize._ajax_url,
data: {
_ajax_nonce: localize._ajax_nonce,
action: '_wpso_73934145',
latitude: lat,
longitude: lon,
openStreetMapObject: adress,
},
success: function ( response ) {
console.log( response.data );
},
} );
} );
} );
};
my-template.php (to view everything).
$user_id = get_current_user_id();
$meta_key = '_user_position';
if ( metadata_exists( 'user', $user_id, $meta_key ) ) {
$meta_value = get_user_meta( $user_id, $meta_key, true);
//var_dump( $meta_value );
//var_dump( $meta_value['openStreetMapObject']["ISO3166-2-lvl6"] );
//echo $meta_value['openStreetMapObject']['county'];
//echo $meta_value['openStreetMapObject']['country'];
//var_dump( $meta_value['openStreetMapObject']['city_district'] );
//echo $meta_value['openStreetMapObject']['city_district'] ;
$mybrowser = $_SERVER['HTTP_USER_AGENT'] . "\n\n";
$browser = get_browser(null, true);
$mybrowser = $_SERVER['HTTP_USER_AGENT'];
if (strpos(strtolower($mybrowser), "safari/") and strpos(strtolower($mybrowser), "opr/")) {
// OPERA
$mybrowsername="Opera";
} else if (strpos(strtolower($mybrowser), "safari/") and strpos(strtolower($mybrowser), "chrome/")) {
// CHROME
$mybrowsername="Chrome";
} else if (strpos(strtolower($mybrowser), "msie")) {
// INTERNET EXPLORER
$mybrowsername="Internet Explorer";
} else if (strpos(strtolower($mybrowser), "firefox/")) {
// FIREFOX
$mybrowsername="Firefox";
} else if (strpos(strtolower($mybrowser), "safari/") and strpos(strtolower($mybrowser), "opr/")==false and strpos(strtolower($mybrowser), "chrome/")==false) {
// SAFARI
$mybrowsername="Safari";
} else {
// OUT OF DATA
$mybrowsername="OUT OF DATA";
};
echo $mybrowsername;
echo $meta_value['openStreetMapObject']['county'];
echo $meta_value['openStreetMapObject']['country'];
echo $meta_value['openStreetMapObject']["ISO3166-2-lvl6"];
} else {
echo 'You need to share your location';
};
your current code cannot work with what you're trying to achieve, you need to save a login activity everytime a user perform a login which includes all the details you want to pull later.
Here is a full example.
1. modify the login form and add two hidden input fields for latitude and longitude from navigator.geolocation which you can do via login_form action hook
add_action('login_form', function() {
?>
<input type="hidden" name="latitude" id="latitude" />
<input type="hidden" name="longitude" id="longitude" />
<script>
if ( navigator.geolocation ) {
navigator.geolocation.getCurrentPosition( (position) => {
const latitude = document.getElementById('latitude') // get the latitude input field
const longitude = document.getElementById('longitude') // get the longitude input field
latitude.value = position.coords.latitude // assign the latitude input value
longitude.value = position.coords.longitude // assign the longitude input value
})
}
</script>
<?php
});
2. Process all the data you want to pull later and save it on user meta once the user successfully login, you can inject it via wp_login action hook
add_action('wp_login', function( $uname, $user) {
$limit = 5; // the activity limit you want to save
$lat = $_REQUEST['latitude']; // get the latitude value from the login request
$long = $_REQUEST['longitude']; // get the longitude value from the login request
$browser = detectBrowser(); // generate browser data based on user agent
//generate location if latitude and longitude is present. Otherwise, use the user ip to generate the location
$location = $lat && $long && getLatLongLocation($lat, $long)->address ? getLatLongLocation($lat, $long)->address : getIPLocation();
$date = date('j/m/Y - H:i');
// Format the data to be saved as login activity
$loginDetails = [
'date' => $date,
'browser' => [
'ua' => $_SERVER['HTTP_USER_AGENT'],
'name' => ( isset( $browser->client ) && isset($browser->client->name) ) ? $browser->client->name : '',
'device_type' => ( isset( $browser->device ) && isset($browser->device->type) ) ? $browser->device->type : '',
'os' => ( isset( $browser->os ) && isset($browser->os->name) ) ? $browser->os->name : '',
],
'location' => [
'ip' => $_SERVER['REMOTE_ADDR'],
'city' => isset( $location->city ) ? $location->city : '',
'country' => isset( $location->country ) ? $location->country : '',
'lat' => $lat,
'long' => $long
]
];
$logins = get_user_meta($user->ID, '_login_activity', true); // get the user meta that holds the login activities
$logins = $logins ? $logins : []; // pass empty array if the user meta does not contain anything yet
array_unshift($logins, $loginDetails); // push the recent $loginDetails to the top of the login activities array
//Save the login activities, only save the array from 0 to $limit position
update_user_meta( $user->ID, '_login_activity', array_slice($logins, 0, $limit) );
}, 10, 2);
the above code you uses the following functions that request to 3rd party APIs to get the data;
// Get location details from IP address
function getIPLocation( $ip = false) {
$ip = $ip ? $ip : $_SERVER['REMOTE_ADDR'];
$details = json_decode(file_get_contents("https://ipinfo.io/{$ip}/json"));
return $details;
}
// Get location details from latitude and longitude
function getLatLongLocation( $lat = false, $long = false) {
if ( !$lat || !$long )
return;
$query = "format=json&lat=$lat&lon=$long&limit=1&email=test#email.com";
$details = json_decode(file_get_contents("https://nominatim.openstreetmap.org/reverse?$query"));
return $details;
}
// Get browser details from user-agent
function detectBrowser( $ua = false ) {
$ua = $ua ? $ua : $_SERVER['HTTP_USER_AGENT'];
$ua = urlencode( $ua);
$details = json_decode(file_get_contents("https://api.apicagent.com/?ua={$ua}"));
return $details;
}
You can check the output of these function by simply dumping the output like;
add_action('wp_head', function() {
$latLongLocation = getLatLongLocation('lat-here', 'long-here');
$ipLocation = getIPLocation('ip-here');
$uaDetails = detectBrowser('user-agent-here');
echo '<pre>', print_r($latLongLocation, 1), '</pre>';
echo '<pre>', print_r($ipLocation, 1), '</pre>';
echo '<pre>', print_r($uaDetails, 1), '</pre>';
});
After, you've added the modification for login_form and wp_login action hook, there should be a user meta with a key _login_activity everytime a user perform a login.
Now you can simply create a function to pull the value and display anywhere you want.
First, a function to format the HTML output for invidiual login record
// display format for individual login activity
function logFormat( $log ) {
if ( !$log || !is_array( $log ) )
return;
return '<div class="login-activity">
<div>Date: '.$log['date'].'</div>
<div>Browser: '.$log['browser']['name'].'</div>
<div>OS: '.$log['browser']['os'].'</div>
<div>City: '.$log['location']['city'].'</div>
<div>Country: '.$log['location']['country'].'</div>
<div>IP: '.$log['location']['ip'].'</div>
</div>';
}
then a function to get all or a single specific login record
// Pull the login activity with dynamic position attribute
function getLoginActivity( $atts ) {
//exit function of user is not logged
if ( !get_current_user_id() )
return;
// get the current user meta
$logins = get_user_meta(get_current_user_id(), '_login_activity', true);
//add shortcode attribute support
$attr = shortcode_atts([
'position' => 'all'
], $atts );
if ( !isset( $logins[0] ) )
return 'No Login Activity';
// Output all login activity if position is left to default
if ($attr['position'] === 'all' ) {
$out = '<div class="all-logins">';
foreach( $logins as $login ) {
$out .= logFormat( $login );
}
return $out. '</div>';
}
//return the login activity with exact position
if ( isset( $logins[ (int) $attr['position'] ] ) )
return logFormat( $logins[ (int) $attr['position'] ] );
return 'No activity with position: '. $attr['position'];
}
add_shortcode('login-activity', 'getLoginActivity'); // add shortcode support
then you can simply use getLoginActivity function anywhere in your php file, the current login details should be the 0 position and previous last login details should be the 1 position
so you can simply do
echo getLoginActivity(['position' => '0']); // current login data
echo getLoginActivity(['position' => '1']); // last login data
echo getLoginActivity(); // all login data
or via shortcode added to a page
[login-activity position="0"]
Related
I read a few topics like "Javascript inside PHP doesn't work" but I couldn't find a solution. I have a WP plugin that sends emails when someone clicks on a button. Also when an email has been sent a PHP pop-up with confirmation appears. I think it's in the part where "wp_mail()" is. When an email was sent properly, I want to run some JS, right before PHP message. So I tried to do this outside PHP (first attempt) and through echo (second attempt below). I don't see these console logs. Also when I have this JS there, then this PHP alert doesn't show. When I remove it, it works. This code is run for sure because when I change the text in PHP alert message I see it. Also above this function is another function "add_action('wp_footer'..) and there is only JS, and this JS works, when I change something. I can't understand why it doesn't work there.
Function where I have problem:
function updateRequest()
{
$admin_email = get_option('admin_email');
$senderEmail = empty(trim(get_option('settings_page_sender_email'))) ? "no-reply#".$_SERVER['HTTP_HOST'] : get_option('settings_page_sender_email');
$order = wc_get_order($_POST['orderID']);
$title = empty(trim(get_option('settings_page_email_title')))?"“[UPDATE REQUEST]”":get_option('settings_page_email_title');
$recipient = $admin_email;
$subject = str_replace('[PRODUCTTITLE]', $_POST['productTitle'], $title);
$message = " ";
$headers = array(
'Content-Type: text/html; charset=UTF-8',
'From: '.$_POST['name'].' <'.$senderEmail.'>',
'Reply-To: '.$_POST['name'].' <'.$_POST['email'].'>'
);
if(wp_mail( $recipient, $subject, $message, $headers )){
?>
<script type="text/javascript">console.log("Data alert");</script>
<?php
echo'<script type="text/javascript">console.log("Data alert");</script>';
$confirmationTxt = empty(trim(get_option('settings_page_confirmation_text'))) ? "Request has been sent" : get_option('settings_page_confirmation_text');
wp_send_json_success($confirmationTxt , $status_code = null );
}else{
wp_send_json_error( "Something Went Wrong ...!", $status_code );
}
}
And this is the whole file
<?php
// If this file is called directly, abort.
if ( ! defined( 'WPINC' ) ) {
die;
}
function console_log($output, $with_script_tags = true) {
$js_code = 'console.log(' . json_encode($output, JSON_HEX_TAG) .
');';
if ($with_script_tags) {
$js_code = '<script>' . $js_code . '</script>';
}
echo $js_code;
}
/**
* Currently plugin version.
* Start at version 1.0.0 and use SemVer - https://semver.org
* Rename this for your plugin and update it as you release new versions.
*/
define( 'VIRTUAL_PRODUCT_WOOCOMMERCE_UPDATE_REQUEST_VERSION', '1.0.0' );
// Define global constants
$plugin_data = get_file_data( __FILE__, array( 'name'=>'Plugin Name', 'version'=>'Version', 'text'=>'Text Domain' ) );
function VPWUR_constants( $constant_name, $value ) {
$constant_name_prefix = 'VPWUR_VERSION';
$constant_name = $constant_name_prefix . $constant_name;
if ( !defined( $constant_name ) )
define( $constant_name, $value );
}
VPWUR_constants( 'DIR', dirname( plugin_basename( __FILE__ ) ) );
VPWUR_constants( 'BASE', plugin_basename( __FILE__ ) );
VPWUR_constants( 'URL', plugin_dir_url( __FILE__ ) );
VPWUR_constants( 'PATH', plugin_dir_path( __FILE__ ) );
VPWUR_constants( 'SLUG', dirname( plugin_basename( __FILE__ ) ) );
VPWUR_constants( 'NAME', $plugin_data['name'] );
VPWUR_constants( 'VERSION', $plugin_data['version'] );
VPWUR_constants( 'TEXT', $plugin_data['text'] );
VPWUR_constants( 'PREFIX', '' );
VPWUR_constants( 'SETTINGS', '' );
/**
* The code that runs during plugin activation.
* This action is documented in includes/class-virtual-product-woocommerce-update-request-activator.php
*/
function activate_virtual_product_woocommerce_update_request() {
require_once plugin_dir_path( __FILE__ ) . 'includes/class-virtual-product-woocommerce-update-request-activator.php';
Virtual_Product_Woocommerce_Update_Request_Activator::activate();
}
/**
* The code that runs during plugin deactivation.
* This action is documented in includes/class-virtual-product-woocommerce-update-request-deactivator.php
*/
function deactivate_virtual_product_woocommerce_update_request() {
require_once plugin_dir_path( __FILE__ ) . 'includes/class-virtual-product-woocommerce-update-request-deactivator.php';
Virtual_Product_Woocommerce_Update_Request_Deactivator::deactivate();
}
register_activation_hook( __FILE__, 'activate_virtual_product_woocommerce_update_request' );
register_deactivation_hook( __FILE__, 'deactivate_virtual_product_woocommerce_update_request' );
/**
* The core plugin class that is used to define internationalization,
* admin-specific hooks, and public-facing site hooks.
*/
require plugin_dir_path( __FILE__ ) . 'includes/class-virtual-product-woocommerce-update-request.php';
/**
* Begins execution of the plugin.
*
* Since everything within the plugin is registered via hooks,
* then kicking off the plugin from this point in the file does
* not affect the page life cycle.
*
* #since 1.0.0
*/
function run_virtual_product_woocommerce_update_request() {
$plugin = new Virtual_Product_Woocommerce_Update_Request();
$plugin->run();
}
run_virtual_product_woocommerce_update_request();
add_action('wp_footer', function ()
{
echo "<br><br><br><br><br>";
echo 'Hamza';
if (shortcode_exists( 'UpdateRequstBtn' )) {
echo "<pre>Shortcode Registered</pre>";
}
});
/* Adding CSS style for public */
function my_enqueued_assets() {
wp_enqueue_style('virtual-product-woocommerce-update-request-public', plugin_dir_url(__FILE__) . '/public/css/virtual-product-woocommerce-update-request-public.css', '', time());
}
add_action('wp_enqueue_scripts', 'my_enqueued_assets');
function updateRequstBtn($atts) {
global $product, $woocommerce;
$html = "";
if (method_exists($product, 'get_id')) {
$id = $product->get_id();
}
$atts = shortcode_atts( array(
'id' => #$id,
), $atts, 'UpdateRequstBtn' );
// echo $atts['id'];
$product = new WC_Product($atts['id']);
if (empty($atts['id']) || $atts['id'] == 0 || !get_current_user_id()) {
return;
}
$order = has_bought_items([$atts['id']]);
if (!$order) {
// you can remove this no orders from here ... just remove the text "No Orders"
return "";
}
// // print_r($order->get_billing_email());
$btnText = empty(trim(get_option( 'settings_page_btn_txt' ))) ? "Update Request": get_option( 'settings_page_btn_txt' );
$html .= '<div class="woocommerce-product-gallery vpwur-button-div">';
$html .= '<a href="javascript:void(0)" onclick="updateRequest(this);" class="button vpwur-button-a"
data-email="'.$order->get_billing_email().'"
data-orderID="'.$order->get_id().'"
data-productTitle="'.get_the_title($atts['id']).'"
data-name="'.$order->get_billing_first_name()." ".$order->get_billing_last_name().'"
>'. $btnText .'</a>';
$html .= '<p class="vpwur-sending-txt-pre">Trwa wysylanie zadania...</div>';
return $html;
}
add_shortcode( 'UpdateRequstBtn', 'UpdateRequstBtn' );
/**
* Show number list of downloadable files for group product
*
* #param array $download
* #return void
*/
/*function prefix_downloads_column_download_file( array $download ) {
// print_r($download);
echo '<a href="', $download['download_url'], '" download>', $download['download_name'], '</a>';
// do_shortcode( '[UpdateRequstBtn id="'.$download['product_id'].'"]' );
// echo shortcode_exists( 'UpdateRequstBtn' );
}
add_action( 'woocommerce_account_downloads_column_download-file', 'prefix_downloads_column_download_file' );*/
add_action( 'woocommerce_account_downloads_column_update-request', function( $download ) {
if (get_option( 'enable_download_page_btn' )) {
echo do_shortcode( '[UpdateRequstBtn id="'.$download['product_id'].'"]' );
}
} );
add_filter( 'woocommerce_account_downloads_columns', function( $columns ) {
if (get_option( 'enable_download_page_btn' )) {
// Add Column
$columnName = empty(trim(get_option( 'download_page_column_name' ))) ? "Update Request": get_option( 'download_page_column_name' );
$columns['update-request'] = $columnName;
}
// Return
return $columns;
} );
add_action('wp_footer', function ()
{
?>
<script type="text/javascript">
function updateRequest(e) {
var data = {
'action': 'updateRequest',
'name': e.dataset.name, // We pass php values differently!
'email': e.dataset.email, // We pass php values differently!
'orderID': e.dataset.orderid, // We pass php values differently!
'productTitle': e.dataset.producttitle, // We pass php values differently!
};
// console.log(data);
jQuery.post('<?php echo admin_url('admin-ajax.php') ?>', data, function(response) {
alert(response.data);
// alert('Got this from the server: ' + response);
});
/* Changing CSS for sending email message under button */
const confirmTxtsList = Array.from(document.getElementsByClassName('vpwur-sending-txt-pre'));
confirmTxtsList.forEach(p => {
p.classList.remove('vpwur-sending-txt-pre');
p.classList.add('vpwur-sending-txt-on');
});
}
</script>
<?php
});
add_action('wp_ajax_updateRequest','updateRequest');
add_action('wp_ajax_nopriv_updateRequest','updateRequest');
function updateRequest()
{
$admin_email = get_option('admin_email');
$senderEmail = empty(trim(get_option('settings_page_sender_email'))) ? "no-reply#".$_SERVER['HTTP_HOST'] : get_option('settings_page_sender_email');
$order = wc_get_order($_POST['orderID']);
$title = empty(trim(get_option('settings_page_email_title')))?"“[UPDATE REQUEST]”":get_option('settings_page_email_title');
$recipient = $admin_email;
$subject = str_replace('[PRODUCTTITLE]', $_POST['productTitle'], $title);
$message = " ";
$headers = array(
'Content-Type: text/html; charset=UTF-8',
'From: '.$_POST['name'].' <'.$senderEmail.'>',
'Reply-To: '.$_POST['name'].' <'.$_POST['email'].'>'
);
if(wp_mail( $recipient, $subject, $message, $headers )){
?>
<script type="text/javascript">console.log("Data alert");</script>
<?php
echo'<script type="text/javascript">console.log("Data alert");</script>';
$confirmationTxt = empty(trim(get_option('settings_page_confirmation_text'))) ? "Request has been sent" : get_option('settings_page_confirmation_text');
wp_send_json_success($confirmationTxt , $status_code = null );
}else{
wp_send_json_error( "Something Went Wrong ...!", $status_code );
}
}
function has_bought_items($prod_arr=[]) {
$bought = false;
// Set HERE ine the array your specific target product IDs
// $prod_arr = array( '21', '67' );
// Get all customer orders
$customer_orders = get_posts( array(
'numberposts' => -1,
'meta_key' => '_customer_user',
'meta_value' => get_current_user_id(),
'post_type' => 'shop_order', // WC orders post type
'post_status' => 'wc-completed' // Only orders with status "completed"
) );
foreach ( $customer_orders as $customer_order ) {
// Updated compatibility with WooCommerce 3+
$order_id = method_exists( $customer_order, 'get_id' ) ? $customer_order->get_id() : $customer_order->id;
$order = wc_get_order( $customer_order );
// Iterating through each current customer products bought in the order
foreach ($order->get_items() as $item) {
// WC 3+ compatibility
if ( version_compare( WC_VERSION, '3.0', '<' ) )
$product_id = $item['product_id'];
else
$product_id = $item->get_product_id();
// Your condition related to your 2 specific products Ids
if ( in_array( $product_id, $prod_arr ) )
$bought = $order;
}
}
// return "true" if one the specifics products have been bought before by customer
return $bought;
}
PS there is no "?>" at the end, as this is main plugin file and must be part of some other file probably.
I have added a custom message that now appears below woocommerce_after_order_notes, But I just want it to be displayed for one of the variables of a product.
The following code shows it only for the main product
Please tell me how to change it for a variable.
add_action( 'woocommerce_after_order_notes', 'allclean_add_checkout_content', 12 );
function allclean_add_checkout_content() {
// set your products IDs here:
$product_ids = array( 91);
$bool = false;
foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
$item = $cart_item['data'];
if ( in_array( $item->id, $product_ids ) )
$bool = true;
}
// If the special cat is detected in one items of the cart
// It displays the message
if ($bool)
echo '<div class="checkoutdisc">This is Your custom message displayed.</div>';
}
You can check if there is any variation_id in cart like this $cart_item['variation_id']. try the below code.
add_action( 'woocommerce_after_order_notes', 'allclean_add_checkout_content', 12 );
function allclean_add_checkout_content() {
// set your products IDs here:
$product_ids = array( 82, 94 ); // add your both product and variation id.
$parent_ids_in_cart = false;
foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
$item = $cart_item['data'];
if ( in_array( $item->id, $product_ids ) ){
$parent_ids_in_cart = true;
}
}
$variation_ids_in_cart = false;
// Loop through cart items
foreach( WC()->cart->get_cart() as $cart_item ) {
// Collecting product variation IDs if they are in cart for this variable product
if ( $cart_item['variation_id'] > 0 && in_array( $cart_item['variation_id'], $product_ids ) ){
$variation_ids_in_cart = true;
}
}
// It displays the message
if ( $parent_ids_in_cart || $variation_ids_in_cart ){
echo '<div class="checkoutdisc">This is Your custom message displayed.</div>';
}
}
My question is regarding suggestions for improvements of a feature I created on a Wordpress site that changes the phone number displayed to user in the header based on their IP address. The default is a 1-866 number to be displayed if area does not appear to be serviced etc.
In my functions.php file I created the below functions to use ipinfo.io to find the city of the user, compare it to the field of city I created to be associated with each location post and then if there is a match the second function returns the phone number field associated with that location. See functions below:
//Returns users city based on IP address
function get_the_user_ip() {
if ( ! empty( $_SERVER['HTTP_CLIENT_IP'] ) ) {
//Checks if IP is from shared internet
$ip = $_SERVER['HTTP_CLIENT_IP'];
}
elseif ( ! empty( $_SERVER['HTTP_X_FORWARDED_FOR'] ) ) {
//Checks if IP is passed from proxy
$ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
}
else {
//Most trustworthy source of IP address
$ip = $_SERVER['REMOTE_ADDR'];
}
//$ip='104.238.96.194'; //--used this to test different IP addresses--
//Uses ipinfo.io to find location information based on IP address
$details = json_decode(file_get_contents("https://ipinfo.io/{$ip}"));
//Returns city value from the details array
$city=$details->city;
return apply_filters('wpb_get_ip', $city );
}
//Returns correct phone number based on a user's location
function zip_display(){
$args = array(
'posts_per_page' => -1,
'post_type' => 'Locations',
'post_status' => ('publish')
);
$wp_query = new WP_Query($args);
//var_dump($wp_query);
if( $wp_query->have_posts() ): while( $wp_query->have_posts() ) : $wp_query->the_post();
$userCity=get_the_user_ip();
$stateField=get_field('state');
$cityField=get_field('city');
$phoneField=get_field('phone_number');
if($userCity==$cityField){
return ( '<span class="phone-span">' . $phoneField . '</span>');
}
endwhile;
wp_reset_postdata();
endif;
}
To display the correct phone number in the header I inserted a <div> element with the id of phone directly into an auxiliary header like so:
Then to target this div id I inserted the below JavaScript directly into my footer.php
<script>document.getElementById("phone").innerHTML = '<?php echo zip_display(); ?>';</script>
Is this an acceptable way to go about doing this? Everything is working correctly more or less right now. The only issue I am having so far is it seems for at least one person neither the default 1-866 number is being displayed to them nor a specific number based on their location? Does anyone have any ideas why that would be? Does it possibly have to do with a browser setting that does not allow JavaScript scripts to be shown in the way I constructed it?
The zip_display() function in your posted code will only return a span element if the $userCity matches the $cityField. You need to return the span containing the default phone number if the cities do not match. Change your condition to something like this:
if($userCity==$cityField){
return ( '<span class="phone-span">' . $phoneField . '</span>');
}else{
return ( '<span class="phone-span">' . $defaultPhoneNumber . '</span>');
}
In order to improve the functionality of this feature I did the following:
In my get_the_user_ip function I decided to use the free WordPress plugin GeoIP Detection, instead of ipinfo.io
See modification to get_the_user_ip function below:
`//Returns users city based on IP address`
function get_the_user_ip() {
if ( ! empty( $_SERVER['HTTP_CLIENT_IP'] ) ) {
//Checks if IP is from shared internet
$ip = $_SERVER['HTTP_CLIENT_IP'];
}
elseif ( ! empty( $_SERVER['HTTP_X_FORWARDED_FOR'] ) ) {
//Checks if IP is passed from proxy
$ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
}
else {
//Most trustworthy source of IP address
$ip = $_SERVER['REMOTE_ADDR'];
}
$record = geoip_detect2_get_info_from_ip($ip, NULL);
$city=$record->city->name;
return apply_filters('wpb_get_ip', $city );
}
In my zip_display function I added a return statement outside of while loop. In order to return a default phone number if the user's city cannot be matched to a location. This works better than an if/else statement because it will only execute once the loop has completed all iterations.
function zip_display(){
$args = array(
'posts_per_page' => -1,
'post_type' => 'Locations',
'post_status' => ('publish')
);
$wp_query = new WP_Query($args);
if( $wp_query->have_posts() ): while( $wp_query->have_posts() ) : $wp_query->the_post();
$userCity=get_the_user_ip();
$cityField=get_field('city');
$phoneField=get_field('phone_number');
if($userCity==$cityField){
return ('<a class="phone-span" href="tel:1-'. $phoneField . '">' . $phoneField . '</a>');
}
endwhile;
return('<a class="phone-span" href="tel:1-866-000-0000">1-866-000-0000</a>');
wp_reset_postdata();
endif;
}
Lastly I modified my footer.php file, separating my JavaScript script into a variable so that the script would not throw an Uncaught TypeErron: Cannot read property '....' of null.
<script>
var ipphone = '<?php echo zip_display(); ?>'
if(ipphone){document.getElementById("phone").innerHTML = ipphone;}
</script>
sorry if this seems like a ridiculous question, however, I've been pulling my hair out for 3 days trying to work out how to do this...
I essentially want to pull out this (query var?) and use the parameters in my current function...
?vote=up&comment_id=8
Here is my current function:
<?php
// This file is used for buildimng the custom comment upvote and downvote functionality.
add_action( 'wp_enqueue_scripts', 'ajax_enqueue' );
function ajax_enqueue() {
// Enqueue File from 'inc' folder.
wp_enqueue_script( 'ajax-script', get_template_directory_uri() . '/inc/ajax/comment_vote_ajax.js', array('jquery') );
// in JavaScript, object properties are accessed as
ajax_object.ajax_url, ajax_object.we_value
wp_localize_script( 'ajax-script', 'ajax_object',
array(
'ajax_url' => admin_url( 'admin-ajax.php' ),
'user_id' => get_current_user_id()
)
);
}
// Same handler function...
function ajax_action() {
global $wpdb;
if ( ! is_user_logged_in() ) {
return;
}
if ( ! isset( $_GET[ 'vote' ] ) && ! isset( $_GET[ 'comment_id' ] ) ) {
return;
}
$up_or_down = esc_attr( $_GET[ 'vote' ]) ;
if ( ! in_array( $up_or_down, [ 'up', 'down' ] ) ) {
return;
}
$comment_id = (int) esc_attr( $_GET[ 'comment_id' ] );
if ( $comment_id < 1 ) {
return;
}
// Retreive the existing comment up/down vote ID's - we don't know who did what at this point..
$vote_user_ids = get_comment_meta( $comment_id, '_vote_user_ids', true );
// If the comment upvote count isn't set, create an empty array.
// This will always be the case on the first instance of a user "upvoting" a comment
if ( ! is_array( $vote_user_ids ) ) {
$vote_user_ids = [];
}
// Check if the user has already "voted"
if ( array_key_exists( get_current_user_id(), $vote_user_ids ) ) {
// If the user HAS voted and they are repeating themselves (e.g. the voted up and are trying to do this again) ignore them..
if ( $up_or_down === $vote_user_ids[ $user_id ] ) {
return;
} else {
// The user voted already but have changed their vote - update this
//$vote_user_ids[ get_current_user_id() ] = $up_or_down;
unset ( $vote_user_ids[ get_current_user_id() ] );
}
} else {
// The user HAS NOT voted, add them
$vote_user_ids[ get_current_user_id() ] = $up_or_down;
}
// Whatever the results of ^^ we need to update now
$update_result = update_comment_meta( $comment_id, '_vote_user_ids', $vote_user_ids );
delete_transient( "comment_vote_count_comment_{$comment_id}" );
if ( ! $update_result ) {
error_log( "Error updating comment meta to update $comment_id to set user ID $user_id $up_or_down." );
}
wp_die();
}
add_action( 'wp_ajax_my_action', 'ajax_action' );
add_action( 'wp_ajax_nopriv_my_action', 'ajax_action' );
// End of the ajax call.
Here is the current script I have...
var $ = jQuery.noConflict();
function getParameterByName(name, url) {
if (!url) url = $(this).attr('href');
name = name.replace(/[\[\]]/g, "\\$&");
var regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)"),
results = regex.exec(url);
if (!results) return null;
if (!results[2]) return '';
return decodeURIComponent(results[2].replace(/\+/g, " "));
}
$(document).ready(function(){
$("a.upvote").click(function(e) {
e.preventDefault();
var comment_id = getParameterByName('comment_id', $(this).attr('href'));
filters_get = {
'vote': 'up',
'comment_id': comment_id
};
$.ajax({
url: ajax_object.ajax_url,
type: "post", //send it through get method
data: filters_get,
cache: false,
success: function(data) {
console.log( 'comment_id' + ' = ' + comment_id );
console.dir(data);
console.log(data);
$('.comment p').after(data);
},
error: function(xhr) {
}
});
});
});
I'm working in a ecommerce with wordpresss and woocommerce, im adding to the shop page and category pages buttons that display the sizes for each product. with this code inside the theme function:
function woocommerce_variable_add_to_carts() {
global $product, $post;
$variations = $product->get_available_variations();
$product_sku = $product->get_sku();
$out = '<ul class="iconic-was-swatches iconic-was-swatches--loop iconic-was-swatches--text-swatch iconic-was-swatches--square">';
foreach ($variations as $key => $value) {
if (!empty($value['attributes'])) {
foreach ($value['attributes'] as $attr_key => $attr_value) {
$out .= '<li><a id="'.esc_attr($post->ID).'" data-quantity="1" data-product_id="'.esc_attr($post->ID).'" data-product_sku="'.$product_sku.'" class="iconic-was-swatch iconic-was-swatch--follow iconic-was-swatch--text-swatch add_to_cart_button">';
$out .= $attr_value . '</a></li>';
}
}
}
$out .= '</ul>';
echo $out;
}
add_action('woocommerce_before_shop_loop_item_title', 'woocommerce_variable_add_to_carts');
The idea is that when the users click in one of those sizes buttons the product is added to the cart directly in that page (shop page, category page). I made a custom endpoint to solve that from the answer provided here. I call the ajax function in the js file that Contains this:
$('.add_to_cart_button').on('click',function(){
jQuery.ajax({
url: WC_VARIATION_ADD_TO_CART.ajax_url,
type: "POST",
data: {
action : "customAdd_to_cart",
product_id : "697",
variation_id : "707",
quantity : 1,
variation : {
size : "s",
color: "pink"
}
},
success: function(){
alert('Ajax Success ');
}
});
});
(i'm using a specific product_id and variation_id for testing) then i add the callback function in the themes function page to add the products to the cart :
function customAddToCart() {
ob_start();
try {
$product_id = apply_filters( 'woocommerce_add_to_cart_product_id', absint( $data['product_id'] ) );
$quantity = empty( $data['quantity'] ) ? 1 : wc_stock_amount( $data['quantity'] );
$variation_id = isset( $data['variation_id'] ) ? absint( $data['variation_id'] ) : '';
$variations = $variation_id ? (array) get_variation_data_from_variation_id( $variation_id ) : null;
$product_status = get_post_status( $product_id );
$passed_validation = apply_filters( 'woocommerce_add_to_cart_validation', true, $product_id, $quantity, $variation_id, $variations, $cart_item_data );
if ( $passed_validation && WC()->cart->add_to_cart( $product_id, $quantity, $variation_id, $variations ) && 'publish' === $product_status ) {
do_action( 'woocommerce_ajax_added_to_cart', $product_id );
$res = getCartFragments();
} else {
$res = array(
'error' => true
);
}
return $res;
} catch (Exception $e) {
return new WP_Error('add_to_cart_error', $e->getMessage(), array('status' => 500));
}
}
add_action( 'wp_ajax_nopriv_woocommerce_add_variation_to_cart', 'customAddToCart' );
all this seems to work fine because doesn't give any error in console but the problems is that the variation Size in not added with the product that is selected just add the product. I dont know why this is happening, i even add an alert in the ajax success function
alert('Ajax Success ');
and that alert is displayed but the data it seems is not been sending like it should.
i want to know what i'm missing in any of this codes or it could be the js file and his location or i need to send another value in the a> builded in the first function above. i have try a lot things but the behavior still the same.
A quick scan over your code and I've noticed that the action you are calling with ajax is not correct. It should be woocommerce_add_variation_to_cart not customAdd_to_cart. Also it is common practice to use wp_send_json (or the more specific wp_send_json_success and wp_send_json_error functions) at the end of your ajax callback function so that you get a readable and sensible response in jQuery. Check out the following link if you have not used it before:
https://codex.wordpress.org/Function_Reference/wp_send_json
Hope this helps.