Changing Pages ParentID in onBeforeWrite does not always work

96 views
Skip to first unread message

Corey Sewell

unread,
Oct 4, 2015, 1:35:16 PM10/4/15
to SilverStripe Core Development
Hi All,

I have an issue with a concept I am trying to create.

I would like to move particular pages under a /year/month type hierarchy based on a Date property once it has been saved.

Here is what I have so far:
https://gist.github.com/cjsewell/9d41c5c278bd36fac877

One issue I have, is that the page is not always moved after a save. On add it seems to work fine, but after that the page has to be saved twice before it to actually moved, even though the Debug::log seems to suggested the ParentID is set correctly, this action is not reflected in the DB.
Also, to reflect the change in the page tree I have to refresh the entire page.

Any suggestions?

Cheers

Nicolaas Thiemen Francken - Sunny Side Up

unread,
Oct 4, 2015, 5:43:28 PM10/4/15
to silverstripe-dev
Hi

Here are some hunches - mere hunches, nothing more.

1. I usually write:

$page->writeToStage("Stage");
$page->publish("Stage", "Live");
//NOTE THAT I put Stage and then Live ... 

2. do you need to flush - e.g. $page->flush() or something like that (basically clearing any caches)?

Hope that helps (mere hunches ... nothing more!)

--
You received this message because you are subscribed to the Google Groups "SilverStripe Core Development" group.
To unsubscribe from this group and stop receiving emails from it, send an email to silverstripe-d...@googlegroups.com.
To post to this group, send email to silverst...@googlegroups.com.
Visit this group at http://groups.google.com/group/silverstripe-dev.
For more options, visit https://groups.google.com/d/optout.



--
Nicolaas Thiemen Francken
  www.sunnysideup.co.nz
  phone: +64221697577

Daniel Hensby

unread,
Oct 7, 2015, 5:21:27 AM10/7/15
to silverstripe-dev
Unfortunately re-arranging pages like this isn't fool proof and can lead to accidentally publishing changes that weren't intended.

I tried a while ago (with some success) to get the site to create an artificial heirachy based on date in this way; effectively adding bespoke URL rules and Link functions to the relevant pages, to create /ParentULR/YYYY/mm/URLSegment.

Getting this working in the CMS is tricky (to create some kind of fake filing system) - I did get it KIND of working, but it was such a long time ago that I can't remember how or if it was particularly stable.

tl;dr - Look at creating a conceptual hierarchy for your pages rather than trying to shuffle pages into new places on the site.

Patrick Nelson

unread,
Oct 7, 2015, 9:31:16 AM10/7/15
to silverst...@googlegroups.com
This seems like it'd be a pretty easy thing to do partially outside of SilverStripe once you've setup your pages to live under a specific parent. They'd have two URL's. The SilverStripe URL directly under the parent and then the mod_rewrite version of the URL. 

I know that because this is SilverStripe(TM) your initial inclination is to use a parent/child taxonomy to handle basically everything, but things like this make a lot of sense to keep as simple as possible. A few major points you want to accomplish: 

- Maintain a URL organized by date
- Ensure the URL is still unique per page (at least within the entire subsection, at most within the specific month) 
- KISS (keep it simple, stupid)

I'd suggest either encoding this information into the URL segment before saving and instead of using dashes, use slashes, and then do a 301 to point to the slash version and use mod_rewrite to internally redirect to the dash version. Alternatively, which I like more if you're fine with having page URL segments be unique across the entire subsection is to follow the same technique but instead if you visit that specific URL that matches the month/year/urlsegment patterm internally redirect to that exact URL without the month/year and if you visit It without that pattern, simply redirect to the correct one. Then you can still (in either approach) centralize the determination of the correct URL and just compare in the controller with the current request uri. 

Bundle that with a grid view (if you have a lot of pages) which is capable of handling versions objects, just to maintain them easily and keep them paginated (forgot the extension/module you need for this, it also needs a custom add button if you want to add that adjacent to the field). But that's just if you want it and are going to have thousands of pages. 

That to me is waaaay easier than trying to do a jig around the draft vs published dance that the page will do as you transition the page's hierarchy by actually manipulating the parent id. Some things are easily accomplished outside of SilverStripe. In this case it's a concept. And that concept is to tackle 98% within SilverStripe's php code and the the remainder in a few lines of .htaccess.

Will that work?

Sent from my iPad

Patrick Nelson

unread,
Oct 7, 2015, 9:44:56 AM10/7/15
to silverst...@googlegroups.com
Also, Corey on your last point, I think it's possibly because of published vs draft mode. I'm not sure which one the CMS references but that may be related to why. It may also just be that the site tree pane Ajax just wasn't triggered until that second click. Either way I think that's a little hacks and should be avoided due to how simple the alternatives are (also since pages when moved need to have a unique urlsegment and etc). Too many moving parts to do something like that without a good API built into core, in my opinion, to handle these things for you, like "->moveToParent(SiteTree $parent)" which can throw an exception on failure, for example (wish that existed, but even still not for this scenario). 

For nick, I'd say you should use the built in ->doPublish() method for publishing pages, if that is indeed something you do. Again I don't recommend doing that here since it's probably not necessary if ee takes a different approach I recommended :)

Also, if you really want to be bullheaded, you could hit the database directly and set the parent ID on the draft and live tables so you can be certain it's reflected, then proceed with the save action that the user is attempting (and they COULD very well just be saving a draft, which is why you don't want to go publishing all willy nilly). 

Again I say keep it simple and just use regular SilverStripe functionality and extensibility for 98% of this and do the rest in mod_rewrite. This worked very well for me for years when I was in other systems that didn't have a centralized router of some sort. E.g. In Laravel this would be a simple route (but you'd have to build the entire CMS which may not be half as functional as this). 

Sent from my iPad

Damian Mooyman

unread,
Oct 7, 2015, 8:01:58 PM10/7/15
to SilverStripe Core Development
Hi Corey,

I've solved this problem before, back in 2.x when I created the datelink module (which I used the the blog module to create wordpress stylelinks).


It's been updated to work with 3.1, but I haven't used it for quite some time.

Rather than moving the page, the url is generated programatically and routed on page request. This is a lot safer than altering your underlying data model.

Kind regards,

Damian

Marcus Nyeholt

unread,
Oct 7, 2015, 8:19:34 PM10/7/15
to silverst...@googlegroups.com
Reply all
Reply to author
Forward
0 new messages