I got a product custom field named organic with the values yes/no. I want to show a checkbox in our filter that says "Organic". And when checked search for yes values in db. The deafult setup of a checkbox in FacetWP shows the values from db.
How do I set that up in FacetWP?
here is your code for this task, do not forget to re-index after each name change.
/**
* reindex after adding or updating this filter
*/
add_filter( 'facetwp_index_row', function( $params, $class ) {
if ( 'new_facet' == $params['facet_name'] ) { // change my_facet to your facet's name/slug
if ( '1' == $params['facet_value'] ) { // be careful with 1 and 0 as values - https://www.php.net/manual/en/types.comparisons.php
$params['facet_display_value'] = 'Organic'; // text to display in the facet choices
}
if ( '0' == $params['facet_value'] ) {
$params['facet_display_value'] = 'McDonalds';
}
}
return $params;
}, 10, 2 );
Related
I struggle a bit in creating a piece of code, that will have an impact on Advanced Custom Fields within my wordpress instance.
What is the way it should work?
On the admin dashboard/backend, while creating a post a user has access to two tabs (genereated through ACF). In the first tab, there are three toggle buttons (true / false) called: fruits_selection, veggies_selection and items_selection. In the second tab there is a dropdown/select field called platform. I want to avoid providing 'fixed' list of values. Instead I wanted to leave it up to a user. So when he/she marks specific button, then on the select field those values should be visible.
So IF a user will set fruits_selection to TRUE, then the dropdown should have available values [value : label]:
apple-bundles : Mix of apples,
banana-bundles : Bananas basket,
kiwi-set : Tasty kiwi set,
IF a user will set veggies_selection to TRUE, then the dropdown should have available value: potato-bag : 10lbs Potato Bag
IF a user will set items_selection to TRUE, then the dropdown should have available value: basket : Wooden basket
Obviously, the more buttons are set to true, the more values will be available in the select field.
This is my current code:
function acf_load_platform_field_choices( $field ) {
// reset choices
$field['choices'] = array();
$choices = array();
$fruits = get_field('fruits_selection');
$veggies = get_field('veggies_selection');
$items = get_field('items_selection');
if( $fruits ) {
$choices = array_push('apple-bundles : Mix of apples', 'banana-bundles : Bananas basket', 'kiwi-set : Tasty kiwi set');
}
if( $veggies ) {
$choices = array_push('potato-bag : 10lbs Potato Bag');
}
if( $items ) {
$choices = array_push('basket : Wooden basket');
}
// loop through array and add to field 'choices'
if( is_array($choices) ) {
foreach( $choices as $choice ) {
$field['choices'][ $choice ] = $choice;
}
}
// return the field
return $field;
}
add_filter('acf/load_field/name=platform', 'acf_load_platform_field_choices');
Unfortunately, my current code doesn't work. It always makes the dropdown blank (no values) no matter of the button (true/false) selection. On top of that while trying to save it i get the info Updating failed. The response is not a valid JSON response.
So what im doing here wrong?
I'm not sure which hook/action needs to setup to know when the admin is updating shipping/billing addresses once the order has been created.
So what I'm trying to achieve here is:
In WooCommerce order section when the admin updates the shipping/billing address then it triggers an action.
this action basically makes a single curl call to my custom script and lets me know that the address of the order has been changed by the admin.
I'll do some magic in my script.
I found below but I don't think its more from admin side.
// define the woocommerce_admin_order_data_after_shipping_address callback
function action_woocommerce_admin_order_data_after_shipping_address(
$delta_wccs_custom_checkout_details_pro_shipping, $int, $int ) {
// make action magic happen here...
};
// add the action
add_action( 'woocommerce_admin_order_data_after_shipping_address', 'action_woocommerce_admin_order_data_after_shipping_address', 10, 3 );
Please let me know if anyone knows the right action to trigger when order shipping/billing address change.
The woocommerce_admin_order_data_after_shipping_address hook is to display extra content on the order edit page (backend)
To trigger $order_item actions before or after saving to the DB, use:
/**
* Trigger action before saving to the DB. Allows you to adjust object props before save.
*
* #param WC_Data $this The object being saved.
* #param WC_Data_Store_WP $data_store THe data store persisting the data.
*/
function action_woocommerce_before_order_item_object_save( $order_item, $data_store ) {
// Get type
$data_type = $order_item->get_type();
// Before billing changes
if ( $data_type == 'billing' ) {
// Do..
}
// Before shipping changes
if ( $data_type == 'shipping' ) {
// Do..
}
}
add_action( 'woocommerce_before_order_item_object_save', 'action_woocommerce_before_order_item_object_save', 10, 2 );
/**
* Trigger action after saving to the DB.
*
* #param WC_Data $this The object being saved.
* #param WC_Data_Store_WP $data_store THe data store persisting the data.
*/
function action_woocommerce_after_order_item_object_save( $order_item, $data_store ) {
// Get type
$data_type = $order_item->get_type();
// After billing changes
if ( $data_type == 'billing' ) {
// Do..
}
// After shipping changes
if ( $data_type == 'shipping' ) {
// Do..
}
}
add_action( 'woocommerce_after_order_item_object_save', 'action_woocommerce_after_order_item_object_save', 10, 2 );
OR
Use the almost identical woocommerce_before_order_object_save hook that may be even more suitable, because via $order->get_changes() you can trigger/log/compare which $order data has been changed
function action_woocommerce_before_order_object_save( $order, $data_store ) {
// Get changes
$changes = $order->get_changes();
// Billing OR shipping
if ( isset( $changes['billing'] ) || isset( $changes['shipping'] ) ) {
// Do..
}
// OR even more specific (e.g.: shipping first name field was changed)
if ( isset( $changes['shipping_first_name'] ) ) {
// Do..
}
}
add_action( 'woocommerce_before_order_object_save', 'action_woocommerce_before_order_object_save', 10, 2 );
EDIT: it is a known issue that these hooks are called multiple times when they are not intended to be
See: https://github.com/woocommerce/woocommerce/issues/25771
As a workaround, add:
if ( did_action( 'replace_by_the_desired_hook_name' ) >= 2 ) return;
As first line in your callback function
// Define the woocommerce_admin_order_data_after_shipping_address callback .
function action_woocommerce_admin_order_data_after_shipping_address( $order ) {
// This hook will only fire in backend when viewing the order edit screen. Not for orders placed from checkout
};
// add the action
add_action( 'woocommerce_admin_order_data_after_shipping_address', 'action_woocommerce_admin_order_data_after_shipping_address', 10, 1 );
I would like to prevent that some categories are accidentally deleted. For this I use a meta entry for the category to be protected.
I use the following code for this:
// edit: wrong hook! ** add_action( 'delete_term_taxonomy', 'taxonomy_delete_protection', 10, 1 );
add_action( 'pre_delete_term', 'taxonomy_delete_protection', 10, 1 );
function taxonomy_delete_protection ( $term_id )
{
if (get_term_meta ($term_id, 'delete-protect', true) === true)
{
wp_die('Cannot delete this category');
}
}
Unfortunately, instead of my error message, only "Something went wrong" is displayed. Why?
Edit: The `delete_term_taxonomy` is the wrong hook for my code, because it deleted the meta before i can check the meta entry. `pre_delete_term` does fire before anything happens with the category.
The "Why" is because of the following JavaScript that ships with WordPress:
$.post(ajaxurl, data, function(r){
if ( '1' == r ) {
$('#ajax-response').empty();
tr.fadeOut('normal', function(){ tr.remove(); });
/**
* Removes the term from the parent box and the tag cloud.
*
* `data.match(/tag_ID=(\d+)/)[1]` matches the term ID from the data variable.
* This term ID is then used to select the relevant HTML elements:
* The parent box and the tag cloud.
*/
$('select#parent option[value="' + data.match(/tag_ID=(\d+)/)[1] + '"]').remove();
$('a.tag-link-' + data.match(/tag_ID=(\d+)/)[1]).remove();
} else if ( '-1' == r ) {
$('#ajax-response').empty().append('<div class="error"><p>' + wp.i18n.__( 'Sorry, you are not allowed to do that.' ) + '</p></div>');
tr.children().css('backgroundColor', '');
} else {
$('#ajax-response').empty().append('<div class="error"><p>' + wp.i18n.__( 'Something went wrong.' ) + '</p></div>');
tr.children().css('backgroundColor', '');
}
});
The expected response to this POST request is:
'1' if the term was deleted
'-1' if your user doesn't have permission to delete the term.
For all other cases, "Something went wrong" is displayed.
You are terminating the script early with wp_die, yielding an unexpected response, which comes under "other cases".
There isn't a way to provide a custom error message in the notice box here without writing some JavaScript of your own.
This is my current solution, not perfect but it works.
The "Something went wrong" message show up if you delete the taxonomy with the row action. So i unset the "delete" action so it couldn't be triggered this way.
add_filter ('category_row_actions', 'unset_taxonomy_row_actions', 10, 2);
function unset_taxonomy_row_actions ($actions, $term)
{
$delete_protected = get_term_meta ($term->term_id, 'delete-protect', true);
if ($delete_protected)
{
unset ($actions['delete']);
}
return $actions;
}
Then i hide the "Delete" Link in the taxonomy edit form with css. It's still could be triggered if you inspect the site and it's link, but there is no hook to remove this action otherwise.
add_action( 'category_edit_form', 'remove_delete_edit_term_form', 10, 2 );
function remove_delete_edit_term_form ($term, $taxonomy)
{
$delete_protected = get_term_meta ($term->term_id, 'delete-protect', true);
if ($delete_protected)
{
// insert css
echo '<style type="text/css">#delete-link {display: none !important;}</style>';
}
}
Finally the check before deleting the taxonomy. This should catch all other ways, like the bulk action "delete". I didn't found another way yet to stop the script from deleting the taxonomy.
add_action ('pre_delete_term', 'taxonomy_delete_protection', 10, 1 );
function taxonomy_delete_protection ( $term_id )
{
$delete_protected = get_term_meta ($term_id, 'delete-protect', true);
if ($delete_protected)
{
$term = get_term ($term_id);
$error = new WP_Error ();
$error->add (1, '<h2>Delete Protection Active!</h2>You cannot delete "' . $term->name . '"!');
wp_die ($error);
}
}
This solution provides a way to disable all categories from being deleted by a non Admin. This is for anyone like myself who's been searching.
function disable_delete_cat() {
global $wp_taxonomies;
if(!current_user_can('administrator')){
$wp_taxonomies[ 'category' ]->cap->delete_terms = 'do_not_allow';
}
}
add_action('init','disable_delete_cat');
The easiest solution (that will automatically take care of all different places where you can possibly delete the category/term) and in my opinion the most flexible one is using the user_has_cap hook:
function maybeDoNotAllowDeletion($allcaps, $caps, array $args, $user)
{
if ($args[0] !== 'delete_term') return $allcaps;
// you can skip protection for any user here
// let's say that for the default admin with id === 1
if ($args[1] === 1) return $allcaps;
$termId = $args[2];
$term = get_term($termId);
// you can skip protection for all taxonomies except
// some special one - let's say it is called 'sections'
if ($term->taxonomy !== 'sections') return $allcaps;
// you can protect only selected set of terms from
// the 'sections' taxonomy here
$protectedTermIds = [23, 122, 3234];
if (in_array($termId, $protectedTermIds )) {
$allcaps['delete_categories'] = false;
// if you have some custom caps set
$allcaps['delete_sections'] = false;
}
return $allcaps;
}
add_filter('user_has_cap', 'maybeDoNotAllowDeletion', 10, 4);
I want to put user's previous data at the checkout page fields by default in my website which based on woocommerce. I cant set value for first name, last name and phone fields, although I can set value for other fields. How can I solve this problem?
Looking at the WC_Checkout class (/includes/class-wc-checkout.php), it contains a get_value method that is responsible for the default methods in the form.
This method has a filter woocommerce_checkout_get_value that you can use to override the default value that is loaded for each field.
Here's an example that overrides both the first name (both billing and shipping) and the last name:
add_filter('woocommerce_checkout_get_value', function( $value, $input ) {
// first check if user is logged in
if ( is_user_logged_in() ) {
$current_user = wp_get_current_user();
switch ($input) {
case 'billing_first_name':
case 'shipping_first_name':
$value = 'Jack'; // fixed default
break;
case 'billing_last_name':
case 'shipping_last_name':
$value = $current_user->user_lastname; // use lastname from user profile
break;
default:
// don't change if we don't have substituting data
break;
}
}
return $value;
},10 ,2 );
In the same method there's also a filter default_checkout_{form_field} that would let you check existing values first (the former is a short-circuit that prevents the normal default from loading), ex:
add_filter('default_checkout_billing_first_name', 'woocommerce_override_default_checkout_values', 10, 2 );
add_filter('default_checkout_billing_last_name', 'woocommerce_override_default_checkout_values', 10, 2 );
add_filter('default_checkout_shipping_first_name', 'woocommerce_override_default_checkout_values', 10, 2 );
add_filter('default_checkout_shipping_last_name', 'woocommerce_override_default_checkout_values', 10, 2 );
function woocommerce_override_default_checkout_values( $value, $input ) {
// first check if user is logged in
if ( is_user_logged_in() ) {
// only load if value is empty
if (empty($value)) {
// read your own
$value = '...';
}
}
return $value;
}
Is there a way to limit the search only to post titles with Algolia on Wordpress?
I need this for the autocomplete feature.
You can definitely customize on what field the search will be based on.
First of all you have to let Algolia know that you only want to search on the post title field by changing the attributesToIndex setting:
/**
* #param array $settings
*
* #return array
*/
function custom_posts_index_settings( array $settings ) {
$settings['attributesToIndex'] = array( 'unordered(post_title)' );
return $settings;
}
add_filter('algolia_posts_index_settings', 'custom_posts_index_settings');
add_filter('algolia_searchable_posts_index_settings', 'custom_posts_index_settings');
Then you need to customize the suggestions templates of the autocomplete by first moving the autocomplete.php file to your theme's folder like explained in this guide: https://community.algolia.com/wordpress/customize-autocomplete.html
Basically you will remove the part which looks like this one:
<#
var attributes = ['content', 'title6', 'title5', 'title4', 'title3', 'title2', 'title1'];
var attribute_name;
var relevant_content = '';
for ( var index in attributes ) {
attribute_name = attributes[ index ];
if ( data._highlightResult[ attribute_name ].matchedWords.length > 0 ) {
relevant_content = data._snippetResult[ attribute_name ].value;
break;
} else if( data._snippetResult[ attribute_name ].value !== '' ) {
relevant_content = data._snippetResult[ attribute_name ].value;
}
}
#>