Jump to content

Planning a page version/history module - making PageFinder hookable


Rob
 Share

Recommended Posts

We're teetering on the brink of choosing PW for rebuilding a moderately complex site, and as part of that decision-making we're assessing how easy it is to develop modules for custom behaviour, add admin pages for our own bespoke needs etc.

One thing we may want is a version history for pages, whcih in turns feeds into the ability to have an edit->preview->publish workflow.

I think the module/hook system is excellent by comparison to most CMS', but I am a little unsure of how to handle the cases where I find parts of the core code (in this case, PageFinder class) that don't seem to be hookable by virtue of not having the three underscores in the method names.

Is it as simple as me adding these three underscores, and the rest of the system knows how to then make this hookable, or is there deeper work that needs to be done to make methods hookable?

Thanks in advance.

Link to comment
Share on other sites

I can't answer your questions, but it's worth mentioning that a "Page history module" is already on the roadmap.

http://processwire.com/about/roadmap/

Thanks for pointing that out.  It's not necessarily a deal-breaker for us, but if we do need the functionality, May 2012 is a bit of a wait so we may try to do something ourselves.  I suppose it wouldn't hurt to see if Ryan needs help to speed up that part of the development, seems it might be a waste to have simultaneous develoopment of the same set of features.

Link to comment
Share on other sites

One thing we may want is a version history for pages, whcih in turns feeds into the ability to have an edit->preview->publish workflow.

Sinnut is right that there is already a revisions/history module in the works. It is already somewhat functional, but I've set it aside till version 2.3 as multi language support is the focus of 2.2.

The edit/preview/publish workflow is already in PW to some extent, but you can only preview when something is unpublished. Once published, you no longer have a preview. We're going to be enabling that functionality by management of separate draft and published versions of a page, and it will technically be a separate component than the revisions/history module. Behind the scenes, it will work by making an unpublished clone of the original page that overwrites the published page only when you hit 'publish'.

Is it as simple as me adding these three underscores, and the rest of the system knows how to then make this hookable, or is there deeper work that needs to be done to make methods hookable?

There actually isn't anything more to it than prepending the 3 underscores. PW takes care of the rest internally. But you do have to use some care in determining which functions should be hookable. When you make a method hookable, you are telling ProcessWire to handle the function call rather than PHP (and the fast low level C code that PHP is written in). So there is more overhead in calling a hookable method than with a native PHP one (regardless of whether any hooks are attached). Methods that are called hundreds or thousands of times aren't great candidates to be hookable because it may slow execution.

You mentioned a desire to make something in PageFinder hookable. Which method? I can take a look and it and see if it's a good candidate for hooks and if so I can just make it hookable in the core. Also let me know what you are trying to achieve with the hook, as I may be able to suggest alternatives too.

Link to comment
Share on other sites

You mentioned a desire to make something in PageFinder hookable. Which method? I can take a look and it and see if it's a good candidate for hooks and if so I can just make it hookable in the core. Also let me know what you are trying to achieve with the hook, as I may be able to suggest alternatives too.

Hi Ryan, thanks for the swift reply.

Basically I've been trying to trace through the code and establish which bits I'd need to hook into in order to work out how I might add page versioning.  WHat I had in mind was to make the page saving function save a new copy into the 'Pages' DB table each time (on the understanding that each unique page is based on a set of page name, parent and template which I think won't be duped between pages) and then have a separate table that jsut stores which version of each page that is live.

As a newbie to PW I'm probably overshootig myself a bit but I thought it'd be a good learning experience to get to grips with module development and learning the inner workings.

With that in mid, I'd have to write a module thyat hooked into many parts of the system to make this idea work, as every page save would need to work in a new way, page load/filtering would need to take into account the new system etc so it's quite a big undertaking.

Just to be clear, I'm not just talking about a temporary page to be able to preview edits, I'm talking about every page save being a new version, and being able to preview any version and then publish any version as the current 'live' version.

Another concern is that your code treats lots of elements in the system as "pages" including users, roles etc so I don't know if this adds complexity.  You wouldn't want to be able to version-control things like users, roles, admin pages etc.  It's just standard pages that need to be version controlled.  It ultimately may not be worth the grief of the development complexity against the benefits gained.

Link to comment
Share on other sites

I think that using pages in the system to maintain versions does simplify a lot of things, but it might be tricky and limited in others. If you are literally saving a version on every save, then you could end up with quite a large site tree and tables of data (whether visible or not). All the data in the tree is setup to be optimized for fast selection and searches. Everything is indexed. Past versions of pages don't really need that. So you end up with adding unnecessary overhead to the live tree. I am shy about the idea of having hundreds of thousands of pages in the system that don't contribute to the live site's data ... kind of like keeping all my past work projects on my desktop. :) But if you are in control of when you want to create a new revision (so that you don't end up with dozens-hundreds for each page) then the overhead might be a good price to pay for that capability. In fact, if you are using versions in a controlled and careful manner like this, then pages would probably be a good way to go. But if you are automatically creating a new page every time someone hits save, then I would be worried about the scalability of that. Either way, I like the way you are thinking about this and I think your ideas here have a lot of merit.

The approach I took in the revisions module in development was to make a version on every page save() but just keep it JSON encoded in a flat table or files. I figured this is archived data and didn't need to be indexed in the DB. It prepares the array of data by calling each field's $field->type->sleepValue() function, which reduces the data for that page's field down to a format that can be stored anywhere. The big challenge is how to handle fieldtypes that involve files. I haven't solved that one yet. If you use pages to create your versions, you won't have to worry about that because PW's clone() function will take care of it for you.

I wouldn't worry about things like users, roles, admin pages, etc. Instead, I would just suggest letting your module have a configuration option where one could check boxes next to all the templates they want to maintain versions for.

  • Like 1
Link to comment
Share on other sites

Having just discussed this with a colleague, there does seem to be an agreement that a complete page "history" of every save is overkill.

We would be happy to have a system where you could "preview" a page at any given point and I think there must be simpler ways to do this, perhaps using page cloning as Ryan has mentioned.

The serialisation of data idea is intriguing, but of course once it is serialised you can't query it in the same way as a regular DB table.

In the meantime I'm going to keep thinking about options to allow previewing or a single draft version of any page. Conceptually I can't figure out how I would allow a user to save+preview a page they are editing and not touch the current "live" page data.  I understand that I can clone pages, but I need to keep the cloned pages tucked out of harms way, have the system ignore them for searching/filtering, and give the user a way to then "publish" this cloned "draft" data by copying it into the "live" page.

No doubt these are all relatively straightforward tasks but I just don't yet have the requisite knowledge of PW.

Link to comment
Share on other sites

The serialisation of data idea is intriguing, but of course once it is serialised you can't query it in the same way as a regular DB table.

But is having past versions of pages query-able in that manner very useful? I'm sure there are uses, but I couldn't think of any situation where I would need it to be (outside of page_id and timestamp). I think of past revisions as archives kind of like a Time Machine backup on my Mac. The main value is just in having the archives. The data is no longer current and won't ever be queried for anything other than page_id or date. At least, that's my outlook on it. But I'm sure the same could be said the other way around. It's just a matter of where you want to make the compromise. I think having selective versions of pages like you mentioned is a good compromise. 

In the meantime I'm going to keep thinking about options to allow previewing or a single draft version of any page. Conceptually I can't figure out how I would allow a user to save+preview a page they are editing and not touch the current "live" page data.  I understand that I can clone pages, but I need to keep the cloned pages tucked out of harms way, have the system ignore them for searching/filtering, and give the user a way to then "publish" this cloned "draft" data by copying it into the "live" page.

This is something that I think may be best to implement in the core ProcessPageEdit module. Right now I don't think the hooks are there to do it without having a module come in and create a clone and modify the POST 'id' var before ProcessPageEdit init() is called. Though I suppose you could hook in before Pages::save, see if there is a $_POST['save_draft'] var set (or something like that), clone, then substitute in your new draft version. There are options, but it's not as straightforward as I'd like. It would probably be a frustrating first module to build. :) I think this capability belongs in the core, and it will be straightforward to implement there. But if you want to try building the capability, I'd recommend working in the core module: ProcessPageEdit. You can always save it out as another module and just change the Process being used by the /processwire/page/edit/ page in the system.

Link to comment
Share on other sites

  • 2 years later...

Definitely check out version control for text fields if you haven't already. This module is so good, that it's rare I wish for anything else. That's not to say that there isn't more to be done with regards to core version control, but Teppo's module covers the most common version control needs beautifully. 

  • Like 1
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...