So, I was following this example on How to change the city field to a dropdown by Jeroen in my Billing/Shipping section of my site.
/**
* Change the checkout city field to a dropdown field.
*/
function city_to_dropdown( $fields ) {
$city_args = wp_parse_args( array(
'type' => 'select',
'options' => array(
'amsterdam' => 'Amsterdam',
'rotterdam' => 'Rotterdam',
'den-haag' => 'Den Haag',
'utrecht' => 'Utrecht',
'leiden' => 'Leiden',
'groningen' => 'Groningen',
),
), $fields['shipping']['shipping_city'] );
$fields['shipping']['shipping_city'] = $city_args;
$fields['billing']['billing_city'] = $city_args; // Also change for billing field
return $fields;
}
add_filter( 'woocommerce_checkout_fields', 'city_to_dropdown' );
Everything works as expected, but here is what I want to do different.
I want to be able to query all the list of cities from the from shipping rates based on city and display them in the dropdown code above.
So then I wouldn’t have to add the cities manually in multiple places. My list of cities will always be the cities added in using the shipping rates based on city functionality.
What do I need to do to be able to remove the manually entered cities and have something similar to the following :
‘options’ => get_list_cities_from_shipping_rate(),
Question :
What filters or hooks in woocommerce do I have to call to be able to return the list of cities in my function get_list_cities_from_shipping_rate() ?
I'm new to writing these custom codes in wordpress. Any help pointers on how to get this started would be appreciated.
Thank you in advance
Try this:
function get_list_cities_from_shipping_rate( $rate_id ) {
$cities = '';
$key = '_wafs_shipping_method_conditions';
$conditions = get_post_meta( $rate_id, $key, true );
foreach ( (array) $conditions as $group ) {
foreach ( (array) $group as $cond ) {
if ( ! isset( $cond['condition'] ) ) {
continue;
}
if (
'city' === $cond['condition'] &&
'==' === $cond['operator']
) {
$cities .= $cities ? ', ' : '';
$cities .= $cond['value'];
}
}
}
$cities = preg_split( '/, */', $cities );
return array_unique( array_filter( $cities ) );
}
Things to note:
On the WooCommerce → Settings → Advanced Free Shipping page, the $rate_id is the one after the post= as in http://example.com/wp-admin/post.php?post=123&action=edit. Hover on the Free shipping rates table rows and you'd see the Edit URL having that post query.
You must use the city's name and not its slug. E.g. Den Haag instead of den-haag. See the image you provided.
Related
I'm using wordpress and elementor and woocommerce for my site : https://endoftheworldlottery.com
I would like to show number of sold products (which are in fact votes) in a nice bar graph on the result page.
I found a nice php code that outputs exactly what I want, but in text in a shortcode as seen here :
function wc_products_allsold() {
// Get last week orders
$all_orders = wc_get_orders(
array(
'limit' => -1,
'status' => array_map( 'wc_get_order_status_name', wc_get_is_paid_statuses() ),
'return' => 'ids',
)
);
// Sum quantities purchased
$count = 0;
$product_sale_list = array();
foreach ( $all_orders as $all_order ) {
$order = wc_get_order( $all_order );
$items = $order->get_items();
foreach ( $items as $item ) {
$product_sale_list[ $item->get_name() ][] = $item[ 'qty' ];
$count = $count + absint( $item[ 'qty' ] );
}
}
foreach ( $product_sale_list as $product_sold => $value ) {
echo "<p><b>$product_sold: </b> " . array_sum( $value ) . " vote(s)</p>";
}
if ( $count > 0 )
echo "<p><b>All votes:</b> $count</p>";
}
print_r($product_sale_list);
I would like to output these data (sold product name and number of sales (or votes), if possible ordered by "popularity", to show them in a nice bar graph, ideally scaled.
I found some graph plugins (visualizer, wpdatatable, etc…) that accept either database (paid, but ok), or json, or serialised PHP array, or URL as data input…
I don't know which method would be better…
In the code I'm using, there are a couple of arrays, but I don't understand which contains what, and I don't know how to output them in a proper json file (using json_encode ?) or serialize them (but what and where ?)
Or maybe just code the graph in php ? But for me, a simple shortcode would be great.
Anyway, I'm lost. Can you help me ?
(I can pay for a custom code.) But I'm sure a simple solution is before my eyes…
PS : Do you like the idea of the site ? It's a fun personal project…
I am building my website. I have a WooCommerce plugin installed and the country I live in it doesn't have postcode or zip. So to calculate the shipping I use districts. I am adding all districts as a dropdown in the cart page in (calculate shipping) area and checkout page. below the code for checkout page
function custom_override_default_postcode_field( $address_fields ) {
// Your postcodes array
$postcode_array = array(
'ALMOHAMMDIAH' => "ALMOHAMMDIAH",
'ALNAEEM' => "ALNAEEM",
'ALZAHRRA' => "ALZAHRRA"
);
$address_fields['postcode']['type'] = 'select';
$address_fields['postcode']['options'] = $postcode_array;
return $address_fields;
}
and adding the district in cart page in (calculate shipping) area code below
'woocommerce_shipping_calculator_enable_postcode', true ) ) : ?>
<p class="form-row form-row-wide" id="calc_shipping_postcode_field">
<?php
// HERE <===== define your array of cities
$postcodes = array('ALMOHAMMDIAH','ALNAEEM','ALZAHRRA');
$current_postcode = esc_attr( WC()->customer->get_shipping_postcode() );
?>
<select name="calc_shipping_postcode" id="calc_shipping_postcode">
<option value=""><?php _e( 'Select a District…', 'woocommerce' ); ?></option>
<?php foreach( $postcodes as $postcode ):
echo '<option value="'.$postcode.'" '.selected( $current_postcode, $postcode ).'>'.$postcode.'</option>';
endforeach; ?>
</select>
</p>
then I change the postcode / ZIP to districts by this core below
function my_text_strings( $translated_text, $text, $domain ) {
switch ( $translated_text ) {
case 'Postcode / ZIP' :
$translated_text = __( 'District', 'woocommerce' );
break;
}
return $translated_text;
}
add_filter( 'gettext', 'my_text_strings', 20, 3 );
All the code above I found them online and changed some text and they are working.
The problem now is that the postcode in WooCommerce backend forces me to use all caps. Some districts must have spaces and I need to do that but I can't figure it out. How can I make the postcode in the backend accept spaces or at least - or _ ?
like ( AL MOHAMMDIAH or AL-MOHAMMDIAH ) instead of (ALMOHAMMDIAH)
btw the codes above I caps all districts so the calculation works. If I added space, _ or - it brock and nothing shows.
There is no easy fix. It would require editing core files and it should never be done if possible. ALL postcode data is sent through the 'cleaning' process, which removes all unwanted data in normal use cases (also made uppercase). There are no filters to stop it.
Now to a solution. There is no simple solution. The best way would be to make a small plugin, which would add field district and remove postcode, but only for your country. Then apply shipping logic to get prices etc. An alternative is to just ignore spaces and live without them, or replace the district names with something else.
What I did to make this work is I changed the state/Country field to be districts and hide the ZIP code. its working fine so far the only downside is the district name comes after the city. I guess its no big deal in the country where I live in
/* district added as state/Country for shipping purposes */
add_filter('woocommerce_states', 'add_custom_states_to_country');
add_filter('woocommerce_countries_allowed_country_states', 'add_custom_states_to_country');
function add_custom_states_to_country( $states ) {
$states['SA'] = array(
'JOR' => __('Abruq-Ar-Rughamah', 'woocommerce'),
'JAL' => __('Al-Adel', 'woocommerce'),
'JAJ' => __('Al-Ajaweed', 'woocommerce'),
'JAD' => __('Al-Ajwad', 'woocommerce'),
'JAW' => __('Al-Amwaj', 'woocommerce'),
'JAS' => __('Al-Andalus', 'woocommerce'),
'JAH' => __('Al-Asalah', 'woocommerce'),
'JZZ' => __('Al-Aziziyah', 'woocommerce'),
'JBH' => __('Al-Baghdadiyah', 'woocommerce'),
);
return $states;
}
and changed the text to districts
add_filter( 'woocommerce_default_address_fields' , 'bbloomer_override_postcode_validation' );
function bbloomer_override_postcode_validation( $address_fields ) {
unset($address_fields['company']); /* remove company */
unset($address_fields['postcode']); /* remove zip */
/*$address_fields['postcode']['required'] = false;*/ /* postcode req */
$address_fields['state']['required'] = true; /* state required */
$address_fields['state']['label'] = __('District'); /* state name to dist */
return $address_fields;
}
I hope this is useful for someone somewhere.
I am using gravity forms plugin, and I'm trying to display the categories as a drop down list in the form I have already created.
If required, please here's a link to my website
I've been on this for too long, and no way out. Kindly help me out.
add_filter( 'gform_pre_render_1', 'populate_categories' );
add_filter( 'gform_pre_validation_1', 'populate_categories' );
add_filter( 'gform_pre_submission_filter_1', 'populate_categories' );
add_filter( 'gform_admin_pre_render_1', 'populate_categories' );
function populate_categories( $form ) {
foreach ( $form['fields'] as &$field ) {
if ( $field->id != 1 ) {
continue;
}
// you can add additional parameters here to alter the posts that are retrieved
// more info: [http://codex.wordpress.org/Template_Tags/get_posts](http://codex.wordpress.org/Template_Tags/get_posts)
$categories = get_categories ;
$choices = array();
foreach ( $categories as $categories ) {
$choices[] = array( 'text' => $categories->name, 'value' => $categories->name );
}
// update 'Select a Post' to whatever you'd like the instructive option to be
$field->placeholder = 'Category';
$field->choices = $choices;
}
return $form;
}
You can dynamically generate drop downs for gravity forms using the syntax provided below in this link. You have to take control over the functions.php file of the theme to retrieve your output as per your requirement.
Here is the clear documentation provided and you can create in a simple manner using this methods. There are two methods available refer to it.
https://www.gravityhelp.com/documentation/article/dynamically-populating-drop-down-fields/
If you face any problem with creation let me know we shall solve it.
I'm new in the php world and i'm trying to build something in wordpress by gravity forms.
Basicly for now I just playing around and try to create some codes I can use when I start building. My question is: I have a form 1 where I can enter a name e.g. Football,Baseball,Hockey and it get saved to my data base. Then I have another form with the id 2 where there is a drop down box, here i want those values(names) submitted in form 1 to be dynamically populated. I have been trying to create a code by finding pieces around some websites (you will properly discover I'm mixing everything together) and ended up with this:
add_filter("gform_pre_render", "test_task");
add_filter("gform_admin_pre_render", "test_task");
add_filter('gform_pre_submission_filter', 'test_task');
function test_task($entry, $form){
if($form["id"] != 2)
return $form;
$entry["1"];
$items = array();
$items[] = array("text" => "Choose Sport", "value" => "");
foreach($posts as $post)
$items[] = array("value" => $post->post_title, "text" => $post->post_title);
foreach($form["fields"] as &$field)
if($field["id"] == 2){
$field["choices"] = $items;
}
return $form;
}
Hope someone can show me how it should be done so I can learn to do it in the future.
Sincerely
Lars
I'm afraid the $entry object is not available to the gform_pre_render, gform_pre_submission_filter or gform_admin_pre_render hooks. Give the following a try.
add_filter( 'gform_pre_render', 'populate_sports_choices' );
add_filter( 'gform_pre_validation', 'populate_sports_choices' );
add_filter( 'gform_pre_submission_filter', 'populate_sports_choices' );
add_filter( 'gform_admin_pre_render', 'populate_sports_choices' );
function populate_sports_choices( $form ) {
// only run for form 2
if( $form['id'] != 2 )
return $form;
foreach ( $form['fields'] as &$field ) {
function populate_sports_choices( $form ) {
foreach ( $form['fields'] as &$field ) {
// only populate the field if it is a select and has the designated css class name
if ( $field['type'] != 'select' || strpos( $field['cssClass'], 'populate-sport' ) === false )
continue;
// get form 1 field 4 entry values
$sports = get_entry_field_values( 4, 1 );
// create the $choices array and set the placeholder choice
$choices = array( array( 'text' => 'Select a Sport', 'value' => '' ) );
// loop through each of the sports and add them to the $choices array
foreach ( $sports as $sport ) {
$choices[] = array( 'text' => $sport['value'], 'value' => $sport['value'] );
}
//replace the field choices with the contents of the $choices array
$field['choices'] = $choices;
}
return $form;
}
/**
* Allows you to retrieve an array of field values.
* Requires either the $field object or a field ID and a form ID.
*
* Example: $values = get_entry_field_values( 5, 113 );
*/
function get_entry_field_values( $field_id, $form_id ) {
global $wpdb;
if ( is_array( $field_id ) ) {
$field_id = rgget( 'id', $field_id );
}
$tablename = $wpdb->prefix . 'rg_lead_detail';
$sql = "SELECT value FROM $tablename WHERE form_id = %d AND CAST(field_number as unsigned) = %d";
return $wpdb->get_results( $wpdb->prepare( $sql, $form_id, $field_id ), ARRAY_A );
}
The above is based on examples from the following sources:
http://www.gravityhelp.com/documentation/page/Dynamically_Populating_Drop_Down_Fields
http://www.gravityhelp.com/forums/topic/drop-down-dynamic-population-from-single-line-text
I don't think you need to write any code at all. This is supported by Gravity Forms itself. In the form editor go to settings > confirmations, then choose redirect, enter the page form 2 is on and select Pass Field Data Via Query String then enter name={Name:1} or something similar depending on the name and id of the fields in Form 1. And then in Form 2, go to the field you want to populate and select advanced and dynamically prepopulate and enter what you typed to the left of the =, in this case name.
The products in my clients website require certain attributes which I have added via Products -> Attributes in the Wordpress administration. In this import script I'm coding I need to use the function update_post_meta($post_id, $meta_key, $meta_value) to import the proper attributes and values.
Currently I have the function like so:
update_post_meta( $post_id, '_product_attributes', array());
However I'm not sure how to properly pass along the attributes and their values?
Right so it took me a while to figure it out myself but I finally managed to do this by writing the following function:
// #param int $post_id - The id of the post that you are setting the attributes for
// #param array[] $attributes - This needs to be an array containing ALL your attributes so it can insert them in one go
function wcproduct_set_attributes($post_id, $attributes) {
$i = 0;
// Loop through the attributes array
foreach ($attributes as $name => $value) {
$product_attributes[$i] = array (
'name' => htmlspecialchars( stripslashes( $name ) ), // set attribute name
'value' => $value, // set attribute value
'position' => 1,
'is_visible' => 1,
'is_variation' => 1,
'is_taxonomy' => 0
);
$i++;
}
// Now update the post with its new attributes
update_post_meta($post_id, '_product_attributes', $product_attributes);
}
// Example on using this function
// The attribute parameter that you pass along must contain all attributes for your product in one go
// so that the wcproduct_set_attributes function can insert them into the correct meta field.
$my_product_attributes = array('hdd_size' => $product->hdd_size, 'ram_size' => $product->ram_size);
// After inserting post
wcproduct_set_attributes($post_id, $my_product_attributes);
// Woohay done!
I hope this function will help other people if they need to import multiple attributes pro-grammatically in WooCommerce!
I tried Daniel's answer, and it didn't work for me. It might be that the Wordpress/Woocommerce code has changed since, or perhaps I didn't quite understand how to do it, but either way that code did nothing for me. After a lot of work using it as a base, however, I came up with this snippet of code and put it on my theme's functions.php:
function wcproduct_set_attributes($id) {
$material = get_the_terms( $id, 'pa_material');
$material = $material[0]->name;
// Now update the post with its new attributes
update_post_meta($id, '_material', $material);
}
// After inserting post
add_action( 'save_post_product', 'wcproduct_set_attributes', 10);
With this, I can take what I set as "material" on my WooCommerce install as a custom attribute and add it to the formal meta as _material. This in turn allows me to use another snippet of code so the WooCommerce search function extends to meta fields, meaning I can search for a material in the WooCommerce search field and have all items with that material appear.
I hope this is useful to somebody.
#Daniels's answer works, won't decide on right or wrong, however if you want to add the values as a taxonomy term under attributes you have to adapt the code as below (set is_taxonomy = 1). Otherwise Woocommerce sees it as custom meta field(?). It still adds the value under attributes. This will only work for strings. For values that are arrays the code has to be adapted.
Additionally it uses the wp_set_object_terms that #Anand suggests as well. I was using that, because all the documentation I could find led to believe that had to be used. However if one only uses the wp_set_object_terms then I couldn't see the attributes in the edit product screen. Using the information from both answers and reading on the subject resulted in the solution.
You will need to tweak the code for things such as product variations.
/*
* Save Woocommerce custom attributes
*/
function save_wc_custom_attributes($post_id, $custom_attributes) {
$i = 0;
// Loop through the attributes array
foreach ($custom_attributes as $name => $value) {
// Relate post to a custom attribute, add term if it does not exist
wp_set_object_terms($post_id, $value, $name, true);
// Create product attributes array
$product_attributes[$i] = array(
'name' => $name, // set attribute name
'value' => $value, // set attribute value
'is_visible' => 1,
'is_variation' => 0,
'is_taxonomy' => 1
);
$i++;
}
// Now update the post with its new attributes
update_post_meta($post_id, '_product_attributes', $product_attributes);
}
Then call the function:
$custom_attributes = array('pa_name_1' => $value_1, 'pa_name_2' => $value_2, 'pa_name_3' => $value_3);
save_wc_custom_attributes($post_id, $custom_attributes);
Thank you for posting the code Daniel & Anand. It helped me a great deal.
Don't know if this is the "correct" way to do this... But I needed a function to add ACF repeater fields with a date value as a attribute on post save, so this was the function I came up with:
add_action( 'save_post', 'ed_save_post_function', 10, 3 );
function ed_save_post_function( $post_ID, $post, $update ) {
//print_r($post);
if($post->post_type == 'product')
{
$dates = get_field('course_dates', $post->ID);
//print_r($dates);
if($dates)
{
$date_arr = array();
$val = '';
$i = 0;
foreach($dates as $d)
{
if($i > 0)
{
$val .= ' | '.date('d-m-Y', strtotime($d['date']));
}
else{
$val .= date('d-m-Y', strtotime($d['date']));
}
$i++;
}
$entry = array(
'course-dates' => array(
'name' => 'Course Dates',
'value' => $val,
'position' => '0',
'is_visible' => 1,
'is_variation' => 1,
'is_taxonomy' => 0
)
);
update_post_meta($post->ID, '_product_attributes', $entry);
}
}
}
Hope this helps someone.