Just changed to WooCommerce 7.2.2. Wc-admin-function.php used to have a query around line 500 that read:
$invalid_variation_count = $wpdb->get_var(
"
SELECT count(post_id) FROM {$wpdb->postmeta}
WHERE post_id in (" . implode( ',', array_map( 'absint', $variation_ids ) ) . ")
AND ( meta_key='_subscription_sign_up_fee' OR meta_key='_price' )
AND meta_value >= 0
AND meta_value != ''
"
);
Now, line 508 reads meta_value > 0 and this breaks the functionality of my shop because variation-products with a price of zero are considered invalid. It leads to a warning in admin (which confuses the shop managers) and potentially prevents free products. There isn't a hook, filter or anything in sight that allows me change the query. I have come up with two possible workarounds, neither of them acceptable (making a change to the core of WC or entering prices of 0.001 which get rounded to 0.00 on the frontend).
Two questions:
Does anybody know why the smart people behind WooCommerce made this did change?
Is there a fix without resorting to changing the core of
WooCommerce?
Related
I have a custom pod, product_type, in that pod I have a custom field named label. I want to find all the pods where the label matches a certain strings.
Iv been trying this (and some other variations):
$mypod = pods('product_type', array(
'where' => 'product_type.label LIKE "%'.$someLabelString.'%"',
'limit'=>-1
));
I've also tried changing the product_type.label part of the query to t.label, but to no avail. I get this error:
Database Error; SQL: SELECT DISTINCT `t`.* FROM `wp_posts` AS `t` WHERE ( ( `product_type`.`label` LIKE "%hello%" ) AND ( `t`.`post_type` = "product_type" ) AND ( `t`.`post_status` IN ( "publish" ) ) ) ORDER BY `t`.`menu_order`, `t`.`post_title`, `t`.`post_date`; Response: Unknown column 'product_type.label' in 'where clause'
Here’s a super handy break down of what field syntax to use for each pod type:
http://pods.io/docs/code/pods/find/#additional-information
Custom simple lists consist of a label (for display) and a value (the underlying “raw” value). For the ‘where’ parameter, you probably need to check against whatever you set as the ‘value’.
When you create a simple custom defined list, a box becomes available for “Custom Defined Options”. As the help pop-up says: “One option per line, use value|Label for separate values and labels”
If you added the label field to your pod, you would just use product_type.label if your pod is table-based for storage, otherwise if it’s meta-based you would use label.meta_value
Excuse me if I ask the obvious, but I am quite mySQL illiterate .
I am referring to a standard wordpress DB install, although this is not a wordpress specific question, but more mySQL general knowledge ..
If I want to change all the values of a certain field across all posts , I usually do :
UPDATE `wp_postmeta` SET `meta_value` = replace(meta_value, 'old_value', 'new_value') WHERE `meta_key` LIKE 'my_meta_key'
The problem is as follows :
In that specific DB , the INITIAL values were inserted with a white space prefix and suffix , e.g. :
"city name"
was actually inserted as
" city name "
of course , being a PHP person, I immediately thought of the trim() command - which I found out exists also in mySQL.
SO now I thought I could just do
UPDATE `wp_postmeta` SET `meta_value` = TRIM('meta_value') WHERE `meta_key` LIKE 'my_meta_key'
But It is not working ..
What Am I doing wrong ? I know that mySQL is "ticks sensetive" ( so to speak ) But I tried both 'meta_value' and `meta_value' ( sorry, markdown limitations seems to truncate the backticks)
Doing replace(meta_value, ' ', '') is dengaurous because some cities havea spaces in their name, and LTRIM RTRIM is somewhat not working for me as well
I also know there is a way to set a variable in sql ( #my_var )
but what is the correct syntax of doing that in my case ?
SET #my_var = `meta_value`
and then
UPDATE `wp_postmeta` TRIM(#my_var) WHERE `meta_key` LIKE 'my_meta_key'
I of course know how to fix it in a php loop (with trim() ) but I would like to learn what is the best way to do it in mySQL..
To refer to the column, you need backticks:
UPDATE `wp_postmeta`
SET `meta_value` = TRIM(`meta_value`)
WHERE `meta_key` LIKE 'my_meta_key';
Your expression TRIM('meta_value') is trimming the string 'meta_value', not the value in the column.
My question is about $wpdb methods in wordpress. Before running these methods for example:
$wpdb->query
$wpdb->get_results
$wpdb->get_var ...
do we need to escape/filter inputs? Is this required/preferred for every method or only some?
Is this enough for example to deal with all illegal chars (example from wordpress codex) :
$wpdb->query(
$wpdb->prepare( "DELETE FROM $wpdb->postmeta WHERE post_id = '13' AND meta_key = 'gargle'" ,$id, $key )
);
EDIT:
As indicated in the answer bellow, indeed for every single user input you should check parameter values prior insertion to the database. Its not about only security, its about general logic of the web app (for example, parsing something on frontend, will not end up with proper result for end user if data you contain in the database is not something what you expect - even that data is not questionable from security standpoint).
Having this said, the prepare method mentioned above for the wordpress - is the method which will guaranty and remove any security concerns from perspective of sql injection.
The example from wordpress codex pages has an error. They should use the %d and %s instead of '13' and 'gargle':
$wpdb->query(
$wpdb->prepare(
"DELETE FROM $wpdb->postmeta
WHERE post_id = %d
AND meta_key = %s
", $id, $key )
);
However, you should check the variables' content type every time. You need to insure that the types are correct. For example, check that the 'post_id' variable content is an integer.
I'm trying to filter my orders which are returned back by the magento API by a customer attribute. I tried several approaches but nothing seem to work.
I'm using Magento 1.4.1.1 atm and the api does this at the moment:
$billingAliasName = 'billing_o_a';
$shippingAliasName = 'shipping_o_a';
$collection = Mage::getModel("sales/order")->getCollection()
->addAttributeToSelect('*')
->addAddressFields()
->addExpressionFieldToSelect(
'billing_firstname', "{{billing_firstname}}", array('billing_firstname'=>"$billingAliasName.firstname")
)
->addExpressionFieldToSelect(
'billing_lastname', "{{billing_lastname}}", array('billing_lastname'=>"$billingAliasName.lastname")
)
->addExpressionFieldToSelect(
'shipping_firstname', "{{shipping_firstname}}", array('shipping_firstname'=>"$shippingAliasName.firstname")
)
->addExpressionFieldToSelect(
'shipping_lastname', "{{shipping_lastname}}", array('shipping_lastname'=>"$shippingAliasName.lastname")
)
->addExpressionFieldToSelect(
'billing_name',
"CONCAT({{billing_firstname}}, ' ', {{billing_lastname}})",
array('billing_firstname'=>"$billingAliasName.firstname", 'billing_lastname'=>"$billingAliasName.lastname")
)
->addExpressionFieldToSelect(
'shipping_name',
'CONCAT({{shipping_firstname}}, " ", {{shipping_lastname}})',
array('shipping_firstname'=>"$shippingAliasName.firstname", 'shipping_lastname'=>"$shippingAliasName.lastname")
);
Which is the default API call I guess. Now I just want to join a customer attribute called update - how do I achieve this simple task?
Or is this not possible on a flat table like sales_flat_order?
Whenever I need to do this I use something like:
Joining An EAV Table (With Attributes) To A Flat Table
It's not well optimised but you should be able to pick out the parts you need.
PS.
I think I'll explain what I mean by optimised since it's important. In the heart of the method is this bit:
->joinLeft(array($alias => $table),
'main_table.'.$mainTableForeignKey.' = '.$alias.'.entity_id and '.$alias.'.attribute_id = '.$attribute->getAttributeId(),
array($attribute->getAttributeCode() => $field)
);
If you know MySQL then you'll know it will only pick one index when joining a table, the more specific the better. In this case only the entity_id and attribute_id fields are being used so MySQL is restricted to those. Both columns are indexed but the cardinality is low.
If the condition also included the entity type then MySQL would have the choice of using IDX_BASE which indexes the columns entity_type_id,entity_id,attribute_id,store_id in that order (it needs to process them left to right). So something like this results in a much improved EAV performance - depending on how many rows on the 'left' table it could be several hundred- or thousand-fold better.
$alias.'.entity_type_id='.$entityType->getId().' AND main_table.'.$mainTableForeignKey.' = '.$alias.'.entity_id AND '.$alias.'.attribute_id = '.$attribute->getAttributeId().' AND '.$alias.'.store_id=0'
I use the following in mysql to get titles in libray sort, e.g. The Godfather is sorted as Godfather.
SELECT apnumber, aptitle, IF( aptitle LIKE 'The %', SUBSTRING( aptitle, 5 ) , IF( aptitle LIKE 'A %', SUBSTRING( aptitle, 3 ) , IF( aptitle LIKE 'An %', SUBSTRING( aptitle, 4 ) , aptitle ) ) ) AS sorttitle etc...
What's the most efficient way in PHP to change a string into a library sorted version? That is dropping any "An ", "A " or "The " at the beginning of a title. Am I correct in assuming I need to be looking at something like:
substr_replace( "The " , "" , 0)
I think you are generally correct, yes. As far as I'm aware, there is nothing built in to either PHP or MySQL to assist with this type of sorting. Code implementations I've seen have all used a set of substring replacement rules to get rid of unwanted prefixes, just as you are assuming above. Generally preg_replace() is used so that you can specify a match at the beginning of the string only:
preg_replace("/^The /",'',$title,1);
Something to consider if you're willing to forego a little disk space and normalization would be to store a second column called something like sort_title, and do the prefix removal before inserting the records. This would allow you to index and ORDER BY on the sort_title field within MySQL, and reduce the complexity of your SELECT statements.
As another aside, this would be a great extension to write for PHP!