Everytime I fire my custom action an success message "Order updated" is displayed.
Is there a way to hide this message after firing custom order action? For example if my action do not process?
function _custom_order_action_process( $order ) {
// some code
// some code
// some code
if ( ! $valid1 ) {
// Oooops...
return;
}
if ( ! $valid2 ) {
return;
}
//here we go...
}
add_action( 'woocommerce_order_action_custom_order_action','_custom_order_action_process' );
One thing you can do is change the message value.
we can use redirect_post_location for that.
function _custom_order_action_process( $order ) {
// some code
// some code
// some code
if ( ! $valid1 ) {
// Oooops...
add_filter( 'redirect_post_location', 'redirect_post_location', 99 );
}
if ( ! $valid2 ) {
add_filter( 'redirect_post_location', 'redirect_post_location', 99 );
}
//here we go...
}
add_action( 'woocommerce_order_action_custom_order_action','_custom_order_action_process' );
function redirect_post_location( $location ) {
remove_filter( 'redirect_post_location', __FUNCTION__, 99 ); // remove this filter so it will only work with your validations.
$location = add_query_arg('message', 99, $location); // 99 is empty message, it will not show. Or if by any chance it has a message, you change to higher number.
return $location;
}
Related
In WooCommerce, I have set different shipping methods, but one in particular must be exclusive for companies.
For this I am using the following code:
add_filter( 'woocommerce_package_rates', array( $this, 'package_rates' ), 10, 2 );
public function package_rates( $rates, $package ) {
$company_rate_id = 'flat_rate:7';
if(!empty(WC()->customer->get_billing_company())){
$company_rates = $rates[ $company_rate_id ];
$rates = array( $company_rate_id => $company_rates );
}else{
unset( $rates[ $company_rate_id ] );
}
return $rates;
}
The solution works, but only if the billing company already exist and is saved in the database. So if a customer updates this information on the checkout page, it doesn't work.
A possible solution would be to save this field live (billing_company).
I tried the following function:
add_filter( 'woocommerce_checkout_fields' , 'trigger_update_checkout_on_change' );
function trigger_update_checkout_on_change( $fields ) {
$fields['billing']['billing_company']['class'][] = 'update_totals_on_change';
return $fields;
}
This updates the shipping method, the problem is that again, the field is not saved in the database and the package_rates() function can not find it live.
This is a bit more complicated than that… jQuery and Ajax code are required to allow showing/hiding shipping methods based on a checkout field user input.
The following code will enable show/hide pre defined shipping methods based on checkout billing company field:
// Conditionally show/hide shipping methods
add_filter( 'woocommerce_package_rates', 'shipping_package_rates_filter_callback', 100, 2 );
function shipping_package_rates_filter_callback( $rates, $package ) {
// The defined rate id
$company_rate_id = 'flat_rate:7';
if( WC()->session->get('company' ) === '1' ) {
$rates = array( $company_rate_id => $rates[ $company_rate_id ] );
} else {
unset( $rates[ $company_rate_id ] );
}
return $rates;
}
// function that gets the Ajax data
add_action( 'wp_ajax_get_customer_company', 'wc_get_customer_company' );
add_action( 'wp_ajax_nopriv_get_customer_company', 'wc_get_customer_company' );
function wc_get_customer_company() {
if ( isset($_POST['company']) && ! empty($_POST['company']) ){
WC()->session->set('company', '1' );
} else {
WC()->session->set('company', '0' );
}
die(); // (required)
}
// The Jquery Ajax script
add_action( 'wp_footer', 'custom_checkout_script' );
function custom_checkout_script() {
if( WC()->session->__isset('company') )
WC()->session->__unset('company');
// Only on checkout when billing company is not defined
if( is_checkout() && ! is_wc_endpoint_url() ):
?>
<script type="text/javascript">
jQuery( function($){
if (typeof wc_checkout_params === 'undefined')
return false;
var fieldId = 'input#billing_company';
function companyTriggerAjax( company ){
$.ajax({
type: 'POST',
url: wc_checkout_params.ajax_url,
data: {
'action': 'get_customer_company',
'company': company,
},
success: function (result) {
// Trigger refresh checkout
$('body').trigger('update_checkout');
}
});
}
// On start
if( $(fieldId).val() != '' ) {
companyTriggerAjax( $(fieldId).val() );
}
// On change
$(fieldId).change( function () {
companyTriggerAjax( $(this).val() );
});
});
</script>
<?php
endif;
}
// Enabling, disabling and refreshing session shipping methods data
add_action( 'woocommerce_checkout_update_order_review', 'refresh_shipping_methods', 10, 1 );
function refresh_shipping_methods( $post_data ){
$bool = true;
if ( WC()->session->get('company' ) === '1' )
$bool = false;
// Mandatory to make it work with shipping methods
foreach ( WC()->cart->get_shipping_packages() as $package_key => $package ){
WC()->session->set( 'shipping_for_package_' . $package_key, $bool );
}
WC()->cart->calculate_shipping();
}
Code goes in function.php file of your active child theme (or active theme). Tested and works.
Related: Remove shipping cost if custom checkbox is checked in WooCommerce Checkout
Implemented the following solution https://stackoverflow.com/a/55174664/1759546 with success but, how could one apply the same logic in the order confirmation emails that are sent to the users? I'm trying to send just one of many accounts available, depending on meta data from order.
Thanks in advance
Ok, so I was being dumb.
We just have to pass a second argument to woocommerce_bacs_accounts which is the order_id. And as the filter runs inside the order_email it will apply the same rules.
add_filter( 'woocommerce_bacs_accounts', 'filter_woocommerce_bacs_accounts_callback', 10, 2 );
function filter_woocommerce_bacs_accounts_callback( $bacs_accounts, $order_id ){
if ( empty($bacs_accounts) ) {
return $bacs_accounts; // Exit
}
if( is_wc_endpoint_url('order-received') ) {
$endpoint = 'order-received';
// Get the WC_Order Object
$order = wc_get_order( get_query_var($endpoint) );
} elseif( is_wc_endpoint_url('view-order') ) {
$endpoint = 'view-order';
// Get the WC_Order Object
$order = wc_get_order( get_query_var($endpoint) );
} else if ($order_id){
// Get the WC_Order Object
$order = wc_get_order($order_id );
}
$sort_codes = []; // Initializing variable array
// Loop through order items
foreach ( $order->get_items() as $item ) {
$sort_codes[] = $item->get_meta("pa_sede");
}
if ( empty($sort_codes) ) {
return $bacs_accounts; // Exit
}
// Loop through Bacs accounts
foreach ( $bacs_accounts as $key => $bacs_account ) {
$bacs_account = (object) $bacs_account;
// Remove the non matching bank accounts
if ( ! in_array($bacs_account->sort_code, $sort_codes ) ) {
unset($bacs_accounts[$key]);
}
}
return $bacs_accounts;
}
In reference to this Remove selected checkout fields with woocommerce depending on shipping method
How can I adapt the codes in order remove different fields based on different shipping methods selected?
I've tried modifying the beginnging part to below, but it just stops working...
add_filter( 'woocommerce_checkout_fields', 'xa_remove_billing_checkout_fields' );
function xa_remove_billing_checkout_fields( $fields ) {
$chosen_methods = WC()->session->get( 'chosen_shipping_methods' );
// uncomment below line and reload checkout page to check current $chosen_methods
// print_r($chosen_methods);
$chosen_shipping = $chosen_methods[0];
if ($chosen_shipping == 'flat_rate:13') {
$shipping_method = 'flat_rate:13';
$hide_fields = array( 'billing_address_2', 'billing_city', 'billing_state', 'billing_postcode' );
}
if ($chosen_shipping =='flat_rate:7') {
$shipping_method = 'flat_rate:7';
$hide_fields = array( 'billing_city', 'billing_state', 'billing_postcode' );
}
foreach($hide_fields as $field ) {
if ($chosen_shipping == $shipping_method) {
$fields['billing'][$field]['required'] = false;
$fields['billing'][$field]['class'][] = 'hide';
}
$fields['billing'][$field]['class'][] = 'billing-dynamic';
}
return $fields;
}
The other part looks like this, which I copied and modified from another answer
add_action( 'wp_footer', 'cart_update_script', 999 );
function cart_update_script() {
if (is_checkout()) :
?>
<style>
.hide {display: none!important;}
</style>
<script>
jQuery( function( $ ) {
// woocommerce_params is required to continue, ensure the object exists
if ( typeof woocommerce_params === 'undefined' ) {
return false;
}
var show = ['flar_rate:7', 'flat_rate:13'];
$(document).on( 'change', '#shipping_method input[type="radio"]', function() {
// console.log($.inArray($(this).val(), show));
if ($.inArray($(this).val(), show) > -1) { // >-1 if found in array
$('.billing-dynamic').removeClass('hide');
// console.log('show');
} else {
$('.billing-dynamic').addClass('hide');
// console.log('hide');
}
});
});
</script>
<?php
endif;
}
Also, if I change the country, which changes also the shipping zone, the fields ain't reverted until I select the shipping method again.
Thanks in advance.
Need to add blank and already exist validation for 'supports' => array( 'title') on my custom post type. But i dont want to use any plugin for this.
Thanks in advance.
add_action( 'admin_notices', 'custom_error_notice' );
function custom_error_notice(){
global $current_screen, $post;
if ( $current_screen->parent_base == 'edit' ){
if((!$post->post_name) && $_GET['post']) {
wp_redirect(admin_url('post-new.php?empty=1'));
}
if($_GET['empty']) echo '<div class="error"><p>Warning - Please fill up all fields correctly!</p></div>';
}
}
But this not working properly.
This may help you:-
add_action('save_post', 'album_save_post', 10, 2);
function album_save_post( $album_id, $album ) {
if( defined('DOING_AUTOSAVE') && DOING_AUTOSAVE || $album->post_type != 'music_album') return;
// echo '<pre>';
// print_r($album);
// echo '</pre>';
// die();
$errors = array();
// Validation filters
$title = $album->post_title;
if ( ! $title ) {
$errors['title'] = "The title is required";
}
// if we have errors lets setup some messages
if (! empty($errors)) {
// we must remove this action or it will loop for ever
remove_action('save_post', 'album_save_post');
// save the errors as option
update_option('album_errors', $errors);
// Change post from published to draft
$album->post_status = 'draft';
// update the post
wp_update_post( $album );
// we must add back this action
add_action('save_post', 'album_save_post');
// admin_notice is create by a $_GET['message'] with a number that wordpress uses to
// display the admin message so we will add a filter for replacing default admin message with a redirect
add_filter( 'redirect_post_location', 'album_post_redirect_filter' );
}
}
function album_post_redirect_filter( $location ) {
// remove $_GET['message']
$location = remove_query_arg( 'message', $location );
// add our new query sting
$location = add_query_arg( 'album', 'error', $location );
// return the location query string
return $location;
}
// Add new admin message
add_action( 'admin_notices', 'album_post_error_admin_message' );
function album_post_error_admin_message() {
if ( isset( $_GET['album'] ) && $_GET['album'] == 'error' ) {
// lets get the errors from the option album_errors
$errors = get_option('album_errors');
// now delete the option album errors
delete_option('album_errors');
$display = '<div id="notice" class="error"><ul>';
// Because we are storing as an array we should loop through them
foreach ( $errors as $error ) {
$display .= '<li>' . $error . '</li>';
}
$display .= '</ul></div>';
// finally echo out our display
echo $display;
// add some jQuery
?>
<script>
jQuery(function($) {
$("#title").css({"border": "1px solid red"})
});
</script>
<?php
}
}
i got the solution.
/** ADD Validation for title */
function force_post_title_init()
{
wp_enqueue_script('jquery');
}
function force_post_title()
{
echo "<script type='text/javascript'>\n";
echo "
jQuery('#publish').click(function(){
var testervar = jQuery('[id^=\"titlediv\"]')
.find('#title');
if (testervar.val().length < 1)
{
jQuery('[id^=\"titlediv\"]').css('border', '1px solid red');
alert('Post title is required');
return false;
}
});
";
echo "</script>\n";
}
add_action('admin_init', 'force_post_title_init');
add_action('edit_form_advanced', 'force_post_title');
// Add this row below to get the same functionality for page creations.
add_action('edit_page_form', 'force_post_title');
May be this also help for all of you.
I need to abort the post saving process when the post content contains a specific string and then display a message to the user.
I found a method to display the message but didn't find a way to refuse post saving.
So far here's what i've done
add_action( "pre_post_update", "checkPost");
function checkPost($post_ID) {
$post = get_post($post_ID);
$postContent = $post->post_content;
if ( wp_is_post_revision( $post_ID ) )
return;
if(preg_match("/bad string/", $postContent) == 1) {
//
// cancel post save
//
// then
add_filter("redirect_post_location", "my_redirect_post_location_filter", 99);
}
}
function my_redirect_post_location_filter($location) {
remove_filter('redirect_post_location', __FUNCTION__, 99);
$location = add_query_arg('message', 99, $location);
return $location;
}
add_filter('post_updated_messages', 'my_post_updated_messages_filter');
function my_post_updated_messages_filter($messages) {
$messages['post'][99] = 'Publish not allowed';
return $messages;
}
Hope this helps you to check post content
function to_err_is_human( $post_id ) {
// If this is just a revision, don't check
if ( wp_is_post_revision( $post_id ) )
return;
$post_content = wp_unslash(!empty($_REQUEST['content']) ? $_REQUEST['content'] : $post_data['content']);
if ($post_content=="abc")
{ add_filter("redirect_post_location", "my_redirect_post_location_filter", 99);}
}
add_action( 'save_post', 'to_err_is_human' );
function my_redirect_post_location_filter($location) {
remove_filter('redirect_post_location', __FUNCTION__, 99);
$location = add_query_arg('message', 99, $location);
return $location;
}
add_filter('post_updated_messages', 'my_post_updated_messages_filter');
function my_post_updated_messages_filter($messages) {
$messages['post'][99] = 'Publish not allowed';
return $messages;
}