N2CMS: restricting the number of ContentItems of a certain type below another ContentItem - n2cms

I'm using N2CMS, and I have two classes that inherit from ContentItem - say HomePage and NewsPage. NewsPage is set to only appear under HomePage (using the RestrictParents attribute):
[RestrictParents(typeof(HomePage))]
Can I make it so there is a maximum number of NewsPages (in this case 1) below the home page?

The answer is that you can use the
[RestrictCardinality]
attribute. In the example I gave in the question, you would use
[RestrictCardinality(ComparableType=typeof(NewsPart), MaximumCount=1)]

Related

How can I inherit page properties in AEM 6.2?

In our AEM 6.2 project, I ran to a scenario where I need to config a navigation in one page (let call this Homepage), all of the other pages can use home navigation config or use their own navigation config values.
I decided to use live copy because the clone pages can cancel the linked properties at any time and use their own values. But there is two problem with this approach:
Users must set the template for clone pages by edit their jcr: content/sling:resourceType and jcr: content/cq: template because the navigation is used in all pages and our web uses about 5+ templates.
Live copy does no allowed clone pages are children of source pages. But I was required to make web structure like this :
Home
|_ Page 1
|_ Page 1.1
|_ Page 2
|_ Page 3
Live copy maybe not suitable for this situation, we change to use HTL ${inheritedPageProperties}, this solve the template and structure issue but it creates two new problems:
Inherited properties in property config dialog of child page will be blank (because they are not set and called via ${inheritedPageProperties} )
If users change properties in "Page 1" page, "Page 1.1" (and Page 1.1.1, etc ...) will use these values (Because ${inheritedPageProperties} search the upper nodes to get value).
What our client want are :
All page can use navigation setting only from the homepage or their own page (use home page by default).
If use homepage properties, these values must show in their config dialog.
Try to avoid config template in CRXDE Lite
The website must have the parent-child structure
How can I achieve these requirements?
You can achieve this with a simple Sling Model and Sling's CompositeValueMap
CompositeValueMap docs state:
An implementation of the ValueMap based on two ValueMaps: - One containing the properties - Another one containing the defaults to use in case the properties map does not contain the values. In case you would like to avoid duplicating properties on multiple resources, you can use a CompositeValueMap to get a concatenated map of properties.
We can use this by supplying the descendant's value map (the current page's) then finding the correct ancestor and supplying its properties valuemap as the defaults.
for the purposes of this question, I always assume that 2rd descendant from root is always the ancestor (you can find your ancestor according to your requirnments)
package com.sample.helpers;
import com.day.cq.wcm.api.Page;
import com.day.cq.wcm.api.PageManager;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ValueMap;
import org.apache.sling.api.wrappers.CompositeValueMap;
import org.apache.sling.models.annotations.Model;
import org.apache.sling.models.annotations.injectorspecific.OSGiService;
import org.apache.sling.models.annotations.injectorspecific.Self;
import javax.annotation.PostConstruct;
#Model(adaptables = Resource.class)
public class CustomInheritedPageProperties
{
ValueMap inheritedProperties;
#Self
Resource currentResource;
#OSGiService
PageManager pageManager;
#PostConstruct
protected void init() {
// get the current page, or the "descendant"
Page descendant = pageManager.getContainingPage(currentResource);
/* You have to add your custom logic to get the ancestor page.
* for this question's purposes, I'm always assuming it's the 3rd decendant of root
* more here: https://helpx.adobe.com/experience-manager/6-2/sites/developing/using/reference-materials/javadoc/com/day/cq/wcm/api/Page.html#getParent(int)
*/
Page ancestor = descendant.getParent(2);
// create a CompositeValueMap where the properties are descendant's and the defaults are ancestor's
inheritedProperties = new CompositeValueMap(descendant.getProperties(), ancestor.getProperties());
}
public ValueMap getInheritedProperties()
{
return inheritedProperties;
}
}
Now you can use this as follows
<sly data-sly-use.propHelper="com.sample.helpers.CustomInheritedPageProperties">>/sly>
<!--/* someProp here refers to the property you wish to get (inherited, of course)*/-->
<h1>propHelper.inheritedProperties.someProp</h1>

With setResponsePage, how can I add the page version of the page I want?

With setReponsePage, how can I add the page version of the page I want? So for example 3 in http://localhost:8080/wicket-testing/?3.
Thanks.
You need to use #setResponsePage(Page) instead, not #setResponsePage(Class).
First you need to get a reference to the page with that id: session.getPageManager().getPage(pageId).
Are you confusing wicket pages (where the constructor does not need a wicket-id) with panels (where you have to provide a wicket-id)?
setResponsePage itself accepts either a class (with optional PageParameters) or an instance as a parameter:
setResponsePage(DestinationPage.class);
setResponsePage(DestinationPageWithPageParameters.class, new PageParameters().add("id", 42));
setResponsePage(new DestinationPageWithConstructorParameters(param1, param2));
If you are talking about panels (e.g. MyPanel(String wicketId)) then you need to embed this panel into a wicket page because you cannot pass a panel to setReponsePage.

Kentico: Can i get Page Title via nodeID?

I would like to display a list of a couple of my pages in a list.
Is there a macro or something else to get the page title of another site then the actual one?
All i need is a little smart function that can give me the name of a page.
Thanks for your help.
If you have the nodeID of the page you want the title of, you can use the TreeHelper static functions.
TreeNode yourNode = TreeHelper.SelectSingleNode(nodeID);
then easily enough access the name from there.
yourNode.DocumentName;
Note the difference between a TreeNode and a Document is that there are possibly multiple Document's for one TreeNode, where each is a different language/culture.

Prestashop - variables not accessible in header.tpl-$category class not available

I am currently learning template variables and trying to understand how they work and what they mean.
I've done a test on {$category->id_cms_category}, which I put in cms.tpl and I get a result 9, but when I put this in header.tpl or blockcms.tpl (left column), there is no results, it's blank.
Can somebody please explain how this works and how I can get the same result in different .tpl file?
I think the question is really how to assign $category class to for example header.tpl. Is it something to do with controllers?
Why can't I use certain variables everywhere? How does this work? I would be very happy if somebody explain this.
I am also still learning smarty.
Unfortunately you're hitting a common problem with smarty, and particularly how it's implemented within Prestashop.
Smarty variables are very much limited in scope within Prestashop and their scope is determined by which point the portion of code they are assigned in is run. In the case of {$category->id_cms_category} it is assigned within the CMSController at the point in which the main content (important stuff in the middle) is rendered, and so will be available within cms.tpl as you have demonstrated.
The reason it isn't available in the left column or in the header is due to the order in which each of these sections are rendered. This will be:
a) Header (top of page rather than the html header block specifically), then
b) Left Column, then
c) "Main" Content, then
d) Right Column, then
e) Footer
You should find that if you were to reference it in the right column or the footer of the page, then magically it will be available to you (on CMS pages only of course as we're relying on the CMSController being run and assigning it a value).
If you need to reference things like the cms category within the header of the page (maybe to set a highlight on horizontal navigation) then you're going to need to fetch the value and assign it to smarty yourself. You can do this in one of two ways:
1) Write a module which is hooked into the header and assign your variable there
2) Override the FrontController class and assign the smarty variable there (e.g. in the init function)
An example of 2) which you could try is to create a file /override/classes/FrontController.php containing:
<?php
class FrontController extends FrontControllerCore
{
function init() {
parent::init();
$id_cms_category = (int)Tools::getValue('id_cms_category');
$id_cms_page = (int)Tools::getValue('id_cms');
self::$smarty->assign(array(
'my_cms_category_id' => $id_cms_category,
'my_cms_page_id' => $id_cms_page
)
);
}
}
The above should allow you to display {my_cms_category_id} and {my_cms_page_id} anywhere in your theme (because we're setting the smarty variables before everything else is rendered). For a non-cms page they should both be 0, my_cms_category_id should be set non-zero on cms category pages, and {my_cms_page_id} should be non-zero when on a specific cms page.
Hope this goes some way to making it a little clearer!

typo3 extension two times on page, different setup?

I have written a Typo3 extension that I want to put 2 times on the same Typo3 page (actually in two parts defined through a templavoila template), but the two instances need different setups!
When I add content to the page through the "Page" module, I can add as many instances of my extension as I want. But in the "Template" module, there is only 1 configuration per page.
So my question is: what is the best way to have different typoscript setups for different instances of a single plugin on the same page?
Thanks for any hints!
If a configuration option is not available as flexform, or there are other reasons why to change the options via TypoScript, you may do it like this:
temp.tx_yourextension < plugin.tx_yourextension
plugin.tx_yourextension >
plugin.tx_yourextension = CASE
plugin.tx_yourextension {
# check for the uid of the content element (the plugin)
key.field = uid
# if nothing special is defined
default < temp.tx_yourextension
# the plugin with the uid 1234 needs different configuration
1234 < temp.tx_yourextension
1234 {
property = whatever
}
}
Instead of requesting the uid, you could check for section_frame or any other field.
But keep in mind, some extensions accessing directly the TypoScript via $GLOBALS['TSFE']->tmpl->setup['plugin.']['tx_yourextension.']['property'] which will prevent this option.
You could do the same on tt_content.list.*
# without tx_ prefix
temp.yourextension < tt_content.list.20.yourextension
tt_content.list.20.yourextension >
tt_content.list.20.yourextension = CASE
...
Why using template configuration? You could define some configurations for the frontend plugin itself (with flexforms), so every instance could be customized.
You can use the flexform to have different setups. Each flexform is stored in a separate database field.