I'm having trouble disabling a function in the Woocommerce Force Sells extension. The function adds some text under the buy button on the frontend product page, that I would like to remove.
I think I have found the function in question in the woocommerce-force-sells.php file:
/**
* Displays information of what linked products that will get added when current
* product is added to cart.
*/
public function show_force_sell_products() {
global $post;
$product_ids = $this->get_force_sell_ids( $post->ID, array( 'normal', 'synced' ) );
$titles = array();
// Make sure the products still exist and don't display duplicates.
foreach( array_values( array_unique( $product_ids ) ) as $key => $product_id ) {
$product = wc_get_product( $product_id );
if ( $product && $product->exists() && 'trash' !== $product->get_status() ) {
$titles[] = version_compare( WC_VERSION, '3.0', '>=' ) ? $product->get_title() : get_the_title( $product_id );
}
}
if ( ! empty( $titles ) ) {
echo '<div class="clear"></div>';
echo '<div class="wc-force-sells">';
echo '<p>' . __( 'This will also add the following products to your cart:', 'woocommerce-force-sells' ) . '</p>';
echo '<ul>';
foreach ( $titles as $title ) {
echo '<li>' . $title . '</li>';
}
echo '</ul></div>';
}
}
I have looked at https://codex.wordpress.org/Function_Reference/remove_action but I can't really figure out how to employ that in the code above.
Thanks a lot in advance!
The easy way to do this is by hiding the content from the page. Look for the class and add
display:none ;
to that class in css.
or
you can edit it in woocommerce template files. it is hard to find from which page it is coming from (look in all possible pages in templates ). once you find it remember to copy that template to child theme.(create a folder in child theme named as woocommerce---add folder path if there is some in actual location). or else you will loose all the edits when woocommerce is updated.
easy way is just hiding it from css
You cannot remove a function, you can only prevent it from being executed. That is not the same as removing an action though. However, if you want to remove text from a button, you are probably better off changing the template file that adds the button to the page.
Here is some more information about changing the template: https://docs.woocommerce.com/document/template-structure/
Related
I am working on an e-commerce website using woocommerce.
I am styling the product card (The second container which includes the product name,price,etc..) in shop categories and all locations using hooks and content-product.php file.
My code for product.php file is
<div class="second-container">
<div class="product_info">
<?php do_action( 'woocommerce_before_shop_loop_item_title'); ?>
<?php do_action( 'woocommerce_shop_loop_item_title' ); ?>
<?php do_action( 'woocommerce_after_shop_loop_item_title' ); ?>
This one to show the name.
For my first entry which is a custom attribute named "Brand" I use the following function in my functions.php file.
add_action('woocommerce_shop_loop_item_title', 'display_custom_product_attributes_on_loop', 5 );
function display_custom_product_attributes_on_loop() {
global $product;
$value2 = $product->get_attribute('Brand');
if ( ! empty($value2) ) {
echo '<div class="items" style=";"><p>';
$attributes = array(); // Initializing
if ( ! empty($value2) ) {
$attributes[] = __("") . ' ' . $value2;
}
echo implode( '', $attributes ) . '</p></div>';
}
}
It was very hard for me to get to this point anyway as I know nothing about php, it works fine but there is a problem, which is there is some spacing between the two hooks See image:
where brand= loft
title = Men’s Black Turtleneck Sweater 2600
I tried to manipulate the padding in css using all containers available top/bottom padding but no luck to remove the spacing.
I am seeking help to do one of the following
1- Concatenate both brand and title in the same line giving the brand click a permalink to the global filter of the attribute and the name a permalink of the product itself ( 100% recommended)
OR
2- Concatenate both brand and title in the same line giving both of them the permalink for the product only (80% recommended)
OR
3- Reduce the spacing between the first and second line.
My shop page for refrence
I use Swoof plugin for filtering
Much thanks and appreciation in advance for any help.
You could use the_title filter hook to manipulate the title. Also use some conditional check to manipulate only the products name on the shop page. So i'd do something like this:
add_filter('the_title', 'display_custom_product_attributes_on_loop', 20, 2);
function display_custom_product_attributes_on_loop($the_title, $id)
{
global $product;
if (is_shop() && get_post_type($id) == 'product') :
$value2 = $product->get_attribute('Brand');
if ( ! empty($value2) ):
$the_title = $value2 . ' ' . '' . $the_title . '';
endif;
endif;
return $the_title;
}
This will output attribute value + your product title which is a link to the single product page.
OR
add_filter('the_title', 'display_custom_product_attributes_on_loop', 20, 2);
function display_custom_product_attributes_on_loop($the_title, $id)
{
global $product;
if (is_shop() && get_post_type($id) == 'product') :
$value2 = $product->get_attribute('Brand');
if ( ! empty($value2) ):
$the_title = $the_title . ' ' . '' . $value2 . '';
endif;
endif;
return $the_title;
}
This will output the product title + your attribute value which is a link to the single product page.
I keep searching for a way to do this, but I can't find anything unfortunately.
I an trying to display all the product's attributes and values, separated by a pipe, in a custom place on the single-product (so for that I was thinking to create a shortcode, so I can place it anywhere I want). the output would be something like this:
BRAND: RENAULT | MODEL: 12 | YEAR: 1973
The code on the Woocommerce template product-attributes.php lists the attributes of the current product on single-product page, but it will list it with some styles I don't want in a place I don't want.
I want to create a shortcode with that code, which is:
<?php foreach ( $product_attributes as $product_attribute_key => $product_attribute ) : ?>
<?php echo wp_kses_post( $product_attribute['label'] ); ?>: <?php echo wp_kses_post( $product_attribute['value'] ); ?> |
<?php endforeach; ?>
How can I create a shortcode with it? I know the general code for a shortcode, but I don't know how to actually integrate the above one in it:
function custom_attributes_product_page() {
// integrate the required code
// Output needs to be return
return
}
// register shortcode
add_shortcode('custom-attributes', 'custom_attributes_product_page');
Would be great if this shortcode would list the attributes and their values separated by a column, like I said above (how to do that?)
Any help is highly appreciated.
Try the following shortcode that will display all product attribute(s) set for a product and their value(s), handling custom attributes too:
function get_product_attributes_shortcode($atts ) {
// Extract shortcode attributes
extract( shortcode_atts( array(
'id' => get_the_ID(),
), $atts, 'display-attributes' ) );
global $product;
if ( ! is_a($product, 'WC_Product') ) {
$product = wc_get_product( $id );
}
if ( is_a($product, 'WC_Product') ) {
$html = []; // Initializing
foreach ( $product->get_attributes() as $attribute => $values ) {
$attribute_name = wc_attribute_label($values->get_name());
$attribute_data = $values->get_data();
$is_taxonomy = $attribute_data['is_taxonomy'];
$option_values = array(); // Initializing
// For taxonomy product attribute values
if( $is_taxonomy ) {
$terms = $values->get_terms(); // Get attribute WP_Terms
// Loop through attribute WP_Term(s)
foreach ( $terms as $term ) {
$term_link = get_term_link( $term, $attribute );
$option_values[] = ''.$term->name.'';
}
}
// For "custom" product attributes values
else {
// Loop through attribute option values
foreach ( $values->get_options() as $term_name ) {
$option_values[] = $term_name;
}
}
$html[] = '<strong>' . $attribute_name . '</strong>: ' . implode(', ', $option_values);
}
return '<div class="product-attributes">' . implode(' | ', $html) . '<div>';
}
}
add_shortcode( 'display-attributes', 'get_product_attributes_shortcode' );
Code goes in functions.php file of the active child theme (or active theme). Tested and works.
USAGE: [display-attributes] or with a defined product Id [display-attributes id="254"]
You will get a display like: BRAND: RENAULT | MODEL: 12 | YEAR: 1973
If you don't want the linked terms, replace:
$term_link = get_term_link( $term, $attribute );
$option_values[] = ''.$term->name.'';
by this:
$option_values[] = $term->name;
I want to change the page titles (entry titles) for each page in the WooCommerce My Account section so that they relate to the actual page you are on rather than outputting a generic "My Account" on each page.
I have looked around and seen this solution in several places:
function wpb_woo_endpoint_title( $title, $id ) {
if ( is_wc_endpoint_url( 'downloads' ) && in_the_loop() ) { // add your endpoint urls
$title = "Download MP3s"; // change your entry-title
}
elseif ( is_wc_endpoint_url( 'orders' ) && in_the_loop() ) {
$title = "My Orders";
}
elseif ( is_wc_endpoint_url( 'edit-account' ) && in_the_loop() ) {
$title = "Change My Details";
}
return $title;
}
add_filter( 'the_title', 'wpb_woo_endpoint_title', 10, 2 );
This does not work unless you remove the in_the_loop check, which obviously isn't ideal as then it ends up changing other things on the page too.
Then I found this answer, as an example on how to change the title for the "Account Details" page:
add_filter( 'woocommerce_endpoint_edit-account_title', 'change_my_account_edit_account_title', 10, 2 );
function change_my_account_edit_account_title( $title, $endpoint ) {
$title = __( "Edit your account details", "woocommerce" );
return $title;
}
But this didn't work, it didn't even seem to go into the function at all.
Is there a way to do this that actually works?
Changing main my account page title and My account page title sub sections:
1) For "My Account: dashbord (main page):
To change the main "My account" page title, you just need to change the title of the page in backend directly because it's not an endpoint, and to check in Settings > Advanced section that the page (with the renamed title) is still assigned to "My account page".
2) For the other "endpoints" page titles in My account section:
Use woocommerce_endpoint_{$endpoint}_title composite dedicated filter hook, where {$endpoint} need to be replaced by the targeted endpoint (see available endpoints on Settings > Advanced section)
Example: To change My account "orders" endpoint page title you will use:
add_filter( 'woocommerce_endpoint_orders_title', 'change_my_account_orders_title', 10, 2 );
function change_my_account_orders_title( $title, $endpoint ) {
$title = __( "Your orders", "woocommerce" );
return $title;
}
Code goes in function.php file of your active child theme (or active theme). Tested and works.
If it doesn't work, it's because something else is making trouble, like your own customizations, your theme's customizations, a plugin or something else…
Related StackOverFlow answers:
Changing the titles on My Account pages in Woocommerce
Rename My account tabbed menu items in Woocommerce
Reorder menu items in Woocommerce My Account section
Display custom content for a custom account menu item in Woocommerce 3
You can change you MyAccount item titles this way:
/**
* Rename WooCommerce MyAccount menu items
*/
add_filter( 'woocommerce_account_menu_items', 'rename_menu_items' );
function rename_menu_items( $items ) {
$items['downloads'] = 'Download MP3s';
$items['orders'] = 'My Orders';
$items['edit-account'] = 'Change My Details';
return $items;
}
To change the title on each account page as well, you need to add this too:
/**
* Change page titles
*/
add_filter( 'the_title', 'custom_account_endpoint_titles' );
function custom_account_endpoint_titles( $title ) {
global $wp_query;
if ( isset( $wp_query->query_vars['downloads'] ) && in_the_loop() ) {
return 'Download MP3s';
}
if ( isset( $wp_query->query_vars['orders'] ) && in_the_loop() ) {
return 'My Orders';
}
if ( isset( $wp_query->query_vars['edit-account'] ) && in_the_loop() ) {
return 'Change My Details';
}
return $title;
}
If you're using Yoast SEO, you need to add another function to set the correct page titles in the browser tab. If you also need this, I'll expand my answer.
Put this into you functions.php file. Tested and works.
I notice I had some issues implementing the is_wc_endpoint_url() && in_the_loop solution, it did not work out with the && in_the_loop(), removing is not a viable option since it created even more conflicts.
So instead I chose to work on the template file directly, I am sharing this because I noticed that some people had the same issues and this solution might help others achieve the similar results using a different approach.
I basically replaced the header in page-my-account.php with this code:
<header>
<?php
$main_title = get_the_title();
$endpoint = WC()->query->get_current_endpoint();
$endpoint_title = __( WC()->query->get_endpoint_title( $endpoint ), 'text-domain' );
if ( $endpoint_title ){
//If the endpoint exists use itself as the new custom title
$custom_title = $endpoint_title;
}
else{
// Here we can define the custom title for each endpoint we can use home_url() or strpos + add_query_arg()
global $wp;
if( basename( home_url($wp->request) ) == 'points-and-rewards' || ( strpos( (add_query_arg( $wp->query_vars)) , 'points-and-rewards' ) !== false ) ){
$custom_title = __( 'Points and rewards', 'text-domain' );
}
elseif( basename(home_url($wp->request)) == 'payment-methods' ){
$custom_title = __( 'Payment methods', 'text-domain' );
}
elseif( basename(home_url($wp->request)) == 'my-account' ){
$custom_title = __( 'Dashboard', 'text-domain' );
}
//Add more custom titles here
}
if ( !empty( $custom_title ) ){
//If there is a custom title
$new_endpoint_title = sprintf( '<h2>%s > %s</h2>', $main_title, $custom_title );
}
else{
//If there is no custom title default to get_title()
$new_endpoint_title = sprintf( '<h2>%s</h2>' , $main_title );
}
?>
<?php //Echo's the resulting title ?>
<?php echo $new_endpoint_title; ?>
</header>
I would like to use the WooCommerce shortcode
[product id="99"]
However I would like to have both the product image and product name itself not link to the individual product page. All I want is the "Add to Cart" button working as intended but nothing else being clickable.
Is this possible? What template would I need to edit?
This doesn't need to be applicable to only a specific shortcode if it's easier. I never want to have people be able to get to product pages at all, so if there is a "global" way to do this, it'll work too.
Here it the logic you need to do in your functions.php, I have created a custom shortcode to get the product as you explained.
function get_c_product($atts){
$params = shortcode_atts(array(
'id' => '0',
), $atts );
$args = array('post_type'=>'product','post__in'=>array($params['id']));
$the_query = new WP_Query( $args );
// The Loop
if ( $the_query->have_posts() ) {
$return = '<ul>';
while ( $the_query->have_posts() ) {
$the_query->the_post();
$_product = wc_get_product( get_the_ID() );
$return .= '<li>' . woocommerce_get_product_thumbnail() . '</li>';
$return .= '<li>' . get_the_title() . '</li>';
$return .= '<li>' . do_shortcode('[add_to_cart id='.get_the_ID().']') . '</li>';
}
$return .= '</ul>';
/* Restore original Post Data */
wp_reset_postdata();
} else {
// no posts found
}
return $return;
}
add_shortcode('product_custom','get_c_product');
Then use the shortcode like this : echo do_shortcode('[product_custom id="99"]'); or [product_custom id="99"]
I've written two functions to show custom fields on the shop pages below each product, which can be viewed here. The ones specifically are Light Bulb Type and Coverage Area. However, these only apply to certain products. Right now, I am typing in N/A when they don't apply, but I would like to write a conditional statement to hide the entire section if the field is left empty.
Unfortunately, every time I do so, the code breaks the site because it is incorrectly written.
These are the functions I've written to show the custom fields.
add_action('woocommerce_shop_loop_item_title','show_coverage');
function show_coverage() {
echo '<span class="extra-info-head">Coverage Area:</span> ';
$coverage = get_post_meta( $post->ID );
$custom_fields = get_post_custom();
$coverage = $custom_fields['wpcf-coverage-area'];
foreach ( $coverage as $key => $value ) {
echo $value . '<br/>';
}}
add_action('woocommerce_shop_loop_item_title','show_bulbs');
function show_bulbs() {
echo '<span class="extra-info-head">Light Bulbs:</span> ';
$custom_fields = get_post_custom();
$bulbs = $custom_fields['wpcf-light-bulbs'];
foreach ( $bulbs as $key => $value ) {
echo $value;
}}
Apologies if these are poorly written and much appreciation to any suggestions and help!
*UPDATE: This was solved with a combination of the answer below and back-end options on WordPress's custom field posts.
Unfortunately, every time I do so, the code breaks the site because it is incorrectly written.
Your site is erroring out because you have an "undeclared variable."
In the callback function show_coverage(), you are using an undefined variable $post. The function doesn't know about this variable, because you haven't brought it into the function' scope.
While you could include the global $post, it's better to use the API function instead of the global variable.
$coverage = get_post_meta( get_the_ID(), 'wpcf-coverage-area' );
Let's go one step further. What if the custom metadata doesn't exist in the database? Then $coverage is not going to have anything in it. Let's protect for that by checking and then bailing out if nothing is returned.
function show_coverage() {
$coverage = get_post_meta( get_the_ID(), 'wpcf-coverage-area' );
if ( ! $coverage ) {
return;
}
echo '<span class="extra-info-head">Coverage Area:</span>';
foreach ( $coverage as $key => $value ) {
echo $value . '<br/>';
}
}
Now, let's do the same treatment to the other callback function:
function show_bulbs() {
$bulbs = get_post_meta( get_the_ID(), 'wpcf-light-bulbs' );
if ( ! $bulbs ) {
return;
}
echo '<span class="extra-info-head">Light Bulbs:</span> ';
foreach ( $bulbs as $key => $value ) {
echo $value;
}
}
Now the above functions will fetch the custom field (which is metadata). If it does not exist, you bail out. Otherwise, you start building the HTML markup and rendering it out to the browser.