Remove action 'woocommerce_email_before_order_table' not working - wordpress

I am trying to remove the "Our bank information" and payment instructions from Woocommerce BACS gateway thankyou page and emails.
I know it should be done simply by removing the woocommerce_thankyou_bacs and woocommerce_email_before_order_table action.
I managed to remove the message from thankyou page, but it still appears in the emails. I checked, woocommerce_thankyou_bacs and woocommerce_email_before_order_table are both removed from wp_filter global.
I am relying on a function i copied from here: http://wpquestions.com/question/showChrono/id/9204 due to having similar problem of remove_action not working due to different unique id, and it works, in a way that the actions are gone from wp_filter global.
I have tried all kind of priorities, 0-20, the thankyou page message is gone but email still shows the payment instructions.
My code is as follows:
add_action( 'woocommerce_thankyou_bacs', function() {
if( function_exists( 'wc_gateway_remove_hook' ) ) {
//Remove BACS payment instructions from thankyou page <- WORKS!
wc_gateway_remove_hook( 'WC_Gateway_BACS', 'woocommerce_thankyou_bacs', 'thankyou_page' );
//Remove BACS payment instructions from email <- DOESN'T WORK!
wc_gateway_remove_hook( 'WC_Gateway_BACS', 'woocommerce_email_before_order_table', 'email_instructions' );
}
}, 10 );
function wc_gateway_remove_hook( $classname, $hook, $callback ) {
foreach( (array) $GLOBALS['woocommerce']->payment_gateways->payment_gateways as $key => $gateway_obj ) {
if( $classname === get_class( $gateway_obj ) ) {
remove_action( $hook, array( $gateway_obj, $callback ) );
}
}
}

Try this:
add_action( 'woocommerce_email_before_order_table', function() {
if( function_exists( 'wc_gateway_remove_hook' ) ) {
wc_gateway_remove_hook( 'WC_Gateway_BACS', 'woocommerce_email_before_order_table', 'email_instructions' );
}
}, 10);
function wc_gateway_remove_hook( $classname, $hook, $callback ) {
foreach( (array) $GLOBALS['woocommerce']->payment_gateways->payment_gateways as $key => $gateway_obj ) {
if( $classname === get_class( $gateway_obj ) ) {
remove_action( $hook, array( $gateway_obj, $callback ) );
}
}
}

Related

How to skip "You cannot add another to your cart" Error in woocommerce and directly jump to Checkout?

What Woocommerce Does is...
When products are Sold Individually, and when the product already exists in the Cart and customer clicks on Add to Cart, Woocommerce shows Error Message "You cannot add another to your cart.....View Cart"
Instead of the above flow I want..
When customer clicks on Add to Cart and if the product already exists in the Cart then woocommerce should redirect to Checkout page straightway.
I think this can be achieved by editing few lines of code in class-wc-cart.php of Woocommerce Plugin.
The is given below:
// Force quantity to 1 if sold individually and check for existing item in cart
if ( $product_data->is_sold_individually() ) {
$quantity = apply_filters( 'woocommerce_add_to_cart_sold_individually_quantity', 1, $quantity, $product_id, $variation_id, $cart_item_data );
$in_cart_quantity = $cart_item_key ? $this->cart_contents[ $cart_item_key ]['quantity'] : 0;
if ( $in_cart_quantity > 0 ) {
throw new Exception( sprintf( '%s %s', wc_get_cart_url(), __( 'View Cart', 'woocommerce' ), sprintf( __( 'You cannot add another "%s" to your cart.', 'woocommerce' ), $product_data->get_title() ) ) );
}
}
I was just looking into how to do this myself. user1072884's answer is okay, however, it only works for one productID at a time. Not ideal if you have multiple products.
Here's a simplified solution that will work for all products.
Simply add the following code to your child theme functions.php and swap the placeholder text with your checkout page URL.
/** If multiple items are in the cart redirect to the checkout page instead of throwing an error **/
add_filter( 'woocommerce_add_to_cart_validation', 'check_cart' );
function check_cart( $cart_item_data ) {
global $woocommerce;
if ( $woocommerce->cart->cart_contents_count > 0 ) {
$direct_url = home_url( 'xyz' ); // Change the value of your actual redirect url.
wp_redirect( $direct_url );
exit();
}
}
Old thread, but maybe someone else will find this helpful.
Try this it will work:
add_filter( 'woocommerce_add_to_cart_sold_individually_quantity', 'vipcomment_change_quantity_to_zero', 10, 5 );
function vipcomment_change_quantity_to_zero( $one, $quantity, $product_id, $variation_id, $cart_item_data ) {
$your_product_id = 96;
if ( $product_id == $your_product_id ) {
$product_cart_id = WC()->cart->generate_cart_id( $product_id );
$in_cart = WC()->cart->find_product_in_cart( $product_cart_id );
if ( $in_cart ) {
return 0;
} else {
return $quantity;
}
} else {
return $quantity;
}
}
add_filter( 'woocommerce_add_to_cart_sold_individually_found_in_cart', 'vipcomment_is_product_exist_in_cart', 10, 5 );
function vipcomment_is_product_exist_in_cart( $exist, $product_id, $variation_id, $cart_item_data, $cart_id ) {
$your_product_id = 96;
if ( $product_id == $your_product_id ) {
return false;
} else {
return $exist;
}
}
Simplest way would be:
throw new Exception( sprintf( '%s %s',
wc_get_cart_url(), __( 'View cart', 'woocommerce' ),
header( "Location: https://www.example.com/cart/" ) ) );
instead of that error. Be advised: this will redirect the user to the cart page ( where the product should already be in place ).

custom error message instead of FATAL ERROR in Wordpress plugin activation if WooCommerce is not acive

I am trying to give a graceful custom message upon activation of the plugin, if Woocommerce is not activated.
if ( in_array( 'woocommerce/woocommerce.php', apply_filters( 'active_plugins', get_option( 'active_plugins' ) ) ) ) {
The above express is to check whether Woocommerce is active and if it returns false, I do not want the plugin to be activated and wants to throw a custom error. I have tried to stop execution with die() and trigger_error. In these cases, it shows a FATAL ERROR.
What I usually do is throw and admin notice if WooCommerce isn't available. And then just stop the running of your plugin.
if ( ! in_array( 'woocommerce/woocommerce.php', apply_filters( 'active_plugins', get_option( 'active_plugins' ) ) ) ){
add_action( 'admin_notices', 'so_32551934_woocommerce_warning' );
return; // STOP THE WHOLE PLUGIN
}
function so_32551934_woocommerce_warning(){ ?>
<div class="error">
<p><?php _e( 'Whoa, you\'re gonna need WooCommerce to run my fancy plugin!', 'my-text-domain' ); ?></p>
</div>
<?php
}
// The rest of your plugin follows here
Any code that you put here at the end will be run as long as WooCommerce is active. Note, I didn't test this so be careful of typos.
Have a look at deactivate_plugins function . Try this:
class MyPlugin {
public function __construct() {
register_activation_hook( __FILE__, array( $this , 'activate' ) );
}
public function activate() {
// Check if Woo is active
if ( in_array( 'woocommerce/woocommerce.php', apply_filters( 'active_plugins', get_option( 'active_plugins' ) ) ) ) {
// Woo is active.
} else {
deactivate_plugins( plugin_basename( __FILE__ ) );
wp_die( __( 'Please activate WooCommerce.', 'my-plugin' ), 'Plugin dependency check', array( 'back_link' => true ) );
}
// Do activate Stuff now.
}
}
new MyPlugin();
Here my solution:
class FT_AdminNotice {
/**
* Register the activation hook
*/
public function __construct() {
register_activation_hook( __FILE__, array( $this, 'ft_install' ) );
}
/**
* Deactivate the plugin and display a notice if the dependent plugin is not active.
*/
public function ft_install() {
if ( ! class_exists( 'WooCommerce' ) )
{
$this->ft_deactivate_plugin();
wp_die( sprintf(__( 'This plugin requires Woocommerce to be installed and activated.', 'domain-text' ) ) );
}
}
/**
* Function to deactivate the plugin
*/
protected function ft_deactivate_plugin() {
require_once( ABSPATH . 'wp-admin/includes/plugin.php' );
deactivate_plugins( plugin_basename( __FILE__ ) );
if ( isset( $_GET['activate'] ) ) {
unset( $_GET['activate'] );
}
}
}
new FT_AdminNotice();
This way show message and you can enrich it like explain here and stop execution too.

how can I prevent multiple login from same user id from different browsers in wordpress?

How to prevent this situation when a user has already logged in from one browser and tries to log in into wordpress again with the same user id but from a different web browser?
One login per ip address also does not solve the problem if a user access the site from mobile and a laptop simultaneously.
create a plugin or place it under function.php. here is the refrence wordpress one session per user
and the code is
<?php
/*
Plugin name: Single user login
Plugin URI:
Description:
Author: Ben May
Author URI:
Version: 0.1
*/
if( !class_exists( 'WPSingleUserLoggin' ) )
{
class WPSingleUserLoggin
{
private $session_id;
function __construct()
{
if ( ! session_id() )
session_start();
$this->session_id = session_id();
add_action( 'init', array( $this, 'init' ) );
add_action( 'wp_login', array( $this, 'wp_login' ), 10, 2 );
}
function init()
{
if( ! is_user_logged_in() )
return;
$stored_sess_id = get_user_meta( get_current_user_id(), '_wp_single_user_hash', true );
if( $stored_sess_id != $this->session_id )
{
wp_logout();
wp_redirect( wp_login_url() );
exit;
}
}
function wp_login( $user_login, $user )
{
update_user_meta( $user->ID, '_wp_single_user_hash', $this->session_id );
return;
}
}
new WPSingleUserLoggin();
}
UPDATE
it will autometically destroy the old session .
if you want to change the functionality do your stuff in
if( $stored_sess_id != $this->session_id )
{
wp_logout();
wp_redirect( wp_login_url() );
exit;
}
and this function
function wp_login( $user_login, $user )
{
update_user_meta( $user->ID, '_wp_single_user_hash', $this->session_id );
return;
}

Add input field to every item in cart

I am trying to add a new field on my cart.php file.
I actually want to insert a URL field, so user can set a URL for each order item.
I tried to use a code from another post here but I can't get it to work.
The first and the second functions are working but when it comes to the third one, 'woocommerce_get_item_data' the $cart_item['url'] doesn't contain anything even if I add something in the field and I press Update Cart.
$cart_totals[ $cart_item_key ]['url'] from the first function is outputting the right value when the page load.
I don't know what to do now, thanks for any help.
Here is the code
Add the field
cart/cart.php
<td class="product-url">
<?php
$html = sprintf( '<div class="url"><input type="text" name="cart[%s][url]" value="%s" size="4" title="Url" class="input-text url text" /></div>', $cart_item_key, esc_attr( $values['url'] ) );
echo $html;
?>
</td>
functions.php
// get from session your URL variable and add it to item
add_filter('woocommerce_get_cart_item_from_session', 'cart_item_from_session', 99, 3);
function cart_item_from_session( $data, $values, $key ) {
$data['url'] = isset( $values['url'] ) ? $values['url'] : '';
return $data;
}
// this one does the same as woocommerce_update_cart_action() in plugins\woocommerce\woocommerce-functions.php
// but with your URL variable
// this might not be the best way but it works
add_action( 'init', 'update_cart_action', 9);
function update_cart_action() {
global $woocommerce;
if ( ( ! empty( $_POST['update_cart'] ) || ! empty( $_POST['proceed'] ) ) ) {
$cart_totals = isset( $_POST['cart'] ) ? $_POST['cart'] : '';
if ( sizeof( $woocommerce->cart->get_cart() ) > 0 ) {
foreach ( $woocommerce->cart->get_cart() as $cart_item_key => $values ) {
if ( isset( $cart_totals[ $cart_item_key ]['url'] ) ) {
$woocommerce->cart->cart_contents[ $cart_item_key ]['url'] = $cart_totals[ $cart_item_key ]['url'];
}
}
}
}
}
// this is in Order summary. It show Url variable under product name. Same place where Variations are shown.
add_filter( 'woocommerce_get_item_data', 'item_data', 10, 2 );
function item_data( $data, $cart_item ) {
if ( isset( $cart_item['url'] ) ) {
$data['url'] = array('name' => 'Url', 'value' => $cart_item['url']);
}
return $data;
}
// this adds Url as meta in Order for item
add_action ('woocommerce_add_order_item_meta', 'add_item_meta', 10, 2);
function add_item_meta( $item_id, $values ) {
woocommerce_add_order_item_meta( $item_id, 'Url', $values['url'] );
}
Add a textarea field to a WooCommerce cart item
First, we just need to add the textarea field. We use the woocommerce_after_cart_item_name hook so our textarea will appear after the product name.
<?php
/**
* Add a text field to each cart item
*/
function prefix_after_cart_item_name( $cart_item, $cart_item_key ) {
$notes = isset( $cart_item['notes'] ) ? $cart_item['notes'] : '';
printf(
'<div><textarea class="%s" id="cart_notes_%s" data-cart-id="%s">%s</textarea></div>',
'prefix-cart-notes',
$cart_item_key,
$cart_item_key,
$notes
);
}
add_action( 'woocommerce_after_cart_item_name', 'prefix_after_cart_item_name', 10, 2 );
/**
* Enqueue our JS file
*/
function prefix_enqueue_scripts() {
wp_register_script( 'prefix-script', trailingslashit( plugin_dir_url( __FILE__ ) ) . 'update-cart-item-ajax.js', array( 'jquery-blockui' ), time(), true );
wp_localize_script(
'prefix-script',
'prefix_vars',
array(
'ajaxurl' => admin_url( 'admin-ajax.php' )
)
);
wp_enqueue_script( 'prefix-script' );
}
add_action( 'wp_enqueue_scripts', 'prefix_enqueue_scripts' );
´´´
At the moment, the user will be able to enter text into the field but the text won’t save. We are going to use some AJAX to save the text.
The code above not only adds the textarea to the cart item, it also enqueues a JavaScript file ready for our AJAX.
It’s assumed that you’re using the code on this page to create a new plugin. If so, you should create a new JS file with the code below and place the file in the root directory of your plugin.
However, if you’ve added the PHP above to your theme functions.php or as a snippet on your site, you’ll need to change the location of the JS file by updating line 21 of the snippet above to identify the location of the JS file.
´´´
(function($){
$(document).ready(function(){
$('.prefix-cart-notes').on('change keyup paste',function(){
$('.cart_totals').block({
message: null,
overlayCSS: {
background: '#fff',
opacity: 0.6
}
});
var cart_id = $(this).data('cart-id');
$.ajax(
{
type: 'POST',
url: prefix_vars.ajaxurl,
data: {
action: 'prefix_update_cart_notes',
security: $('#woocommerce-cart-nonce').val(),
notes: $('#cart_notes_' + cart_id).val(),
cart_id: cart_id
},
success: function( response ) {
$('.cart_totals').unblock();
}
}
)
});
});
})(jQuery);
´´´
Now, when the user types anything, the contents of the text field get sent back to the server ready to be saved as meta data to the cart item.
´´´
<?php
/**
* Update cart item notes
*/
function prefix_update_cart_notes() {
// Do a nonce check
if( ! isset( $_POST['security'] ) || ! wp_verify_nonce( $_POST['security'], 'woocommerce-cart' ) ) {
wp_send_json( array( 'nonce_fail' => 1 ) );
exit;
}
// Save the notes to the cart meta
$cart = WC()->cart->cart_contents;
$cart_id = $_POST['cart_id'];
$notes = $_POST['notes'];
$cart_item = $cart[$cart_id];
$cart_item['notes'] = $notes;
WC()->cart->cart_contents[$cart_id] = $cart_item;
WC()->cart->set_session();
wp_send_json( array( 'success' => 1 ) );
exit;
}
add_action( 'wp_ajax_prefix_update_cart_notes', 'prefix_update_cart_notes' );
function prefix_checkout_create_order_line_item( $item, $cart_item_key, $values, $order ) {
foreach( $item as $cart_item_key=>$cart_item ) {
if( isset( $cart_item['notes'] ) ) {
$item->add_meta_data( 'notes', $cart_item['notes'], true );
}
}
}
add_action( 'woocommerce_checkout_create_order_line_item', 'prefix_checkout_create_order_line_item', 10, 4 );
´´´
The prefix_update_cart_notes function does a security check using the WooCommerce cart nonce then saves the content of the textarea as meta data in the cart item. You can check out this article for more information about updating cart meta for items that have already been added to the cart.
Add the custom text to the order meta
Finally, we want to pass our meta data to the order so that we can use it after the customer has checked out. The prefix_checkout_create_order_line_item function takes care of that, iterating through each item and saving notes when it finds them.
https://pluginrepublic.com/how-to-add-an-input-field-to-woocommerce-cart-items/

WordPress SEO plugin only visible to specific user

I am using the Yoast SEO plugin in WordPress and wanted to know if there was a way to make it only visible to one specific user in the db or in the functions.php file? Not a role, an actual user.
I tried an universal solution to simply add "plugin-name" and disable it, but failed.
But, to show WPSEO only to a specific user (ID equals 2), the following works:
add_action( 'plugins_loaded', 'seo_so_25654837' );
function seo_so_25654837()
{
if ( '2' == get_current_user_id() )
return;
remove_action( 'plugins_loaded', 'wpseo_admin_init', 15 );
}
Don't add the code to functions.php, use it as a normal plugin.
The following is also needed to remove the SEO menu from the admin bar:
add_action( 'wp_before_admin_bar_render', 'bar_so_25654837' );
function bar_so_25654837()
{
if ( '2' == get_current_user_id() )
return;
global $wp_admin_bar;
$nodes = $wp_admin_bar->get_nodes();
foreach( $nodes as $node )
{
if( !$node->parent )
{
if( 'wpseo-menu' === $node->id )
$wp_admin_bar->remove_menu( $node->id );
}
}
}
You can hook to pre_current_active_plugins to remove elements from the table before it is displayed. Using get_current_user_id() within the function will let you selectively hide a plugin.
function hide_plugins_by_user( $all_plugins=false ) {
global $wp_list_table;
// if the current user ID is not 1, hide it.
if ( 1 != get_current_user_id() ){
// the active plugins from the table
$plugins = $wp_list_table->items;
// loop through them
foreach ( $plugins as $key => $val ) {
// use the dir + filename of the plugin to hide
if ( $key == 'plugindir/plugin.php' ) {
unset( $wp_list_table->items[$key] );
}
}
}
}
add_action( 'pre_current_active_plugins', 'hide_plugins_by_user' );
This code is working fine (Credits goes to Hislop):
// Returns true if user has specific role
function check_user_role( $role, $user_id = null ) {
if ( is_numeric( $user_id ) )
$user = get_userdata( $user_id );
else
$user = wp_get_current_user();
if ( empty( $user ) )
return false;
return in_array( $role, (array) $user->roles );
}
// Disable WordPress SEO meta box for all roles other than administrator and seo
function wpse_init(){
if( !(check_user_role('seo') || check_user_role('administrator')) ){
// Remove page analysis columns from post lists, also SEO status on post editor
add_filter('wpseo_use_page_analysis', '__return_false');
// Remove Yoast meta boxes
add_action('add_meta_boxes', 'disable_seo_metabox', 100000);
}
}
add_action('init', 'wpse_init');
function disable_seo_metabox(){
remove_meta_box('wpseo_meta', 'post', 'normal');
remove_meta_box('wpseo_meta', 'page', 'normal');
}
Just place it in the functions.php file.
To disable the Yoast for all the users and enable it for just for few or specific, just add the following piece of code to your function.php file.
function remove_wpseo(){
/* if you want to keep it enabled for user with id 2 */
if ( '2' == get_current_user_id() ) {
return;
}
global $wpseo_front;
if(defined($wpseo_front)){
remove_action('wp_head',array($wpseo_front,'head'),1);
}
else {
$wp_thing = WPSEO_Frontend::get_instance();
remove_action('wp_head',array($wp_thing,'head'),1);
}
}
add_action('template_redirect','remove_wpseo');
Reference: https://makersbyte.com/disable-yoast-seo-plugin-specific-page/

Resources