CraftCMS custom entry query - twig

I'm trying to create a custom query for a page in CraftCMS but it seems that, if I link an entry to a template, entry query is already loaded as the entry variable.
I know that I can create a twig extension and link a service class with it, then inside that service, execute a custom query but I would like to hook into the process that initially injects the entry query object into the template.
Does anyone know if that is possible?

Can't you use EVENT_BEFORE_LOAD_ENTRY?
use craft\events\ElementEvent;
use craft\services\Elements;
use yii\base\Event;
Event::on(Elements::class, Elements::EVENT_BEFORE_LOAD_ENTRY, function(ElementEvent $event) {
// Get the entry query object
$entryQuery = $event->query;
// Modify the entry query object as needed
// ...
// Assign the modified entry query object back to the event
$event->query = $entryQuery;
});

Related

Is it possible to query Azure SearchServiceClient for a list of document properties

I have a process that dynamically create fields on an an Azure "Search service", and a separate site that uses the index.
I would like the site that's searching the index to check for the existence of a column before using it, as using it throws an exception.
So is there a way to query the index for the field definitions?
I found the SearchServiceClient has a Get that fetches the definition
var client = new SearchServiceClient(index.IndexSearchServiceName, new SearchCredentials(index.IndexAdminKey));
var indexDefinition = await client.Indexes.GetAsync(ProductSearchFields.ProductsIndex);

Shopware6 : How to create rules for custom field in order

My goal is to achieve something like the following with flowbuilder:
Trigger: order placed (achievable with the flowbuilder)
If : if order.customFields.customtextField not empty (trying to implement this)
Action : send email with (achievable with the flowbuilder)
For this, I am trying to add a custom rule for order following this : https://developer.shopware.com/docs/guides/plugins/plugins/framework/rule/add-custom-rules#create-custom-rule
But, I see that the last created order is not easily accessible in the rule class. Is there a better/recommended way to do check for an order custom field after order is placed?
Within the flow the order is converted back to a cart with the order line items becoming cart line items once again. This is done to make existing rules work for both evaluating carts and orders. This also means the custom fields of a placed order are not available in the context of the cart as they wouldn't be available yet during checkout. Unfortunately within a rule condition there is no ideal way to identify if the cart was converted from an existing order, no less which order it is.
What you could do however is add a new flow action. Within the scope of the action you could have access to the order entity and then decide within the action what to do with it. The triggers for order placed or enter/leave states will dispatch CheckoutOrderPlacedEvent or OrderStateMachineStateChangeEvent respectively. Both of these have a getter for the order entity which you will be able to access from within your action.
public function handle(FlowEvent $event): void
{
$baseEvent = $event->getEvent();
if (!$baseEvent instanceof CheckoutOrderPlacedEvent && !$baseEvent instanceof OrderStateMachineStateChangeEvent) {
return;
}
$order = $baseEvent->getOrder();
// evaluate the order and decide what to do with it
}
I see that another approach that worked for me was with adding a custom trigger(event) which is dispatched when checkout.order.placed event is fired and if that event's order has the custom field that I am looking for.

Customized Tridion Search Index Handler: Custom vs Standard field for page url?

I was playing around with custom Search Indexing Handlers for SDL Tridion 2011 (GA). I got something working, using the very helpful information provided by Arjen, however I am not sure if my execution is the best option.
The requirement is to be able to search for pages in the CMS by url (eg www.example.com/news/index.html). In order to do this I have the created a class using the ISearchIndexingHandler interface (code below). I am indexing the url in the ContentText field of the item, however I am not sure if this would normally contain something else for a page (I think a page only has metadata so this should be OK). The advantage of using this over a custom field is that I can simply type the url in the search box without having to use <url> IN <fieldname> or something like that.
So my question is, is there any reason not to use ContentText for Pages, and is there any advantage in using a custom field? Also bonus marks go to anyone with good ideas on how to handle BluePrinting (if I create a page in a parent publication, I want the local urls also to be indexed in the child publications), and the case where a Structure group path is altered (I guess I can somehow trigger a re-index of child page items from within my indexing handler).
The code:
using System;
using Tridion.ContentManager.Search;
using Tridion.ContentManager.Search.Indexing.Handling;
using Tridion.ContentManager.Search.Indexing.Service;
using Tridion.ContentManager.Search.Indexing;
using Tridion.ContentManager.Search.Fields;
namespace ExampleSearchIndexHandler
{
public class PageUrlHandler : ISearchIndexingHandler
{
public void Configure(SearchIndexingHandlerSettings settings)
{
}
public void ExtractIndexFields(IdentifiableObjectData subjectData, Item item, CoreServiceProxy serviceProxy)
{
PageData data = subjectData as PageData;
if (data != null)
{
PublishLocationInfo info = data.LocationInfo as PublishLocationInfo;
string url = GetUrlPrefix(data) + info.PublishLocationUrl;
item.ContentText = url;
}
}
private string GetUrlPrefix(PageData page)
{
//hardcoded for now, but will be read from publication metadata
return "www.example.com";
}
}
}
You can store the url in the ContextText Property. Thies field is used to index Template content data.
Tridion does not index shared item(s) of child publication.
Indexing is triggered on Item modification(create, update, delete, localize and unlocalize).
Or you can use reindexing tool to reindex ur item. but there is no way to index shared items in child publication.
I don't think you can include the URL prefix in neither your search query as the indexed item. Because shared items are not indexed, you will probably index the Page from the Website Structure layer, which is never published.
When a Structure Group is moved you would have to make an event handler that triggers re-indexing all child pages using a protected method of the TOM.NET API. This method is not part of the public API, so posting the code for that solution would probably declare me a persona non grata with R&D :)
Before you re-index anything you should store the original publish location url of the Structure Group in the TcmEventArgs.ContextVariables property, so you can verify whether or not a re-indexing action is necessary.

Orchard - Query Custom Fields in Content Item

I have a Content Type "News" with custom field "NewsDate" (DateTimeField) and "Active" (BooleanField)
Now I'm need to get 3 active atimes order desc by NewsDate
Get all news, make them toList() and from there manipulate the data is not a solution.
P.S. I need to do something like:
var items = contentManager
.Query(Entities[PageType.Press])
.OrderByDescending<CommonPartRecord, DateTime?>(record => record.PublishedUtc)
.Slice(0, 3);
but instead of PublishedUTC use my custom field "NewsDate" and add Active == true, However it is not possible due to Orchard architecture of storing custom data in a separate field as XML data.
UPDATED:
In a nutshell I want to generate from code behind the following Query:
DECLARE #temp as TABLE(id int, xmldata xml)
INSERT #temp VALUES(1,'<Data><News><NewsDate>07/14/2011 11:42:00</NewsDate><Link Title="" DisplayText="" Link="www.example.com" OpenInNewTab="True">www.example.com</Link></News></Data>')
INSERT #temp VALUES(2,'<Data><News><NewsDate>07/11/2011 12:11:00</NewsDate><Link Title="" DisplayText="" Link="www.example.com" OpenInNewTab="True">www.example.com</Link></News></Data>')
INSERT #temp VALUES(3,'<Data><News><NewsDate>02/21/2012 16:56:00</NewsDate><Link Title="" DisplayText="" Link="www.example.com" OpenInNewTab="True">www.example.com</Link><NewsLink></NewsLink></News></Data>')
SELECT
TOP 3 [id],
[xmldata].value('(Data/News/NewsDate)[1]', 'datetime') as NewsDate
FROM #temp
ORDER BY NewsDate DESC
P.S. I looked through the code for DynamicContentQueryTests, however all the examples uses the Part, and in my case Fields are just in the ContentItem:
E.g. News content type contains NewsDate field (datetime field) and some parts as well
Any suggestions are greatly appreciated.
Querying fields is possible since 1.4 through Projector and underlying index tables and new APIs on Content Manager. Your simplest bet actually may be to create a projection.
To get the values of fields that have been attached directly to a Content Item, you need to first look for the Content Part with the same name as the item, which is created by Orchard. So in your case in the Parts list for each News Content Item you'll find a part called "NewsPart", and inside this the Fields property will have your NewsDate and Active fields.
However, like you say Orchard serializes the field values into XML for storage to prevent it having to change the database structure every time you add/remove a field to/from a content type. For this reason, querying and ordering by fields is not recommended because all the serialized data needs to be de-serialized for each Content Item. If you want to be able to do this, the best way is to make your own Content Part with a Content Part Record and use your own table for storage, then you can do this:
contentManager.Query<NewsPart, NewsPartRecord>()...
...and query/sort on whatever values you like.
Bertrand is correct. Check this link : http://www.davidhayden.me/blog/projector-module-in-orchard-cms. You can implement your requirements easily with Projection Module. The link will tell you the steps to do that. If you don't want a widget, you can create a page with your query too. Once the module is enabled, you will see the option to create a Projection Page in the left hand side navigation.
EDIT :
Can't you simply parse the XML? You can query your content type 'News'. Something like -
var contentItems = contentManager.Query<ContentPart>("News").Join<TitlePartRecord>().Join<AutoroutePartRecord>().Join<CommonPartRecord>().List();
Once you have that, you can access the XML data by :
foreach (var item in contentItems)
{
var contentItem = (ContentItem)item.ContentItem;
ContentItemVersionRecord contentItemRecord = contentItem.VersionRecord;
string data = contentItemRecord.Data;
//Call some function here to parse 'data' and store the object in the list.
}
'data' has the information in XML format that you need.
You can parse it and then store the objects in your list that you can order by your custom field.

Saving custom object programmatically in salesforce

I defined a custom object (called Transaction). I populated it within a trigger. The trigger is defined after insert of Task object. After populating Transaction object i want to save it such that it shows up as a object of type Transaction in data management->storage usage.
How do i do this?
The only way I have saved custom objects is by using dataloader to import them. Not sure how to save them directly from within Sdfc apex code.
Any pointers would be appreciated.
regards
Sameer
Not sure if understand correctly, but in trigger You probably got something like this:
Transaction__c trans = new Transaction__c();
trans.Some_Field__c = 'some value';
And after that You should have add:
insert trans;
Hope that helps

Resources