SlideShare ist ein Scribd-Unternehmen logo
1 von 87
Downloaden Sie, um offline zu lesen
Ancient To Modern 
Upgrading nearly a decade of Plone in Public Radio
!Image Credit: Fall Path by john22s CC-BY 
(https://www.flickr.com/photos/21926145@N04/15242844379) 
this is the story of a journey
Of how a site born to Plone nearly a decade ago 
! 
Has grown with Plone ever since.
Image Credit: Amy Marbach “puppy snuggles are the best” CC-BY-NC-ND 
https://www.flickr.com/photos/amyofbadgroove/14327508940 
Of how a site born to Plone nearly a decade ago 
! 
Has grown with Plone ever since.
Image Credit: Amy Marbach “puppy snuggles are the best” CC-BY-NC-ND 
https://www.flickr.com/photos/amyofbadgroove/14327508940 
Image Credit: Richard Miles “Who Walks Who?…” CC-BY_NC_ND 
https://www.flickr.com/photos/_f1guy68_/2231052733 
Of how a site born to Plone nearly a decade ago 
! 
Has grown with Plone ever since.
Image Credit: Tym “Great Strength” CC-BY-NC-ND 
https://www.flickr.com/photos/tym/269105455 
It’s a success story for Plone, which plays to its greatest strengths
Image Credit: David Ellis CC- B Y -N C - N 
D 
https://www.flickr.com/photos/97578613@N08/10771455296 
Also a morality play about how incautious customizations can make upgrading a challenge.
The Beginning…
Plone 2.0 
It started back in 2005, with Plone 2.0
The site had a nice, modern mid-aughts look and feel, with a clean color scheme and simple navigation.
It also featured drop-down menus for the many top-level navigation targets, for that easy-to-discover feel.
especially in areas where there were a large number of sub-items, like music shows in the “music” area.
Image Credit: Louise Docker CC - B Y 
-NC-ND 
https://www.flickr.com/photos/aussiegall/6417891273 
But like a lot of old things, it worked fine for its purpose
A new theme doesn’t 
justify an upgrade
There’s more! 
But the look-and-feel were not the only issues
This method is called each time a “show” is viewed. 
! 
The highlighted line is preparing to run a query against an external RDBMS 
! 
This system was built to serve certain information from the Plone content to legacy PERL scripts, which were later abandoned.
This method is called each time a “show” is viewed. 
! 
The highlighted line is preparing to run a query against an external RDBMS 
! 
This system was built to serve certain information from the Plone content to legacy PERL scripts, which were later abandoned.
ZSQL scripts like this ran through much of the site functionality
* SQLWindowStorage to store some AT field data in an external database 
* Inefficient to retrieve this data field-by-field 
* Leads to “optimization” code that retrieves values all at once and stores them persistently in object attributes 
* Since this happens on __view__ of an object, there are lots of conflict errors and retries, meaning less efficient operations and more potential for real 
errors.
* SQLWindowStorage to store some AT field data in an external database 
* Inefficient to retrieve this data field-by-field 
* Leads to “optimization” code that retrieves values all at once and stores them persistently in object attributes 
* Since this happens on __view__ of an object, there are lots of conflict errors and retries, meaning less efficient operations and more potential for real 
errors.
* SQLWindowStorage to store some AT field data in an external database 
* Inefficient to retrieve this data field-by-field 
* Leads to “optimization” code that retrieves values all at once and stores them persistently in object attributes 
* Since this happens on __view__ of an object, there are lots of conflict errors and retries, meaning less efficient operations and more potential for real 
errors.
* SQLWindowStorage to store some AT field data in an external database 
* Inefficient to retrieve this data field-by-field 
* Leads to “optimization” code that retrieves values all at once and stores them persistently in object attributes 
* Since this happens on __view__ of an object, there are lots of conflict errors and retries, meaning less efficient operations and more potential for real 
errors.
Image Credit: http://failblog.cheezburger.com/thereifixedit 
http://failblog.cheezburger.com/thereifixedit 
Clearly a safe and stable system for production. 
!
Image Credit: Todd Jordan “Wednesday’s Angry Boss” CC-BY-NC-ND 
https://www.flickr.com/photos/tojosan/14374817787 
This raised the level of anger enough to really justify a large scale upgrade project.
Time for a Change
Plone? 
But first, is Plone the right tool going forward?
Reasons To Stay 
• Heterogenous content in a deep tree 
• Broad editorial staff with different access 
rights 
• In-Place management model 
• Staff familiarity 
• Transmogrifier 
There were definitely reasons to stay
Upgrade or Migrate? 
• Want to use dexterity types for new site 
• Heavy customizations 
• Lots of not-best-practice code 
• Better just to “start over” 
Once the decision to stay was made, the next decision is to run an in-place upgrade, or a more extensive migration. 
!I 
n this case, starting from scratch was really desirable, though the content needed to be preserved
Migration Out 
• Read content out from old Plone 2.5 site 
• quintagroup.transmogrifier 
• Marshall as json 
• collective.jsonify 
• Write site structure to disk 
• modified q.transmogrifier writer 
So a two-phase migration was planned, allowing us to transport the site content, stretching back into the late 1990s, into the new site.
A simple export pipeline moved the content to the filesystem as a series of folders and .json files
A simple export pipeline moved the content to the filesystem as a series of folders and .json files
A simple export pipeline moved the content to the filesystem as a series of folders and .json files
New Content Types 
• Dexterity Based 
• Custom shared behaviors 
• IAirings (for things that go on air) 
• IScheduled (for things that occur on a 
schedule) 
• IContentImages (for things that have a 
standard set of images associated) 
• … 
Next, time to set up the new content types. Using dexterity allowed us to build shared behaviors that would be used by different types.
Migration In 
• Read in json and map old types to new 
• Split pipeline for individual type handling 
• Remap locationsCreate new content 
objects 
• Or, identify existing and update 
(repeatable) 
• Reconnect related objects 
With content types in place, the second phase involved migrating the content back into the new Plone site. 
! 
This process featured a number of the nice properties of the transmogrifier system.
The “splitter” pipeline section allows you to set up individual pipelines associated with some subset of your migrating content. 
! 
You can predicate entry to a particular pipeline on any number of tests, but in this case we used the portal type to determine the path to take. 
! 
A second feature is the ability to annotate the transmogrifier object itself with values like a mapping of user ids in the old system to UIDs for user objects 
in the new system. 
! 
This mapping can then be shared from other pipeline sections that need to re-connect radio shows with their hosts and producers, or episodes with guests 
and artists.
The “splitter” pipeline section allows you to set up individual pipelines associated with some subset of your migrating content. 
! 
You can predicate entry to a particular pipeline on any number of tests, but in this case we used the portal type to determine the path to take. 
! 
A second feature is the ability to annotate the transmogrifier object itself with values like a mapping of user ids in the old system to UIDs for user objects 
in the new system. 
! 
This mapping can then be shared from other pipeline sections that need to re-connect radio shows with their hosts and producers, or episodes with guests 
and artists.
The “splitter” pipeline section allows you to set up individual pipelines associated with some subset of your migrating content. 
! 
You can predicate entry to a particular pipeline on any number of tests, but in this case we used the portal type to determine the path to take. 
! 
A second feature is the ability to annotate the transmogrifier object itself with values like a mapping of user ids in the old system to UIDs for user objects 
in the new system. 
! 
This mapping can then be shared from other pipeline sections that need to re-connect radio shows with their hosts and producers, or episodes with guests 
and artists.
The “splitter” pipeline section allows you to set up individual pipelines associated with some subset of your migrating content. 
! 
You can predicate entry to a particular pipeline on any number of tests, but in this case we used the portal type to determine the path to take. 
! 
A second feature is the ability to annotate the transmogrifier object itself with values like a mapping of user ids in the old system to UIDs for user objects 
in the new system. 
! 
This mapping can then be shared from other pipeline sections that need to re-connect radio shows with their hosts and producers, or episodes with guests 
and artists.
The “splitter” pipeline section allows you to set up individual pipelines associated with some subset of your migrating content. 
! 
You can predicate entry to a particular pipeline on any number of tests, but in this case we used the portal type to determine the path to take. 
! 
A second feature is the ability to annotate the transmogrifier object itself with values like a mapping of user ids in the old system to UIDs for user objects 
in the new system. 
! 
This mapping can then be shared from other pipeline sections that need to re-connect radio shows with their hosts and producers, or episodes with guests 
and artists.
The “splitter” pipeline section allows you to set up individual pipelines associated with some subset of your migrating content. 
! 
You can predicate entry to a particular pipeline on any number of tests, but in this case we used the portal type to determine the path to take. 
! 
A second feature is the ability to annotate the transmogrifier object itself with values like a mapping of user ids in the old system to UIDs for user objects 
in the new system. 
! 
This mapping can then be shared from other pipeline sections that need to re-connect radio shows with their hosts and producers, or episodes with guests 
and artists.
36 hours later 
Finally, we were able to run the migration. 
! 
An advantage of the generator-based approach of transmogrifier is that although the migration took 36 hours, and moved well over 300,000 objects, 
including images fetched over HTTP, the memory usage was constant and the server had little problem completing the job.
Now we have content! 
And now we have plone content, but it isn’t all that great looking.
Make it pretty! 
Image Credit: Kevin O’Mara “I Feel Pretty” 
https://www.flickr.com/photos/kevinomara/13394685405
The client engaged a well-known design firm in NYC, Hard Candy Shell
! fully responsive, changing UI elements size and positioning to fit the device. 
stylish, modern design
! fully responsive, changing UI elements size and positioning to fit the device. 
stylish, modern design
! fully responsive, changing UI elements size and positioning to fit the device. 
stylish, modern design
The mockups featured a lot of “block” content 
! 
With the same types of items appearing in different ways depending on location and purpose 
! 
HTML consists of a lot of repeating fragments showing up in various places
The mockups featured a lot of “block” content 
! 
With the same types of items appearing in different ways depending on location and purpose 
! 
HTML consists of a lot of repeating fragments showing up in various places
The mockups featured a lot of “block” content 
! 
With the same types of items appearing in different ways depending on location and purpose 
! 
HTML consists of a lot of repeating fragments showing up in various places
Other Requirements 
• Some pages had to be “composable” 
• collective.cover 
• Some pages would be pre-built, but 
feature dynamic content selection 
• custom browserviews & templates 
• We want to keep our code DRY
zope.contentprovider 
• Much like a browserview, but for a fragment 
• Multi-adapters of context, request and view 
• Allows you to render some object differently 
due to the view in which it is being seen. 
• Add named adapters, and you have four 
possible axes for choosing a rendering 
These requirements led us to investigate a little-known zope package that powers the Plone portlet system.
Content Providers 
A content provider is and adapter, initializing it works much like its cousin the browser view. Then, when called, it is updated via an “update” method and 
then rendered to an HTML fragment via the template. 
! 
Once a generic version is set up, making a custom version can be as simple as subclassing, giving it a different name, and providing a different template.
Content Providers 
A content provider is and adapter, initializing it works much like its cousin the browser view. Then, when called, it is updated via an “update” method and 
then rendered to an HTML fragment via the template. 
! 
Once a generic version is set up, making a custom version can be as simple as subclassing, giving it a different name, and providing a different template.
In Cover Tiles 
In cover tiles, we created a “content provider” tile, which was essentially identical to the basic persistent tile from collective.cover. 
! 
The big difference was an added “content_provider” method, which resolved a name and passed that and the other required arguments into a 
“content_provider” module-level function. 
! 
This method was then called from the template for all “tiles” in the project. 
! 
The pass-through to the module-level function simply ran the standard content provider rendering chain, but allowed for a name-based resolution of 
which provider to render.
In Cover Tiles 
In cover tiles, we created a “content provider” tile, which was essentially identical to the basic persistent tile from collective.cover. 
! 
The big difference was an added “content_provider” method, which resolved a name and passed that and the other required arguments into a 
“content_provider” module-level function. 
! 
This method was then called from the template for all “tiles” in the project. 
! 
The pass-through to the module-level function simply ran the standard content provider rendering chain, but allowed for a name-based resolution of 
which provider to render.
In Cover Tiles 
In cover tiles, we created a “content provider” tile, which was essentially identical to the basic persistent tile from collective.cover. 
! 
The big difference was an added “content_provider” method, which resolved a name and passed that and the other required arguments into a 
“content_provider” module-level function. 
! 
This method was then called from the template for all “tiles” in the project. 
! 
The pass-through to the module-level function simply ran the standard content provider rendering chain, but allowed for a name-based resolution of 
which provider to render.
Picture of KCRW homepage 
This let us build features like this row on the live homepage, which contains two shows and one episode, managed by KCRW staff.
In Browserviews 
We can use the same basic trick in a browser view. First we add a “content_provider” method to the view code, then we call that code from the view 
template, passing in any arguments we need to customize each call. Finally, that same method renders a contextually appropriate provider, and returns an 
HTML fragment for the page to use.
In Browserviews 
We can use the same basic trick in a browser view. First we add a “content_provider” method to the view code, then we call that code from the view 
template, passing in any arguments we need to customize each call. Finally, that same method renders a contextually appropriate provider, and returns an 
HTML fragment for the page to use.
In Browserviews 
We can use the same basic trick in a browser view. First we add a “content_provider” method to the view code, then we call that code from the view 
template, passing in any arguments we need to customize each call. Finally, that same method renders a contextually appropriate provider, and returns an 
HTML fragment for the page to use.
In Browserviews 
We can use the same basic trick in a browser view. First we add a “content_provider” method to the view code, then we call that code from the view 
template, passing in any arguments we need to customize each call. Finally, that same method renders a contextually appropriate provider, and returns an 
HTML fragment for the page to use.
Picture of HR show homepage 
This style allowed us to create sections like these “featured content” blocks on the music area and individual show landing pages. Here, individual items 
gathered by a view method are individually rendered with contextually appropriate HTML, creating a dynamic and flexible page.
Picture of HR show homepage 
This style allowed us to create sections like these “featured content” blocks on the music area and individual show landing pages. Here, individual items 
gathered by a view method are individually rendered with contextually appropriate HTML, creating a dynamic and flexible page.
Outcomes 
• Using the same content provider let us 
write templates once, use anywhere 
• Having default names let us establish a 
standard display and then custom ones 
• Adapting catalog brains as context let us 
avoid expensive .getObject() calls 
In general, the outcomes of this approach were positive. Early investments in flexibility paid off as later additions “just worked”, with minimal updates.
Quirks 
• HCS design used a custom grid system 
• All rows shared the same markup 
• But cell markup differed depending on 
how many in a row 
• Not convenient for dynamic content 
• Required a custom grid engine for 
collective.cover 
• Would have been nice to have input in 
that decision 
But there were issues. For example, in service of the responsive design the custom grid provided by HCS put the responsibility for awareness of layout on 
cells within a row. From a programming perspective, this inversion of responsibility caused a bit of a headache. In retrospect I would recommend having 
a member of the development team on board in the theme planning process to allow for better coordination of approach.
Happily, collective.cover allows for customized grid layout engines, and we built one with a special case for every possible configuration of the layout. 
!
Ugly, but it works 
But It Works 
No, it wasn’t pretty, but it worked.
Other Features 
• Adapters provide consistent API for 
shared behavior 
• Views expose these APIs 
• Client-side .js plugins consume and 
display the data 
• Mobile app also consumes the same 
apis 
shared behavior apis: 
get latest airing 
get airings between x and y 
get upcoming things 
get playable media for this thing 
get data about media to be played
For example, the IPlayable adapter. The interface defined a number of properties and methods. An abstract implementation provided methods that could 
be coded the same for all content types. Then individual adapters for various content types, including catalog brains, allowed for customized approaches 
for various API methods. 
! 
The approach allows us to use a single API on various content types to provide information like download links for playable media files. These can be used 
in javascript plugins to power the download flyout menus that appear throughout the site.
For example, the IPlayable adapter. The interface defined a number of properties and methods. An abstract implementation provided methods that could 
be coded the same for all content types. Then individual adapters for various content types, including catalog brains, allowed for customized approaches 
for various API methods. 
! 
The approach allows us to use a single API on various content types to provide information like download links for playable media files. These can be used 
in javascript plugins to power the download flyout menus that appear throughout the site.
For example, the IPlayable adapter. The interface defined a number of properties and methods. An abstract implementation provided methods that could 
be coded the same for all content types. Then individual adapters for various content types, including catalog brains, allowed for customized approaches 
for various API methods. 
! 
The approach allows us to use a single API on various content types to provide information like download links for playable media files. These can be used 
in javascript plugins to power the download flyout menus that appear throughout the site.
For example, the IPlayable adapter. The interface defined a number of properties and methods. An abstract implementation provided methods that could 
be coded the same for all content types. Then individual adapters for various content types, including catalog brains, allowed for customized approaches 
for various API methods. 
! 
The approach allows us to use a single API on various content types to provide information like download links for playable media files. These can be used 
in javascript plugins to power the download flyout menus that appear throughout the site.
For example, the IPlayable adapter. The interface defined a number of properties and methods. An abstract implementation provided methods that could 
be coded the same for all content types. Then individual adapters for various content types, including catalog brains, allowed for customized approaches 
for various API methods. 
! 
The approach allows us to use a single API on various content types to provide information like download links for playable media files. These can be used 
in javascript plugins to power the download flyout menus that appear throughout the site.
For example, the IPlayable adapter. The interface defined a number of properties and methods. An abstract implementation provided methods that could 
be coded the same for all content types. Then individual adapters for various content types, including catalog brains, allowed for customized approaches 
for various API methods. 
! 
The approach allows us to use a single API on various content types to provide information like download links for playable media files. These can be used 
in javascript plugins to power the download flyout menus that appear throughout the site.
Other Features 
• Javascript-based player for live or 
recorded audio 
• Player can be broken out into a stand-alone 
window 
• Viewed on mobile, player can play when 
browser app is closed 
• Player is persistent across page loads 
The HCS designs called for an in-browser media player. One challenge was allowing playback in this player to persist across page loads as the user 
browsed the site.
By extending the powerful history.js plugin, we were able to ajaxify links, forms and other page-loading elements in the design. We were also able to 
include calls to google analytics, and reload all dynamic front-end features so that from the user’s perspective the site experience is smooth and 
unsurprising.
By extending the powerful history.js plugin, we were able to ajaxify links, forms and other page-loading elements in the design. We were also able to 
include calls to google analytics, and reload all dynamic front-end features so that from the user’s perspective the site experience is smooth and 
unsurprising.
By extending the powerful history.js plugin, we were able to ajaxify links, forms and other page-loading elements in the design. We were also able to 
include calls to google analytics, and reload all dynamic front-end features so that from the user’s perspective the site experience is smooth and 
unsurprising.
Other Features 
• Solr integration provides great search 
results (alm.solrindex) 
• Content from external WP blogs is 
regularly indexed and searchable 
• Content_provider approach helps theme 
external content distinctively 
A final feature was integration of the solr text search engine. We are now wrapping up a new feature that will index external blog content from KCRWs 
extensive WordPress blogiverse into their Plone site. This allows in-site search to surface external content alongside the content managed inside the site.
A celery-managed task runs daily to collect the blogs named in the site. 
! 
This fires off individual celery tasks to read and index the content from each blog. 
! 
The tasks result in the temporary creation of objects for each posts that live just long enough to be indexed into the catalog. 
! 
Then, our content providers allow us to represent these posts in a distinct way within search results.
A celery-managed task runs daily to collect the blogs named in the site. 
! 
This fires off individual celery tasks to read and index the content from each blog. 
! 
The tasks result in the temporary creation of objects for each posts that live just long enough to be indexed into the catalog. 
! 
Then, our content providers allow us to represent these posts in a distinct way within search results.
A celery-managed task runs daily to collect the blogs named in the site. 
! 
This fires off individual celery tasks to read and index the content from each blog. 
! 
The tasks result in the temporary creation of objects for each posts that live just long enough to be indexed into the catalog. 
! 
Then, our content providers allow us to represent these posts in a distinct way within search results.
A celery-managed task runs daily to collect the blogs named in the site. 
! 
This fires off individual celery tasks to read and index the content from each blog. 
! 
The tasks result in the temporary creation of objects for each posts that live just long enough to be indexed into the catalog. 
! 
Then, our content providers allow us to represent these posts in a distinct way within search results.
Many Thanks To 
• KCRW, who gave us the job 
• Alec Mitchell, who led the project 
• HCS, for the wonderful and feature-rich 
design 
• The creators and maintainers of the add-ons 
we used 
• PloneConf for the chance to show it all off 
And that’s all we have time for. There’s much more to cover, but at this point I’ll have to stop. 
! 
Before I do, thanks to all the folks involved in this project. It was enormously fun to build and satisfying to see in action.
And You! 
Any questions?
And You! 
questions? 
Any questions?

Weitere ähnliche Inhalte

Was ist angesagt?

Consuming RESTful services in PHP
Consuming RESTful services in PHPConsuming RESTful services in PHP
Consuming RESTful services in PHP
Zoran Jeremic
 
Reviewing CPAN modules
Reviewing CPAN modulesReviewing CPAN modules
Reviewing CPAN modules
neilbowers
 
Getting started with Catalyst and extjs
Getting started with Catalyst and extjsGetting started with Catalyst and extjs
Getting started with Catalyst and extjs
Peter Edwards
 

Was ist angesagt? (20)

Engage 2014 OpenNTF Domino API Slides
Engage 2014 OpenNTF Domino API SlidesEngage 2014 OpenNTF Domino API Slides
Engage 2014 OpenNTF Domino API Slides
 
Build Automation of PHP Applications
Build Automation of PHP ApplicationsBuild Automation of PHP Applications
Build Automation of PHP Applications
 
Devel::NYTProf v3 - 200908 (OUTDATED, see 201008)
Devel::NYTProf v3 - 200908 (OUTDATED, see 201008)Devel::NYTProf v3 - 200908 (OUTDATED, see 201008)
Devel::NYTProf v3 - 200908 (OUTDATED, see 201008)
 
CPAN Exporter modules for Perl 5
CPAN Exporter modules for Perl 5CPAN Exporter modules for Perl 5
CPAN Exporter modules for Perl 5
 
Stackato v6
Stackato v6Stackato v6
Stackato v6
 
Docker for Developers - PHP Detroit 2018
Docker for Developers - PHP Detroit 2018Docker for Developers - PHP Detroit 2018
Docker for Developers - PHP Detroit 2018
 
Laravel and Django and Rails, Oh My!
Laravel and Django and Rails, Oh My!Laravel and Django and Rails, Oh My!
Laravel and Django and Rails, Oh My!
 
Beyond 'Set it and Forget it': Proactively managing your EZproxy server
Beyond 'Set it and Forget it': Proactively managing your EZproxy serverBeyond 'Set it and Forget it': Proactively managing your EZproxy server
Beyond 'Set it and Forget it': Proactively managing your EZproxy server
 
Using PHP Functions! (Not those functions, Google Cloud Functions)
Using PHP Functions! (Not those functions, Google Cloud Functions)Using PHP Functions! (Not those functions, Google Cloud Functions)
Using PHP Functions! (Not those functions, Google Cloud Functions)
 
2021.laravelconf.tw.slides1
2021.laravelconf.tw.slides12021.laravelconf.tw.slides1
2021.laravelconf.tw.slides1
 
Consuming RESTful services in PHP
Consuming RESTful services in PHPConsuming RESTful services in PHP
Consuming RESTful services in PHP
 
Perl-Critic
Perl-CriticPerl-Critic
Perl-Critic
 
Reviewing CPAN modules
Reviewing CPAN modulesReviewing CPAN modules
Reviewing CPAN modules
 
Lisp in the Cloud
Lisp in the CloudLisp in the Cloud
Lisp in the Cloud
 
CakePHP 2.0 - PHP Matsuri 2011
CakePHP 2.0 - PHP Matsuri 2011CakePHP 2.0 - PHP Matsuri 2011
CakePHP 2.0 - PHP Matsuri 2011
 
Functional Programming for Busy Object Oriented Programmers
Functional Programming for Busy Object Oriented ProgrammersFunctional Programming for Busy Object Oriented Programmers
Functional Programming for Busy Object Oriented Programmers
 
MobileConf 2021 Slides: Let's build macOS CLI Utilities using Swift
MobileConf 2021 Slides:  Let's build macOS CLI Utilities using SwiftMobileConf 2021 Slides:  Let's build macOS CLI Utilities using Swift
MobileConf 2021 Slides: Let's build macOS CLI Utilities using Swift
 
Getting started with Catalyst and extjs
Getting started with Catalyst and extjsGetting started with Catalyst and extjs
Getting started with Catalyst and extjs
 
Webpack & EcmaScript 6 (Webelement #32)
Webpack & EcmaScript 6 (Webelement #32)Webpack & EcmaScript 6 (Webelement #32)
Webpack & EcmaScript 6 (Webelement #32)
 
Practical catalyst
Practical catalystPractical catalyst
Practical catalyst
 

Andere mochten auch

Andere mochten auch (18)

Code analysis for a better future
Code analysis for a better futureCode analysis for a better future
Code analysis for a better future
 
Lightning Talk: Security matters @ploneconf 2014
Lightning Talk: Security matters @ploneconf 2014Lightning Talk: Security matters @ploneconf 2014
Lightning Talk: Security matters @ploneconf 2014
 
The state of Plone Intranet
The state of Plone IntranetThe state of Plone Intranet
The state of Plone Intranet
 
Mosaic - flexibele layouts voor Plone
Mosaic - flexibele layouts voor PloneMosaic - flexibele layouts voor Plone
Mosaic - flexibele layouts voor Plone
 
Plone Hosting: A Panel Discussion
Plone Hosting: A Panel DiscussionPlone Hosting: A Panel Discussion
Plone Hosting: A Panel Discussion
 
Content's quality for Plone editors
Content's quality for Plone editorsContent's quality for Plone editors
Content's quality for Plone editors
 
Why CMS will not die
Why CMS will not dieWhy CMS will not die
Why CMS will not die
 
Historico das Conferencias Python Brasil
Historico das Conferencias Python BrasilHistorico das Conferencias Python Brasil
Historico das Conferencias Python Brasil
 
The Mountaineers: Scaling the Heights with Plone
The Mountaineers: Scaling the Heights with PloneThe Mountaineers: Scaling the Heights with Plone
The Mountaineers: Scaling the Heights with Plone
 
Resource registries plone conf 2014
Resource registries plone conf 2014Resource registries plone conf 2014
Resource registries plone conf 2014
 
PloneConf 2014 CDN terada
PloneConf 2014 CDN teradaPloneConf 2014 CDN terada
PloneConf 2014 CDN terada
 
TTW FTW: Plone as the new wordpress
TTW FTW: Plone as the new wordpressTTW FTW: Plone as the new wordpress
TTW FTW: Plone as the new wordpress
 
Plone deployment made easy
Plone deployment made easyPlone deployment made easy
Plone deployment made easy
 
Plone 5 theming unleashed
Plone 5 theming unleashedPlone 5 theming unleashed
Plone 5 theming unleashed
 
Plone Intranet Consortium - united we stand, divided we fall
Plone Intranet Consortium - united we stand, divided we fallPlone Intranet Consortium - united we stand, divided we fall
Plone Intranet Consortium - united we stand, divided we fall
 
Social, Digital & Mobile Around The World (January 2014)
Social, Digital & Mobile Around The World (January 2014)Social, Digital & Mobile Around The World (January 2014)
Social, Digital & Mobile Around The World (January 2014)
 
Recommender Systems (Machine Learning Summer School 2014 @ CMU)
Recommender Systems (Machine Learning Summer School 2014 @ CMU)Recommender Systems (Machine Learning Summer School 2014 @ CMU)
Recommender Systems (Machine Learning Summer School 2014 @ CMU)
 
Digital, Social & Mobile in 2015
Digital, Social & Mobile in 2015Digital, Social & Mobile in 2015
Digital, Social & Mobile in 2015
 

Ähnlich wie Ancient To Modern: Upgrading nearly a decade of Plone in public radio

CTS2 Development Framework In Action
CTS2 Development Framework In ActionCTS2 Development Framework In Action
CTS2 Development Framework In Action
cts2framework
 
Kubernetes @ meetic
Kubernetes @ meeticKubernetes @ meetic
Kubernetes @ meetic
SĂŠbastien Le Gall
 
04 integrate entityframework
04 integrate entityframework04 integrate entityframework
04 integrate entityframework
Erhwen Kuo
 

Ähnlich wie Ancient To Modern: Upgrading nearly a decade of Plone in public radio (20)

Genomic Computation at Scale with Serverless, StackStorm and Docker Swarm
Genomic Computation at Scale with Serverless, StackStorm and Docker SwarmGenomic Computation at Scale with Serverless, StackStorm and Docker Swarm
Genomic Computation at Scale with Serverless, StackStorm and Docker Swarm
 
Advanced Container Scheduling
Advanced Container SchedulingAdvanced Container Scheduling
Advanced Container Scheduling
 
Show Some Spine!
Show Some Spine!Show Some Spine!
Show Some Spine!
 
Intro to kubernetes
Intro to kubernetesIntro to kubernetes
Intro to kubernetes
 
Kubernetes Internals
Kubernetes InternalsKubernetes Internals
Kubernetes Internals
 
Building APIs in an easy way using API Platform
Building APIs in an easy way using API PlatformBuilding APIs in an easy way using API Platform
Building APIs in an easy way using API Platform
 
CTS2 Development Framework In Action
CTS2 Development Framework In ActionCTS2 Development Framework In Action
CTS2 Development Framework In Action
 
Docker in development
Docker in developmentDocker in development
Docker in development
 
Automation using Puppet 3
Automation using Puppet 3 Automation using Puppet 3
Automation using Puppet 3
 
Kubernetes @ meetic
Kubernetes @ meeticKubernetes @ meetic
Kubernetes @ meetic
 
How to – wrap soap web service around a database
How to – wrap soap web service around a databaseHow to – wrap soap web service around a database
How to – wrap soap web service around a database
 
Untangling - fall2017 - week 9
Untangling - fall2017 - week 9Untangling - fall2017 - week 9
Untangling - fall2017 - week 9
 
PLAT-8 Spring Web Scripts and Spring Surf
PLAT-8 Spring Web Scripts and Spring SurfPLAT-8 Spring Web Scripts and Spring Surf
PLAT-8 Spring Web Scripts and Spring Surf
 
Kubernetes Security with Calico and Open Policy Agent
Kubernetes Security with Calico and Open Policy AgentKubernetes Security with Calico and Open Policy Agent
Kubernetes Security with Calico and Open Policy Agent
 
[AWS Dev Day] 실습워크샵 | Amazon EKS 핸즈온 워크샵
 [AWS Dev Day] 실습워크샵 | Amazon EKS 핸즈온 워크샵 [AWS Dev Day] 실습워크샵 | Amazon EKS 핸즈온 워크샵
[AWS Dev Day] 실습워크샵 | Amazon EKS 핸즈온 워크샵
 
Web of things introduction
Web of things introductionWeb of things introduction
Web of things introduction
 
Puppet – Make stateful apps easier than stateless
Puppet – Make stateful apps easier than statelessPuppet – Make stateful apps easier than stateless
Puppet – Make stateful apps easier than stateless
 
04 integrate entityframework
04 integrate entityframework04 integrate entityframework
04 integrate entityframework
 
Advanced web application architecture Way2Web
Advanced web application architecture Way2WebAdvanced web application architecture Way2Web
Advanced web application architecture Way2Web
 
IE10 PP4 update for W3C HTML5 KIG
IE10 PP4 update for W3C HTML5 KIGIE10 PP4 update for W3C HTML5 KIG
IE10 PP4 update for W3C HTML5 KIG
 

Mehr von Cristopher Ewing

Mehr von Cristopher Ewing (9)

Getting Things Done with Content Rules
Getting Things Done with Content RulesGetting Things Done with Content Rules
Getting Things Done with Content Rules
 
Speaking at PyCon: The how and why
Speaking at PyCon: The how and whySpeaking at PyCon: The how and why
Speaking at PyCon: The how and why
 
Adaptation in Open Source Software, PyCon 2016 Keynote
Adaptation in Open Source Software, PyCon 2016 KeynoteAdaptation in Open Source Software, PyCon 2016 Keynote
Adaptation in Open Source Software, PyCon 2016 Keynote
 
Plone for Education: Bibliographies
Plone for Education: BibliographiesPlone for Education: Bibliographies
Plone for Education: Bibliographies
 
Jumpstart Your Development with ZopeSkel
Jumpstart Your Development with ZopeSkelJumpstart Your Development with ZopeSkel
Jumpstart Your Development with ZopeSkel
 
ZopeSkel: The past, present and future
ZopeSkel: The past, present and futureZopeSkel: The past, present and future
ZopeSkel: The past, present and future
 
Transmogrifier: Beyond the Magic Box
Transmogrifier: Beyond the Magic BoxTransmogrifier: Beyond the Magic Box
Transmogrifier: Beyond the Magic Box
 
Yes It Can: Leverage Workflow in Plone to Bring Business Process Online
Yes It Can: Leverage Workflow in Plone to Bring Business Process OnlineYes It Can: Leverage Workflow in Plone to Bring Business Process Online
Yes It Can: Leverage Workflow in Plone to Bring Business Process Online
 
We All Stand Together
We All Stand TogetherWe All Stand Together
We All Stand Together
 

KĂźrzlich hochgeladen

Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Safe Software
 
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
?#DUbAI#??##{{(☎️+971_581248768%)**%*]'#abortion pills for sale in dubai@
 

KĂźrzlich hochgeladen (20)

Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
 
DBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor PresentationDBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor Presentation
 
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
 
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, AdobeApidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
 
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
 
Apidays Singapore 2024 - Scalable LLM APIs for AI and Generative AI Applicati...
Apidays Singapore 2024 - Scalable LLM APIs for AI and Generative AI Applicati...Apidays Singapore 2024 - Scalable LLM APIs for AI and Generative AI Applicati...
Apidays Singapore 2024 - Scalable LLM APIs for AI and Generative AI Applicati...
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt Robison
 
MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024
 
Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processors
 
MS Copilot expands with MS Graph connectors
MS Copilot expands with MS Graph connectorsMS Copilot expands with MS Graph connectors
MS Copilot expands with MS Graph connectors
 
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...
 
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin WoodPolkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
 
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot TakeoffStrategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
 
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
 
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
 
AWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of TerraformAWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of Terraform
 
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
 
Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Script
 
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
 

Ancient To Modern: Upgrading nearly a decade of Plone in public radio

  • 1. Ancient To Modern Upgrading nearly a decade of Plone in Public Radio
  • 2. !Image Credit: Fall Path by john22s CC-BY (https://www.flickr.com/photos/21926145@N04/15242844379) this is the story of a journey
  • 3. Of how a site born to Plone nearly a decade ago ! Has grown with Plone ever since.
  • 4. Image Credit: Amy Marbach “puppy snuggles are the best” CC-BY-NC-ND https://www.flickr.com/photos/amyofbadgroove/14327508940 Of how a site born to Plone nearly a decade ago ! Has grown with Plone ever since.
  • 5. Image Credit: Amy Marbach “puppy snuggles are the best” CC-BY-NC-ND https://www.flickr.com/photos/amyofbadgroove/14327508940 Image Credit: Richard Miles “Who Walks Who?…” CC-BY_NC_ND https://www.flickr.com/photos/_f1guy68_/2231052733 Of how a site born to Plone nearly a decade ago ! Has grown with Plone ever since.
  • 6. Image Credit: Tym “Great Strength” CC-BY-NC-ND https://www.flickr.com/photos/tym/269105455 It’s a success story for Plone, which plays to its greatest strengths
  • 7. Image Credit: David Ellis CC- B Y -N C - N D https://www.flickr.com/photos/97578613@N08/10771455296 Also a morality play about how incautious customizations can make upgrading a challenge.
  • 9. Plone 2.0 It started back in 2005, with Plone 2.0
  • 10. The site had a nice, modern mid-aughts look and feel, with a clean color scheme and simple navigation.
  • 11. It also featured drop-down menus for the many top-level navigation targets, for that easy-to-discover feel.
  • 12. especially in areas where there were a large number of sub-items, like music shows in the “music” area.
  • 13. Image Credit: Louise Docker CC - B Y -NC-ND https://www.flickr.com/photos/aussiegall/6417891273 But like a lot of old things, it worked fine for its purpose
  • 14. A new theme doesn’t justify an upgrade
  • 15. There’s more! But the look-and-feel were not the only issues
  • 16. This method is called each time a “show” is viewed. ! The highlighted line is preparing to run a query against an external RDBMS ! This system was built to serve certain information from the Plone content to legacy PERL scripts, which were later abandoned.
  • 17. This method is called each time a “show” is viewed. ! The highlighted line is preparing to run a query against an external RDBMS ! This system was built to serve certain information from the Plone content to legacy PERL scripts, which were later abandoned.
  • 18. ZSQL scripts like this ran through much of the site functionality
  • 19. * SQLWindowStorage to store some AT field data in an external database * Inefficient to retrieve this data field-by-field * Leads to “optimization” code that retrieves values all at once and stores them persistently in object attributes * Since this happens on __view__ of an object, there are lots of conflict errors and retries, meaning less efficient operations and more potential for real errors.
  • 20. * SQLWindowStorage to store some AT field data in an external database * Inefficient to retrieve this data field-by-field * Leads to “optimization” code that retrieves values all at once and stores them persistently in object attributes * Since this happens on __view__ of an object, there are lots of conflict errors and retries, meaning less efficient operations and more potential for real errors.
  • 21. * SQLWindowStorage to store some AT field data in an external database * Inefficient to retrieve this data field-by-field * Leads to “optimization” code that retrieves values all at once and stores them persistently in object attributes * Since this happens on __view__ of an object, there are lots of conflict errors and retries, meaning less efficient operations and more potential for real errors.
  • 22. * SQLWindowStorage to store some AT field data in an external database * Inefficient to retrieve this data field-by-field * Leads to “optimization” code that retrieves values all at once and stores them persistently in object attributes * Since this happens on __view__ of an object, there are lots of conflict errors and retries, meaning less efficient operations and more potential for real errors.
  • 23. Image Credit: http://failblog.cheezburger.com/thereifixedit http://failblog.cheezburger.com/thereifixedit Clearly a safe and stable system for production. !
  • 24. Image Credit: Todd Jordan “Wednesday’s Angry Boss” CC-BY-NC-ND https://www.flickr.com/photos/tojosan/14374817787 This raised the level of anger enough to really justify a large scale upgrade project.
  • 25. Time for a Change
  • 26. Plone? But first, is Plone the right tool going forward?
  • 27. Reasons To Stay • Heterogenous content in a deep tree • Broad editorial staff with different access rights • In-Place management model • Staff familiarity • Transmogrifier There were definitely reasons to stay
  • 28. Upgrade or Migrate? • Want to use dexterity types for new site • Heavy customizations • Lots of not-best-practice code • Better just to “start over” Once the decision to stay was made, the next decision is to run an in-place upgrade, or a more extensive migration. !I n this case, starting from scratch was really desirable, though the content needed to be preserved
  • 29. Migration Out • Read content out from old Plone 2.5 site • quintagroup.transmogrifier • Marshall as json • collective.jsonify • Write site structure to disk • modified q.transmogrifier writer So a two-phase migration was planned, allowing us to transport the site content, stretching back into the late 1990s, into the new site.
  • 30. A simple export pipeline moved the content to the filesystem as a series of folders and .json files
  • 31. A simple export pipeline moved the content to the filesystem as a series of folders and .json files
  • 32. A simple export pipeline moved the content to the filesystem as a series of folders and .json files
  • 33. New Content Types • Dexterity Based • Custom shared behaviors • IAirings (for things that go on air) • IScheduled (for things that occur on a schedule) • IContentImages (for things that have a standard set of images associated) • … Next, time to set up the new content types. Using dexterity allowed us to build shared behaviors that would be used by different types.
  • 34. Migration In • Read in json and map old types to new • Split pipeline for individual type handling • Remap locationsCreate new content objects • Or, identify existing and update (repeatable) • Reconnect related objects With content types in place, the second phase involved migrating the content back into the new Plone site. ! This process featured a number of the nice properties of the transmogrifier system.
  • 35. The “splitter” pipeline section allows you to set up individual pipelines associated with some subset of your migrating content. ! You can predicate entry to a particular pipeline on any number of tests, but in this case we used the portal type to determine the path to take. ! A second feature is the ability to annotate the transmogrifier object itself with values like a mapping of user ids in the old system to UIDs for user objects in the new system. ! This mapping can then be shared from other pipeline sections that need to re-connect radio shows with their hosts and producers, or episodes with guests and artists.
  • 36. The “splitter” pipeline section allows you to set up individual pipelines associated with some subset of your migrating content. ! You can predicate entry to a particular pipeline on any number of tests, but in this case we used the portal type to determine the path to take. ! A second feature is the ability to annotate the transmogrifier object itself with values like a mapping of user ids in the old system to UIDs for user objects in the new system. ! This mapping can then be shared from other pipeline sections that need to re-connect radio shows with their hosts and producers, or episodes with guests and artists.
  • 37. The “splitter” pipeline section allows you to set up individual pipelines associated with some subset of your migrating content. ! You can predicate entry to a particular pipeline on any number of tests, but in this case we used the portal type to determine the path to take. ! A second feature is the ability to annotate the transmogrifier object itself with values like a mapping of user ids in the old system to UIDs for user objects in the new system. ! This mapping can then be shared from other pipeline sections that need to re-connect radio shows with their hosts and producers, or episodes with guests and artists.
  • 38. The “splitter” pipeline section allows you to set up individual pipelines associated with some subset of your migrating content. ! You can predicate entry to a particular pipeline on any number of tests, but in this case we used the portal type to determine the path to take. ! A second feature is the ability to annotate the transmogrifier object itself with values like a mapping of user ids in the old system to UIDs for user objects in the new system. ! This mapping can then be shared from other pipeline sections that need to re-connect radio shows with their hosts and producers, or episodes with guests and artists.
  • 39. The “splitter” pipeline section allows you to set up individual pipelines associated with some subset of your migrating content. ! You can predicate entry to a particular pipeline on any number of tests, but in this case we used the portal type to determine the path to take. ! A second feature is the ability to annotate the transmogrifier object itself with values like a mapping of user ids in the old system to UIDs for user objects in the new system. ! This mapping can then be shared from other pipeline sections that need to re-connect radio shows with their hosts and producers, or episodes with guests and artists.
  • 40. The “splitter” pipeline section allows you to set up individual pipelines associated with some subset of your migrating content. ! You can predicate entry to a particular pipeline on any number of tests, but in this case we used the portal type to determine the path to take. ! A second feature is the ability to annotate the transmogrifier object itself with values like a mapping of user ids in the old system to UIDs for user objects in the new system. ! This mapping can then be shared from other pipeline sections that need to re-connect radio shows with their hosts and producers, or episodes with guests and artists.
  • 41. 36 hours later Finally, we were able to run the migration. ! An advantage of the generator-based approach of transmogrifier is that although the migration took 36 hours, and moved well over 300,000 objects, including images fetched over HTTP, the memory usage was constant and the server had little problem completing the job.
  • 42. Now we have content! And now we have plone content, but it isn’t all that great looking.
  • 43. Make it pretty! Image Credit: Kevin O’Mara “I Feel Pretty” https://www.flickr.com/photos/kevinomara/13394685405
  • 44. The client engaged a well-known design firm in NYC, Hard Candy Shell
  • 45. ! fully responsive, changing UI elements size and positioning to fit the device. stylish, modern design
  • 46. ! fully responsive, changing UI elements size and positioning to fit the device. stylish, modern design
  • 47. ! fully responsive, changing UI elements size and positioning to fit the device. stylish, modern design
  • 48. The mockups featured a lot of “block” content ! With the same types of items appearing in different ways depending on location and purpose ! HTML consists of a lot of repeating fragments showing up in various places
  • 49. The mockups featured a lot of “block” content ! With the same types of items appearing in different ways depending on location and purpose ! HTML consists of a lot of repeating fragments showing up in various places
  • 50. The mockups featured a lot of “block” content ! With the same types of items appearing in different ways depending on location and purpose ! HTML consists of a lot of repeating fragments showing up in various places
  • 51. Other Requirements • Some pages had to be “composable” • collective.cover • Some pages would be pre-built, but feature dynamic content selection • custom browserviews & templates • We want to keep our code DRY
  • 52. zope.contentprovider • Much like a browserview, but for a fragment • Multi-adapters of context, request and view • Allows you to render some object differently due to the view in which it is being seen. • Add named adapters, and you have four possible axes for choosing a rendering These requirements led us to investigate a little-known zope package that powers the Plone portlet system.
  • 53. Content Providers A content provider is and adapter, initializing it works much like its cousin the browser view. Then, when called, it is updated via an “update” method and then rendered to an HTML fragment via the template. ! Once a generic version is set up, making a custom version can be as simple as subclassing, giving it a different name, and providing a different template.
  • 54. Content Providers A content provider is and adapter, initializing it works much like its cousin the browser view. Then, when called, it is updated via an “update” method and then rendered to an HTML fragment via the template. ! Once a generic version is set up, making a custom version can be as simple as subclassing, giving it a different name, and providing a different template.
  • 55. In Cover Tiles In cover tiles, we created a “content provider” tile, which was essentially identical to the basic persistent tile from collective.cover. ! The big difference was an added “content_provider” method, which resolved a name and passed that and the other required arguments into a “content_provider” module-level function. ! This method was then called from the template for all “tiles” in the project. ! The pass-through to the module-level function simply ran the standard content provider rendering chain, but allowed for a name-based resolution of which provider to render.
  • 56. In Cover Tiles In cover tiles, we created a “content provider” tile, which was essentially identical to the basic persistent tile from collective.cover. ! The big difference was an added “content_provider” method, which resolved a name and passed that and the other required arguments into a “content_provider” module-level function. ! This method was then called from the template for all “tiles” in the project. ! The pass-through to the module-level function simply ran the standard content provider rendering chain, but allowed for a name-based resolution of which provider to render.
  • 57. In Cover Tiles In cover tiles, we created a “content provider” tile, which was essentially identical to the basic persistent tile from collective.cover. ! The big difference was an added “content_provider” method, which resolved a name and passed that and the other required arguments into a “content_provider” module-level function. ! This method was then called from the template for all “tiles” in the project. ! The pass-through to the module-level function simply ran the standard content provider rendering chain, but allowed for a name-based resolution of which provider to render.
  • 58. Picture of KCRW homepage This let us build features like this row on the live homepage, which contains two shows and one episode, managed by KCRW staff.
  • 59. In Browserviews We can use the same basic trick in a browser view. First we add a “content_provider” method to the view code, then we call that code from the view template, passing in any arguments we need to customize each call. Finally, that same method renders a contextually appropriate provider, and returns an HTML fragment for the page to use.
  • 60. In Browserviews We can use the same basic trick in a browser view. First we add a “content_provider” method to the view code, then we call that code from the view template, passing in any arguments we need to customize each call. Finally, that same method renders a contextually appropriate provider, and returns an HTML fragment for the page to use.
  • 61. In Browserviews We can use the same basic trick in a browser view. First we add a “content_provider” method to the view code, then we call that code from the view template, passing in any arguments we need to customize each call. Finally, that same method renders a contextually appropriate provider, and returns an HTML fragment for the page to use.
  • 62. In Browserviews We can use the same basic trick in a browser view. First we add a “content_provider” method to the view code, then we call that code from the view template, passing in any arguments we need to customize each call. Finally, that same method renders a contextually appropriate provider, and returns an HTML fragment for the page to use.
  • 63. Picture of HR show homepage This style allowed us to create sections like these “featured content” blocks on the music area and individual show landing pages. Here, individual items gathered by a view method are individually rendered with contextually appropriate HTML, creating a dynamic and flexible page.
  • 64. Picture of HR show homepage This style allowed us to create sections like these “featured content” blocks on the music area and individual show landing pages. Here, individual items gathered by a view method are individually rendered with contextually appropriate HTML, creating a dynamic and flexible page.
  • 65. Outcomes • Using the same content provider let us write templates once, use anywhere • Having default names let us establish a standard display and then custom ones • Adapting catalog brains as context let us avoid expensive .getObject() calls In general, the outcomes of this approach were positive. Early investments in flexibility paid off as later additions “just worked”, with minimal updates.
  • 66. Quirks • HCS design used a custom grid system • All rows shared the same markup • But cell markup differed depending on how many in a row • Not convenient for dynamic content • Required a custom grid engine for collective.cover • Would have been nice to have input in that decision But there were issues. For example, in service of the responsive design the custom grid provided by HCS put the responsibility for awareness of layout on cells within a row. From a programming perspective, this inversion of responsibility caused a bit of a headache. In retrospect I would recommend having a member of the development team on board in the theme planning process to allow for better coordination of approach.
  • 67. Happily, collective.cover allows for customized grid layout engines, and we built one with a special case for every possible configuration of the layout. !
  • 68. Ugly, but it works But It Works No, it wasn’t pretty, but it worked.
  • 69. Other Features • Adapters provide consistent API for shared behavior • Views expose these APIs • Client-side .js plugins consume and display the data • Mobile app also consumes the same apis shared behavior apis: get latest airing get airings between x and y get upcoming things get playable media for this thing get data about media to be played
  • 70. For example, the IPlayable adapter. The interface defined a number of properties and methods. An abstract implementation provided methods that could be coded the same for all content types. Then individual adapters for various content types, including catalog brains, allowed for customized approaches for various API methods. ! The approach allows us to use a single API on various content types to provide information like download links for playable media files. These can be used in javascript plugins to power the download flyout menus that appear throughout the site.
  • 71. For example, the IPlayable adapter. The interface defined a number of properties and methods. An abstract implementation provided methods that could be coded the same for all content types. Then individual adapters for various content types, including catalog brains, allowed for customized approaches for various API methods. ! The approach allows us to use a single API on various content types to provide information like download links for playable media files. These can be used in javascript plugins to power the download flyout menus that appear throughout the site.
  • 72. For example, the IPlayable adapter. The interface defined a number of properties and methods. An abstract implementation provided methods that could be coded the same for all content types. Then individual adapters for various content types, including catalog brains, allowed for customized approaches for various API methods. ! The approach allows us to use a single API on various content types to provide information like download links for playable media files. These can be used in javascript plugins to power the download flyout menus that appear throughout the site.
  • 73. For example, the IPlayable adapter. The interface defined a number of properties and methods. An abstract implementation provided methods that could be coded the same for all content types. Then individual adapters for various content types, including catalog brains, allowed for customized approaches for various API methods. ! The approach allows us to use a single API on various content types to provide information like download links for playable media files. These can be used in javascript plugins to power the download flyout menus that appear throughout the site.
  • 74. For example, the IPlayable adapter. The interface defined a number of properties and methods. An abstract implementation provided methods that could be coded the same for all content types. Then individual adapters for various content types, including catalog brains, allowed for customized approaches for various API methods. ! The approach allows us to use a single API on various content types to provide information like download links for playable media files. These can be used in javascript plugins to power the download flyout menus that appear throughout the site.
  • 75. For example, the IPlayable adapter. The interface defined a number of properties and methods. An abstract implementation provided methods that could be coded the same for all content types. Then individual adapters for various content types, including catalog brains, allowed for customized approaches for various API methods. ! The approach allows us to use a single API on various content types to provide information like download links for playable media files. These can be used in javascript plugins to power the download flyout menus that appear throughout the site.
  • 76. Other Features • Javascript-based player for live or recorded audio • Player can be broken out into a stand-alone window • Viewed on mobile, player can play when browser app is closed • Player is persistent across page loads The HCS designs called for an in-browser media player. One challenge was allowing playback in this player to persist across page loads as the user browsed the site.
  • 77. By extending the powerful history.js plugin, we were able to ajaxify links, forms and other page-loading elements in the design. We were also able to include calls to google analytics, and reload all dynamic front-end features so that from the user’s perspective the site experience is smooth and unsurprising.
  • 78. By extending the powerful history.js plugin, we were able to ajaxify links, forms and other page-loading elements in the design. We were also able to include calls to google analytics, and reload all dynamic front-end features so that from the user’s perspective the site experience is smooth and unsurprising.
  • 79. By extending the powerful history.js plugin, we were able to ajaxify links, forms and other page-loading elements in the design. We were also able to include calls to google analytics, and reload all dynamic front-end features so that from the user’s perspective the site experience is smooth and unsurprising.
  • 80. Other Features • Solr integration provides great search results (alm.solrindex) • Content from external WP blogs is regularly indexed and searchable • Content_provider approach helps theme external content distinctively A final feature was integration of the solr text search engine. We are now wrapping up a new feature that will index external blog content from KCRWs extensive WordPress blogiverse into their Plone site. This allows in-site search to surface external content alongside the content managed inside the site.
  • 81. A celery-managed task runs daily to collect the blogs named in the site. ! This fires off individual celery tasks to read and index the content from each blog. ! The tasks result in the temporary creation of objects for each posts that live just long enough to be indexed into the catalog. ! Then, our content providers allow us to represent these posts in a distinct way within search results.
  • 82. A celery-managed task runs daily to collect the blogs named in the site. ! This fires off individual celery tasks to read and index the content from each blog. ! The tasks result in the temporary creation of objects for each posts that live just long enough to be indexed into the catalog. ! Then, our content providers allow us to represent these posts in a distinct way within search results.
  • 83. A celery-managed task runs daily to collect the blogs named in the site. ! This fires off individual celery tasks to read and index the content from each blog. ! The tasks result in the temporary creation of objects for each posts that live just long enough to be indexed into the catalog. ! Then, our content providers allow us to represent these posts in a distinct way within search results.
  • 84. A celery-managed task runs daily to collect the blogs named in the site. ! This fires off individual celery tasks to read and index the content from each blog. ! The tasks result in the temporary creation of objects for each posts that live just long enough to be indexed into the catalog. ! Then, our content providers allow us to represent these posts in a distinct way within search results.
  • 85. Many Thanks To • KCRW, who gave us the job • Alec Mitchell, who led the project • HCS, for the wonderful and feature-rich design • The creators and maintainers of the add-ons we used • PloneConf for the chance to show it all off And that’s all we have time for. There’s much more to cover, but at this point I’ll have to stop. ! Before I do, thanks to all the folks involved in this project. It was enormously fun to build and satisfying to see in action.
  • 86. And You! Any questions?
  • 87. And You! questions? Any questions?