Orchard CMS Projection Query String With Taxonomies - asp.net

I have created a Content Type called "Products" which has a few fields, 2 of which are Taxonomy Fields (Product Type and Material)
Product Types: Cable cleats, Cable clamps, Pole cleats, Cable core
Material: Stainless steel, Aluminium, Galvanised steel
I have a product listing and would like to filter it using the query string, over both taxonomies for example
List all products with product type of Cable cleats and material of Stainless steel
~/products?product-type[]=Cable cleats&material[]=Stainless steel
List all products with product type of Cable cleats or Pole cleats and material of Stainless steel
~/products?product-type[]=Cable cleats&product-type[]=Pole cleats&material[]=Stainless steel
(guessing it will be IDs used not the full text string for all queries)
Is there a way in Orchard to do this? or would it need a custom Module?
Any help would be much appreciated
Many thanks
Anto

Many projection filters have parameters where you can use tokens. To use the query string, you would use the QueryString token, like this: {QueryString:product-type}. Unfortunately, the taxonomy term filter does not currently work with tokens. It shouldn't be too hard to add that possibility however. Most of the code is already there.

Quite an old question, but because it was referenced here, i give here a copy of my answer...
Note: Tried with a recent Orchard dev branch.
Here, for testing, i've done some changes directly in TermsFilter.cs and TermsFilterForms.cs, but based on this example, you will be able to write your own IFilterProvider and IFormProvider...
So, in TermsFilterForms.cs, in the Describe() method where the form is defined, try to add this:
...
),
_ProductType: Shape.TextBox(
Id: "product-type", Name: "ProductType",
Title: T("Product Type"),
Classes: new[] { "text medium", "tokenized" },
Description: T("Enter the product type.")
)
);
...
Then, when editing your filter, you will see a new input field that can be tokenized and where e.g you can put:
{Request.QueryString:product-type}
Then, in TermsFilter.cs, you can inject a tokenizer:
...
private readonly ITokenizer _tokenizer;
public TermsFilter(ITaxonomyService taxonomyService, ITokenizer tokenizer) {
_taxonomyService = taxonomyService;
T = NullLocalizer.Instance;
_tokenizer = tokenizer;
}
...
Then in the ApplyFilter(dynamic contex) method, you can tokenize your product-type field like this:
var termName = _tokenizer.Replace((string)context.State.ProductType, null);
Here, for testing, in the query string product-type parameter, i expect only one value (not an array) that is a term name (not an id). But you can change the code according to your needs...
Then, by using the taxonomy service, you can do things like that:
var taxoPart = _taxonomyService.GetTaxonomyByName("Product Type");
var termPart = _taxonomyService.GetTermByName(taxoPart.Id, termName);
And then you can use e.g the termPart.Id to update the context.Query (see in the code)...
Best

Related

Is there a way in GTM to create a variable tracking the product category of a checkout conversion without duplicate categories?

I currently have a custom variable that pulls ecommerce information out of the data layer and returns with the product categories for that purchase. I did this through two custom variables - the first being "PurchaseProducts", which has the data layer variable of "ecommerce.purchase.products", and then making a second Custom JavaScript variable with the code
function () { return {{PurchaseProducts}}.map(function(a) {return a.category;}); }
This does work on returning the categories for that purchase, however it seems to be returning the category of each item. (For example, "Produce, Produce, Pantry, Health and Beauty, Specialty Cheese, Pantry")
Is there a way to adjust the code to have the different categories be pulled but not have the duplicates? Or should I look into having separate variables for each of the categories?
You just need something like remove duplicate in JavaScript array.
Here is a way:
var arr = ["apple", "mango", "apple", "orange", "mango", "mango"];
var unique = arr.reduce(function (acc, curr) {
if (!acc.includes(curr))
acc.push(curr);
return acc;
}, []);
console.log(unique);
If you search about it. Make sure you are not using JS ES6 since Google Tag Manager not support it. If you are not familiar, when you see const, let, => in the code. It is ES6 and paste it in GTM will show error when previewing.

How to update djangocms-blog post extensions fields position?

I have some post extensions adding new fields in my Posts objects.
I created the migration, launched my website, and I thought that maybe customizing the fieldsets would allow me to customize the position of the post extensions fieldset too.
That didn't seems to be the case. I created a new SmallIntegerField named my_new_field in a PostExtension class that I registered using blog_admin.register_extension(PostExtensionInline) (I also created the PostExtensionInline class by following the doc).
I added a breakpoint in my update_fields function that I'm using to update the order of the fields of my posts (see this SO question and its answer for more infos on this), and I can't find any mention to my_new_field in the fgets arg:
Quit the server with CONTROL-C.
> /home/me/my-test-app/my_test_app/update_fields.py(3)update_fields()
-> return fsets
(Pdb) l
1 def update_fields(fsets, request, obj):
2 breakpoint()
3 -> return fsets
[EOF]
(Pdb) fsets
[(None, {'fields': ['title', 'subtitle', 'slug', 'publish', 'categories', 'abstract', 'sites', 'author']}), ('Info', {'fields': [['tags', 'related'], ['date_published', 'date_published_end', 'date_featured'], 'app_config', 'enable_comments'], 'classes': ('collapse',)}), ('Images', {'fields': [['main_image', 'main_image_thumbnail', 'main_image_full']], 'classes': ('collapse',)}), ('SEO', {'fields': [['meta_description', 'meta_title', 'meta_keywords']], 'classes': ('collapse',)})]
How can I update my field position? (see edit below)
edit: I can't think of a way to tweak the order of the post extension fields. But I realized that my real problem (yeah yeah that's a case of XYproblem) is that I want conditional inline (only include the post extension for a certain apphook that's using a defined BlogConfig instance.
How to conditionally add the inline post extension form/fields to my admin create form based on the BlogConfig instance?
So I figured it out (and it's not pretty, but it works).
I added those lines in my admin.py:
# replace PostAdmin get_inlines function in order to hide event_date on regular blog posts
from djangocms_blog.admin import PostAdmin
from .misc import get_inline_instances as patched_get_inline_instances
PostAdmin.get_inline_instances = patched_get_inline_instances
And here's my code on misc.py:
def get_inline_instances(self, request, obj=None):
from djangocms_blog.cms_appconfig import BlogConfig
from djangocms_blog.admin import PostAdmin
from json import loads
inline_instances = super(PostAdmin, self).get_inline_instances(request, obj)
if "app_config" in request.GET:
# get blog config instance from request
blog_config = BlogConfig.objects.filter(pk=request.GET["app_config"])
# get config from saved json
config = loads(blog_config.values()[0]["app_data"])
# get template_prefix from config
if config:
template_prefix = config['config']['template_prefix']
if template_prefix == "djangocms_blog_agenda":
return inline_instances
return []
I used the template_prefix value in a BlogConfig instance of djangocms_blog to update the code based on the request:
If we have "djangocms_blog_agenda" in the template_prefix, then return the inline instances.
If we don't have this (default BlogConfig, another BlogConfig that do not need my current post extension fields), return an empty list.
The result can be viewed here:
Blog posts list screenshot, we can see that the articles are displayed by most recent "published date" first.
We can select our blog config after a click on "Blog > Add Post...".
Agenda post creation screenshot, we can see that there's a post extension named "event date" (not present in Blog post creation screenshot).
Agenda list screenshot, we can see that the "events" are displayed by nearest future "event date" date.

Search fields in Firebase with Flutter

Somebody has a solution for this:
I have a collection "stores". Every document from the collection "stores" has its fields like name, address, etc., and has a sub collection called "products". Every documento from the subcolletion "products" has its fields like name, price, etc., as shown in the print screen.
Using firestore, how can I search for a word in the "products" sub collection and retrieve the data from its parent? Search for a word in "products" and built a list with the documents of the collection "stores" that have in its subcollection "products" the searched word?
I have something like this in my project:
Future<DocumentSnapshot> get() {
return firestore.collection('products').document('Banana Frita').get();
}
Then, on my other class I would have something like this:
result = await firestoreBloc.get();
print(result.data['name']) // Banna Frita
Let me know if that works for you
PS: queria ter respondido em português :)

$firebaseArray join with other table

I have a Firebase table named Orders:
{productID: xyz,
userID: abc,
quantity: 100}
There is another table Products containing product details. When showing a user's orders, I need to show some product details along with each order. How can I use $firebaseArray for this purpose?
$firebaseArray seems can only go with a table. Here, I'd need to query each ordered product's detail and add the detail to each order. Is the $extend the way to go? If so, any good example would be very appreciated.
Just saw this one. What you want to use is the NormalizedCollection. This way you can write your statement something like this:
var fb = new Firebase('https://<instance>.firebaseio.com');
var norm = new Firebase.util.NormalizedCollection(
fb.child('products'),
fb.child('productDetails')
);
var productsRef = $firebaseArray(norm.ref());

Include "Change Note" when creating content from InvokeFactory

I am creating a content item from a PloneFormGen Form Custom Script Adapter using invokeFactory. Everything is working fine so far, however we want to start generating a comment to be included in the create action, for the history of the item. The comment itself will be generated using fields from the form and some preset text.
Is this something that would be possible from PFG?
The content type is a custom type, and it is versionable. Using Plone 4.3.2, PFG 1.7.14
EDIT
My current code:
from Products.CMFPlone.utils import normalizeString
portal_root = context.portal_url.getPortalObject()
target = portal_root['first-folder']['my-folder']
form = request.form
title = "My Title: "+form['title-1']
id = normalizeString(title)
id = id+"_"+str(DateTime().millis())
target.invokeFactory(
"MyCustomType",
id=id,
title=title,
text=form['comments'],
relatedItems=form['uid']
)
I have tried using keys like comments, comment, message, and even cmfeditions_version_comment within the target.invokeFactory arguments. No luck so far.
I'm not sure if that's possible in a custom script adapter.
The action of you first entry is None. The history automatically shows Create if the action is None. This is implemented here (plone.app.layout.viewlets.content)
# On a default Plone site you got the following
>>> item.workflow_history
{'simple_publication_workflow': ({'action': None, 'review_state': 'private', 'actor': 'admin', 'comments': '', 'time': DateTime('2014/10/02 08:08:53.659345 GMT+2')},)}
Key of the the dict is the workflow id and the value is a tuple of all entries.
So you can manipulate the entry like you want. But I don't know if this is possible with restricted python (custom script adapter can only use restricted python).
But you could also add a new entry, by extending you script with:
...
new_object = target.get(id)
workflow_tool = getToolByName(new_object, 'portal_workflow')
workflows = workflow_tool.getWorkflowsFor(new_object)
if not workflows:
return
workflow_id = workflows[0].id # Grap first workflow, if you have more, take the the one you need
review_state = workflow_tool.getInfoFor(new_object, 'review_state', None)
history_entry = {
'action' : action, # Your action
'review_state' : review_state,
'comments' : comment, # Your comment
'actor' : actor, # Probably you could get the logged in user
'time' : time,
}
workflow_tool.setStatusOf(workflow_id, context, history_entry)

Resources