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.
Related
Can I use old style collections rather than the new collection? If so, how?
Go to http://[HOST]/[PLONESITE_ID]/##types-controlpanel?type_id=Topic, check the box where it says "Globally addable" and hit the "Apply Changes" on bottom of the form.
Programatically reproducable by adding /profiles/default/Topic.xml to your addon with the following content:
<object name="Topic">
<!-- Enable old-style-collections
By default turned off since >= Plone-4.1 -->
<property name="global_allow">True</property>
</object>
To turn off the new-style-collections, you can do the same procedure, just replace "Topic" with "Collection" and set "global_allow" to False.
If you also want be able to define which fields are available as a choosable criterion in a collection's edit-mode, via the site's UI, go to http://[HOST]/[PLONESITE_ID]/portal_controlpanel/manage_editActionsForm and check "Collections (old style)" entry, then "Collections (old style)" will become visible for configuration in the site's controlpanel, accessible via http://[HOST]/[PLONESITE_ID]/##overview-controlpanel.
Also these settings can be reproduced programatically via a profiles/default/portal_atct, you can export the relevant xml-file via http://[HOST]/[PLONESITE_ID]/portal_setup/manage_main, or have a look at this example for an orientation: https://raw.githubusercontent.com/ida/adi/master/adi.tickets/adi/tickets/profiles/default/portal_atct.xml
Note: In case you are adding new fields as criteria here, you'll need to register them in the catalogue also, via profiles/default/catalog.xml, another example for that case: https://github.com/ida/adi/blob/master/adi.tickets/adi/tickets/profiles/default/catalog.xml
Furthermore: If you want to allow visitors to change the criteria's values to search for, on the fly via the UI – a search-form in other words – look at collective.formcriteria, written by Ross Patterson.
I am using Plone 4.1.4 with Doormat and Diazo in an institute I work and the Footer has to be made manually by adding each column and item that links internally to items from main menu.
What I want is that this footer, which is the site map, to change automatically every-time some user create, edite or delete an item from the main menu (content folders).
When I got the job I noticed many of those links in footer are out of date, and as there are many users in their each sections of the institute that are allowed to change the structure, I know they won't update both folders and footer.
I searched the Internet for some product or tip but I cant' find anything that resolves that problem.
If your Diazo theme was created as a Python package using mr.bob or zopeskel, you probably already have z3c.jbot, which allows you to easily override templates, available. If so, you likely have a template_overrides or similar directory in the package. If so, just drop into it a file named plone.app.layout.viewlets.footer.pt with the contents:
<div i18n:domain="plone"
id="portal-footer">
<ul id="portal-doormat"
class="navTreeLevel0 visualNoMarker">
<tal:sitemap replace="structure context/##sitemap/createSiteMap" />
</ul>
</div>
Then style away!
Alternatively, you may replace the colophon by naming the file plone.app.layout.viewlets.colophon.pt.
If you aren't using a Python package for your theme (if the Diazo theme was created through-the-web) then you may use the portal_view_customizations tool in the ZMI to make the same template override.
You may wish to also customize the depth of the site map. That may be changed via the portal_properties tool, navtree_properties property sheet. Or, just use CSS to hide unwanted depth.
An alternative and much easier way to realize your demand, can be to use portlets instead of viewlets, in combination with the addons "Products.ContentWellPortlets" and "collective.portlet.sitemap":
1.) Hide the footer-viewlets via a GenericSetup-config like in this example:
http://svn.plone.org/svn/collective/adi.simplestructure/trunk/adi/simplestructure/profiles/default/viewlets.xml
2.) Assign a sitemap-portlet in the footer-area via a GenericSetup-config, similar to this example:
http://svn.plone.org/svn/collective/adi.simplestructure/trunk/adi/simplestructure/profiles/default/portlets.xml
Tip: First assign the sitemap-portlet via the Web-UI, then go to [SITE-URL]/portal_setup, search for "portlets", check its box and click the export-button on the bottom, to get the needed xml-file.
I've created a Dexterity product that includes container and non-container Dexterity content types. Having discovered collective.documentviewer (yay! thanks! huzzah!), I'd like to use its dvpdf-group-view, but that is registered in ZCML as being for Folders, and my Dexterity containers don't qualify. I've looked through the web interfaces available on my container type, added SiteRoot, and that enabled the view to be applied, but is also completely wrong.
I'm confident there's a right way to do this, and I'm pretty sure it's central to the whole adapter/interface mechanism, but I just can't find it in any of the books.
Anyone care to try an explanation? First, the line or two that would enable a Dexterity container to pretend it's also a Folder; second, how to change the default view of a single instance of a Dexterity type so that it presents a foreign component's view?
Thanks.
1. Register the view for dexterity containers too
The view is registered for the Archetypes folder interface (Products.CMFCore.interfaces._content.IFolderish), but your dexterity container does not provide this interface (but plone.dexterity.interfaces.IDexterityContainer).
The reason may be that the product and/or the view is not compatible with dexterity.
Anway, you can try it out yourself by registering the view also for the the IDexterityContainer interface by putting a little ZCML in the configure.zcml in your package (see also the Creating a package section of the Dexterity Developer Manual):
<configure
xmlns="http://namespaces.zope.org/zope"
xmlns:browser="http://namespaces.zope.org/browser">
<configure package="collective.documentviewer">
<browser:page
name="dvpdf-group-view"
for="plone.dexterity.interfaces.IDexterityContainer"
class=".views.GroupView"
template="templates/group-view.pt"
permission="zope2.View"
layer=".interfaces.ILayer" />
</configure>
</configure>
The <browser:page> is copied from the collective.documentviewer configure.zcml but I've changed the interface for= to the dexterity container interface, so that the view also works for dexterity containers.
The inner <configure package="collective.documentviewer"> tells the ZCML parser that the configuration should be applied as if the configure.zcml would be directly in collective.documentviewer - this allows you for example to use the original template (otherwise you would have to copy it or do some nasty things).
I did not test it myself: it may still be that the view needs an archetypes container and does not work with a dexterity container. It may also be that you have to register more components from the documentviewer for dexterity containers (maybe the menus? take a look at what is registered in the original configure.zcml.
If everything works well you should consider doing the changes in collective.documentviewer on github directly and make a pull-request to the author (be aware that dexterity is not plone-core yet). But first ask if and how you should do it :-)
2. Changing the default view
With plone it is possible to define multiple views for a specific type. The view can then be selected in the display menu per instance of this type. If you open up http://localhost:8080/Plone/portal_types/manage_main and click on your type, there is a field Available view methods, where you can add the view-name (dvpdf-group-view) on a seperate line.
After you create a new object of your type or visit an existing one, you have a "Display"-menu which should list the view. Select it and this object now has this view as default.
(If you want to make the view not selectable on other objects of this type you could just remove it from the type configuration so that it is not selectable anymore - the existing configuration of your object will stay).
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.
I know that I need to add the tracking code snippet at the bottom of all my pages, but is there a central location to do this?
Or do I need to add this tracking code to all of my templates?
I guess that I could wrap the snippet in a user control, or external .js file, and reference it on each page, but is there a global footer somewhere? The site I'm working on has about 30-40 layouts, and adding it to each one would be a pain!
Thanks in advance!
Actually, the role of a Sitecore layout is exactly this; to act as a global file that all individual page templates "derive" from.
Normally you'd stick the analytics code into the master layout, and use Sitecore sublayout/placeholder techniques to construct the various page templates you need. You would not normally need more than perhaps one or two layouts for any device you are serving content to. And I guess for most sites, the only device in use is regular web content delivery.
That being said, what you could do, is have all the layouts inherit their codebase from a common base class (inheriting from Page), and inject the google code centrally from here. Would still require you to go through all layout files however.
I have not tried the module, I think that is codebehind version. I have made this in XSLT, its pretty fast and easy to make. I have footer.xslt where I put the code that simply checks if page you are standing on uses template that I want to index and does not belong to page names that I want to exclude. Then I have an item with a custom template for Google Analytics with following memo fields.
IncludeTemplates -field contains list of templates that I want to include for analytics :
ExcludeItemsNames -field for excluding pages by item name
contains($includeTemplates, concat('|',./#template,'|')) and not(contains($excludeItemNames, concat('|',./#template,'|')))
Remember #key and #template is always in small letters
If you run many domains don't forget to add pageTracker._setDomainName("www.example.com"); in analytics script so you can separate sub-domains etc. if they use same footer.xslt
Normally we consider the actual Google code as content. Within Sitecore we normally have a settings folder, something like /sitecore/content/settings. This exists outside the root of the site. Beneath this have a settings item with a plain multi-line text field, I think the field type is memo or something similar.
Afterwards create an XSLT that renders out the content of this settings item. Something like (assuming the field is called value in the setting item):
<xsl:value-of select="sc:fld('Value','/sitecore/content/settings/footerJavaScript')" />
You may or may not need to set the disable-output-escaping attribute.
Then on the aspx page that your pages use as the template add a control that looks at the xslt rendering:
<sc:XslFile runat="server" Path="/xsl/footerJavaScript" />
The reason that we normally keep the javascript as content is this allows the client to change the analytics code without having to contact us.