Advanced Custom Fields—Custom location rule that matches custom taxonomy - ajax

I am using the Advanced Custom Fields plugin on a WordPress site. I am aiming to have a custom location rule to show the custom filed group when any term within a custom taxonomy is selected.
Following the custom location rule tutorial on the ACF site I have added custom types, operators, and values to the rules row.
My matching function (code below) works only when the page is reloaded, but not via AJAX. How do I add custom taxonomies to the $options array so the matching function can evaluate via AJAX when custom taxonomy terms are checked/unchecked.
function acf_location_rules_match_taxonomyTerm( $match, $rule, $options ){
// vars
$taxonomies = get_object_taxonomies( $options['post_type'] );
$terms = $options['taxonomy'];
// not AJAX
if( !$options['ajax'] ){
// no terms? Load them from the post_id
if( empty($terms) ){
if( is_array($taxonomies) ){
foreach( $taxonomies as $tax ){
$all_terms = get_the_terms( $options['post_id'], $tax );
if($all_terms){
foreach($all_terms as $all_term){
$terms[] = $all_term->term_id;
}
}
}
}
}
if($rule['operator'] == "<==>"){
$match = false;
if($terms){
$current_terms = get_the_terms($options['post_id'], $rule['value']);
if ( $current_terms && ! is_wp_error( $terms ) ) {
$current_term_ids = array();
foreach ($current_terms as $current_term) {
$current_term_ids[] = $current_term->term_id;
}
}
foreach ($current_term_ids as $current_term_id) {
if( in_array($current_term_id, $terms) ){
$match = true;
}
}
}
}
else{
$match = false;
}
}
return $match;
}

Have you tried this using this plugin? might help. though its a bit late. :)
https://wordpress.org/plugins/advanced-custom-fields-meta-location-rule/

Related

Order items logic with Laravel

For my Laravel-application I've implemented a sort-functionality. In the list of the options I show two buttons (up and down) which trigger the functions up and down in the OptionController (see below).
Question 1
At the moment I am justing a DECIMAL(30,15) field for the sort-column in the database. I choose this 30,15 randomly. Can you give me an advice, which DECIMAL(?,?) is best for this sort field?
Question 2
I want to move the up and down logic to a place, where I can use it in different controllers with generic models (e.g. Sort::up($models, $item). What would be the right place to place such a logic? Service? Helper-function? ...?
Question 3
When I create a new item (e.g. option in my example below) I need to set the sort automatically to the sort of the last item + 1. Of course, I could do this in the controller when storing it, but can I put this logic to the model itself? And: Where can I put this logic to use it in more than one model without repeating the code?
namespace App\Http\Controllers;
use App\Models\Option;
use App\Models\Attribute;
class OptionController extends Controller
{
public function up($id, $attributeId) {
$options = Attribute::findOrFail($attributeId)->options;
$option = Option::findOrFail($id);
foreach ($options as $index => $o) {
// Search for the current position of the
// option we have to move.
if( $option->id == $o->id ) {
// Will be first element?
if( $index == 1) {
// Set the sort to current first element sort - 1
$option->sort = $options[0]->sort-1;
} else if( $index > 1) {
// Get the previous and the pre-previous items from the options
$pre = $options[$index-1]->sort;
$prepre = $options[$index-2]->sort;
$diff = ($pre - $prepre) / 2;
$option->sort = $prepre + $diff;
}
break;
}
}
$option->save();
Session::flash('message', __(':option moved up.', [ 'option' => $option->name ]));
Session::flash('message-type', 'success');
return redirect()->back();
}
public function down($id, $attributeId) {
$options = Attribute::findOrFail($attributeId)->options;
$option = Option::findOrFail($id);
foreach ($options as $index => $o) {
// Search for the current position of the
// option we have to move.
if( $option->id == $o->id ) {
// Will be last element?
if( $index == count($options)-2 ) {
// Set the sort to current last element sort + 1
$option->sort = $options[count($options)-1]->sort+1;
} else if( $index < count($options)-2) { // ???
// Get the previous and the pre-previous items from the options
$next = $options[$index+1]->sort;
$nextnext = $options[$index+2]->sort;
$diff = ($nextnext - $next) / 2;
$option->sort = $next + $diff;
}
break;
}
}
$option->save();
Session::flash('message', __(':option moved down.', [ 'option' => $option->name ]));
Session::flash('message-type', 'success');
return redirect()->back();
}
}
You can use a trait for this. See link for more details.

joomla tag form loads whole list from db

I noticed that joomla tag input field is quite stupid. It loads everything from db, in this case 9K tags. Obviously ui becomes so slow.
Any ideas how to fix it? it seems there is already an ajax functionality present, so why not rely on that completely? J ways are crazy.
1 idea is to modify getOption method, and load only the tags that are related to current article editor is editing.
But in this context I don't seem to have article id.
Any ideas how to solve situation? I'm sure some of you've run into this :S
/**
* Method to get a list of tags
*
* #return array The field option objects.
*
* #since 3.1
*/
protected function getOptions()
{
$published = $this->element['published']? $this->element['published'] : array(0,1);
$db = JFactory::getDbo();
$query = $db->getQuery(true)
->select('DISTINCT a.id AS value, a.path, a.title AS text, a.level, a.published, a.lft')
->from('#__tags AS a')
->join('LEFT', $db->qn('#__tags') . ' AS b ON a.lft > b.lft AND a.rgt < b.rgt');
// Filter language
if (!empty($this->element['language']))
{
$query->where('a.language = ' . $db->q($this->element['language']));
}
$query->where($db->qn('a.lft') . ' > 0');
// Filter on the published state
if (is_numeric($published))
{
$query->where('a.published = ' . (int) $published);
}
elseif (is_array($published))
{
JArrayHelper::toInteger($published);
$query->where('a.published IN (' . implode(',', $published) . ')');
}
$query->order('a.lft ASC');
// Get the options.
$db->setQuery($query);
try
{
$options = $db->loadObjectList();
}
catch (RuntimeException $e)
{
return false;
}
// Block the possibility to set a tag as it own parent
if ($this->form->getName() == 'com_tags.tag')
{
$id = (int) $this->form->getValue('id', 0);
foreach ($options as $option)
{
if ($option->value == $id)
{
$option->disable = true;
}
}
}
// Merge any additional options in the XML definition.
$options = array_merge(parent::getOptions(), $options);
// Prepare nested data
if ($this->isNested())
{
$this->prepareOptionsNested($options);
}
else
{
$options = JHelperTags::convertPathsToNames($options);
}
return $options;
}
So I've modified list that gets preloaded, only to load tags that are present in the article (saved as belonging to article). Autocomplete still works with ajax so no loss of functionality there.

Woocommerce - Different 'default' sorting for different categories

I'm trying to override the default sorting option (from settings), to a price based sorting for a few categories where lowest price products should be at the top.
For this I'm trying with
if ( is_product_category( 'shirts' ) ) {
add_filter('woocommerce_get_catalog_ordering_args', 'tk_woocommerce_catalog_orderby');
function tk_woocommerce_catalog_orderby( $args ) {
$args['orderby'] = 'price';
$args['order'] = 'asc';
return $args;
}
}
But, it's not working. What's missing?
How can we achieve Price based (lowest to highest) sorting for specific categories in Woocommerce 2.1.x ?
Thanks
You just need to add the condition inside the filter callback like this
add_filter('woocommerce_get_catalog_ordering_args', 'tk_woocommerce_catalog_orderby');
function tk_woocommerce_catalog_orderby( $args ) {
if( is_product_category( 'shirts' ) ) {
$args['orderby'] = 'meta_value_num';
$args['order'] = 'ASC';
$args['meta_key'] = '_price';
}
return $args;
}

Woocommerce - Cannot delete a product variation

Using WooCommerce 2.6.1
I cannot delete a product variation for a variable product: the record is still in the database after the ajax call.
It seems the ajax call doesn't go through: putting error_log(print_r('remove_variation', true)); doesn't output anything (line 387 in class-wc-ajax.php).
The action is added in the constructor of the class. The function public function remove_variation() is just not called.
Has anyone had the same issue, and found a way to make it work?
/**
* Trash a variation, don't delete it permanently.
*
* This is hooked to
* Hijack WooCommerce's WC_AJAX::remove_variation() "Delete Variation" Trash a variation if it is a subscription variation via ajax function
*/
public static function remove_variations() {
if ( isset( $_POST['variation_id'] ) ) { // removing single variation
error_log("here3");
check_ajax_referer( 'delete-variation', 'security' );
$variation_ids = array( $_POST['variation_id'] );
error_log($_POST['variation_id']);
} else { // removing multiple variations
error_log("here4");
check_ajax_referer( 'delete-variations', 'security' );
$variation_ids = (array) $_POST['variation_ids'];
}
foreach ( $variation_ids as $variation_id ) {
$variation_post = get_post( $variation_id );
error_log(print_r($variation_post, ));
if ( $variation_post && $variation_post->post_type == 'product_variation' ) {
$variation_product = get_product( $variation_id );
if ( $variation_product && $variation_product->is_type( 'subscription_variation' ) ) {
wp_trash_post( $variation_id );
}
}
}
die();
}
remove && $variation_product->is_type( 'subscription_variation' ) to solve the problem of un-deletable variations. http://support.woothemes.com/requests/162693 should provide a patch, issue has been reported.
Deleting the variation completely
This is for WooCommerece version 3+
(this code to be put in functions or a custom plugin: not Rest api)
Trashing the variation does not remove the swatch,
it just makes the swatch disabled.(which may be a litle bit embarasing)
If you don't want the variation in your product portfolio anymore, you should delete it.
If you have created your variation using recognizable string in the slug (SKU), you can use below code.
function delete_variation($product_cat="all",$Sku__search_string="",$force_delete=false,$document_it=false){
// 'posts_per_page' => -1: goes through all posts
if($product_cat=="all") {
$args = array(
'post_type' => 'product',
'posts_per_page' => -1,
);
} else {
$args = array(
'post_type' => 'product',
'posts_per_page' => -1,
'product_cat' => $product_cat
);
}
$query = new WP_Query($args);
while ( $query->have_posts() ) {
$query->the_post();
$post_id = get_the_ID();
$product = wc_get_product($post_id);
$product_id = $product->get_id(); //same as post_id
//if you want to see what you are doing put $document_it to true;
if($document_it) echo "<br>*********** $product_id ****************<br>";
if($Sku__search_string!="") {
$variations = $product->get_available_variations();
foreach($variations as $variation){
//get the SKU slug of the variation
$sku=$variation["sku"];
//get the variation id
$variation_id=$variation['variation_id'];
if($document_it) echo "varid $variation_id <br>";
//and then get the actual variation product
$var_product=wc_get_product($variation_id);
//Check if the search_string is in the slug
//You can modify this, or modify the $args above,
//if you have other criteria
if(stripos($sku,$Sku__search_string)>0){
$is_deleted=false;
//here the variation is deleted
$is_deleted=$var_product->delete($force_delete);
if($is_deleted){
if($document_it) echo "<br>Deleted: $sku";
} else {
if($document_it) echo "<br>Not deleted: $sku";
}
}
}
}
}
}
If you want to delete all variations you may use this

Error 500 "View Not Found" when using SEF and URL Rewriting

I am writing a custom component. I have the view employees. Under this view, I have two layouts, default and modal.
I have a menu item in the toplevel of the main menu, Employees that points to my employee view:
index.php?option=com_mycomponent&view=employees which resolves to domain.com/joomla/employees and displayes the default view as expected.
Now, inside my component I want to link to the modal view, and I do so using JRoute and this url:
index.php?option=com_mycomponent&view=employees&layout=modal
Which resolves to
domain.com/joomla/employees/modal
And produces this error:
500 - View not found [name, type, prefix]: modal, html,
mycomponentView
If I visit index.php using index.php?option=com_mycomponent&view=employees&layout=modal my modal view is displayed.
I have also found that visiting domain.com/joomla/employees/employees/modal displays the correct layout. It is as if joomla is forgetting what view is associated with the menu item at /joomla/employees, and instead looks for the view "modal" unless the extra "employees" is provided in the url.
Also worth noting, domain.com/joomla/employee?layout=modal works fine as well.
Here is what I have for my router.php. This was file was generated for me using the component generator at j-cook.pro.
<?php
defined('_JEXEC') or die;
function MycomponentBuildRoute(&$query){
$segments = array();
if(isset($query['view']))
{
$view = $query['view'];
$segments[] = $view;
unset( $query['view'] );
}
if(isset($query['layout']))
{
$segments[] = $query['layout'];
unset( $query['layout'] );
}
if(isset($query['id']))
{
if(in_array($view, array('edit','view','view','editfacility','view','edit','client','editclient','viewposition','editposition','edit','view','edit','view','view','edit','view','edit','view','edit','view','edit')))
{
$segments[] = (is_array($query['id'])?implode(',', $query['id']):$query['id']);
unset( $query['id'] );
}
};
return $segments;
}
function MycomponentParseRoute($segments)
{
$vars = array();
$vars['view'] = $segments[0];
$nextPos = 1;
if (isset($segments[$nextPos]))
{
$vars['layout'] = $segments[$nextPos];
$nextPos++;
}
if(in_array($vars['view'], array('edit','view','view','editfacility','view','edit','client','editclient','viewposition','editposition','edit','view','edit','view','view','edit','view','edit','view','edit','view','edit'))
&& isset($segments[$nextPos]))
{
$slug = $segments[$nextPos];
$id = explode( ':', $slug );
$vars['id'] = (int) $id[0];
$nextPos++;
}
return $vars;
}
So it is hard to provide an exact answer for this without knowing all the different ways that you want to have urls be parsed. But I will try to give a hint at what will solve this present situation (without hopefully introducing too many new issues!)
The basic issue is that the BuildRoute side does not get a view value so it is not included in the url. On the one hand it is not necessary, because it is in the menu. But it makes it a little harder to parse, so option one is to force there to be a view if you can by changing the top function to start like this:
function MycomponentBuildRoute(&$query){
$segments = array();
if(isset($query['view']))
{
$view = $query['view'];
$segments[] = $view;
unset( $query['view'] );
}
else
{
$app = JFactory::getApplication();
$menu = $app->getMenu();
$active = $menu->getActive();
if ($view = $active->query['view']) {
$segments[] = $view;
}
}
...
In this way, if there is a menu item for this and it has a view we will tack it on. This should generate domain.com/joomla/employees/employees/modal.
You could also probably do this logic on the parse side too. This would go instead of the other option above:
function MycomponentParseRoute($segments)
{
$vars = array();
$app = JFactory::getApplication();
$menu = $app->getMenu();
$active = $menu->getActive();
if ($active->query['view']) {
$vars['layout'] = $segments[0];
$nextPos = 1;
} else {
$vars['view'] = $segments[0];
$nextPos = 1;
if (isset($segments[$nextPos]))
{
$vars['layout'] = $segments[$nextPos];
$nextPos++;
}
}
... continue with final check for id
I would probably use the second option but both are an option. By the way, you are also likely to run into issues if you try to use an id without setting a layout.

Resources