cant access woocommerce cart in contact form 7 hook? - wordpress

Using the the wpcf7 hook wpcf7_special_mail_tags() I want to get the cart contents and return the output, but WC()->cart object is null in this hook, I cant access any methods on WC()->cart as its a call to an undefined method. I cant work out how to get access to WC()->cart in this hook.
I can access WC()->cart fine in the WPCF7 hook wpcf7_add_form_tag()
The wpcf7_special_mail_tags() works fine and inserts other data into email, I just want cart data though.
Thanks for any help.
function my_special_mail_tag( $output, $name, $html ) {
if ( 'mytag' == $name ) {
$cart = WC()->cart;
if(!WC()->cart->is_empty()) {
// do something with output
}
}
return $output;
}
add_filter( 'wpcf7_special_mail_tags', 'my_special_mail_tag', 10, 3 );

Here you go. I'm ok with this.
function my_special_mail_tag( $output, $name, $html ) {
if ( 'mytag' == $name ) {
$cart = WC()->cart;
if(!WC()->cart->is_empty()) {
// do something with output
}
}
return $output;
}
add_filter( 'wpcf7_special_mail_tags', 'my_special_mail_tag', 10, 3 );

Related

woocommerce conditional email template if product type in order

I try to send a customized email template when a customer has a ticket (custom product type) in cart.
I have the following:
function bc_customer_completed_order_template($template, $template_name, $template_path)
{
foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
$product = wc_get_product( $cart_item['product_id'] );
$type = get_class($product);
if ( $type == 'WC_Product_Tickets' && 'customer-completed-order.php' === basename($template) ) {
$template = trailingslashit(plugin_dir_path( __FILE__ )) . 'templates/customer-completed-order.php';
}
}
return $template;
}
add_filter('woocommerce_locate_template', 'bc_customer_completed_order_template', 10, 3);
The conditionals are working (on cart and checkout page for example), but when the order is placed, the new template is not used.
Anybody?
Your email template will look like this:
Code snippets:
// Suppose orders don't have ticket products.
$has_tickets = false;
// Loop order items.
foreach ( $order->get_items() as $item_id => $item ) {
// Get product object from order item.
$_product = $item->get_product();
// Check if the product object is valid and the class is `WC_Product_Tickets`
if ( $_product && 'WC_Product_Tickets' === get_class( $_product ) ) {
// Change the flag.
$has_tickets = true;
// Break the loop as we alreay have true flag.
break;
}
}
// Check if order have tickets items.
if ( $has_tickets ) {
// Load custom email template.
wc_get_template( 'templates/custom-customer-completed-order.php' );
// Return as we don't need the below code.
return;
}
It turned out, although the above solution is correct in its idea, in reality one cannot load a template and make use of the $order without extending the woocommerce email class.
Therefore i loaded the function inside the email template itself and made an if - else statement so for situation A the layout is different then for situation b.
Like so:
$has_tickets = false;
// Loop order items.
foreach ( $order->get_items() as $item_id => $item ) {
// Get product object from order item.
$_product = $item->get_product();
// Check if the product object is valid and the class is `WC_Product_Tickets`
if ( $_product && 'WC_Product_Tickets' === get_class( $_product ) ) {
// Change the flag.
$has_tickets = true;
// Break the loop as we alreay have true flag.
break;
}
}
// Check if order have tickets items.
if ( $has_tickets ) {
do_action( 'woocommerce_email_header', $email_heading, $email ); ?>
//custom email layout here//
}
else{
//Regular email template here
}

Woocommerce hook that fires after a product is updated via REST API

I am using this hook to run some code after the product is updated:
add_action( 'updated_post_meta', 'attach_variation_images_on_product_save', 10, 4 );
function attach_variation_images_on_product_save( $meta_id, $post_id, $meta_key, $meta_value ) {
if ( $meta_key == '_edit_lock' ) {
if ( get_post_type( $post_id ) == 'product' ) {
//do something
}
}
}
This is working as expected, the function is executed after the product is updated. I want to run the same function when a product is getting updated via the REST API. I hooked my function to woocommerce_rest_insert_product_object like this but it did not work:
add_action( 'woocommerce_rest_insert_product_object', 'attach_variation_images_on_product_update_via_rest', 10, 3 );
function attach_variation_images_on_product_update_via_rest( $post, $request, $true ) {
if ( get_post_type( $post ) == 'product' ) {
$product = wc_get_product( $post );
//do something
}
}
Am I not using the right hook? Is there another hook I can use?
EDIT 1: It seems that my code was not running because get_post_type($post) is type of post and not product. I am trying to attach an image to variations using add_post_meta($variation_id, '_thumbnail_id', $image_id); inside a loop. It seems the function attach_variation_images_on_product_update_via_rest( $post, $request, $true ) is executed till the end but it does not attach the image to the variations.
I ended up using this hook add_action( 'woocommerce_update_product', 'my_callback_function', 10, 1 ); that executes the callback function when you updating products from Woocommerce back-end as well from the REST API.

Disabinge woocommerce variable product price doesn't work

I tried several codes to disable the price in product variable in woocommerce.
I've tried this but nothing happened:
/*
Disable Variable Product Price Range completely:
*/
add_filter( 'woocommerce_variable_sale_price_html','my_remove_variation_price', 10, 2 );
add_filter( 'woocommerce_variable_price_html', 'my_remove_variation_price', 10, 2 );
function my_remove_variation_price( $price ) {
$price = '';
return $price;
}
I put it in functions.php but nothing happened.
My theme is saha from theme-junkie.
Best way would be to hook into woocommerce_get_price_html filter.
It passes $price HTML and WC_Product* object. You can check if it is instance of WC_Product_Variable to determine if it is a variable product. Then just return '' empty string if it is. This will handle the price display for parent Variable product.
Example
add_filter('woocommerce_get_price_html', 'mm_handle_variation_prices', 10, 2);
function mm_handle_variation_prices( $price_html, $product_obj ){
// Bail unless we are on WooCommerce page on frontend and this is an ajax request.
if( is_admin() || is_ajax() || ! is_woocommerce() ) {
return $price_html;
}
// If this is an Variable product only then return empty string.
// '$product_obj instanceof WC_Product_Variable' check would work as well.
if( 'variable' === $product_obj->get_tyepe() ) {
return '';
} else {
return $price_html;
}
}

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/

Need Woocommerce to only allow 1 product in the cart. If a product is already in the cart and another 1 is added then it should remove the previous 1

I think this code should work but not exactly sure where to place it. Everywhere I have tried has failed so far...
add_action('init', 'woocommerce_clear_cart');
function woocommerce_clear_cart() {
global $woocommerce, $post, $wpdb;
$url = explode('/', 'http://'.$_SERVER["HTTP_HOST"] . $_SERVER["REQUEST_URI"]);
$slug=$url[4];
$postid = $wpdb->get_var("SELECT ID FROM $wpdb->posts WHERE post_status='publish' AND post_name = '$slug'");
if ($postid){
if ($postid == PRODUCTID1 || $postid == PRODUCTID2){
$woocommerce->cart->empty_cart();
}
}
}
Unfortunately there is no 'action' hook before WooCommerce adds an item to the cart. But they have a 'filter' hook before adding to cart.
That is how I use it:
add_filter( 'woocommerce_add_cart_item_data', 'woo_custom_add_to_cart' );
function woo_custom_add_to_cart( $cart_item_data ) {
global $woocommerce;
$woocommerce->cart->empty_cart();
// Do nothing with the data and return
return $cart_item_data;
}
Based on the accepted answer and the latest Woo version 2.5.1 I updated the function to be slightly cleaner using the code woo uses in class-wc-checkout.php to clear the cart
add_filter( 'woocommerce_add_cart_item_data', '_empty_cart' );
function _empty_cart( $cart_item_data ) {
WC()->cart->empty_cart();
return $cart_item_data;
}
There is a filter/hook that runs before an item is added to the cart as each product goes through validation before it is added.
So when validating a product, we can check if the item if there are already items in the cart and clears those (if the current item is able to be added) and adds an error message.
/**
* When an item is added to the cart, remove other products
*/
function so_27030769_maybe_empty_cart( $valid, $product_id, $quantity ) {
if( ! empty ( WC()->cart->get_cart() ) && $valid ){
WC()->cart->empty_cart();
wc_add_notice( 'Whoa hold up. You can only have 1 item in your cart', 'error' );
}
return $valid;
}
add_filter( 'woocommerce_add_to_cart_validation', 'so_27030769_maybe_empty_cart', 10, 3 );
This worked like a charm for me, removes the previous product and adds the new one with the new product configuration. Cheers
Update: For WooCommerce 3.0.X
function check_if_cart_has_product( $valid, $product_id, $quantity ) {
if(!empty(WC()->cart->get_cart()) && $valid){
foreach (WC()->cart->get_cart() as $cart_item_key => $values) {
$_product = $values['data'];
if( $product_id == $_product->get_id() ) {
unset(WC()->cart->cart_contents[$cart_item_key]);
}
}
}
return $valid;
}
add_filter( 'woocommerce_add_to_cart_validation', 'check_if_cart_has_product', 10, 3 );
For WooCommerce version less than 3.0.X
function check_if_cart_has_product( $valid, $product_id, $quantity ) {
if(!empty(WC()->cart->get_cart()) && $valid){
foreach (WC()->cart->get_cart() as $cart_item_key => $values) {
$_product = $values['data'];
if( $product_id == $_product->id ) {
unset(WC()->cart->cart_contents[$cart_item_key]);
}
}
}
return $valid;
}
add_filter( 'woocommerce_add_to_cart_validation', 'check_if_cart_has_product', 10, 3 );
You have two options:
WooCommerce Min/Max Quantities extension
The following code added to your functions.php theme file
add_filter ( 'woocommerce_before_cart' , 'allow_single_quantity_in_cart' );
function allow_single_quantity_in_cart() {
global $woocommerce;
$cart_contents = $woocommerce->cart->get_cart();
$keys = array_keys ( $cart_contents );
foreach ( $keys as $key ) {
$woocommerce->cart->set_quantity ( $key, 1, true );
}
}
Don't add functions directly to your commerce files...you'll lose all your code when you update.
User functions should always be hooked through the functions.php of your theme.
Add this to your child-themes functions.php (tested in 2022, requires PHP 7 or higher):
add_filter('woocommerce_add_cart_item_data', function($cart_data) {
wc_empty_cart();
return $cart_data;
}, 99);
The "woocommerce_add_cart_item_data" filter fires every time a new item is added to the cart. We use this chance to call "wc_empty_cart" which empties the cart and optionally the persistent cart too. The new items is therefore alone in the cart.
Try this,
For removing the all products from the cart and adding the last added one,
//For removing all the items from the cart
global $woocommerce;
$woocommerce->cart->empty_cart();
$woocommerce->cart->add_to_cart($product_id,$qty);
class file is wp-content/plugins/woocommerce/classes/class-wc-cart.php.
You can add the above code on the add to cart function in functions.php.
Hope its works..
Eu coloco na function.php do tema, o que faço ou no woocomerce
function check_if_cart_has_product( $valid, $product_id, $quantity ) {
if(!empty(WC()->cart->get_cart()) && $valid){
foreach (WC()->cart->get_cart() as $cart_item_key => $values) {
$_product = $values['data'];
if( $product_id == $_product->id ) {
wc_add_notice( 'The product is already in cart', 'error' );
return false;
}
}
}
return $valid;
}
add_filter( 'woocommerce_add_to_cart_validation', 'check_if_cart_has_product', 10, 3 );
On WordPress 5.6.1. no need to add a custom filter or write code there is an option to limit one product add to the cart.

Resources