How can I easily override SEO Sulu CMS page extension in Symfony? - symfony

I want to override the SeoStructureExtension with my own implementation, which will support OpenGraph (OG) tags.
What is the easiest way to override it and add additional inputs?

I am afraid to say that overriding the SeoStructureExtension file can not be achieved very easily... The fields it saves are hardcoded. So the first thing you would have to do is override the sulu_page.extension.seo service, which references this class. I would say your best bet to achieve this, is to decorate this service.
The other part you have to extend is the XML file describing the page_seo form. Luckily this part is a little bit easier. Your Sulu installation should already come with a config/forms folder, where you can put a file similar to the original page_seo form. Give it the same key (page_seo) and only add the new fields you want to add (the name of the properties have to match what you are implementing in the decorated service). If you e.g. want to add a new text field, this file would look something like this:
<?xml version="1.0" ?>
<form xmlns="http://schemas.sulu.io/template/template"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://schemas.sulu.io/template/template http://schemas.sulu.io/template/form-1.0.xsd"
>
<key>page_seo</key>
<properties>
<property name="ext/seo/ogTitle" type="text_line">
<meta>
<title lang="en">OG Title</title>
</meta>
</property>
</properties>
</form>
Mind the ext/seo/ prefix before ogTitle, which is need for the information to be passed to the SeoStructureExtension.
I also think that these fields might make sense to be added to the core of Sulu. I would be happy if you create an issue, explaining what fields exactly you need etc. Then we can discuss if we implement it in the core as well, so that you don't have to add this manually in future versions.

Related

Custom type not showing up in rule config

Trying to add a folder rule which should specialize cm:content to our custom type my:content (which inherits from cm:content).
We have configured the following in share-config-custom.xml:
<type name="cm:content">
<subtype name="my:content"/>
</type>
Our type shows up correctly in the specialize type action in the document library, but when trying to specify a rule the listbox that should contain our type remains empty. :(
What could we be missing?
You need to add to web-client-config-custom.xml in alfresco/extension
<config evaluator="string-compare" condition="Action Wizards"
replace="true">
<subtypes>
<type name="my:content" />
</subtypes>
<specialise-types>
<type name="my:content" />
</specialise-types>
</config>
And then the trick is to provide title & description for the types in the content model or via messages/properties; otherwise they will not be there.
Wrote about similar issues here: http://experiencewithalfresco.blogspot.dk/2012/08/remember-to-define-title-and.html
For adding custom messages you need to create custom-message-context.xml
<beans>
<bean id="mycompany.resources" class="org.springframework.extensions.surf.util.ResourceBundleBootstrapComponent">
<property name="resourceBundles">
<list>
<value>alfresco.messages.custom</value>
</list>
</property>
Then create custom.properties file and place it in /shared/classes/alfresco/message folder.
And for adding custom type to rule your config should be working only thing to make sure is config inside which you have put sub-type related config is proper.
Disclaimer: This answer is for Alfresco 6.2.2+.
Answering an old thread. For me, I tried this thread all vague answers on Alfresco Hub and nothing worked out.
I have been through this nightmare. Its frustrating and I don't know why Alfresco team relies on "Display Label" instead of "Name".
As shown in the screenshot, I was missing Display Label. As soon as I edited my custom type and provided Display Label, all worked as expected.
If I would have designed it, I would include, Name and Display Label both in the drop down in my rule window.
Hope it helps someone like me.

Is it possible to create a constraint based on another defined type in Alfresco?

I can find anything that would suggest this is possible or otherwise I have the following declared models.
The product:
<type name="syn:produit">
<title>Produit</title>
<parent>cm:cmobject</parent>
<properties>
<!-- properties defined -->
</properties>
</type>
product order:
<type name="syn:produitCommande">
<title></title>
<parent>cm:object</parent>
<properties>
<propert name="productType">
</property>
</properties>
</type>
I would like to constraint the productType of the syn:produitCommande to a list of syn:produit. Is it possible to do this OOTB (I think no is the answer to that), I have seen example codes of dynamic constraints but a lot of "That's a bad idea" warnings that goes with the code. I need advice on how to proceed with resolving this issue with possible code examples. (Not entirely understood the text on how to build the custom constraint yet.)
Fist to answer your question, there is No XML config where you can configure that.
A DB example from the forum is here
I probably wouldn't make a custom constraint if it's only for UI usage.
My approach would be to make a custom form control (in share) which loads a search (through Ajax in json format) from the Repository.
It really is bad idea.
There will be various problems as with each type fix set of properties attached so you cannot configure this thing though model for sure.
I think you have a requirement where you don't want to fix the type of document on creation.
you want to provide the option to user to allow change type of document after it is created right?In that case you can create all your custom content types in model and there is one action called change type in alfresco share which you can configure to showup all your custom content types.In that way even after creating the content you will be able to change its content type.

Spring Message Resource Bundles - Suitable for white labelling and versioning?

I wonder if anyone can help. We are putting together a Spring MVC & Webflow app, and want to put all screen text etc in a database backed message resource bundle. I've got a simple implementation of this working no problem. However, we need to support white labeling the application, including versioning of the text.
When I say 'white labeling' I mean that the core application needs to be branded for different commercial brands. The css elements of the branding is easy - we will be using Spring Themes. But the branding extends to different screen text. For example, brandX might ask "What is your name", and brandY might ask "Please enter your name".
In addition, we need to support versioning of the screen text per brand. This is give a consistent user journey and message to a customer - eg: if they see a given set of screen labels on day 1 and save their quote, they should see the same set of screen labels etc when they retrieve their quote on day 10, even if there have been 5 iterations of screen text for that brand in the mean time. (in reality the frequency of changes wont be that often, but we still need to support it)
I've been playing with this for a while, and in my early experimentation thought I could simply prefix the message keys in the resource bundle:
brandX.firstName = What is your firstname?
brandY.firstName = Please enter your firstname
But this feels wrong on several counts.
Unless we have a view per brand (which we might have to), then the view needs to somehow apply the prefix based on either something in the model or the theme. It feels wrong for the view to know about the model in order to select the right messages to display
I dont know how to apply versioning (other than adding it to the composite key = brandX.firstname.v2 = What is your firstname?)
All in all, I'm coming to the conclusion that this is not what message resource bundles are for - they are great for locale based internationalisation (which is what they are for!), but now I am trying to do something quite different with them. It feels that message resource bundles as a solution may not be right for my requirement.
Has anyone else done anything like this? How did you go about solving it?
Cheers
Nathan
I've done something similar to this with a themed web app that could be deployed with different themes or branding. I also needed to have slightly different labels depending on the "brand" being deployed.
The solution I used was to specify the same i18n code in the JSP page but to select the appropriate message bundle according the "brand" being used in the particular deployed instance. So instead of selecting different message bundles according to conventional (language-based) locale, I forced Spring to select a custom i18n bundle by specifying the custom locale via a org.springframework.web.servlet.i18n.CookieLocaleResolver. This in turn was configured by a particular property in the app's main properties file. Here's some of my dispatcher-servlet.xml file:
<bean id="localeChangeInterceptor" class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor">
<property name="paramName" value="lang" />
</bean>
<bean id="localeResolver" class="org.springframework.web.servlet.i18n.CookieLocaleResolver">
<property name="defaultLocale" value="${i18n.code}"/><!-- value from app.properties -->
</bean>
<bean id="handlerMapping" class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
<property name="interceptors">
<ref bean="localeChangeInterceptor" />
</property>
</bean>
The only hand-cranking needed was in deployment of a particular branded version - a shell script did the deployment and it copied a particular properties file, e.g., cp app.properties.BRAND_X app.properties (the other file that needed manipulating was web.xml).
Edit: not sure about the versioning part but you could probably pull that out of the app.properties file as well but specify it in the JSP like:
<!-- custom tag that reads a properties file -->
<c:set var="version"><app:propertyLoader bundle="app" property="site.version"/></c:set>
<fmt:message key="form.firstName.${version}"/>

How to override Plone's display menu for special case content?

To get a one-off view on a Plone folder I do something like this (not all code shown):
In configure.zcml:
<!-- Marker interface. Set this on the folder through the ZMI
interfaces tab.
-->
<interface interface=".interfaces.IMySpecialFolder" />
In browser/configure.zcml:
<!-- Special case view. Set as the folder's view through the ZMI
properties tab (layout property).
-->
<browser:page
for="..interfaces.IMySpecialFolder"
name="special"
template="special.pt"
permission="zope2.View"
/>
This works great, but I would like to control the folder's display menu to list only my special case view. I can add it, and it shows up only on my marked folder, but I have to change the site-wide ATFolder FTI.
In browser/configure.zcml:
<include package="plone.app.contentmenu" />
<browser:menuItem
for="..interfaces.IMySpecialFolder"
menu="plone_displayviews"
title="Special view"
action="##special"
description="Special case folder view"
/>
In profiles/default/types/Folder.xml:
<?xml version="1.0"?>
<object name="Folder">
<property name="view_methods" purge="False">
<element value="special"/>
</property>
</object>
Of course I cannot remove the existing available view methods without affecting every folder on the site.
Is there a way to do this one-off display menu tweaking without changing a content type's FTI?
Actually, it seems like this problem has been tackled before. p4a.z2utils patches CMFDynamicViewFTI to get the list of available views from an IDynamicallyViewable adapter lookup. (dateable.chronos uses this mechanism for its folder calendar views). So my question becomes:
Is there a way to do this one-off display menu tweaking without changing a content type's FTI and without patching Plone?
The plone display menu builder uses ISelectableBrowserDefault to get available options in the Display menu (see
http://dev.plone.org/plone/browser/plone.app.contentmenu/trunk/plone/app/contentmenu/menu.py#L220)
So I think (but I haven't tried this) that if you define an adapter for a more specific interface (in your case IMySpecialFolder) that provides the Products.CMFDynamicViewFTI.interface.ISelectableBrowserDefault it should work.
The adapter should have the methods required by plone.app.contentmenu.menu.DisplayMenu above.
Answering my own question, I've realised that the most straightforward way to achieve one-off folder views is to follow the pattern Plone itself applies in the Members folder: a PythonScript index_html that calls the custom view, e.g.
member_search=context.restrictedTraverse('member_search_form')
return member_search()
Products.CMFPlone illustrates how to setup such a PythonScript with a GenericSetup import handler.
In retrospect I realise I didn't need the marker interface in my question scenario. It's not necessary here in the answer either.
Note that this solution doesn't result in "the folder's display menu listing only my special case view" as I asked, but does away with the display menu altogether. I'm fine with that.
One way you could have solved it is using traversalhook to register menu items, or in this case, unregister menu items, or register menu items with conditions that make them not appear. With the traversal hook you can use a marker interface to make it just happen in a certain folder, subsection or page.
You can see where we implemented similar code here
https://github.com/collective/collective.listingviews/blob/master/src/collective/listingviews/browser/views/controlpanel.py#L105
In this case we just wanted to register new display menu items dynamically based on control panel configuration.

How can I add a classic portlet at the root of the portal when my product is installed?

What is the simplest way to do this? I added it in the portlets.xml file in profiles/default. It is now available in the "Add portlet" dropdown when I go to ##manage-portlets. But I need it automatically created.
Is it possible to explicitly specify the set of portlets I want on the right and left columns inside my profiles/default?
You can register your classic portlet trough the portlets.Classic portlet, configured with a template and macro name, using an assignment element in your portlets.xml file:
<assignment
manager="plone.rightcolumn"
category="context"
key="/"
type="portlets.Classic"
name="my-classic-portlet"
visible="1">
<property name="template">templatename</property>
<property name="macro">macroname-found-in-template</property>
</assignment>
See the Portlets section of the GenericSetup manual on Plone.org or the original PLIP for details on Portlet assignments and GenericSetup.
The properties match the portlet dataprovider interface, see the Classic Portlet source code for the interface definition for the Classic Portlet.
The portlets.xml file does a few different things and there's a difference between registering a kind of portlet that can be added and actually adding a portlet, both of which can be done in portlets.xml. You need to use an "assignment" element to add a portlet:
<assignment
manager="plone.rightcolumn"
category="context"
key="/plone"
type="plone.portlet.static.Static"
name="foo-portlet">
<property name="header">Foo Portlet Title</property>
<property name="text">Foo portlet contents...</property>
</assignment>
For a not experienced product developer (even the others too) the easiest way to achieve this kind of automation is:
do manual configuration o
assignment like a any other common
plone user/administrator, going in
the portal's root and adding the
portlets you want.
go in zmi -> portal_setup -> export
tab
select portlet step and export it
use portlets.xml in the tar.gz just
got.
this xml contains all what you need: registrations and assignments... actually, even a little more stuff so may be a good thing to make a clean of what unneeded in it.

Resources