Replace WooCommerce Class - php

WooCommerce has a class "get_shipping_to_display()" in /wp-content/plugins/woocommerce/classes/class-wc-order.php, that keeps outputting $36 in my invoices (using the Print Invoice & Packing List plugin) as the value for shipping... regardless of what the shipping out is actually.
I've narrowed it down to that class, as using "get_shipping()" displays the actual shipping price.
I don't want to modify WooCommerce core files (so as not to cause problems with updates later on), so how do I go about replacing that class with my own class in functions.php so I can try and narrow down what is causing the issue... and what would that look like?

The last line in the function get_shipping_to_display() is:
return apply_filters( 'woocommerce_order_shipping_to_display', $shipping, $this );
That means that if you create a filter on woocommerce_order_shipping_to_display you can ultimately output whatever you want (though technically contents of that function will still run first). The $shipping variable contains the text output you are seeing now and $this will have all the properties of the class, including the order $id, $status, etc which you could use to do whatever lookups/calculations you want.

Related

What is the cleanest way to override a Wordpress plugins' hook instantiated with $this

I am trying to modify a Wordpress plugins' method without changing the plugin core code itself. I need to set some status flag in a different part of the website.
The method is defined in the plugin class like so:
add_action('plugins_action_name', [$this, 'local_method_name']);
The plugin method does not offer any actions or filters to hook into.
If this wasn't Wordpress but plain PHP I would write my own class, which extends the plugins' original class but has it's own method by the same name - but in Wordpress this gets me nowhere since I just move the problem from one plugin file to the next.
Is there a way to remove the plugins action altogether? And then redefine my own version of it?
Since the add_action has been called with $this - how would I remove it in some functions.php file?
Thanks
UPDATE
Indeed I want to learn how to handle different scenarios. Not expecting a one size fits all solution, but I do need to know how to avoid core changes, as each core-change complicates my deploy/update process exponentially.
Sure I will add some more details. My example plugin is WooCommerce Germanized Pro which comes with a WC_GZDP_Download_Handler::download() method which I needed to modify, in order to set some sort of "Warehouse downloaded the invoice" flag for each order. Which is later used to highlight new orders, filter orders that have been handed over to fulfilment etc.
There seems to be a Invoice Helper class which does in fact have a singleton pattern.
my modification in the download class is trivial:
public static function download( $pdf, $force = false ) {
... /* original code above, now my modifications */
if ($check_some_codition) {
$invoice = $pdf->get_invoice();
update_post_meta($invoice->get_id(), 'some-flag', 'some-value');
}
/* then resume original function (return the file to the browser) */
self::out( $filename, $file, $force );
}

How to display WordPress WooCommerce custom attribute in templates/functions?

Would put this in WP Stack Exchange, but often they say since it has PHP it should be in SO, so never quite sure where is best. Can move if more appropriate.
To display a custom woocommerce product attribute called, “Fabrics” for example I’ve read you could do the following.
$fabric_values = get_the_terms( $product->id, ‘pa_fabrics’);
foreach ( $fabric_values as $fabric_value ) {
echo $fabric_value->name;
}
However, is there a shorter way since we would be using a lot of attributes throughout php templates.
For instance is there a way to simply do, “echo get_the_terms( $product->id, ‘pa_fabrics’);”
Or is there a single function one could add to their site, so that would then be able to echo any product attribute which a single very short line like above like you can when use “Advanced Custom Fields” with non WooCommerce sites?
UPDATE
Found this thread on SO that offers a way to create a single short code to relatively easily get the data. While that's certainly an option, would like to see if there is any cleaner built in ways such as:
echo get_the_terms( $product->id, 'pa_fabrics');
or
echo $product->get_attributes('pa_fabrics');
The last option seems the cleanest and most ideal but results in an error: "Fatal error: Uncaught Error: Call to a member function get_attributes() on null in (my functions.php file where the code was added).
The answer to your question is it depends. Consider for a moment how flexible you need this to be.
Let's start by looking at what is wrong with the 2 suggested examples.
1) echo get_the_terms( . . .
When using a function it's important to know the return type. get_the_terms() will return an array when successful. You need to do something with that array in order to display it.
https://developer.wordpress.org/reference/functions/get_the_terms/
2) echo $product->get_attributes(...
You're heading down the right path :) The error you're seeing tells you that $product isn't what you're expecting it to be. get_attributes() is a method of the WC_Product class. You need to have an instance of that class in order to use it.
One way of getting hold of the product would be to use wc_get_product().
$product = wc_get_product();
Now the second problem you have is with the method itself. get_attributes(), like get_the_terms(), will return an array. It's then your responsibility to display that data.
Instead I believe you're looking for get_attribute(). This method takes an attribute name as its only argument and returns a string of attribute values.
Example:
// Get a product instance. I could pass in an ID here.
// I'm leaving empty to get the current product.
$product = wc_get_product();
// Output fabrics in a list separated by commas.
echo $product->get_attribute( 'pa_fabrics' );
// Now that I have $product, I could output other attributes as well.
echo $product->get_attribute( 'pa_colors' );

WordPress do_action and add_action; running arguments in add_action call

I am currently writing a plugin for WordPress, and I'm stumped with the add_action and do_action functions. I think I may be trying to use them in the wrong context, and if that's the case - could someone point me in the right direction?
I've come from hating WordPress to loving it, I never thought I'd write a wordpress plugin but now I am getting the hang of things, it's not all that different from normal PHP Development.
Anyway, if I was to have the following code in a plugin:
class aCoolPlugin {
function __construct() {
add_action('clear_auth_cookie', array( $this, 'aCoolFunction' ), 10, 2 );
}
function aCoolFunction( $arg1, $arg2 ) {
// Do something with the arguments
}
}
How would I actually run the aCoolFunction function? Now, I have tried the following:
do_action( 'init', "arg1 value", "arg2 value" );
However, before even trying to run that code I realised:
It makes no sense, since it will essentially be running the init action far too early, and;
It just doesn't work anyway!
So, from that I learnt:
I use add_action to hook into already existing functions for WP
do_action is reserved for new hooks really, can't really think of a useful situation where a hook should be called earlier, and then again later?
So, my question now is: How the heck can I pass my variables into the add_action code? The Codex doesn't say anything regarding arguments, so what are my options? or, is my logic and understanding flawed?
And what is the overall goal? The goal is to have a function with set arguments run every time a specific hook is called, and for the original hook to not be called any earlier/later than it should be
The add action does not accept any new variables nor will it return any variables to the function that runs it. But you can access variables that are passed to the function.
function custom_function($arga){
echo $arga;
}
add_action ('callname', 'custom_function', 10, 1);// 1= number of arguments accepted, use 2 for 2 etc...must add variables to do action call
//sometime later in the code
do_action('callname', $arga);
If you want to inject variables in you have to think a little bit back to basics. If you want to access variables within functions that are not passed you have 2 options:
Retrieve them from DB or server storage or similar
Use the Global declaration. You can accesss all variables that are set at the time the do_action is run.
You would rarely call do_action for wordpress hooks (see note below), but you may end up in a situation where you are coding a template FILE (which runs after plugins and then after themes) and you want to keep your logic in the plugin you could add do_action() into the template file and the actions set in the plugin will run at that point. Or similarly if you design a plugin that you want to be able to modify in the theme you could add an action to a late wp hook, within the called function, you could call do_action for your custom hook and hook functions to it in your theme. Loads of possibilities.
Whatever your logic for calling a WP hook early is, don't if you are within the WP load pattern

Get ID of the last product added to the cart in magento

I am trying to get the ID of the product that was most recently added to a user’s cart. A quick google search revealed this function
Mage::getSingleton('checkout/session')->getLastAddedProductId(true);
which is also used in Mage_Checkout_Block_Cart_Crosssell. When I try calling the function in my own controller however, it returns nothing.
I have tried to instantiate a core session via
Mage::getSingleton('core/session', array('name'=>'frontend'))
however this approach does not seem to work. I also tried to create the Crossell block and making the protected method that wraps around getLastAddedProductId function public however that returns null just like it does when I try calling it on its own.
Is there something I have to call or instantiate in order to use this function? Here’s my source listing for reference.
class Mymodule_Addcartaftermath_ItemaddedController extends Mage_Core_Controller_Front_Action {
public function generatemessageAction() {
$parameters = $this->getRequest()->getParams();
if (isset($parameters['ajax_call'])) {
$latest_item_id = Mage::getSingleton('checkout/session')->getLastAddedProductId(true);
$response = array('response' => $latest_item_id);
echo json_encode($response);
} else {
$this->_redirect('/');
}
}
}
I tried poking through the source code, particularly the checkout/model/session.php file in the core and I cannot seem to find the definition of the function. I also looked at it’s parent’s class definition but could not find it there either.
If this method is not available to me is there another way of retrieving the most recent item added? I know that the items are added sequentially and I could perhaps just get the last item of the list of items from the cart however this would not work in the case where the user adds the same item to the cart essentially increasing the quantity rather than actual item itself (e.g. the user adds a laptop the cart when there already is one)
The call to
Mage::getSingleton('checkout/session')->getLastAddedProductId(true);
Is actually clearing the session variable after it is read. Magento uses magic methods extensively. In this case you are using the __call magic method which in turn uses the getData() method. In Mage_Core_Model_Session_Abstract_Varien you will see that they override the default behaviour of getData() to expect the second parameter to be a boolean (The first parameter to getData is the key name for the value you are looking for). That boolean is a flag telling the session to clear the variable after reading.
You could always listen for the checkout_cart_product_add_after event and add the item to your own variable in the session. That event is actually fired on the line before setLastAddedProductId() is called.
try to grep the variable you are looking for. As they are coming from magic methods then its hard to find the exact function you are after so it's easier to see the places where data gets set than where it is used
grep '>setLastAddedProductId' app/code -rsn
to see where the product id gets set to that session variable
app/code/core/Mage/Checkout/Model/Cart.php:255: $this->getCheckoutSession()->setLastAddedProductId($product->getId());
and then you can ask this variable (if it is set else empty())
Mage::getSingleton('checkout/session')->getLastAddedProductId();
and you can see all the things that are in checkout/session and verify if the data is there.
var_dump(Mage::getSingleton('checkout/session'));
Haven't a clue why it works this way but it works for me in Magento 1.6...
<?php
require_once ( "app/Mage.php" );
umask(0);
Mage::app("default");
Mage::getSingleton('core/session', array('name'=>'frontend'));
$session = Mage::getSingleton('checkout/session');
$lastadded = $session->getData("last_added_product_id");
print_r($lastadded);
Apparently you have to instantiate the core/session and then the checkout/session. I've tried it every other way but this is the only way I've found it to work. Perhaps someone can explain why it works this way. Hope this helps you out!

Magento ->getSku() or getData(’sku’) returns empty string

I have Magento 1.3.2 and I have weird issue:
When I am in list.phtml, and I try to fetch the SKU by using getSku() or getData('sku') I get empty string. getName() does work. However, when I do that from other pages, it works well.
I var_dump-ed it and no SKU is shown.
What can cause this?
I'm surprised nobody has given you the easiest and most proper answer yet:
Go to your admin, Catalog >> Attributes >> Manage Attributes. Then edit the 'sku' attribute. Change the "Used in Product Listing" from 'No' to 'Yes'. You will then have access to it from the product object in list.phtml with ->getSku()
The other option is to re-load the product object in the list.phtml using the ID of the product you already have. The code reads something a little like:
$sku = Mage::getModel('catalog/product')->load($_product->getId())->getSku();
Note that $_product is what you are getting in your collection already, and note that getSku is case sensitive (as are all Magento attributes getter/setters).
#Prattski's solution is preferable as you don't really want to be messing with loading/manipulating the objects, but it sounds as though your collection is a little messed up. SKU is one of the core fields that exists in the base catalog_product_entity table, so would be unusual not to be loaded.
Probably sku is not added to the list of attributes when a collection is retrieved. I assume you are talking a bout the file /template/catalog/product/list.phtml. If so, then you need to extend the corresponding code file (/app/code/core/Mage/Catalog/Block/Product/List.php).
I think your best bet is to overload the getLoadedProductCollection() method to:
public function getLoadedProductCollection()
{
return $this->_getProductCollection()->addAttributeToSelect('sku');
}
This might not work, I have not been able to test it, as in my store the sku and all other attributes are accessible in the list.phtml template file.
Try this:
<?php
$current_product = Mage::registry('current_product');
if($current_product) {
$sku = $current_product->getSku();
// output sku
echo $sku;
}
?>
I had same problem too but tried $_product['sku']
it works for me
$_product["sku"]; enough to get the product sku.

Categories