I am using the Woocommerce Dynamic Pricing plugin, which is very useful but does not easily allow me to ammend pricing updates via. the database.
Looking at the sample data,
{"set_5339c459a78e7":
{"conditions_type":"all",
"conditions":{"1":{"type":"apply_to","args":{"applies_to":"everyone"}}},
"collector":{"type":"product"},
"mode":"block",
"date_from":"",
"date_to":"",
"rules":{"1":{"from":"","to":"","type":"price_discount","amount":""}},
"blockrules": {"1":{
"from":"2",
"adjust":"1",
"type":"fixed_adjustment",
"amount":"0.26","repeating":"yes"}}}}
it seems that the meta requires set_* to be specific with the product meta, or it will not apply correctly.
Revising the code, I notice this:
$terms = get_terms('product_cat', array('hierarchical' => false, 'hide_empty' => false, 'parent' => 0));
foreach ($terms as $item_id => $item) {
$set_index = $item->term_id;
$name = 'set_' . $set_index;
}
This is bizarre to me, as the term_id appears to be a 13 character alphanumeric string than the expected bigint. Could anyone explain how I can reproduce this string for when I manually update my tables?
I had a look through the code and I found that in /admin/admin-init.php where it specifies the AJAX handlers, this is how it comes up with new set names:
function woocommerce_pricing_product_admin_create_empty_ruleset() {
global $wc_product_pricing_admin;
$wc_product_pricing_admin->create_empty_ruleset( uniqid('set_') );
die();
}
As you can see it just uses PHP's uniqid function prefixed by nothing but "set_" so in the case of product rules it appears to be just a random ID.
Hope that helps.
Related
Is it possible to get all featured sellesrs with dokan (wordpress plugin)?
I found only this option, which gets all sellers, but in returned data, there is no mention if the store is featured or not.
$sellers = dokan_get_sellers();
foreach ($sellers['users'] as $seller) {
$store_info = dokan_get_store_info($seller->ID);
}
Next time you want to know exactly what a functions does and how it does whatever it does, just follow the term. Searching for dokan_get_sellers on all files of the plugin takes us to where the function is written and there we see we can pass an array of arguments to it. One of the arguments it accepts is "featured" and it expects a yes or no for value. So, this is what we can do:
$args = array( 'featured' => 'yes' );
$sellers = dokan_get_sellers( $args );
I did not test it, but it should be right.
I have posts with slugs with special characters. One of them is the following:
http://localhost/wp-json/wp/v2/posts?slug=my-post!
Unfortunately, WP REST API not showing the content since it has (!) within the slug.
Is there any solution you guys would recommend?
I have found the solution (at least for my case), not sure if it'll work for you but may indicate you the way to go. We need to tap into the function used to sanitize the slugs, as I said in my comment, by default is wp_parse_slug_list. Looking at the code the function that actually sanitizes the slug is sanitize_title.
Looking at the source code, wp_parse_slug_list calls sanitize_title with only one argument, which means that the context used is save. This means that, for posts that were already saved without being sanitized by this function, the slug won't match and the post will be inaccessible through the API. The solution is to change the sanitizing function slightly by adding a filter:
add_filter('rest_post_collection_params', function($query_params) {
$query_params['slug']['sanitize_callback'] = 'sanitize_rest_api_slug';
return $query_params;
}, 20, 1);
function sanitize_rest_api_slug( $list ) {
if ( ! is_array( $list ) ) {
$list = preg_split( '/[\s,]+/', $list );
}
foreach ( $list as $key => $value ) {
$list[ $key ] = sanitize_title( $value, '', 'query' );
}
return array_unique( $list );
}
The filter is actually being applied on the function get_collection_params() on the class-wp-rest-posts-controller class, but if you look at the source code, the filter has a variable depending on the post_type, so if you have another special kind of posts defined (besides post) you need to add/change a filter for that kind as well.
I hope this helps somebody else like me, even if it's too late for your issue.
What I need to be able to do is apply a value for an attribute in the URL, so only the products match that attribute are displayed. I don't want to do any widgets or other visible filters on the page.
For this I presume I would need to use one of the webhooks, and filtering out all products that are about to be displayed.
Can anyone advise which hook will be best in this case and a simple explanation on how the triggered function will return the new array of products?
Thanks in advance!
NB: I also want to query a custom attribute, which does not have any terms, just a straight key/value.
UPDATE 1
I'm playing with two techniques; one is very reliable, and that's basically to use:
if (!$product->attributes || $product->get_attribute( 'testKey' ) != $_GET["testKey"]) {
//return;
}
at the top of content-product.php, but of course WooCommerce will still say the original value for found_posts. Certainly not ideal.
I've come across that something like this should work in functions.php:
function testFilter($meta_query) {
$meta_query[] = array (
'key' => 'testKey',
'value' => 'testVal',
'compare' => '='
);
return $meta_query;
}
add_filter( 'woocommerce_product_query_meta_query', 'testFilter', 9 );
Except it doesn't, returns no results, doesn't matter if I use LIKE, EXISTS etc. Am I using it wrong?
UPDATE 2
I'm not going to say this is the answer, as this only seems to look for one value within a group of custom attributes, but this result has helped.
add_filter( 'wpv_filter_query', 'wpv_filter_color_attribute' );
function wpv_filter_color_attribute( $query_args) {
$tax_query = array();
$tax_query['taxonomy'] = 'pa_size';
$tax_query['field'] = 'term_id';
$tax_query['terms'] = $_GET['pa_size'];
$query_args['tax_query'] = array($tax_query);
return $query_args;
}
You should replace "pa_size" with your attribute taxonomy slug, also $_GET['pa_size'] with the right URL parameter.
You can filter products by attributes using above code. I have not tried this. But, this may help you.
I'm trying to setup a bbpress with extended user capabilities.
The problem
My goal is that users need to have different capabilities in each forum, i.e:
UserA can't access ForumW
UserA can only read topics and replies in ForumX
UserA can create topics and write replies in ForumY
UserA can moderate ForumZ
Plugins
These are the plugins I tried so far, but without success:
Ultimate Member, official 1.7 and the new 2.0 version
https://ultimatemember.com/
They claim that they're working on a groups extension for UltimateMember v2, which somehow looks promising, but as of now there's no release date and I still don't know if this extension is going to solve my problem.
itthinx Groups plugin
http://docs.itthinx.com/document/groups/
Allows me to assign multiple groups to users and forums, but there's still a catch.
First attempt
Since itthinx Groups plugin allows me to assign multiple groups to UserA, which is great, it's still not solving my issue.
So, I tried something like this:
ForumX has the following groups assigned: ForumX_readers, ForumX_writers, ForumX_moderators
UserA has the following groups assigned: ForumX_readers, ForumY_writers, ForumZ_moderators
But the problem is, since UserA belongs to groups that have publish_replies and moderate capabilities, he has full access to ForumX.
So what I need is an intersection of the forum-groups and the user-groups - which in this example is ForumX_readers.
The promising part, but...
I digged into the code of the plugin and found the line that handles the capabilities of the user based on his assigned groups and quickly tried to get the current forum groups, to implement the intersection.
Unfortunatelly I was not able to access the global $post, the $_GLOBALS['post'] nor the $_REQUEST[] variables in this part of code. Neither directly nor with an apply_filters() function, that I implemented into the part of the code myself.
UPDATE:
I was able to get the ID with get_posts() and the slug of the current forum/topic.
So, my question
Is there any solution to my first attempt, which I may have overseen?
If not, is there maybe any other plugin that can solve my problem that I'm not aware of?
Or is something like that even impossible in bbpress?
After some further research and trial & error, I finally figured it out.
First step to do is to set up the capabilities, which in my case look something like this.
In the plugins directory, there is the file core/class-groups-user.php. The init_cache() function retrieves the assigned groups to the user, and sets the according capabilities.
To not mess around to much with the core-plugin, I applied a filter to the $group_ids variable which can be found in line: 415.
foreach( $user_groups as $user_group ) {
$group_ids[] = Groups_Utility::id( $user_group->group_id );
}
// added this line
$group_ids = apply_filters('filter_user_group_ids', $group_ids);`
I then created a new plugin, which hooks into this filter.
add_filter('filter_user_group_ids', 'dnmc_filter_groups', 10, 1);
function dnmc_filter_groups($user_group_ids) {
$forum_id = dnmc_get_forum_id();
if(!$forum_id) return $user_group_ids;
$forum_group_ids = Groups_Post_Access::get_read_group_ids( $forum_id);
$user_restricted_forum_group_ids = array_intersect($user_group_ids, $forum_group_ids);
return $user_restricted_forum_group_ids;
}
function dnmc_get_forum_id() {
$args_topic = array(
'name' => basename( untrailingslashit( rtrim($_SERVER['REQUEST_URI'], '/') ) ),
'post_type' => 'topic',
'post_status' => 'publish',
'numberposts' => 1
);
if($topic = get_posts($args_topic)) {
return $topic[0]->post_parent;
}
$args_forum = array(
'name' => basename( untrailingslashit( rtrim($_SERVER['REQUEST_URI'], '/') ) ),
'post_type' => 'forum',
'post_status' => 'publish',
'numberposts' => 1
);
if($forum = get_posts($args_forum)) {
return $forum[0]->ID;
}
return false;
}
I created the following token; however, when I try to use site:coupons as a data selector in a loop action
It does not appear in data selection browser. Note that it does appear as replacement pattern when i use for example "Show a message on the site" action.
I spent lot of time searching in the internet and rules' token' issue queue, i tried to read the source codes of core token , token and rules as well. I also found some information too like data selector are no tokens! or rules only works with entities!
So far i couldn't get this to work no matter hard i tried. My data is not entity. Is there anyway to integrate it with rules?
I couldn't find any official documentation on this so i created an issue with hope that some of the rule's experts can help me out.
Note : if i replace site with coupon-link in the following code, it won't even appear as replacement pattern in rules. but it works fine as token anywhere else but in rules
Thanks in advance
<?php
/**
* Implements hook_token_info().
*/
function coupon_link_token_info() {
$types['coupon-link'] = array(
'name' => t("Coupon link coupon info"),
'description' => t("Info about linked coupon via url."),
);
// Andy Pangus specific tokens.
$tokens['site']['coupon-code'] = array(
'name' => t("Coupon Link Coupon Code"),
'description' => t("The code of the coupon entered via url."),
);
$tokens['site']['coupon'] = array(
'name' => t("Coupon Link Coupon"),
'description' => t("The coupon entered via url."),
'type' => 'commerce_coupon'
);
$tokens['site']['coupons'] = array(
'name' => t("Coupon Link List Coupons"),
'description' => t("The coupons entered via url."),
'type' => 'array'
);
return array(
'types' => $types,
'tokens' => $tokens,
);
}
/**
* Implements hook_tokens().
*
* #ingroup token_example
*/
function coupon_link_tokens($type, $tokens, array $data = array(), array $options = array()) {
$replacements = array();
$sanitize = !empty($options['sanitize']);
// Text format tokens.
if ($type == 'site' && __coupon_link_get_coupon_code()) {
//$format = $data['format'];
foreach ($tokens as $name => $original) {
switch ($name) {
case 'coupon-code':
// Since {filter_format}.format is an integer and not user-entered
// text, it does not need to ever be sanitized.
$replacements[$original] = $sanitize ? filter_xss(__coupon_link_get_coupon_code()) : __coupon_link_get_coupon_code();
break;
case 'coupon':
// Since the format name is user-entered text, santize when requested.
$replacements[$original] = __coupon_link_get_coupon(__coupon_link_get_coupon_code());
break;
case 'coupons':
// Since the format name is user-entered text, santize when requested.
$replacements[$original] = array(__coupon_link_get_coupon(__coupon_link_get_coupon_code()));
break;
}
}
}
return $replacements;
}
?>
A few things.
Tokens are formatted as [type:token] as explained on the hook_token_info api page. For your example, it would be [coupon-link:coupon]. I'm not sure why you're appending your tokens to the site array, as your custom coupon token probably has nothing to do with sitewide tokens like *site_url* or *site_name*.
Because the types are machine names, you should change it to coupon_link as machine names with dashes are not Drupal standard.
If you truly get lost, I suggest also looking at the token example from the examples module.