We are looking at the best way we can delete empty custom fields which are being created by one of our Wordpress plugins.
This can be achieved by adding the following code to our functions.php file.
This works, and prevents the creation of empty custom fields, but this code also prevents us from updating any of our current product(s) status from in stock to out of stock.
Looking for a way to amend the code below, so that it only stops the creation of empty custom fields, without stopping us from being able to put products to zero as out of stock.
Current code:
add_action('save_post','my_cf_check');
function my_cf_check($post_id) {
// verify this is not an auto save routine.
if ( defined('DOING_AUTOSAVE') && DOING_AUTOSAVE ) return;
//authentication checks
if (!current_user_can('edit_post', $post_id)) return;
//obtain custom field meta for this post
$custom_fields = get_post_custom($post_id);
if(!$custom_fields) return;
foreach($custom_fields as $key=>$custom_field):
//$custom_field is an array of values associated with $key - even if there is only one value.
//Filter to remove empty values.
//Be warned this will remove anything that casts as false, e.g. 0 or false
//- if you don't want this, specify a callback.
//See php documentation on array_filter
$values = array_filter($custom_field);
//After removing 'empty' fields, is array empty?
if(empty($values)):
delete_post_meta($post_id,$key); //Remove post's custom field
endif;
endforeach;
return;
}
Related
I am currently trying to add a value to a Wordpress user's meta field and if the field does not have a value, I would like to add it and if it already has a value, I would like to append it to an array and then update the field. I am using an AJAX call to trigger my php function. The AJAX call is working properly, but something in my php function is not working properly.
What I have so far is this:
`
function lesson_watched() {
$lastValue_php = wp_unslash( $_POST['lesson_value'] );
$current_user_id = get_current_user_id();
$found = get_user_meta( $current_user_id, 'lessons_watched_ids', true );
if( empty( $found ) ) :
update_user_meta( $current_user_id, 'lessons_watched_ids', array( $lastValue_php ) );
else :
$lessons_completed = array_merge(
get_user_meta( $current_user_id, 'lessons_watched_ids', true),
array(
$lastValue_php
)
);
update_user_meta( $current_user_id, 'lessons_watched_ids', $lessons_completed );
endif;
wp_die(); // Ends all AJAX handlers
}
`
I am first calling the value passed through the AJAX call and then I am defining the current user's id value. After that I am creating $found to determine if the meta field exists for that user. If it doesn't, then I converted it into an array and then passed it in update_user_meta(). If it did exist, I tried using array_merge() to merge the already existing array with the newest value. After that, I then updated the user meta field.
I have that user field printed on my page using print_r() and this is what shows up after I watch two different videos:
Array([0]=>Array([0]=>127[1]=>124))
The numbers are for lesson ids when a video is watched, so it is pulling both of those correctly, but it appears it is trying to nest it within another array.
Would you have any advice as to how to remove the outer array? Also, is there a way to only add a lesson id once to the array and prevent it from being added if it is already present?
Thank you,
Ian
What I'm trying to do
I'm currently working on a way to update the price of a product when a user go on the product page.
I'm using an API to get the accurate price.
The problem
The function properly update the meta field sellers on back end, but the value of the meta field won't show on front, even after refresh. I have to update the post manually in the back end for the meta field sellers to show on front when refreshing the page.
What I managed to do so far
I managed to handle the API request, then parsed the response. I also managed to fire the API request and modify the price if necessary in the meta field of my product page with an add_action hook. I'm currently using send_headers hook, which is probably not the one to go with but at least it's kinda working :p
The code
add_action( 'send_headers', 'fetch_seller_price' );
function fetch_seller_price(){
//check if is front
if ( !is_admin() ) {
$post_id = get_the_ID();
//Check if is custom post type
if ('bons-plans' == get_post_type( $post_id )) {
//Get ASIN code from custom meta field
$asin_code = get_post_meta( $post_id, 'asin_code', true );
//check if product code is correct
if (strlen( $asin_code ) == 10) {
$sellers = get_post_meta($post_id, 'sellers', true);
foreach ($sellers as $item => $value) {
//Check if seller is Amazon
if ($value["seller"] == "Amazon") {
//get price from api function
$item_price = amazon_price_request( $asin_code );
//If new price != old price, update sellers array with new product price value
if ($value["product-price"] != $item_price) {
$sellers[$item]["product-price"] = $item_price;
}
}
update_post_meta( $post_id, "sellers", $sellers );
}
}
}
}
}
note: sellers meta field is an nested array whitch contains multiple seller arrays of that form:
["item-2"]=>
array(9) {
["seller"]=>
string(6) "Amazon"
["product-link"]=>
string(23) "https://amzn.to/3E90AFS"
["product-price"]=>
string(2) "42"
}
I tried to var_dump() the sellers array after loading the page on front, and also tried with item_price variable. Both return the right number, but the end result appear as it it were empty.
Any help would be greatly appreciated !
I'm kinda new to PHP and I'm well aware my code is kind of trashy, any idea on how to make it proper is also accepted :p
Ok so the problem where simply the way I parsed the json response, variable was float formated, and the expected format was a string :p
What I tried to do:
I have several custom meta field in a custom post type. I want to retrieve the value of all the meta field with the name 'prix-du-produit' for the 'bons-plans' post type, compare them and store the lowest one inside another meta field named 'prix-promo' and do the same thing for the link attached. All of this should happen when the post is saved, published or updated.
It's basically a tool to select the best price of a product to later display it on front end with the corresponding link to the product. For now this isn't working at all and I'm all out of answer.
What I manage to understand or not
As I understood, using usort() is the best way to proceed since it will sort each array inside the first one, which is perfect for what I tried to achieve as it will allow me to select the link within corresponding to the lowest 'prix-du-produit' value. I also understood that using the publish_post hook should do the trick.
The (crappy) code:
function compare_prices($price1, $price2){
if($price1['prix-du-produit'] == $price2['prix-du-produit']){
return rand(0,1) ? 1 : -1//if it is the same then it is random
}
return $price1[0]['prix-du-produit'] > $price2[0]['prix-du-produit'];
// if not it sorts the array
}
function best_product( $id, $post ) {
if ( get_post_type($post->ID) = 'bons-plans' ) {
$products = get_post_meta( $post->ID, 'liens-produits' );
usort($products, 'compare_prices');
$lowest_price = $products[0]['prix-du-produit'];
$best_link = $products[0]['lien-du-produit'];
update_post_meta( $post->ID , 'lien-affilie' , $best_link);
update_post_meta( $post->ID , 'prix-promo' , $lowest_price);
}
}
add_action( 'publish_post', 'best_product', 10, 2 );
Keep in mind that I am still very new to PHP, so for those who are able to give me hint on what I did wrong will have to give me a precise answer.
I am getting an empty array from the woocommerce_add_cart_item_data filter when a product is added to the shopping cart. Example added to functions.php of WordPress theme;
function TEST_post_filter($a,$b,$c) {
print_r($a); //THIS IS EMPTY ARRAY ie returns Array()
return $a;
}
add_filter('woocommerce_add_cart_item_data', 'Test_post_filter',10,3);
Any idea why this might be? I have found no reference to this issue anywhere. I have tried both basket behaviours ie Redirect to the basket page after successful addition and/ or Enable AJAX add to basket buttons on archives. I can't get my head around it. Plugins I have activated are WooCommerce, and WooCommerce Stripe Gateway.
UPDATE - Code which adds product options to product screen
function option_add_to_product() {
global $product;
//get pizza categories
$categories = get_terms( 'product_cat', array(
'hide_empty' => false,
));
$use_product = [];
for($i=0;$i<count($categories);$i++) {
if(strtolower($categories[$i]->slug) === 'bespoke_product')
array_push($use_product,$categories[$i]->term_id);
}
$include_product = false;
if(! count($use_product))
return false;
for($i=0;$i<count($use_product);$i++) {
$this_product_categories = $product->get_category_ids();
for($ii=0;$ii<count($this_product_categories);$ii++) {
if($this_product_categories[$ii] === $use_prouduct[$i]) {
$include_product = true;
break;
}
}
}
if(! $include_product)
return false;
//template to add product option
require plugin_dir_path(__FILE__) . 'templates/add_product_option.php';
}
You can see the html from add_product_option.php will be added to the product if the product has a a category with the slug "bespoke_product". Note, this method of getting a match for a product is temporary (just technical debt for now).
When the filter woocommerce_add_cart_item_data is called the data posted from the product form is available to the corresponding function. Unsanitised data might read as follows:
[extra_option_one] => 0
[extra_option_two] => 0
[extra_options_three] => 1
[extra_option_four] => 0
[order_note] =>
Each of those options will have a lookup table with a related price e.g. extra_options_three might be £1.50. This cost of this option and any others selected needs to up the price of the specific item being added to the cart. It should not be represented separately. The definition of the option added should go into the product field everywhere that purchased item is shown. I'm working through step by step, but it's not easy at the point I am at! I'm guessing the next is tha I'm going to be able to update the item in this order?
The woocommerce_add_cart_item_data hook is used to add custom data to the cart item on simple add to cart submission, like additional fields included in the <form> where "add to cart" button is located…
So if you are not submitting extra custom data from custom fields on add to cart event on (from single product pages), the first function argument is going to be an empty array…
See those related answer threads using this hook.
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.