43
Live Coverage at The New York Times WordPress VIP Developer Workshop Napa, California - May 5, 2015

Live Coverage at The New York Times

Embed Size (px)

Citation preview

Page 1: Live Coverage at The New York Times

Live Coverage at The New York Times

WordPress VIP Developer Workshop Napa, California - May 5, 2015

Page 2: Live Coverage at The New York Times

Scott Taylor• Core Developer, WordPress

open source project

• Release Lead for 4.4

• Sr. Software Engineer, The New York Times

• @wonderboymusic on Twitter/Instagram/Swarm

• I like Music, NYC, and Mexican food

Page 3: Live Coverage at The New York Times

Blogs at the New York Times• The 00s were the glory days

for Blogs and WordPress

• Separate from the rest of the codebase (NYT4)

• Global NYTimes CSS and JS, CSS for all Blogs, custom CSS per-blog

• A universe that assumed jQuery AND Prototype were loaded on the page in global scope

Page 4: Live Coverage at The New York Times

What could possibly go wrong here?

Page 5: Live Coverage at The New York Times

• Inline HTML from 2008 that assumes Prototype will still be a thing in 2015, stored in post_content

• Widgets and inline code that add their own version of jQuery/Prototype, because YOLO

• Even better: widgets/modules from other teams that use a different version of jQuery … at times there could be 4 jQuerys on the page (4 diff versions)

Page 6: Live Coverage at The New York Times

No shared modules• Code/HTML markup can get out of sync with other

projects regularly (header/footer/nav)

• The CSS and JS files split across multiple SVN repos - changes to global assets can affect us without us knowing. Fixing the code requires scouring through multiple repos.

• The blogs team divided front-end and back-end responsibilities. Typically, no one had a full view of features or the architecture as a whole

Page 7: Live Coverage at The New York Times

At the NYT, we don’t use …• WordPress Comments: There is an entire team that deals with

these for the site globally, in a different system called CRNR

• Media: There is another CMS at the Times, Scoop, which stores the images, videos, slideshows, etc

• WordPress native post-locking: This only landed in WordPress core in version 3.6, we have yet to reconcile the differences

• There is layer for Bylines which is separate from Users: Our users are employees authenticated via LDAP, most post authors don’t actually enter the content themselves

Page 8: Live Coverage at The New York Times

Live Blogs at the TimesSince 2008

Page 9: Live Coverage at The New York Times

• A Blog would create a post and check “Start Live Blogging”

• the updates related to the post were stored in custom tables in the database

• the APIs for interacting with these tables duplicated tons of WordPress functionality

• Custom Post Types didn’t exist until WordPress 3.0 (June 2010) - the NYT code was never rewritten to leverage them (would have required porting the content as well)

Page 10: Live Coverage at The New York Times

As Time Went On, A Mess to Update and Maintain

Page 11: Live Coverage at The New York Times

The Next Iteration: Dashboards/Dashblogs

• A Live Blog would be its own blog in the network, its own set of tables

• A special dashboard theme that had hooks to add custom JS/CSS for each individual blog, without baking them into the theme

• Making an entirely new site in the network for a 4-hour event is overkill

• For every 10 or so new blogs that are added, you are adding 100 new database tables - gross!

Page 12: Live Coverage at The New York Times

2013: The New FrontierI arrived at the New York Times

Page 13: Live Coverage at The New York Times
Page 14: Live Coverage at The New York Times
Page 15: Live Coverage at The New York Times
Page 16: Live Coverage at The New York Times

NYT5• NYT5 “apps” are Git repos that are transformed via

Grunt into a new directory structure. You can’t run your repo as a website: it has to be built

• Impossible to create a “theme” this time with shared JS and CSS - CSS is SASS, JS is Require.

• PHP for shared components has Composer dependencies and uses namespaces - the directories are expanded via Grunt in accordance with PSR-0 Autoloading Standard

Page 17: Live Coverage at The New York Times

NYT5 Dealbreakers• We can’t just point at WordPress on every request

and have our code figure out routing. Apache points to app.php in NYT5

• Because PHP Namespaces are used, WP has to load early and outside of them (global scope)

• On the frontend, WP cannot exit prematurely before hitting the framework, which returns the response to the server via Symfony\HttpFoundation

Page 18: Live Coverage at The New York Times

NYT5 Advantages

• “shared” modules - we inherit the “shell” of the page, which includes: navigation, footer, login, etc.

• our nyt5 theme doesn’t need to produce an entire HTML document, just the “content” portion

• With WP in global scope, all of its code is available even when we hit the MVC parts of the NYT5 framework.

• WP output is captured via an output buffer on load - it’s accessible downstream when the app logic is running.

Page 19: Live Coverage at The New York Times

• We can inherit the global Varnish setup and ditch Batcache

• Instead of rendering media HTML, our [nytmedia] shortcodes can just output “markers”

• The NYT5 logic for articles already knows to replace these markers with markup that is generated from shared modules - and the data is fetched using parallel HTTP from internal asset stores (JSON).

• At the end of the day, we were able to eradicate a lot of old, terrible code and lean on code from foundation and shared repos

Page 20: Live Coverage at The New York Times

What about the old code that used inline Prototype JS code?• I wrote a filter on ‘the_content’ that does a quick string

scan to see if one of the old slideshows exists in post’s content. If it does, I wrote RegEx that replaces the slideshow blob on the fly with a new blob that leverages our Require code. I am not proud of this, but it works, and it replaces the need to migrate potentially 100s or 1000s of posts in the database.

• Whenever I can, I choose to not ignore legacy or archival content - since it’s all still searchable on the net, why let it die a death by Prototype?

Page 21: Live Coverage at The New York Times

Bad News for Blogs• Blogs were duplicating Section Fronts, Columns: Mark Bittman has column in the paper.The column also exists on the web as an article. He contributes to the Diner’s Journal blog. There is a section front for dining. He also has his own NYTimes blog. Why?

• Blogs and WordPress were combined in everyone’s mind. So whenever WordPress was mentioned as a solution for anything, the response was: aren’t blogs going away? #dark

Page 22: Live Coverage at The New York Times

First Draft Lens

Live Coverage

Page 23: Live Coverage at The New York Times
Page 24: Live Coverage at The New York Times
Page 25: Live Coverage at The New York Times

What if…• Instead of using those custom tables

and all of that weird code, we could actually create new object types: events and updates!

• To create a new “Live Blog”: you only need to create an event, then go to a Backbone-powered screen to add updates

• Even if WordPress isn’t desired for the front end, it could be the backend for anything that wants a JSON feed for live event data

• Because we would be using custom post types, building a Live Event UI that looks like the NYT5 theme would be nominal

Page 26: Live Coverage at The New York Times

• Built an admin interface with Backbone to quickly produce content - which in turn could be read from JSON feeds.

• When saving, the updates post into a service we have called Invisible City

• Our first real foray into using the JSON API (WP-API)

• Our plan was just to be admin to produce data via self-service URLs

What we did

Page 27: Live Coverage at The New York Times

Live EventsThe new Live Blogs

Page 28: Live Coverage at The New York Times

Complete Rewrite of 2008 code

• nytimes.com/live/{event} and nytimes.com/live/{event}/{update}

• Brand new admin interface: Backbone app that uses the WP-API. Constantly updated filterable stream - Backbone collections that re-fetch on Heartbeat tick

• Custom JSON endpoints that handle processes that need to happen on save

• Front end served by WordPress for SEO, but data is received by web socket from Invisible City and rendered via React

Page 29: Live Coverage at The New York Times
Page 30: Live Coverage at The New York Times
Page 31: Live Coverage at The New York Times

Responsive on Mobile

Page 32: Live Coverage at The New York Times

Some gotchas…

Page 33: Live Coverage at The New York Times

Most plugins only handle POST

• WP-API and Backbone speak REST

• REST will send you requests via PUT, DELETE, POST

Page 34: Live Coverage at The New York Times

$hook = add_menu_page( . . . );add_action( “load-$hook”, ‘custom_load’ );

function old_custom_load() { if ( ‘POST’ !== $_SERVER[‘REQUEST_METHOD’] ) { return; } . . .

}

function new_custom_load() { if ( ‘GET’ === $_SERVER[‘REQUEST_METHOD’] ) { return; } . . .

}

Page 35: Live Coverage at The New York Times

HTTP is time-consuming• Admin needs to be fast

• The front end is typically cached, but page generation shouldn’t be bogged down by HTTP requests

• It is easy to lose track of how many things are happening on the ‘save_post’ hook

• Anything which is time-consuming should be offloaded to a separate “process” or request who response you don’t need to handle

Page 36: Live Coverage at The New York Times

wp_remote_post( $url, wp_parse_args( array(‘timeout’ => 0.01,‘blocking’ => false

), $args ) );

Fire and Forget*

* Stolen from Mark Jaquith’s nginx cache invalidation technique: wp_remote_get( $url, array(

‘timeout’ => 0.01, ‘blocking’ => false, ‘headers’ => array( ‘X-Nginx-Cache-Purge’ => ‘1’ )

) );

Page 37: Live Coverage at The New York Times

Custom JSON Endpoints for POST

• Use fire-and-forget technique on save, instead of waiting for responses inline. You can still log/handle/re-try responses in the separate request.

• Most things that happen on ‘save_post’ only need to know $post_id for context, the endpoint handler can call get_post() from there

Page 38: Live Coverage at The New York Times

Register a route:$routes[ '/live-events/(?P<post_id>\d+)/sns' ] = array(

array( array( $this, 'live_event_sns' ), WP_JSON_Server::CREATABLE

),);

$routes[ '/async-cream-invalidation' ] = array(array(

array( $this, 'async_cream' ), WP_JSON_Server::CREATABLE

),);

Page 39: Live Coverage at The New York Times

Handle the route:public function async_cream() {

$urls = array_map( 'stripslashes', $_POST['urls'] );if ( $urls ) {

nyt_cream_invalidation( $urls );}exit();

}

Page 40: Live Coverage at The New York Times

Trigger the process:NYT_Admin_JSON::async_request( '/async-cream-invalidation', array(‘body’ => array('urls' => $urls

))

);

Page 41: Live Coverage at The New York Times

Custom JSON Endpoints for GET

• We do not hit these endpoints on the front-end

• We have a storage mount that is fronted via Varnish and Akamai

• JSON feeds can show up on the homepage of the NYT to dynamically render “promos” - these have to massively scale

Page 42: Live Coverage at The New York Times

An “Interactive Promo” on an article page

Page 43: Live Coverage at The New York Times

Questions?