I see a message This type of folder does not support ordering when viewing the News or Events folder. My understanding is that items contained in such folder, their position order can not be set arbitrarily. Only alphabetical order for their IDs is applied.
From ZMI, I see News and Events folders are of ATFolder type, everything seems the same with the regular folder I just create. What makes such difference? And what is the rationale behind this?
Edit: My bad that Info message in the above image is enabled by wildcard.foldercontents, which I thought due to Plone 4.3.2. However, the issue remains that position order can not be set arbitrarily. The following image attached to illustrate this.
PS: I ever delete the News folder, create a regular folder named news, this way I can set item position order arbitrarily. However, I find the Calendar Portlet within that folder is not working right. The issue happens when I click to switch months. The URL link will be out of its context, I mean, not staying in the news folder. Maybe this is not related to the folder ordering behavior, anyway, just for your reference.
For some reason Plone is shipping with the news and events folders being unorderable.
>>> news = site.news
>>> news.getOrdering()
<plone.folder.unordered.UnorderedOrdering object at 0x112e434d0>
I consider this a bug in plone's initial site installation.
Plone core actually explicitly sets the folder to unordered: https://github.com/plone/Products.CMFPlone/blob/4.3.x/Products/CMFPlone/setuphandlers.py#L250
I don't understand why. I'll change it if there aren't any objections...
Related
I have have made a folderish content type called supplier_folder, which displays a list of suppliers that can be added under it, and their information. I can add it through the navigation bar, but I would like to add it programatically during setup.
I have been following the tutorial on custom installer code (http://docs.plone.org/develop/addons/components/genericsetup.html#custom-installer-code-setuphandlers-py) and have looked at creating objects programatically (http://docs.plone.org/develop/plone/content/creating.html).
Unfortunately, the second article says I need to have a folder created. How can I get around this and add the supplier_folder object at the Plone Site outside of a folder?
IIRC, only users with role Manager or Site Administrator can add content to the root of the site; you can overcome this limitation in two ways:
by using the _constructInstance method as it bypasses the permissions when creating an item
by switching roles inside your code with plone.api.env.adopt_roles
I personally prefer the second one.
you can see an example of a pretty complex setuphandlers.py in interlegis.portalmodelo.policy package.
When you create a new Plone site, it's also creating some default content types.
Look at how Plone do: https://github.com/plone/Products.CMFPlone/blob/1471828ee97a8dd84396bad4a3286be514819869/Products/CMFPlone/setuphandlers.py#L119
There are a couple of ways to achieve this. The buildin mechanism is to use GenericSetup in combination with "structure" folder as described here: http://koansys.com/tech/create-plone-initial-content-with-generic-setup
In short you need the following:
Create a folder "structure" in your Generic Setup profile (in general, under profiles/default)
Create a .objects file with the following content: "suppliers,supplier_folder"
in "structure" create a folder "suppliers" with a .properties file and content:
[DEFAULT]
title = Suppliers
description = Some usefull description text
As far as I remember this is ok for simple structures likes your. If you have complex structures with folders and sub-folders and want more specific control you probably need to write python code. I made some stuff here: https://github.com/collective/zettwerk.setup/blob/master/zettwerk/setup/structure.py
But zettwerk.setup is not yet released, but you should be able to integrate the structure.py right into your project. Than you can the handle_structure method into your setuphandlers.py and passing a structure dict like this:
handle_structure(portal, [{'id': 'suppliers', 'portal_type': 'supplier_folder'}])
The advantage of this method is, that you can also control metadata like workflow state, default page setting, portlets, local roles and some others.
I'm pretty sure I've read somewhere that you can actually move the main plugin *.php file to somewhere else (I assume under your theme directory) to have it safe in case you made changes to it and your plugin updates. I tried Google but I can't find anything. Google page with good results will suffice.
I've just experienced a situation where my 2 plugins which had its layout changed and accommodated my needs and I want to make sure it doesn't happen again. Apart from having the main file in another location, is there a way to move along any CSS and JS files as well?
In Concrete5 CMS there is a nice way of doing this, by creating a new folder inside a block of an addon (may be regarded as a WP plugin), inside of which you can create copies of main file, any CSS and JS files and then you can simply edit them and choose that template for a page location you are using that block in.
I assume there is no such thing in Wordpress but how close can I get?
UPDATE: I found where I applied that advice on creating a new instance of the file then moving it to the theme directory.
The plugin in question was HL-Twitter. These are the plugin files:
admin.php
archive.php
functions.php
hl_twitter.php
hl_twitter_archive.php
hl_twitter_widget.php
import.php
widget.php
Now, this is the top contents (commented out) of the hl_twitter_widget.php:
Widget Theme for HL Twitter
To change this theme, copy hl_twitter_widget.php
to your current theme folder, do not edit this
file directly.
Available Properties:
$before_widget
$after_widget
$before_title
$after_title
$widget_title
$show_avatars
$show_powered_by
$num_tweets: how many tweets to show
$tweets: array of $tweet
$tweet: object representing a tweet
$tweet->twitter_tweet_id
$tweet->tweet
$tweet->lat
$tweet->lon
$tweet->created
$tweet->reply_tweet_id
$tweet->reply_screen_name
$tweet->source
$tweet->screen_name
$tweet->name
$tweet->avatar
$user: represents the Twitter user (ONLY SET IF SHOWING A SINGLE USERS TWEETS!)
$user->twitter_user_id
$user->screen_name
$user->name
$user->num_friends
$user->num_followers
$user->num_tweets
$user->registered
$user->url
$user->description
$user->location
$user->avatar
So I was wrong about copying the main file (in this case hl_twitter.php), but still - this enabled me to edit the file outside the plugin directory and the system somehow checks for its existence and picks it up if exists.
If this behavior something that is natively supported by Wordpress or it has been integrated in the plugin itself?
With themes, Wordpress has a concept of "child themes" which allows exactly that: to keep changes separate from main theme, in case it changes.
I haven't yet found a way to do this with plugins.
I'm using a few tactics myself:
I bump plugin version to a very high number like 99.9. This way Wordpress won't ever update the plugin.
Store my plugins in version control (i use git, but it doesnt matter), this allows you to update the plugin, run the 'diff' tool and see what changes happend. If you don't like you just revert like it would be a bad code you've written. But this approach requires a bit of skill.
Are you talking about running parts of a modified 3rd party plugin, and an updated version, at the same time?
That's not going to be possible. There is no magical method of "preserve my changes and transfer them into the new version automatically". The way to go here is doing a diff between the edited version and the update, and integrating the changes in the actual source files.
The bottom line is, if you manually edit a third party plugin, you're in for manual review (and possibly rework) once an update takes place. That's why it's usually not a good idea to extensively modify third party plugins.
Well in fact, yes! There is some kind of way.
You have to remove the to be modificated plugin's original actions/filters and then add your altereted actions/filters.
If the desired plugin is even coded in OOP you can just inherit the whole class and rewrite the wanted functions (oh sorry: "methods". we're talking about OOP ;) ). Instantiate your inherited class and rest as above.
Maybe there are better ways! I already search for a method so that the original class won't even get loaded but our altered one instead but I'm no John Carmack.
I am getting a very weird problem when attempted to cut-and-paste folders from one place to another in our intranet Plone site. The paste operation returned the error "Nothing in the clipboard". However it had gone and removed the folder from where it had originally been, and it looks as though it hasn't been inserted yet into the new location. Showing the Content view of the folder in which the paste happened does not show the pasted folder. However, through the ZMI interface I can see that the paste has happened. Clearly something threw an error before the pasted content was moved successfully, and it is left in a weird state.
For example the site search can find the content in the new pasted location, and the bread-crumbs show that those content pages are beneath the folder which is otherwise invisible to Plone.
Is it possible - maybe through the ZMI - to get this folder to be visible in the Plone world?
That is a weird bug. The quick solution to get the folder to display in Plone is to go to the ZMI, then visit portal_catalog, then locate (in one of the tabs) the button to rebuild the catalog. This ought to regenerate the catalog indexes (which may have failed to be updated when you did the cut/paste, through no fault of your own) and thus all the views (folder listings, etc) in Plone will display the new index (the views use the catalog to know what to display).
The same problem as I copied a folder from one language folder to an other the pasted object was only visible in ZMI
As fRiSi said the problem was the language category in Categorization tab > Language
Because I had many subobjects inside a folder I run the script below to change the language categorization recursively
Based on Convert LinguaPlone sub-language back to language for all content?
path = '/'.join(context.getPhysicalPath())
for brain in context.portal_catalog(path={'query': path, 'depth': 1000}, Language="it"):
obj = brain.getObject()
obj.setLanguage('en')
obj.reindexObject(idxs=['Language'])
print brain.getURL()
return printed
I am creating a site which will have a "desktop" and a "mobile" theme. I've two theme packages for this site: mysite.theme and mysite.mobile_theme. The mobile_theme is a stripped down version of the desktop theme, with new views and a reduced set of viewlets. I want to switch between these two themes based on the URL the site is visited from (i.e., mobile.mysite.com vs. www.mysite.com).
As the mobile and desktop themes will share a lot of code, mysite.mobile_theme descends from mysite.theme in the following ways:
1) mobile_theme GS skins.xml has a skin path based on the old theme, so the desktop theme's CSS etc. is used:
<skin-path name="mysite.mobile_theme" based-on="mysite.theme">
2) IThemeSpecific marker subclasses the original one, so views which I'm not overriding for the mobile site fallback to the ones in mysite.theme:
from mysite.theme.browser.interfaces import IThemeSpecific as IBaseTheme
class IThemeSpecific(IBaseTheme):
"""Marker interface that defines a Zope 3 browser layer.
"""
3) I have registered various views in mysite.mobile_theme to override the certain ones in mysite.theme.
4) I've used generic setup to have different viewlet registrations for each theme.
At this stage, if I select mysite.mobile_theme in the "Default skin" option portal skins->properties, everything works correctly: my views are used and the viewlets settings from the mobile_theme's GS profile are picked up correctly. So it appears the theme is set up correctly overall.
As mentioned above, however, I would like to swap between these two themes based on URL.
First, I swapped the "Default skin" back to "mysite.theme". I then created an access_rule in the root on my Plone site, roughly following these instructions to select a skin based on URL. It's at plonesite/access_rule and is set up as the access_rule for the plone site:
url = context.REQUEST.get('ACTUAL_URL', '')
if 'mobile' in url:
context.changeSkin('mysite.mobile_theme', context.REQUEST)
else:
context.changeSkin('mysite.theme', context.REQUEST)
I've also tried using context.REQUEST.set('plone_skin', 'mysite.theme') rather than calling context.changeSkin(...).
Using this setup, the viewlets displayed change correctly based on the URL I've used--so it looks like the skin is being changed at some point--but the mysite.mobile_theme's view classes/templates are not being used in preference to mysite.theme's. In summary:
If I call from a URL containing "mobile" I get mysite.theme's views, but mysite.mobile_theme's viewlet registrations.
Otherwise, I get mysite.theme's views and mysite.theme's viewlet registrations.
It looks like I might have to hook into the traversal mechanism to change it so if "mobile" is in the URL, the mysite.mobile_theme's views registered against its IThemeSpecific are chosen rather than the mysite.theme ones, but I'm not sure this is correct nor how I'd go about this.
Can anyone give me some pointers?
UPDATE 3hrs after originally asking
To answer my own question (which I can't do for another 5 hours due to SO's rules):
"""
It would appear that you must patch much lower down in the stack to make this work. I looked at how it was done in plone.gomobile, and they monkeypatch the skin choosing code itself. See:
http://code.google.com/p/plonegomobile/source/browse/gomobile.mobile/trunk/gomobile/mobile/monkeypatch.py
"""
You could use collective.editskinswitcher. Its main use case is to use the Plone Default theme on say edit.example.com and My Custom Theme on www.example.com. You can probably tweak its property sheet to fit your use case though.
Since the 'mobile theme' use case is fairly common I would accept patches to make that easier; or I may work on that myself some time.
(BTW, note that there is a fix-browser-layers branch that may help when you miss some items that are registered for a specific browser layer; seems ready to merge except that I would like to add some tests first.)
I have done this in some prototypes of mobile themes. Please consider thoses two addons not ready for production:
https://github.com/toutpt/plonetheme.jquerymobile
https://github.com/toutpt/plonetheme.senchatouch
The related code is:
The patch on browserlayer to mark the request with my theme layer: https://github.com/toutpt/plonetheme.jquerymobile/blob/master/plonetheme/jquerymobile/layer.py
The patch on plonetool to add ##mobile on every content page: https://github.com/toutpt/plonetheme.jquerymobile/blob/master/plonetheme/jquerymobile/PloneTool.py
The patch on skintool to tell skin layer is this one if browser layer: https://github.com/toutpt/plonetheme.jquerymobile/blob/master/plonetheme/jquerymobile/SkinsTool.py
If you are using plone.app.theming, you also can switch your diazo theme: https://github.com/toutpt/plonetheme.jquerymobile/blob/master/plonetheme/jquerymobile/transform.py
Do I understand correctly that at the mobile URL your skins are correct, but your Zope3 Views are not? Which makes sense to me, since the view classes are based on Interfaces. In the same code above, where you use context.changeSkin, add:
from zope.interface import alsoProvides
alsoProvides(context, IMobileView)
and have your view zcml specify for ... IMobileView
[edit: on second thoughts, this really should be what happens when you change the skin - where the additional inteface will be your "IThemeSpecific" - so I'm not sure what's at play here, but it wouldn't hurt to try alsoProvides(context, IThemeSpecific)]
So I'm writing a Django based website that allows users select a color scheme through an administration interface.
I already have middleware/context processors that links the current request (based on domain) to the account.
My question is how to dynamically serve the CSS with the account's custom color scheme.
I see two options:
Add a CSS block to the base template that overrides the styles w/variables passed in through a context processors.
Use a custom URL (e.g. "/static/dynamic/css/< website_id >/styles.css") that gets routed to a view that grabs all the necessary values and creates the css file.
I'm content with either option, but was wondering if anyone else out there has dealt with similar problems and could give some insight as to "Best Practices".
Update : I'm leaning towards option number 2, as I think this will allow for better caching down the road. So it's dynamic the first time, gets stored in memcache (or whatever), and invalidated when a user updates their settings in the admin site.
Update: Firstly, I'd like to thank everyone for their suggestions thus far. All the answers thus far have focused around generating static files. Though this would work great in production, it feels like a tremendous burden during development. If I wanted to add a new element to be styled, or tweak existing styles I'd have to go through and recreate each and every css file. Sure, this could be done with a management command, but I just don't feel it's worth it. Doing it dynamically would add 1 maybe 2 queries to each page load, which is something I'm not worried about at this stage. All I need to know is that at some point I will be able to cache it without rewriting the whole thing.
I've used option #2 with success. There are 2 decent ways of updating the generated static files that I know of:
Use a version querystring like /special_path.css?v=11452354234 where the v parameter is generated from a database field, key in memcached, or some other persistent file. Version gets updated by admin, or for development you would just make the generation not save if the parameter was something special like v=-1. You'll need a process to clean up the old generations after some time.
Don't use a version querystring, but have it look first for the generated file, if it can't find it, it generates it. You can create a cron job or WSGI app that looks for filesystem changes for development, and have a hook from your admin panel that deletes generations after an update. Here's an example of the monitoring, which you would have to convert to be specific to your generations and not to Django. http://code.google.com/p/modwsgi/wiki/ReloadingSourceCode#Monitoring%5FFor%5FCode%5FChanges
Could generate the css and store it in a textfield in the same model as the user profile/settings. Could then have a view to recreate them if you change a style. Then do your option 1 above.
Nice question.
I would suggest to pre-generate css file after colors scheme is saved. This would have positive impact on caching and overall page loading time. You can store your css files in directory /media/css/custom/<id or stometing>/styles.css or /media/css/custom/<id or sth>.css and in template add <link rel="stylesheet" href="/media/css/custom/{{some_var_pointing _to_file_name}}" />
You can also do the trick with some random number or date in css file name that could be changed each time file is saved. Thanks to this browser will load the file immediately in case of changes.
UPDATE: example of using model to improve this example
To make managing of those file easy you can create simple model (one per user):
class UserCSS(models.Model):
bg_color = models.CharField(..)
...
...
Fields (like bg_color) can represent parts of your css file. You can ovveride save method to add logic that creates css file for user (by rendering some template).
In case your file format change you can make changes in your's model definition (with some default values for new fields), make little changes in template and run save method for each exisintg instance of class. This would renew your css files.
That should work nicely.
I would create an md5 key with the theme elements, store this key in the user profile and create a ccs file named after this md5 key : you gain static file access and automatic theme change detection.