Strip words from Woocommerce product attributes at checkout - php

I have attributes on all of my products such as "Select your size" and "Select your colour", however in the basket and at checkout I would like to strip "Select your" from all of the attributes so that it is not displayed.
As shown on product page:
As currently shown at checkout, however I really want to remove "Select your":
Is there an easy way to do this in the Woocommerce template files?

fighting away with this will be a battle of the century... you will not just have to remove that string in there... it will also be like that on the email sent and order page will display it. Also some pages I can't remember...
I think you just want the "Select your" string in the product page, is it not?
if so, why not add that string just in there?
So in your variation, in the product admin page, add the variation as size. Then change the display in product page like this:
add_filter('woocommerce_attribute_label','reigel_attribute_label', 10, 2);
function reigel_attribute_label( $label, $name ) {
if (is_product() && $label == 'size') {
$label = 'Select your ' . $label;
}
// another if statement if needed...
if (is_product() && $label == 'color') {
$label = 'Select your ' . $label;
}
return $label;
}
with this approach, you will just have the Select your size in the product page...

You can use WooCommerce's in build API function to do both.
eg.
1. Returns a specific item in the cart.
get_cart_item( $item_key );
https://docs.woothemes.com/wc-apidocs/source-class-WC_Cart.html#751-762
2.Process the checkout after the confirm order button is pressed.
process_checkout();
https://docs.woothemes.com/wc-apidocs/source-class-WC_Checkout.html#343-718
You can take all the reference you need. There are lists of functions are available to do changes.

Related

How to display products with shortcode in custom order?

I'm using woocommerce shortcode to display custom products loop, e.g. [products limit="-1" paginate="true" orderby="menu_order" columns="5" ids="85,11,1083,256,37,12,517,68,2577,104"]. But there's a problem – they are displaying sorted by title, but I need them to be sorted in that exact order they are in shortcode. I found no such option in shortcodes docs. Is there a way to achieve it with shortcode?
The woocommerce_shortcode_products_query_results hook runs after the products have been queried from the database, but before they are displayed on the page. By hooking into this hook and modifying the order of the results, it is possible to display the products in the desired order.
//Products shortcode custom order by id
add_filter('woocommerce_shortcode_products_query_results', 'bytflow_custom_products_shortcode_order', 10, 2);
function bytflow_custom_products_shortcode_order($results, $shortcode_products){
$attributes = $shortcode_products->get_attributes();
$order_by_arg = get_query_var('orderby');
// Check if there are any ids specified and that user didn't change the order
if (empty($order_by_arg) && ! empty( $attributes['ids'] ) ) {
$ids = explode( ',', $attributes['ids'] );
$ordered_results = array();
foreach ($ids as $id){
if(in_array($id, $results->ids)){
$ordered_results[] = $id;
}
}
$results->ids = $ordered_results;
}
return $results;
}
This code checks for the presence of the ids attribute in the shortcode and, if it exists, rearranges the products in the $results->ids array to match the order specified in the attribute. Source
Solution found: orderby = "post__in"
Source: Woocommerce Product Short Code Order by Order of IDs

WooCommerce "CONTACT" button when out of stock

Trying to achieve something that should be simple, but I've tried 3 approaches with multiple code variations and I just can't make it work. I'm trying to create a button that will appear in place of the "ADD TO CART" button on single product pages when the item is out of stock. Clicking the button will fire a popup contact form.
Is creating an add action in functions the right way to go, or should I replace the normal button with an if statement? I've tried both, so help with coding either would be greatly appreciated.
You can either hook into woocommerce_loop_add_to_cart_args using a filter in your functions.php or edit the template file directly by pulling it into your theme. Either way will require a bit of PHP.
If doing it in your functions.php, it would look something like this (untested but should send you down the right path):
<?php
add_filter( 'woocommerce_loop_add_to_cart_link', 'my_out_of_stock_button' );
function my_out_of_stock_button( $args ){
global $product;
if( $product && !$product->is_in_stock() ){
return 'Contact us';
}
return $args;
}
I don't know what your button code should actually look like or what other information you need to capture, but this is how you could override the "Add to Cart" button and replace it if out of stock.
UPDATE
LoicTheAztec brought up a great point - the filter provided only affects the button on the archive, category, tag overview pages - not the individual product pages. There are no hooks for the individual product page buttons BUT you can copy the templates to your theme and override them.
You'll want to look at the files in templates/single-product/add-to-cart. Use a similar if statement as above:
#simple.php
<?php if ( $product->is_in_stock() ) : ?>
// Standard WooCommerce code
<?php else: ?>
// Your button code
<?php endif; ?>
Just add below code in functions.php file of your enabled theme reference
add_action('woocommerce_after_shop_loop_item', 'themelocation_change_outofstock_to_contact_us', 1);
// for shop page
function themelocation_change_outofstock_to_contact_us() {
global $product;
if (!$product->is_in_stock()) {
remove_action('woocommerce_after_shop_loop_item', 'woocommerce_template_loop_add_to_cart');
remove_action('woocommerce_single_product_summary', 'woocommerce_template_single_add_to_cart');
//change the link to your contact us page
echo ' Contact Us ';
}
}
// for single page
add_filter('woocommerce_get_availability', 'wcs_custom_get_availability', 1, 2);
function wcs_custom_get_availability($availability, $_product) {
// Change In Stock Text
if ($_product->is_in_stock()) {
$availability['availability'] = __('Available!', 'woocommerce');
}
// Change Out of Stock Text
if (!$_product->is_in_stock()) {
$availability['availability'] = __(' Contact Us ', 'woocommerce');
}
return $availability;
}
I was looking for a way to show a contact button on bespoke products and
#ahwychkchih solution works great. One issue I had though is that schema markup will show as out of stock for those products which is not the case for beskpoke products is just they can't be purchased straight away so I've added this to force in_stock markup for my products. I'm aware that this solution would affect all products so you can always add a product id filter if needed
// Force In Stock schema markup
function fix_my_product_offers_schema ($markup_offer, $product) {
if (!$product->is_in_stock()) {
$markup_offer['availability'] = 'https://schema.org/InStock';
}
return $markup_offer;
}
add_filter('woocommerce_structured_data_product_offer', 'fix_my_product_offers_schema', 1, 2);

return woocommerce item names from cart only if they are a certain variation

I'm more or less a total newbie to php. My goal is to get the names of items from the logged in user's cart and dynamically populate a GravityForms template with the information. I've successfully managed to do that with the code below, but there are three things that I'm failing to do. 1: I only want to populate the form with all items of a certain variation. 2: the echo function will list all of the item names, but not inside the relevant field, and the return function will populate the field, but only with the first item name. 3: I'd like to have the output items listed with some form of separator in between each item name. Here's what I have so far:
<?php
add_filter( 'gform_field_value_beat_names', 'beat_names_function' );
function beat_names_function( $value ) {
global $woocommerce;
$items = $woocommerce->cart->get_cart();
foreach ($items as $item) {
$product_variation_id = $item['variation_id'];
$license_id = new WC_Product($product_variation_id);
$license_string = $license_id->get_formatted_name();
$beat_id = $item['data']->post;
$beat_name = $beat_id->post_title;
if (strpos($license_string, 'basic') !== false) {
echo $beat_name;
}
}
}?>
As you can see, I'm attempting to use strpos to isolate the particular item variation I want to target, using a certain word found in the name of the variation option, being "basic". I'm sure there's a more secure way of doing that, but it works for now. The problem lies with the return function I set up inside the conditional strpos statement, being that it will still just return the entire list of cart items, as opposed to only the items that I'm trying to isolate with the strpos conditional.
The ultimate goal is to create a license agreement that is dynamically populated with the relevant information, including the names of the items being licensed. The item variations are different license options that I have available for the products in my store. The purpose of the above code is to filter cart items by license type so that the wrong item names don't get listed on the wrong license agreement at checkout.
Any tips would be appreciated
Figured it out after some more tinkering. I broke it down step by step to help anyone as clueless as I am
add_filter( 'gform_field_value_basic_beat_names', 'basic_beat_names_function' );
function basic_beat_names_function( $value ) {
global $woocommerce;
$items = $woocommerce->cart->get_cart();
// the item names you want will be stored in this array
$license_check = array();
// Loop through cart items
foreach ($items as $item) {
// get the id number of each product variation in the cart. this won't work for "simple" products
$product_variation_id = $item['variation_id'];
// translate that id number into a string containing the name of the product, and the options applied to the product
$license_id = new WC_Product($product_variation_id);
$license_string = $license_id->get_formatted_name();
// check to see if the word "basic" is found anywhere in that string. "basic" is contained in the name of the product option being targeted
if (strpos($license_string, 'basic') !== false) {
// if the above condition is met, fetch the name of any products in the cart that have that option applied. The product name will be fetched from the title of the product's page
$beat_id = $item['data']->post;
$beat_name = $beat_id->post_title;
// store the retrieved product names in the $license_check array
$license_check [] = $beat_name;
}
}
// pull the stored product names from the $license_check array, and format them using implode and concatenation, then return the final result to the form field
return "\"" . implode("\", \"", $license_check) . "\"";
}
As a warning, the strpos method is a little hacky. It'll only work properly if your string is specific enough to target ONLY the option you're looking for.
As an example, here's the format for the product variation string being fed into the strpos function:
item-name-option-one-name-option-two-name – variation #xxx of item page title
So, if you want to filter items ONLY by option one, your safest bet would be to write the strpos function like so:
if (strpos($license_string, 'option-one-name') !== false) {
//do something
}
When all is said and done, the final result should look like: "item1", "item2", "item3", etc.
Then, to do the same with any other option, and output the result in a different field, or separate form altogether, I'll just duplicate this code, and replace any mention of the word "basic" with some different unique string contained in the other option. Don't forget to configure the gravity forms field as necessary too.

How to add product attributes in woocommerce product lisitng page in wordpress?

I am developing cart website using woocommerce plugin in wordpress.In products i have two attributes as like SIZE and COLOR.
Currently Product name and Price is displaying on product listing page dafault.now i want to add SIZE attributes below price in product listing page.
I know about to add hook but i don't know that how to add SIZE using hook?
EDITED:
I misunderstood you. This should do it (checked it on my woocommerce test page):
if (!function_exists('shop_attributes_in_loop')) {
function shop_attributes_in_loop(){
global $product;
$attributes = $product->get_attributes();
if(!empty($attributes)){
$attribute_single = array_keys($attributes);
$myArray = array();
echo '<div class="product_attributes">';
foreach ($attribute_single as $attribute => $value) {
$myArray[] = ucfirst($value);
}
echo implode(', ', $myArray).'</div>';
}
}
}
add_action('woocommerce_after_shop_loop_item', 'shop_attributes_in_loop');
This will put your product attributes, if existing, in a div .product_attrributes. You can easily add a translatable string saying that those are product attributes like
echo esc_html('Product attributes', 'my-theme-name') .'<div class="product_attributes">'
in the first echo.

Getting Input Fields from Gravity Forms on Woocommerce

Gravity Forms Product Add-ons for Woocommerce displays the form inputs of a user in the cart and checkout. I want to display these form fields in the user's Account page with their orders. I've been trying for a week and can't seem to get the right php code put together. How can I do this?
My code as it stands is like so:
$form_id = RGFormsModel::get_form_id('Domains');
$form = GFFormsModel::get_form_meta($form_id);
$field = GFFormsModel::get_field($form, 1);
$leads = RGFormsModel::get_leads($form['id']);
foreach($leads as $lead)
{
foreach($field as $field_id)
{
$value = rgar($lead, (string) $field_id);
echo $value;
}
}
This returns all entries for the field I want, however, I only want to return the entry that was submitted with that particular product. Help?
Here's a quick example for clarity on what I'm looking for. A user buys a shirt and selects size large from a Gravity Form that was attached to the product. On the cart and checkout pages, it says beneath the product title "Size: Large". I want to add that same text to the "My Account" page with their order.
The way I solved a similar problem may not be the best in coding practices but it works. It takes custom data associated with the order from Gravity Forms and displays it under the shipping address in WooCommerce individual order page:
<?php
add_action('woocommerce_admin_order_data_after_shipping_address', 'ips_show_signs_in_admin_under_shipping', 10, 1);
/*
function to put in functions.php of the theme to add custom gravityforms data to customer order page in admin area.
*/
function ips_show_signs_in_admin_under_shipping($order)
{
global $woocommerce, $post;
$order_items = $order->get_items(apply_filters('woocommerce_admin_order_item_types', array( 'line_item')));
foreach($order_items as $item_id => $item)
{
if ($metadata = $order->has_meta($item_id)) //not a comparison, so one equal sign. so if there is any data in there it would assign it and thus making it true, if no data it would be false
{
foreach($metadata as $meta)
{
// Skip hidden woocommerce core fields just in case
if (in_array($meta['meta_key'], apply_filters('woocommerce_hidden_order_itemmeta', array(
'_qty',
'_tax_class',
'_product_id',
'_variation_id',
'_line_subtotal',
'_line_subtotal_tax',
'_line_total',
'_line_tax',
)))) continue;
if (is_serialized($meta['meta_value'])) continue; // Skip serialised meta since we dont need it incase its in there
$meta['meta_key'] = esc_attr($meta['meta_key']); //just to make sure there is no surprises in there
$meta['meta_value'] = esc_textarea($meta['meta_value']); // using a textarea check for surprises (sql injection)
if ("Signpost Address" === $meta['meta_key']) //here comes the custom data from gravity forms
{
echo $meta['meta_value']; //this is what i was after from gravity forms collected with order
}
} //closes --- foreach($metadata as $meta)
} //closes --- if ($metadata = $order->has_meta($item_id))
} //closes --- foreach($order_items as $item_id => $item)
} //closes --- function
?>
Edit: This code searches the order meta data
I have added the above code in my functions.php file and unfortunately this hasn't worked for me. I have looked all over for a solution to this and this seems to exactly be what I'm after. Do i simply replace "Signpost Address" with say "Blanket Size" if that were one of my gravity form options?

Categories