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.
Related
First of all, I have no idea how old and / or deprecated (that's the word right?) this code is. My old developer (passed away) gave it to me well over two years ago, and now I am trying to make sense of it all.
Not being a programmer, I need help with two things, whereof the second part is the most important. When ALL products are removed from the checkout, redirect to the shop page.
This is the code I am using for adding qty and what not to the checkout.
add_filter( 'woocommerce_cart_item_name', 'jess_product_thumbnail_on_checkout_order_review', 20, 3 );
function jess_product_thumbnail_on_checkout_order_review( $product_name, $cart_item, $cart_item_key ) {
if ( is_checkout() ) {
$product = $cart_item['data'];
$thumbnail = $product->get_image(array(50, 50));
$image_html = '<div class="product-item-thumbnail">' . $thumbnail . '</div>';
$product_name_link = '' . $product_name . '';
$product_name = $image_html . $product_name_link;
}
return $product_name;
}
add_action( 'wp_footer', 'jess_product_image_css_checkout', 900 );
function jess_product_image_css_checkout(){
if (is_checkout()){ ?>
<style>
.product-item-thumbnail{float:left; padding-right:20px;}
.product-item-thumbnail img{margin:0!important;}
</style>
<?php
}}
add_filter('woocommerce_checkout_cart_item_quantity', 'jess_qty_change_remove_item_checkout_order_review', 1000, 3);
function jess_qty_change_remove_item_checkout_order_review( $quantity_html, $cart_item, $cart_item_key ) {
$_product = $cart_item['data'];
if ($_product->is_sold_individually()){
$product_quantity = sprintf('<input type="hidden" name="cart[%s][qty]" value="" />', $cart_item_key);
}else{
$product_quantity = woocommerce_quantity_input(
array(
'input_name' => "cart[{$cart_item_key}][qty]",
'input_value' => $cart_item['quantity'],
'max_value' => $_product->get_max_purchase_quantity(),
'min_value' => '1',
'class' => 'qtyinput',
'placeholder' => 'Qty',
'product_name' => $_product->get_name(),
),
$_product,
false
);
}
$cart = WC()->cart->get_cart();
foreach ($cart as $cart_key => $cart_value){
if ($cart_key == $cart_item_key){
$product_id = $cart_item['product_id'];
$_product = $cart_item['data'] ;
$remove_product = sprintf(
'Remove',
esc_url(wc_get_cart_remove_url($cart_key)),
__( 'Remove From My Order', 'woocommerce' ),
esc_attr( $product_id ),
esc_attr( $_product->get_sku() ),
esc_attr( $cart_item_key )
);
}}
return '<br><span class="product-quantity">' . sprintf( 'Qty: %s', $cart_item['quantity'] ) . ' / ' . $remove_product . '</span>'.$product_quantity.'';
}
add_action( 'wp_footer', 'refresh_checkout_on_quantity_change' );
function refresh_checkout_on_quantity_change() {
if (is_checkout()){ ?>
<script type="text/javascript">
<?php $admin_url = get_admin_url(); ?>
jQuery("form.checkout").on("change", "input.qty", function(){
var data = {
action: 'update_order_qty',
security: wc_checkout_params.update_order_review_nonce,
post_data: jQuery('form.checkout').serialize()
};
jQuery.post('<?php echo $admin_url; ?>' + 'admin-ajax.php', data, function(response){
jQuery('body').trigger('update_checkout');
});
});
</script>
<?php
}}
add_action( 'init', 'jess_load_ajax_checkout_qty_and_removal' );
function jess_load_ajax_checkout_qty_and_removal(){
if (!is_user_logged_in()){
add_action( 'wp_ajax_nopriv_update_order_qty', 'update_order_qty');
}else{
add_action( 'wp_ajax_update_order_qty', 'update_order_qty');
}}
function update_order_qty(){
$values = array();
parse_str($_POST['post_data'], $values);
$cart = $values['cart'];
foreach ($cart as $cart_key => $cart_value){
WC()->cart->set_quantity( $cart_key, $cart_value['qty'], false );
WC()->cart->calculate_totals();
woocommerce_cart_totals();
}
exit;
}
add_action( 'wp_footer', 'jess_remove_product_from_checkout_script' );
function jess_remove_product_from_checkout_script() { ?>
<script>
jQuery( function($){
if (typeof woocommerce_params === 'undefined')
return false;
console.log('defined');
$(document).on('click', 'tr.cart_item a.remove-product', function (e){
e.preventDefault();
var product_id = $(this).attr("data-product_id"),
cart_item_key = $(this).attr("data-cart_item_key"),
product_container = $(this).parents('.shop_table');
product_container.block({
message: null,
overlayCSS: {
cursor: 'none'
}
});
$.ajax({
type: 'POST',
dataType: 'json',
url: wc_checkout_params.ajax_url,
data: {
action: "product_remove",
product_id: product_id,
cart_item_key: cart_item_key
},
success: function (result) {
$('body').trigger('update_checkout');
console.log(result);
}
});
});
});
</script>
<?php
}
add_action('wp_ajax_product_remove', 'ajax_product_remove');
add_action('wp_ajax_nopriv_product_remove', 'ajax_product_remove');
function ajax_product_remove(){
ob_start();
foreach (WC()->cart->get_cart() as $cart_item_key => $cart_item) {
if($cart_item['product_id'] == $_POST['product_id'] && $cart_item_key == $_POST['cart_item_key'] ) {
WC()->cart->remove_cart_item($cart_item_key);
}
}
WC()->cart->calculate_totals();
WC()->cart->maybe_set_cart_cookies();
woocommerce_order_review();
$woocommerce_order_review = ob_get_clean();
}
Here is the modified code. I have added some comments where what is changed. This is tested on storefront theme and works.
//We need to load cart scripts
function checkout_woocommerce_scripts()
{
if ( is_checkout() ) wp_enqueue_script( 'wc-cart' );
}
add_action( 'wp_enqueue_scripts', 'checkout_woocommerce_scripts', 10 );
//When we remove all products from checkout will redirect to cart so we redirect to shop instead
//This also will work if we are on cart page and remove all products
add_action('template_redirect','redirect_cart_page');
function redirect_cart_page() {
if(is_cart() && WC()->cart->get_cart_contents_count() == 0 ):
wp_safe_redirect(wc_get_page_permalink( 'shop' ));
endif;
}
add_filter( 'woocommerce_cart_item_name', 'jess_product_thumbnail_on_checkout_order_review', 20, 3 );
function jess_product_thumbnail_on_checkout_order_review( $product_name, $cart_item, $cart_item_key ) {
if ( is_checkout() ) {
$product = $cart_item['data'];
$thumbnail = $product->get_image(array(50, 50));
$image_html = '<div class="product-item-thumbnail">' . $thumbnail . '</div>';
$product_name_link = '' . $product_name . '';
$product_name = $image_html . $product_name_link;
}
return $product_name;
}
add_action( 'wp_footer', 'jess_product_image_css_checkout', 900 );
function jess_product_image_css_checkout(){
if (is_checkout()){ ?>
<style>
.product-item-thumbnail{float:left; padding-right:20px;}
.product-item-thumbnail img{margin:0!important;}
</style>
<?php
}
}
//In this function all i did change is the class of the remove button from remove-product to product-remove
add_filter('woocommerce_checkout_cart_item_quantity', 'jess_qty_change_remove_item_checkout_order_review', 1000, 3);
function jess_qty_change_remove_item_checkout_order_review( $quantity_html, $cart_item, $cart_item_key ) {
$_product = $cart_item['data'];
if ($_product->is_sold_individually()){
$product_quantity = sprintf('<input type="hidden" name="cart[%s][qty]" value="" />', $cart_item_key);
}else{
$product_quantity = woocommerce_quantity_input(
array(
'input_name' => "cart[{$cart_item_key}][qty]",
'input_value' => $cart_item['quantity'],
'max_value' => $_product->get_max_purchase_quantity(),
'min_value' => '1',
'class' => 'qtyinput',
'placeholder' => 'Qty',
'product_name' => $_product->get_name(),
),
$_product,
false
);
}
$cart = WC()->cart->get_cart();
foreach ($cart as $cart_key => $cart_value){
if ($cart_key == $cart_item_key){
$product_id = $cart_item['product_id'];
$_product = $cart_item['data'] ;
$remove_product = sprintf(
'Remove',
esc_url(wc_get_cart_remove_url($cart_key)),
__( 'Remove From My Order', 'woocommerce' ),
esc_attr( $product_id ),
esc_attr( $_product->get_sku() ),
esc_attr( $cart_item_key )
);
}
}
return '<br><span class="product-quantity">' . sprintf( 'Qty: %s', $cart_item['quantity'] ) . ' / ' . $remove_product . '</span>'.$product_quantity.'';
}
// I have added wc_fragment_refresh to update your minicart when qty change.
add_action( 'wp_footer', 'refresh_checkout_on_quantity_change' );
function refresh_checkout_on_quantity_change() {
if (is_checkout()){ ?>
<script type="text/javascript">
<?php $admin_url = get_admin_url(); ?>
jQuery("form.checkout").on("change", "input.qty", function(){
var data = {
action: 'update_order_qty',
security: wc_checkout_params.update_order_review_nonce,
post_data: jQuery('form.checkout').serialize()
};
jQuery.post('<?php echo $admin_url; ?>' + 'admin-ajax.php', data, function(response){
jQuery('body').trigger( 'wc_fragment_refresh' );
jQuery('body').trigger('update_checkout');
});
});
</script>
<?php
}
}
// You dont need to wrap this in a function and do checks wp_ajax_nopriv runs for guests where wp_ajax runs for users
add_action( 'wp_ajax_nopriv_update_order_qty', 'update_order_qty');
add_action( 'wp_ajax_update_order_qty', 'update_order_qty');
function update_order_qty(){
$values = array();
parse_str($_POST['post_data'], $values);
$cart = $values['cart'];
foreach ($cart as $cart_key => $cart_value){
WC()->cart->set_quantity( $cart_key, $cart_value['qty'], false );
WC()->cart->calculate_totals();
woocommerce_cart_totals();
}
exit;
}
This is i think the better solution when we want to update cart items in checkout. Its all woocommerce core so it will perform and last longer than custom code for people who are not into coding.
Here is a video how its working https://webm.red/iV0t . It may get deleted after time.
//We need to load cart scripts
function checkout_woocommerce_scripts()
{
if ( is_checkout() ) wp_enqueue_script( 'wc-cart' );
}
add_action( 'wp_enqueue_scripts', 'checkout_woocommerce_scripts', 10 );
//If we want to redirect to shop page when cart or checkout get empty.
add_action('template_redirect','redirect_cart_page');
function redirect_cart_page() {
if(is_cart() && WC()->cart->get_cart_contents_count() == 0 ):
wp_safe_redirect(wc_get_page_permalink( 'shop' ));
endif;
}
//Load the cart form provided by woocommerce as shortcode.
// I will keep it outside the checkout form since its a form on its self.
// If we want we can extend the layout with modifying the checkout template.
add_action('woocommerce_before_checkout_form','checkout_cart_form');
function checkout_cart_form() {
echo do_shortcode('[woocommerce_cart]');
}
//Since we load cart form we dont need the coupon form twice
//Remove checkout coupon form comment this if you want to use this instead
remove_action( 'woocommerce_before_checkout_form', 'woocommerce_checkout_coupon_form', 10 );
//Remove cart coupon form
function hide_coupon_field_on_cart( $enabled ) {
if ( is_cart() ) { $enabled = false; } return $enabled;
}
//Uncomment this if you want to use this coupon form
// add_filter( 'woocommerce_coupons_enabled', 'hide_coupon_field_on_cart' );
//The scripts and styles we gonna use. Feel free to move them in your theme css js files (make sure they are loaded on checkout page)
add_action( 'wp_footer', 'checkout_styles_scripts');
function checkout_styles_scripts() {
?>
<style>
body.woocommerce-checkout button[name="update_cart"],
body.woocommerce-checkout input[name="update_cart"] {
display: none;
}
</style>
<script>
jQuery( function( $ ) {
let timeout;
$('.woocommerce').on( 'change keyup mouseup', 'input.qty', function(){
if ( timeout !== undefined ) {
clearTimeout( timeout );
}
timeout = setTimeout(function() {
$("[name='update_cart']").trigger("click"); // trigger cart update
}, 1000 ); // 1 second delay, half a second (500) seems comfortable too
});
} );
</script>
<?php
}
I modified this script to make a shortcode that shows how much the customer need to spend to get free shipping.
/**
* #author Rodolfo Melogli
* #compatible WooCommerce 3.9
* #donate $9 https://businessbloomer.com/bloomer-armada/
*/
add_shortcode ('woo_freeshipping_target', 'woo_freeship_target' );
function woo_freeship_target() {
ob_start();
$min_amount = 279; //change this to your free shipping threshold
$current = WC()->cart->subtotal;
if ( $current < $min_amount ) {
$added_text = wc_price( $min_amount - $current );
$notice = sprintf( $added_text );
echo '<span> You need to add '.$notice.'</span>';
}
else if ( $current >= $min_amount ) {
echo '<span>Free Shipping!</span>';
}
return ob_get_clean();
}
But I cannot figure out how can I make it to auto update when the items quantity is modified. Any idea?
To ajaxify your message so it updates when the subtotal change (via ajax) use the woocommerce_add_to_cart_fragments filter hook
So you get:
function custom_message() {
// Initialize
$message = __( 'Default message', 'woocommerce' );
// True
if ( WC()->cart ) {
// Change this to your free shipping threshold
$min_amount = 279;
// Get cart subtotal
$subtotal = WC()->cart->get_subtotal();
if ( $subtotal < $min_amount ) {
$message = sprintf( __( 'You need to add %s to get free shipping', 'woocommerce' ), wc_price( $min_amount - $subtotal ) );
} else {
$message = __( 'Free shipping', 'woocommerce' );
}
}
return $message;
}
// Refreshing on cart ajax events
function filter_woocommerce_add_to_cart_fragments( $fragments ) {
$fragments['div.display-message'] = '<div class="display-message">' . custom_message() . '</div>';
return $fragments;
}
add_filter( 'woocommerce_add_to_cart_fragments', 'filter_woocommerce_add_to_cart_fragments', 10, 1 );
// Shortcode
function display_my_message() {
return '<div class="display-message">' . custom_message() . '</div>';
}
// Register shortcode
add_shortcode( 'display_message', 'display_my_message' );
SHORTCODE USAGE
In an existing page:
[display_message]
Or in PHP:
echo do_shortcode("[display_message]");
Related: WooCommerce shortcode to ajaxify message that display: "Buy X more products to get a discount"
I am trying to add product ID as a suffix in the product title for example:
iPhoneX - 123 (where 123 is the ID)
The reason why I need this is something related to the payment gateway I am dealing with. hence, this solution only needs to be applied where it is necessary for the payment gateway to recognize that ID during checkout.
The following code shows product ID as a suffix on checkout the way I wanted. however, When placing the order and redirecting to the third-party payment gateway page; the ID does not show there. I want the third-party payment gateway to display it as well.
add_filter('the_title', 'change_woocommerce_single_title', 1, 2);
function change_woocommerce_single_title($title, $id) {
if ( class_exists( 'woocommerce' ) && is_checkout())
$title = $title . ' - ' . $id;
return $title;
}
Try this:
// For shop
function change_woocommerce_single_title($title, $id) {
if ( in_array( get_post_type( $id ), array( 'product', 'product_variation') ) || is_product() )
$title = $title . ' - ' . $id;
return $title;
}
add_filter('the_title', 'change_woocommerce_single_title', 1, 2);
// For cart
function filter_woocommerce_cart_item_name( $item_name, $cart_item, $cart_item_key ) {
if( $cart_item['variation_id'] )
$id = absint( $cart_item['variation_id'] );
else
$id = absint( $cart_item['product_id'] );
$item_name = $item_name . ' - ' . $id;
return $item_name;
};
add_filter('woocommerce_cart_item_name', 'filter_woocommerce_cart_item_name', 10, 3);
You can create your own function to handle the product title. Put this code to function.php of your child theme:
add_filter('the_title', 'change_woocommerce_single_title', 1, 2);
function change_woocommerce_single_title($title, $id) {
if ( class_exists( 'woocommerce' ) && is_product())
$title = $title . ' - ' . $id;
return $title;
}
I've made a form with two select fields. The first field is populated with the parents of a custom taxonomy. The second field is populated with the children of each one. I used AJAX to do that but does not seem to work. Nothing happens on change.
Below is my PHP code:
function products_selection()
{
$args = array(
'post_type' => 'seller',
'taxonomy' => 'category',
'hide_empty' => 0,
'exclude' => 1,1078,1079
);
$products = get_categories( $args );
if ( $products ) {
echo '<select id="products-select">';
echo '<option selected="" disabled="" value="0"><span>Προϊόντα</span></option>';
foreach ($products as $product) {
echo '<option class="product-name" id="'. $product->term_id .'">'. $product->name .'</option>';
}
echo '</select>';
}
}
function nomoi()
{
$args = array(
'post_type' => 'seller',
'taxonomy' => 'nomos',
'hide_empty'=> 0,
'parent' => 0
);
$categories = get_categories( $args );
if ( $categories ) {
echo '<select id="nomoi-select">';
echo '<option selected="0" value="-1"><span>Νομοί</span></option>';
foreach ( $categories as $category ) {
$id = $category->term_id;
$name = $category->name;
$taxonomy = $category->taxonomy;
echo '<option class="nomos" id="'. $id .'">'. $name .'</option>';
}
echo '</select>';
}
echo '<select id="town-select">';
echo '<option selected="" disabled="" value="0"><span>Πόλεις</span></option>';
echo '</select>';
}
function my_ajax() {
if(isset($_POST['main_catid']))
{
$args = array(
'order_by' => 'name',
'hide_empty' => 0,
'exclude' => 1,
'taxonomy' => 'nomos',
'name' => 'town-select',
'hierarchical' => 1,
'show_option_none' => 'Πόλεις',
'selected' => -1,
'child_of' => $_POST['main_catid'],
'echo' => 1
);
$categories = get_categories( $args );
foreach ( $categories as $cat ) {
$cat_name = $cat->name;
$id = $cat->cat_ID;
echo '<option class="town" id="'. $category->id .'">'. $category->name .'</option>';
}
die();
} // end if
}
My script:
jQuery(document).ready(function() {
// Avoid conflicts
$ = jQuery;
$('#nomoi-select').change(function() {
$mainCat = $('#nomoi-select option:selected').attr('id');
console.log('$mainCat: ' + $mainCat);
// call ajax
$("#town-select").empty();
$.ajax
(
{
url:'index.php',
type:'POST',
// Use an object literal
data: {
"action" : "my_ajax()",
"main_catid" : $mainCat
},
success:function( results )
{
// alert(results);
alert('Successfully called');
$("#town-select").append( results );
},
error:function( exception )
{
alert('Exception: ' + exception);
}
}
);
});
});
And the function to register my script:
function my_scripts() {
wp_enqueue_script( 'header-form', get_template_directory_uri() . '/js/headerform.js', array(), '1.0.0', true );
}
add_action( 'wp_enqueue_scripts', 'my_scripts' );
Since you are working with WordPress, I suspect you could be having jQuery conflict issues. To confirm this, you can try changing all instances of $ to jQuery and see if you get the same errors.
Also - if you are running this script from a .js file, the PHP wont evaluate, but keeping the URL relative should still work fine.
I have made a few changes to the script which you can try:
jQuery(document).ready(function() {
// Avoid conflicts
$ = jQuery;
$('#main_cat').change(function() {
$mainCat = $('#main_cat option:selected').val();
// call ajax
$("#sub_cat").empty();
$.ajax
(
{
url:"/wp-admin/admin-ajax.php",
type:'POST',
// Use an object literal
data: {
"action" : "my_ajax",
"main_catid" : $mainCat
},
success:function( results )
{
// alert(results);
$("#sub_cat").removeAttr("disabled").append( results );
}
}
);
});
});
From the fiddle you provided, simply adding console.log('$mainCat: ' + $mainCat); (see this modified fiddle) ensures that the change event fires as expected.
Beyond that we get a 404 not found error, which is pretty normal in the current state of the fiddle example.
So it is certain that your issue comes from something with the Ajax called script or its returned data.
You only said that "Nothing happens on change", without any precision. In fact you should now use Firebug or similar to look at error messages, which may be, either:
an URL generation error: in this case you should get a 404 not found error too
an error in the server script you're invoking: in this case you should get a 500 server error error
a bad (malformed) return from the server: in this case you should get a JS error
Also note that:
it cannot be an empty return from the server, or your #sub_cat element would have already lost its disabled attribute before a JS error happens
at the opposite (even if unlikely) it also might be an Ajax error: so to be sure you should add an error: or always: member to the $.ajax() argument
Firstly, I know this is 'bad' practice for several different reasons, but for reasons that I won't waste your time with it's something I need to do.
Using a fairly simple plugin and I've tried copying it into functions.php and updating the file paths and dependences, but I'm having some trouble.
Plugin.php file looks like this:-
$plugin_headers = get_file_data( __FILE__, array( 'Version' => 'Version', 'Name' => 'Plugin Name' ) );
/**
* We store our plugin data in the following global array.
* $my_unique_name with your unique name
*/
global $my_unique_name;
$my_unique_name = array();
$my_unique_name['version_key'] = strtolower( str_replace( ' ', '_', $plugin_headers['Name'] ) ) . '_version';
$my_unique_name['version_value'] = $plugin_headers['Version'];
/**
* When the user activates the plugin we add the version number to the
* options table as "my_plugin_name_version" only if this is a newer version.
*/
function inline_comments_acitvation(){
global $my_unique_name;
if ( get_option( $my_unique_name['version_key'] ) && get_option( $my_unique_name['version_key'] ) > $my_unique_name['version_value'] )
return;
update_option( $my_unique_name['version_key'], $my_unique_name['version_value'] );
}
register_activation_hook( __FILE__, 'inline_comments_acitvation' );
/**
* Delete our version number from the database when the plugin is activated.
*/
function inline_comments_deactivate(){
global $my_unique_name;
delete_option( $my_unique_name['version_key'] );
}
register_deactivation_hook( __FILE__, 'inline_comments_deactivate' );
if ( is_admin() )
require_once plugin_dir_path( __FILE__ ) . 'admin/admin-tags.php';
/**
* Theme only functions
*/
require_once plugin_dir_path( __FILE__ ) . 'inc/template-tags.php';
function inline_comments_enqueue_scripts(){
$plugin_headers = get_file_data( __FILE__, array( 'Version' => 'Version', 'Name' => 'Original Plugin Name' ) );
$clean_name = strtolower( str_replace( ' ', '-', $plugin_headers['Name'] ) );
wp_register_style( $clean_name . '-style', plugin_dir_url( __FILE__ ) . 'inc/css/style.css' );
wp_register_script( 'textarea_auto_expand-script', plugin_dir_url( __FILE__ ) . 'vendor/textarea-auto-expand/jquery.textarea_auto_expand.js' );
wp_register_script( $clean_name . '-script', plugin_dir_url( __FILE__ ) . 'inc/js/script.js', array('jquery', 'textarea_auto_expand-script') );
}
add_action('wp_enqueue_scripts', 'inline_comments_enqueue_scripts', 2);
After moving the plugin to the theme folder I've done the following: I've removed the pointless parts and in my functions.php I'm loading the main script.js (it loads) and the css, like so(ie. changed the structure and moved the scripts into relevant folders).
function inline_comments_enqueue_scripts(){
if ( is_singular() || is_page() ) {
wp_enqueue_style( 'inline-style', get_template_directory_uri() . '/css/inline-style.css', '10000', 'all' );
wp_enqueue_script( 'inline-script', get_template_directory_uri() . '/js/inline-script.js', array( 'jquery' ), MEDIUM_VERSION);
}
}
add_action('wp_enqueue_scripts', 'inline_comments_enqueue_scripts', 2);
Ok so this loads the scripts just fine.
The plugin's main template file with the functions and ajax calls is in template-tags.php, but I can't figure out how to get this to load up correctly.
require_once plugin_dir_path( __FILE__ ) . 'inc/template-tags.php';
I've tried copy/pasting this into functions.php and it doesn't seem to work either.
The template-tags.php:
<?php
/**
* #todo Ajax crawling support -- https://developers.google.com/webmasters/ajax-crawling/docs/getting-started
* #todo https://developers.google.com/webmasters/ajax-crawling/
*/
/**
* Perform the following actions/filters when plugins are loaded
*
* #since 0.1-alpha
*/
function inline_comments_loaded(){
add_action( 'wp_ajax_inline_comments_add_comment', 'inline_comments_add_comment' );
add_action( 'wp_ajax_nopriv_inline_comments_add_comment', 'inline_comments_add_comment' );
add_action( 'wp_ajax_nopriv_inline_comments_load_template', 'inline_comments_load_template' );
add_action( 'wp_ajax_inline_comments_load_template', 'inline_comments_load_template' );
add_filter( 'template_redirect', 'inline_comments_template_redirect' );
}
add_action('plugins_loaded', 'inline_comments_loaded');
/**
* Load our JavaScript and Stylesheet on single page only
*
* #since 0.1-alpha
*/
function inline_comments_template_redirect() {
if ( is_singular() || is_page() ) {
add_action( 'wp_enqueue_scripts', 'inline_comments_scripts');
add_action( 'wp_head', 'inline_comments_head');
}
}
/**
* Load our JavaScript and Stylesheet, we include the login-register script only if it is installed.
*
* #uses wp_enqueue_script()
* #uses wp_enqueue_style()
*
* #since 0.1-alpha
*/
function inline_comments_scripts(){
wp_enqueue_script( 'inline-ajax-comments-script' );
wp_enqueue_style( 'inline-ajax-comments-style' );
}
/**
* Print our AJAX URL
*
* #since 0.1-alpha
*/
function inline_comments_head(){
print '<script type="text/javascript"> var ajaxurl = "'. admin_url("admin-ajax.php") .'";</script>';
print '<style type="text/css">'.get_option('additional_styling').'</style>';
}
/**
* Inserts a comment for the current post if the user is logged in.
*
* #since 0.1-alpha
* #uses check_ajax_referer()
* #uses is_user_logged_in()
* #uses wp_insert_comment()
* #uses wp_get_current_user()
* #uses current_time()
* #uses wp_kses()
* #uses get_option()
*/
function inline_comments_add_comment(){
check_ajax_referer('inline_comments_nonce', 'security');
$comment = trim(
wp_kses( $_POST['comment'],
array(
'a' => array(
'href' => array(),
'title' => array()
),
'br' => array(),
'em' => array(),
'strong' => array(),
'blockquote' => array(),
'code' => array()
)
)
);
if ( empty( $comment ) ) die();
if ( get_option('comment_registration') == 1 && ! is_user_logged_in() ) die();
$data = array(
'comment_post_ID' => (int)$_POST['post_id'],
'comment_content' => $comment,
'comment_type' => '',
'comment_parent' => 0,
'comment_author_IP' => $_SERVER['REMOTE_ADDR'],
'comment_agent' => $_SERVER['HTTP_USER_AGENT'],
'comment_date' => current_time('mysql'),
'comment_approved' => 1
);
if ( is_user_logged_in() ){
$current_user = wp_get_current_user();
$author_email = $current_user->user_email;
$author_url = $current_user->user_url;
$author_name = $current_user->user_nicename;
$data['user_id'] = $current_user->ID;
} else {
$author_email = empty( $_POST['user_email'] ) ? null : esc_attr( $_POST['user_email'] );
$author_url = empty( $_POST['user_url'] ) ? null : esc_url( $_POST['user_url'], array('http','https') );
$author_name = empty( $_POST['user_name'] ) ? null : esc_attr( $_POST['user_name'] );
}
$data['comment_author'] = $author_name;
$data['comment_author_email'] = $author_email;
$data['comment_author_url'] = $author_url;
// ck - catch the new comment id for updating comment meta
$comment_id = wp_insert_comment( $data );
// ck - now add the para-id to the comment meta
add_comment_meta( $comment_id, 'para_id' , $_POST['para_id'] );
die();
}
/**
* Load comments and comment form
*
* #since 0.1-alpha
*/
function inline_comments_load_template(){
check_ajax_referer('inline_comments_nonce', 'security');
$comments = get_comments( array(
'post_id' => (int)$_POST['post_id'],
'number' => 100,
'status' => 'approve',
'order' => 'ASC'
) );
?>
<div class="inline-comments-container" id="comments_target">
<?php if ( $comments ) : foreach( $comments as $comment) : ?>
<?php
// ck get the paragraph id from the comment meta
$para_id = get_comment_meta( $comment->comment_ID, 'para_id', true );
$user = new WP_User( $comment->user_id );
$class = null;
if ( ! empty( $user->roles ) && is_array( $user->roles ) ) {
foreach ( $user->roles as $role ){
$class = $role;
}
} else {
$class = 'annon';
}
// ck -added data-comment-para-id to div
?>
<div class="orphan-comment comment-para-id-<?php echo $para_id ?> inline-comments-content inline-comments-<?php echo $class; ?>" id="comment-<?php echo $comment->comment_ID; ?>">
<div class="inline-comments-p">
<?php inline_comments_profile_pic( $comment->comment_author_email ); ?>
<?php print $comment->comment_content; ?><br />
<time class="meta">
<strong><?php $user = get_user_by('login', $comment->comment_author ); if ( ! empty( $user->user_url ) ) : ?><?php print $comment->comment_author; ?><?php else : ?><?php print $comment->comment_author; ?><?php endif; ?></strong>
<?php print human_time_diff( strtotime( $comment->comment_date ), current_time('timestamp') ); ?> ago.
</time>
</div>
</div>
<?php endforeach; endif; ?>
</div>
<?php die();
}
/**
* Determine the profile pic for a user, either the FB pic or
* the gravatar pic. If no ID is passed uses the current logged
* in user.
*
* #uses get_user_meta()
* #uses get_avatar();
*/
function inline_comments_profile_pic( $id_or_email=null, $email=null ){
if ( is_null( $id_or_email ) ) {
global $current_user;
get_currentuserinfo();
$id_or_email = $current_user->ID;
}
$html = get_avatar( $id_or_email, 32 );
print '<span class="inline-comments-profile-pic-container">' . $html . '</span>';
}
function inline_comments_tempalte( $file ){
return plugin_dir_path( dirname( __FILE__ ) ) . 'templates/comments.php';
}
add_filter('comments_template', 'inline_comments_tempalte');
I notice that you've moved the /css and /js directories out of /inc where they seem to have been originally.
So try:
require_once plugin_dir_path( __FILE__ ) . 'template-tags.php';