I am working on woocommerce api to add order manually.
I have ordered variation product manually and it shows good in edit order page in admin side.
Now, problem is the site using polylang plugin.
In that, there is two language. I can successfully add order in english language.
But when I tried to add product in another language(arabic). It returns some order details in weird text format. In my API it returns :
"product_variation_details": "%d8%a7%d9%84%d8%ad%d8%ac%d9%85: صغير"
In edit order page it shows in proper way:
I have used below code to get order details in API:
$variation_id = $single_items['item_meta']['_variation_id'][0];
if ($variation_id != 0) {
$variation = wc_get_product($variation_id);
$product_variation_details = wc_get_formatted_variation($variation->get_variation_attributes(), true);
}
I have search a lot but cant get better solution. any help would be apriciated. thanks in advance.
It seems that there is some decoding going on.
Urldecode
If I'm taking the given string and print it urldecoded it returns this:
print urldecode("%d8%a7%d9%84%d8%ad%d8%ac%d9%85");
الحجم
I hope this helps
Try replacing everything inside your if with:
$variation = wc_get_product( $variation_id );
$variation_attributes = $variation->get_variation_attributes();
$variation_attributes_decoded = array();
foreach ( $variation_attributes as $name => $value ) {
$decoded_name = rawurldecode( $name );
$variation_attributes_decoded[ $decoded_name ] = $value;
}
$product_variation_details = wc_get_formatted_variation( $variation_attributes_decoded, true );
This is untested.
This is the line from wc_get_formatted_variation() that is outputting your text in question:
$variation_list[] = wc_attribute_label( str_replace( 'attribute_', '', $name ) ) . ': ' . rawurldecode( $value );
As you can see, it's decoding the $value but not the $name. My solution should decode the $name ahead of time.
Edit: just fixed a code error.
Related
I want to change the layout of table present in orders.php. Specifically, instead of having rows containing the data (name, date, status, etc.), I want separate horizontal cards for each product.
Example: https://i.stack.imgur.com/itdGU.png. I'm trying to do this with a shortcode, but I'm not sure if that's the right way. Can anyone give me directions ?
For now I'm trying this way: The code below works and returns all order numbers correctly. However I am getting all the order numbers side by side as a simple line of text: https://i.stack.imgur.com/RqdVC.png. I don't know how to insert div, or css classes to change the layout.
Even if I add css classes, the question that remains is how to add other elements such as name, price, status etc. Not sure it can all be done in one shortcode. Advice ?
// GET ALL ORDERS NUMBER OF CURRENT USER
// Give the callback function a clear and descriptive name.
add_shortcode( 'prcsed_order_numbers' , 'prcsed_order_1' );
function prcsed_order_1() {
// Get all orders for the current user.
$customer_orders = wc_get_orders([
'customer_id' => get_current_user_id(),
]);
// Transform the array of order objects into an array of order names.
$order_numbers = array_map( function( $order ) {
return $order->get_order_number();
}, $customer_orders );
// Return as a string, ready for output,
return implode( ', ', $order_numbers );
}
Expanding on what I was typing before. You can access more order variables using what you were already doing in $order_numbers. Here is what I have tested on standalone WooCommerce test site. You will need to input your customer ID function and modify the return HTML structure for styling and editing simplicity. What I have is not clean but does work.
$results = wc_get_orders([ 'cutomer_id'=>1 ]);
foreach ( $results as $order ) {
$first_name = $order->get_billing_first_name();
$last_name = $order->get_billing_last_name();
$status = $order->get_status();
echo '<h1>' . $first_name . ' ' . $last_name . '</h1><p>' . $status . '</p>';
}
The following link gives you the functions/hooks for the order object that you will need accessing to. https://www.businessbloomer.com/woocommerce-easily-get-order-info-total-items-etc-from-order-object/
My developer left me out to dry and while im able to learn pretty quickly, actually adding code to excisiting piece of code is a struggle while reading the code makes sort of sense. My business got hit by corona and this piece of code is part of my core business. I have to solve this and sadly on my own account as im willing to pay if i had the recources.
I guess this is a very basic question for all but beginners but i'd love to understand it. Been spending alot of time just reading the code and now its time for help.
This piece of code
case 'Summary list':
foreach ( $order_ids as $order_id ) {
$user_id = get_post_meta($order_id, '_customer_user', true);
$groups_user = new Groups_User( $user_id );
$orders_group[$groups_user->groups[0]->group->name][$user_id][] = $order_id;
}
$i = 1;
foreach ($orders_group as $group => $users) {
// Group name
$formater->custom_header($group);
// Table header
$formater->table_header();
Displays the group that the user is in on a PDF. Now i know that the foreach part defines the formatter part. the part in particulair is the
// Group name
$formater->custom_header($group);
Now in the same file i need to display that same group name in the following sequence
case 'Delivery note':
foreach ( $order_ids as $order_id ) {
$order = wc_get_order( $order_id );
$user_id = $order->get_user_id();
if(array_key_exists($order->get_user_id(), $orders_group)) {
$orders_group[$user_id]['order_ids'][] = $order_id;
} else {
$orders_group[$user_id]['order'] = $order;
$orders_group[$user_id]['order_ids'][] = $order_id;
}
}
$og_count = count($orders_group);
$og_i = 1;
foreach ($orders_group as $user_id => $data) {
// Delivery header
$formater->delivery_header();
// Client name
$formater->custom_header($data['order']
->get_formatted_shipping_full_name(), 5);
// Client address
$address = join( ", ", array_filter( array(
$data['order']->get_shipping_address_1(),
$data['order']->get_shipping_address_2(),
$data['order']->get_shipping_city(),
$data['order']->get_shipping_postcode() )
)
);
$formater->custom_header($address, 10);
// Group name
$formater->custom_header($group);
// Table header
$formater->table_header();
Now ive already put the
// Group name
$formater->custom_header($group);
part in there but i am unable to define it in the upper part.
Is someone willing to show me how i can get this to work and possibly explain it since i really like understanding it aswelll.
Edit:
https://imgur.com/a/wKPDaM7
The "Registerd" part is what the
// Group name
$formater->custom_header($group); prints.
In the 2nd image, the blue line, thats where i want that to appear aswell.
I am following the instructions set out in the ACF Gallery page at https://www.advancedcustomfields.com/resources/gallery/ in how to create a native Wordpress gallery using the shortcode and dynamically populating the item IDs from the data in the ACF Gallery field.
Example:
EDIT: I have slightly modified the code to include definition for $image_ids
<?php
// Load value (array of ids).
$images = get_field('product_images');
$image_ids = get_field('product_images', false, false);
if( $images ) {
// Generate string of ids ("123,456,789").
$images_string = implode( ',', $image_ids );
// Generate and do shortcode.
$shortcode = sprintf( '', $images_string );
echo do_shortcode( $shortcode );
}
Now my problem is that the an error returns saying that the value for $image_ids is undefined, and rightly so, can't see where that gets defined at all.
I've got some older code that I used to use:
<?php
// different product sizes (gallery)
if(get_field('product_images')) : ?>
<h3>Product Images</h3>
<?php
$image_ids = get_field('product_images', false, false);
$shortcode = '[' . 'gallery ids="' . implode(',', $image_ids) . '"]';
echo do_shortcode( $shortcode );
endif;
?>
This code does work but returns an error php notice array to string conversion in jetpack-carousel. Yes I am using the 'Tiled Galleries Carousel Without Jetpack' plugin.
https://wordpress.org/support/topic/php-notice-array-to-string-conversion-in-jetpack-carousel/page/2/
I really want to follow the recommended way set out in the ACF documentation but it does not work for me. What am I doing wrong?
I don't have ACF installed but after reading their manual, I see a few issues with your code.
Problem one: you are using both $images and $images_ids. Ultimately, both of them are doing the same job and that is to get back the ids array for you. Their data can be different from the last two arguments.
Nonetheless, when you check to see if there is something, you check and evaluation with $images, but then you use $images_ids for your short_code string composition. For the error, I think that is because the version without the optional arguments returned a value while the one($images_ids) that utilized the optional arguments did not return a value but was being utilized anyway by the if clause.
I think you kind of have to figure out, which get_field version you want to use. The one with 3 args or the one with 1 arg.
This was edited after I noticed something, for why you are not getting anything, you may want to contact ACF to update their manual. That sprintf() statement will not do anything. It just going to generate a blank string that all. You may need to alter that sprintf() like the below to follow your old statement, if it still shows array to string conversion error, you would need to debug that.
$image_ids = get_field('product_images', false, false);
if( $image_ids ) {
// Generate string of ids ("123,456,789").
$images_string = implode( ',', $image_ids );
// Generate and do shortcode.
$shortcode = sprintf( '[gallery ids="%s"]', $images_string );
echo do_shortcode( $shortcode );
}
As far as I've tried, the example on the ACF website (https://www.advancedcustomfields.com/resources/gallery/) isn't correct. Here's a less elegant method that worked for me.
<?php
// Get the Gallery Array created by ACF
$galleryarray = get_sub_field('gallery');
// Create an empty array to input the ID's in to
$galleryids = array();
// Loop through the Gallery array
foreach ( $galleryarray as $image ) {
// Grab the image ID
$imageid = $image['id'];
// Put the image ID in to the empty array
array_push($galleryids, $imageid);
}
// Convert the new array into a string, values separated by a comma
$images = implode(',', $galleryids);
// Run the default WordPress Gallery shortcode
echo do_shortcode( '[gallery ids="'.$images.'"]' );
?>
So, this one has my head in for a loop. I've contacted the Support of the plugin and they basically told me I'm SOL, but I refuse to believe there isn't a way to do this.
I'm using AffiliateWP to attribute sales to a single location. Each Affiliate feeds off of a Wordpress User, and for their nickname I've used their address/location.
Unfortunately, the plugin doesn't include this in the Order Details screen or Order Emails, which is a BIG problem. I've frankensteined some code together but keep getting all kinds of undefined errors because they do everything inside classes, which I guess makes sure that people like me can't fiddle in there?
Function for assigning an affiliate to an order: https://github.com/AffiliateWP/AffiliateWP/blob/master/includes/integrations/class-woocommerce.php#L78
Function for retrieving the Affiliates User ID: https://github.com/AffiliateWP/AffiliateWP/blob/master/includes/affiliate-functions.php#L204
Function for retrieving the Affiliates Name: https://github.com/AffiliateWP/AffiliateWP/blob/master/includes/affiliate-functions.php#L132
[Edit] And finally, my Frankenstein:
add_action( 'woocommerce_admin_order_data_after_billing_address', 'my_custom_checkout_field_display_admin_order_meta', 10, 1 );
function my_custom_checkout_field_display_admin_order_meta($order){
global $Affiliate_WP_WooCommerce;
echo '<p><strong>'.__('My Field').':</strong> ' . affiliate_wp()->affiliates->get_affiliate_name( $affiliate_id ) . '</p>';
}
This doesn't throw me an error, but it does throw me a blank area...
Try this:
add_action( 'woocommerce_admin_order_data_after_billing_address', 'my_custom_checkout_field_display_admin_order_meta', 10, 1 );
function my_custom_checkout_field_display_admin_order_meta($order){
global $Affiliate_WP_WooCommerce;
$order_id = $order->get_id();
$referrals = affiliate_wp()->referrals->get_by( 'reference', $order_id);
$affiliate_id = $referrals->affiliate_id;
echo '<p><strong>'.__('My Field').':</strong> ' . affiliate_wp()->affiliates->get_affiliate_name( $affiliate_id ) . '</p>';
}
the affwp_get_affiliate_name method returns blank on three conditions:
if ( ! $affiliate = affwp_get_affiliate( $affiliate ) ) {
return '';
}
if ( ! $user_info = get_userdata( $affiliate->user_id ) ) {
return '';
}
...
// If neither are set, return an empty string.
if ( empty( $first_name ) && empty( $last_name ) ) {
return '';
}
Start by manually passing an affiliate id you know to be associated with a record that contains a $first_name and/or $last_name, for example:
echo '<p><strong>'.__('My Field').':</strong> ' . affiliate_wp()->affiliates->get_affiliate_name(5) . '</p>';
This will rule out if the problem is with the $affiliate_id that you're currently passing it. If you get values returned, it should be a simple matter to fix.
After trying that I would experiment with changing the priority of the add_action(), raising it to 999 or something because it could possibly be executing before the relevant hooks in the plugin.
I have a section on my wordpress website that currently displays the child and parent categories of a listing. I would like for only the child categories to be displayed. I wasn't able to figure out the solution on my own, your help is appreciated.
Here is the current code I'm using for this (which also displays parent categories):
<?php
//NEW
$permalink = get_permalink( $id );
//NEW
$seo = get_the_title()." : ";
$Category_links = ' Found in the ';
$term_list_category = wp_get_post_terms(get_the_ID(), 'listings_categories', array("fields" => "ids"));
//THIS CODE REMOVES PARENTS FROM BEING DISPLAYED IN THE LISTING CATEGORIES
foreach ($term_list_category as $k=>$term) {
$children = get_term_children( $term, 'listings_categories');
if ($children)
unset($term_list_category[$k]);
}
$i = 0;
$count = count($term_list_category);
if ( $count > 0 ){
foreach ( $term_list_category as $term_category ) {
$thisCat = get_term_by( 'id', $term_category, 'listings_categories');
//NEW
$url = '<a id="'.$term_category.'" slug="'.$thisCat->{'slug'}.'" class="listing-links-cat" href="#" title="'.$thisCat->{'name'}.'" >'.$thisCat->{'name'}.'</a>';
$i ++;
$seo .= " " . $thisCat->{'name'} . "";
$Category_links .= " " . $url . "";
if($count-1 == $i){
$Category_links .= " and "; $seo .= ", ";
}elseif($count > 1 && $count !== $i){
$Category_links .= ", "; $seo .= ", ";
}
}
$Category_links .= " Categories";
?>
<? echo $Category_links; ?>
But I feel that the overall code can be improved for performance, so it doesn't search the database as much?
Your code is quite ineffecient and also have unnecessary parts to it. Your additional part makes your code even more ineffecient and causes you to hit the db hard.
FLAWS
You get plus 1 for only getting the term id's from the post terms, but unfortunately in this specific case, this tampers your code and this is the starting point of your ineffeciency as you then need to use get_term_by() on every iteration of your foreach loop. This means extra db calls on every iteration for something that should have already been there
The use of get_term_children() adds to the amount of db calls made on every iteration of your foreach loop. Again, you are making unnecessary db calls for something that should have been there in the first place
It is totally unnecessary to count the amount of terms returned by wp_get_post_terms. This adds extra ineffeciency to your code. wp_get_post_terms returns an empty array if no terms exists or a WP_Error object if the taxonomy does not exist. Keep this in mind for later on
SPEEDING IT UP AND STREAMLINING THE CODE
Lets look at what we can do to make your code more effecient
Remove the fields parameter from wp_get_post_terms. As we need more than just the ids of the terms, we need to return the complete term object. You might think that this is ineffecient, but this will save you a lot of db hits and most importantly, time, as you are getting rid of get_term_by() and get_term_children()
There is no proper way to remove parents from wp_get_post_terms(), so the best way will be to just loop over them and ignore/skip them with continue. I assume you are talking about top level terms which have 0 assigned to its $parent property, so you just need to check that the parent value is not 0
Always do proper failure checks. If you don't do that, and your code fails, php error and notices are returned, which is known as bugs. You would want to avoid that. Also, you would always want your code to fail in a controlled, expected manner without bugs. As I stated before, wp_get_post_terms() returns an empty array or a WP_Error object, so this is what you need to check for. If any of these cases occur, immediately halt execution and return the function to avoid bugs and unexpected output
PUTTING THE ABOVE IN CODE
I like to keep my template files short and sweet. For that reason, bulky code the above always goes into a function and I then just call the function in my template files where necessary. Also, just a tip, I have function specific functions files to keep my code organised and not to overload functions.php. my functions.php file is usually not more than 100 lines of code.
For example, this is part of your post's meta, so this will go into a file with other meta functions like displaying the autor name and post date.
function get_post_child_terms( $taxonomy = '' )
{
$current_post = get_queried_object_id();
$terms = wp_get_post_terms( $current_post, $taxonomy );
/*
* Check if $taxonomy has a value, also check for WP_Error or empty $terms. If any of these conditions
* are met, halt execution and return false
*/
if ( !$taxonomy || is_wp_error( $terms ) || empty( $terms ) )
return false;
/*
* We have made it to here safely, now iterate over the terms
*/
foreach ( $terms as $term ) {
/*
* Check for parent terms and ignore them
*/
if ( $term->parent == 0 )
continue;
/*
* Get an array of term names
*/
$term_names[] = $term->name;
}
/*
* Build our string of names
*/
if ( !isset( $term_names ) )
return false;
$string = 'Some text here maybe to start of: ' . implode( ',', $term_names ) . 'Maybe something at the end';
return $string;
}
USAGE
You can now simply call the function in your template as follow:
echo get_post_child_terms( 'listings_category' );
This will produce a list like this
Some text here maybe to start of: Term name 1, Term name 2, Term name 3 Maybe something at the end
FINAL NOTES
The code above is untested and might be a bit buggy.
The code above is the very least that you need. You can extend and misuse it as you see fit to fit your exact needs. A few ideas for extension might be to work in some arguments to where you can choose to display the parent terms or not, and whether the function should return a string of term names or an array of term names. The sky is the limit here
You can build in a cache system to cache your results to optimize these even further.
EDIT
The above code is now tested and is working as expected