Share
Embed
LoopConf - Burn it down: A case study in CMS replatforming
This session will be a case study of a major media company using WordPress as an enterprise grade CMS. We will cover how improved media editing, editorial workflow, and an API first process can take WordPress beyond its blogging stereotype.
Peter Wilson
February 22, 2018
Transcript
194 slides
-
Peter Wilson ◦ @pwcc ◦ peterwilson.cc Burn it down: A
case study in CMS replatforming -
$must_use_plugins = [ 'ffx-options/plugin.php', // Filter get_option calls. /* ...
Vendor plugins snipped ... */ 'ffx-helpers/plugin.php', // Available during bootstrap. 'ffx-feature-flags/plugin.php', // Available during bootstrap. 'ffx-api-content/plugin.php', 'ffx-api-media/plugin.php', 'ffx-roles-capabilities/plugin.php', 'ffx-article-editor/plugin.php', 'ffx-live-articles/plugin.php', 'ffx-notifications/plugin.php', 'ffx-shortcake/plugin.php', 'ffx-brightcove/plugin.php', 'ffx-profiles/plugin.php', 'ffx-unpublish/plugin.php', 'ffx-wire-feed/plugin.php', 'ffx-image-editor/plugin.php', 'ffx-taxonomies/plugin.php', 'ffx-dashboard/plugin.php', 'ffx-publishing/plugin.php', 'ffx-tooltips/plugin.php', ]; -
GET 50 tags wp_insert_term( /* Roxie Hart */ ); wp_insert_term(
/* Billy Flynn */ ); wp_insert_term( /* Velma Kelly */ ); wp_insert_term( /* x 50 */ ); Content API -
wp_insert_term( 'Roxie Hart', 'ffx_tags', [ 'slug' => 'roxie-hart', 'parent' =>
'105', ] ); add_term_meta( 23170, '_ffx_id', 'h4rt' ); add_term_meta( 23170, '_ffx_term_meta', [ /* */ ] ); -
# Check term exists (slug) SELECT tt.term_id, tt.term_taxonomy_id FROM wp_terms
AS t INNER JOIN wp_term_taxonomy as tt ON tt.term_id = t.term_id WHERE t.slug = 'roxie-hart' AND tt.parent = '105' AND tt.taxonomy = 'ffx_tag' ORDER BY t.term_id ASC LIMIT 1 -
SELECT tt.term_id, tt.term_taxonomy_id FROM wp_terms AS t INNER JOIN wp_term_taxonomy
as tt ON tt.term_id = t.term_id AND tt.parent = '105' AND tt.taxonomy = 'ffx_tag' ORDER BY t.term_id ASC LIMIT 1 -
SELECT tt.term_id, tt.term_taxonomy_id FROM wp_terms AS t INNER JOIN wp_term_taxonomy
as tt ON tt.term_id = t.term_id AND tt.parent = '105' AND tt.taxonomy = 'ffx_tag' ORDER BY t.term_id ASC LIMIT 1 # Check term exists (name) WHERE t.name = 'Roxie Hart' -
# Check if (name) exists with same parent. SELECT t.*,
tt.* FROM wp_terms AS t INNER JOIN wp_term_taxonomy AS tt ON t.term_id = tt.term_id WHERE tt.taxonomy IN ('ffx_tag') AND t.name IN ('Roxie Hart') AND tt.parent = '105' ORDER BY t.name ASC -
# Check slug is unique SELECT term_id FROM wp_terms as
t WHERE t.slug = 'roxie-hart' ORDER BY t.term_id ASC LIMIT 1 -
# Insert the tag INSERT INTO `wp_terms` (`name`,`slug`,`term_group`) VALUES ('Roxie
Hart', 'roxie-hart', 0) -
# Check if the relationship data exists. SELECT tt.term_taxonomy_id FROM
wp_term_taxonomy AS tt INNER JOIN wp_terms AS t ON tt.term_id = t.term_id WHERE tt.taxonomy = 'ffx_tag' AND t.term_id = 23170 -
# Actually insert the relationship data. INSERT INTO `wp_term_taxonomy` (
`term_id`, `taxonomy`, `description`, `parent`, `count` ) VALUES (23170, 'ffx_tag', '', 105, 0) -
# Logic check for duplicates. SELECT t.term_id, tt.term_taxonomy_id FROM wp_terms
t INNER JOIN wp_term_taxonomy tt ON ( tt.term_id = t.term_id ) WHERE t.slug = 'roxie-hart' AND tt.parent = 105 AND tt.taxonomy = 'ffx_tag' AND t.term_id < 23170 AND tt.term_taxonomy_id != 23170 -
# Warm term meta cache SELECT term_id, meta_key, meta_value FROM
wp_ter # Check for meta key inserting SELECT meta_id FROM wp_termmeta WHERE meta_key = # Insert the meta key INSERT INTO `wp_termmeta` (`term_id`, `meta_key` -
# Delete term hierarchy option DELETE FROM `wp_options` WHERE `option_name`
= 'ffx_tag_children' # Get term hierarchy option (for reasons) SELECT option_value FROM wp_options WHERE option_name = 'ffx_tag_children # Select all terms in the taxonomy to work out hierarchy SELECT t.term_id, tt.parent, tt.count, tt.taxonomy FROM wp_terms AS t I # Warm the term meta cache for all (a bug) SELECT term_id, meta_key, meta_value FROM wp_termmeta WHERE term_id IN (9 # Update the term hierarchy option INSERT INTO `wp_options` (`option_name`, `option_value`, `autoload`) -
// Get the total number of pages. $total_pages = get_total_pages();
for ( $page = 1; $page <= $total_pages; $page++ ) { // Get all the tags we need to process on the current page. $tags = get_tags_from_api( $page ); // Schedule a single event to create or update terms. wp_schedule_single_event( time() + ( 10 * $page * MINUTE_IN_SECONDS ), 'ffx_import_some_terms_action', $tags ); } -
Complex sites need scheduled tasks & asynchronous processing. Meet Cavalcade:
A #WordPress jobs processing solution humanmade.com/cavalcade Human Made @humanmadeltd 5:31 AM - 30 May 2017 -
That’s what we forgot HTTP requests time out Prairie Kittin,
flic.kr/p/a4Ujpv -
update_option( 'cron', [ /* ... */ ] ); wp_insert_term( 'Roxie
Hart', 'ffx_tags', [ 'slug' => 'roxie-hart', 'parent' => '105', ] ); add_term_meta( 23170, '_ffx_id', 'h4rt' ); add_term_meta( 23170, '_ffx_term_meta', [ /* */ ] ); -
update_option( 'cron', [ /* ... */ ] ); wp_insert_term( 'Roxie
Hart', 'ffx_tags', [ 'slug' => 'roxie-hart', 'parent' => '105', ] ); add_term_meta( 23170, '_ffx_id', 'h4rt' ); add_term_meta( 23170, '_ffx_term_meta', [ /* */ ] ); wp_insert_term( 'Roxie Hart', 'ffx_tags', [ 'slug' => 'roxie-hart', 'parent' => '105', ] ); add_term_meta( 23170, '_ffx_id', 'h4rt' ); add_term_meta( 23170, '_ffx_term_meta', [ /* */ ] ); -
update_option( 'cron', [ /* ... */ ] ); wp_insert_term( 'Roxie
Hart', 'ffx_tags', [ 'slug' => 'roxie-hart', 'parent' => '105', ] ); add_term_meta( 23170, '_ffx_id', 'h4rt' ); add_term_meta( 23170, '_ffx_term_meta', [ /* */ ] ); wp_insert_term( 'Roxie Hart', 'ffx_tags', [ 'slug' => 'roxie-hart', 'parent' => '105', ] ); add_term_meta( 23170, '_ffx_id', 'h4rt' ); add_term_meta( 23170, '_ffx_term_meta', [ /* */ ] ); wp_insert_term( 'Roxie Hart', 'ffx_tags', [ 'slug' => 'roxie-hart', 'parent' => '105', ] ); add_term_meta( 23170, '_ffx_id', 'h4rt' ); add_term_meta( 23170, '_ffx_term_meta', [ /* */ ] ); wp_insert_term( 'Roxie Hart', 'ffx_tags', [ 'slug' => 'roxie-hart', 'parent' => '105', ] ); add_term_meta( 23170, '_ffx_id', 'h4rt' ); add_term_meta( 23170, '_ffx_term_meta', [ /* */ ] ); wp_insert_term( 'Roxie Hart', 'ffx_tags', [ 'slug' => 'roxie-hart', 'parent' => '105', ] ); add_term_meta( 23170, '_ffx_id', 'h4rt' ); add_term_meta( 23170, '_ffx_term_meta', [ /* */ ] ); wp_insert_term( 'Roxie Hart', 'ffx_tags', [ 'slug' => 'roxie-hart', 'parent' => '105', ] ); add_term_meta( 23170, '_ffx_id', 'h4rt' ); add_term_meta( 23170, '_ffx_term_meta', [ /* */ ] ); wp_insert_term( 'Roxie Hart', 'ffx_tags', [ 'slug' => 'roxie-hart', 'parent' => '105', ] ); add_term_meta( 23170, '_ffx_id', 'h4rt' ); add_term_meta( 23170, '_ffx_term_meta', [ /* */ ] ); wp_insert_term( 'Roxie Hart', 'ffx_tags', [ 'slug' => 'roxie-hart', 'parent' => '105', ] ); add_term_meta( 23170, '_ffx_id', 'h4rt' ); add_term_meta( 23170, '_ffx_term_meta', [ /* */ ] ); wp_insert_term( 'Roxie Hart', 'ffx_tags', [ 'slug' => 'roxie-hart', 'parent' => '105', ] ); add_term_meta( 23170, '_ffx_id', 'h4rt' ); add_term_meta( 23170, '_ffx_term_meta', [ /* */ ] ); wp_insert_term( 'Roxie Hart', 'ffx_tags', [ 'slug' => 'roxie-hart', 'parent' => '105', ] ); add_term_meta( 23170, '_ffx_id', 'h4rt' ); add_term_meta( 23170, '_ffx_term_meta', [ /* */ ] ); -
Complex sites need scheduled tasks & asynchronous processing. Meet Cavalcade:
A #WordPress jobs processing solution humanmade.com/cavalcade Human Made @humanmadeltd 5:31 AM - 30 May 2017 -
/** * Register hooks for WordPress. */ add_filter( 'pre_update_option_cron', 'update_cron_array',
10, 2 add_filter( 'pre_option_cron', 'get_cron_array' ); -
// Get the total number of pages. $total_pages = get_total_pages();
for ( $page = 1; $page <= $total_pages; $page++ ) { // Get all the tags we need to process on the current page. $tags = get_tags_from_api( $page ); // Schedule a single event to create or update terms. wp_schedule_single_event( time() + ( 10 * $page * MINUTE_IN_SECONDS ), 'ffx_import_some_terms_action', $tags ); } -
// Get the total number of pages. $total_pages = get_total_pages();
for ( $page = 1; $page <= $total_pages; $page++ ) { // Get all the tags we need to process on the current page. $tags = get_tags_from_api( $page ); // Schedule a single event to create or update terms. wp_schedule_single_event( time(), // Schedule all pages NOW! 'ffx_import_some_terms_action', $tags ); } -
// Get the total number of pages. $total_pages = get_total_pages();
for ( $page = 1; $page <= $total_pages; $page++ ) { // Get all the tags we need to process on the current page. $tags = get_tags_from_api( $page ); // Schedule a single event to create or update terms. wp_schedule_single_event( time(), // Schedule all pages NOW! 'ffx_import_some_terms_action', $tags ); } -
// Get the total number of pages. $total_pages = get_total_pages();
for ( $page = 1; $page <= $total_pages; $page++ ) { // Set the arguments needed to process the current page. $args = [ 'page' => $page, 'qty' => 50 ]; // Schedule a single event to create or update terms. wp_schedule_single_event( time(), // Schedule all pages NOW! 'ffx_import_tags_cron', $args ); } -
// Update the scheduling lock. update_option( TAGS_SCHEDULING_LOCK_OPTION, time() ); //
Get the total number of pages. $total_pages = get_total_pages(); for ( $page = 1; $page <= $total_pages; $page++ ) { // Set the arguments needed to process the current page. $args = [ 'page' => $page, 'qty' => 50 ]; // Schedule a single event to create or update terms. wp_schedule_single_event( -
wp_schedule_single_event( time(), // Schedule all pages NOW! 'ffx_import_tags_cron', $args );
} // Delete the scheduling lock. delete_option( TAGS_SCHEDULING_LOCK_OPTION ); update_option( TAGS_SCHEDULED_LOCK_OPTION, time() ); -
[11] Worker out: [11] Worker err: [11] Worker ret: 0
[12] Worker status: Array ( [command] => wp cavalcade run 12 [pid] => 57 [running] => [signaled] => [stopped] => [exitcode] => 0 [termsig] => 0 [stopsig] => 0 ) 2018-01-27T01:09:22.458320545Z [12] Worker shutting down... [12] Worker out: [12] Worker err: [12] Worker ret: 0 [14] Running wp cavalcade run 14 (ffx/taxonomies/term_importer/import_tags_cron a:1:{i:0;a:5:{s:8:"tag_ty [14] Started worker [15] Running wp cavalcade run 15 (ffx/taxonomies/term_importer/import_tags_cron a:1:{i:0;a:5:{s:8:"tag_ty [15] Started worker [16] Running wp cavalcade run 16 (ffx/taxonomies/term_importer/import_tags_cron a:1:{i:0;a:5:{s:8:"tag_ty [16] Started worker [ ] Out of workers [ ] Out of workers [ ] Out of workers [ ] Out of workers [14] Worker status: Array -
GET 50 tags wp_insert_term( /* Roxie Hart */ ); wp_insert_term(
/* Billy Flynn */ ); wp_insert_term( /* Velma Kelly */ ); wp_insert_term( /* x 50 */ ); Content API -
wp_insert_term( /* Roxie Hart */ ); wp_insert_term( /* Billy Flynn
*/ ); wp_insert_term( /* Velma Kelly */ ); wp_insert_term( /* x 50 */ ); GET 50 tags Content API " -
wp_insert_term( /* Roxie Hart */ ); wp_insert_term( /* Billy Flynn
*/ ); wp_insert_term( /* Velma Kelly */ ); wp_insert_term( /* x 50 */ ); " GET 50 tags Content API " GET 50 tags Content API " GET 50 tags Content API " GET 50 tags Content API wp_insert_term( /* Roxie Hart */ ); wp_insert_term( /* Billy Flynn */ ); wp_insert_term( /* Velma Kelly */ ); wp_insert_term( /* x 50 */ ); wp_insert_term( /* Roxie Hart */ ); wp_insert_term( /* Billy Flynn */ ); wp_insert_term( /* Velma Kelly */ ); wp_insert_term( /* x 50 */ ); wp_insert_term( /* Roxie Hart */ ); wp_insert_term( /* Billy Flynn */ ); wp_insert_term( /* Velma Kelly */ ); wp_insert_term( /* x 50 */ ); -
wp_insert_term( /* Roxie Hart */ ); wp_insert_term( /* Billy Flynn
*/ ); wp_insert_term( /* Velma Kelly */ ); wp_insert_term( /* x 50 */ ); " GET 50 tags Content API " GET 50 tags Content API " GET 50 tags Content API " GET 50 tags Content API wp_insert_term( /* Roxie Hart */ ); wp_insert_term( /* Billy Flynn */ ); wp_insert_term( /* Velma Kelly */ ); wp_insert_term( /* x 50 */ ); wp_insert_term( /* Roxie Hart */ ); wp_insert_term( /* Billy Flynn */ ); wp_insert_term( /* Velma Kelly */ ); wp_insert_term( /* x 50 */ ); wp_insert_term( /* Roxie Hart */ ); wp_insert_term( /* Billy Flynn */ ); wp_insert_term( /* Velma Kelly */ ); wp_insert_term( /* x 50 */ ); -
# Delete term hierarchy option DELETE FROM `wp_options` WHERE `option_name`
= 'ffx_tag_children' # Get term hierarchy option (for reasons) SELECT option_value FROM wp_options WHERE option_name = 'ffx_tag_children # Select all terms in the taxonomy to work out hierarchy SELECT t.term_id, tt.parent, tt.count, tt.taxonomy FROM wp_terms AS t I # Warm the term meta cache for all (a bug) SELECT term_id, meta_key, meta_value FROM wp_termmeta WHERE term_id IN (9 # Update the term hierarchy cache (335KB at 23K tags) INSERT INTO `wp_options` (`option_name`, `option_value`, `autoload`) -
# Delete term hierarchy option DELETE FROM `wp_options` WHERE `option_name`
= 'ffx_tag_children' # Get term hierarchy option (for reasons) SELECT option_value FROM wp_options WHERE option_name = 'ffx_tag_children # Select all terms in the taxonomy to work out hierarchy SELECT t.term_id, tt.parent, tt.count, tt.taxonomy FROM wp_terms AS t I # Warm the term meta cache for all (a bug) SELECT term_id, meta_key, meta_value FROM wp_termmeta WHERE term_id IN (9 # Update the term hierarchy cache (335KB at 23K tags) INSERT INTO `wp_options` (`option_name`, `option_value`, `autoload`) # Update the term # hierarchy cache # (335KB at 23K tags) -
function import_tags( $taxonomy, $tags ) { /* * Disable term
cache additions to speed up * the import, see comments in CMS-1175. */ wp_suspend_cache_addition( true ); foreach ( $tags[ $taxonomy ] as $tag ) { wp_insert_term( /* $tag */ ); update_term_meta( /* tag meta 1 */ ); update_term_meta( /* tag meta 2 */ ); } } -
function import_tags( $taxonomy, $tags ) { /* * Disable term
cache additions to speed up * the import, see comments in CMS-1175. */ wp_suspend_cache_addition( true ); foreach ( $tags[ $taxonomy ] as $tag ) { wp_insert_term( /* $tag */ ); update_term_meta( /* tag meta 1 */ ); update_term_meta( /* tag meta 2 */ ); } } -
Read Cache Read Cache Read Cache Read Cache Write cache
Write cache Write cache Write cache -
add_action( 'admin_init', 'ajax_upload_attachment', 0 ); /** * Ajax handler for
uploading attachments * * Uploads from the media library are handled * by `async-upload.php`. * We can't override the hook so intercept `admin_init`. */ function ajax_upload_attachment() { // Only intercept the upload-attachment action. if ( ! isset( $_POST['action'] ) || 'upload-attachment' !== $_POST['action'] ) { -
add_action( 'admin_init', 'ajax_upload_attachment', 0 ); /** * Ajax handler for
uploading attachments * * Uploads from the media library are handled * by `async-upload.php`. * We can't override the hook so intercept `admin_init`. */ function ajax_upload_attachment() { // Only intercept the upload-attachment action. if ( ! isset( $_POST['action'] ) || 'upload-attachment' !== $_POST['action'] ) { -
* * Uploads from the media library are handled *
by `async-upload.php`. * We can't override the hook so intercept `admin_init`. */ function ajax_upload_attachment() { // Only intercept the upload-attachment action. if ( ! isset( $_POST['action'] ) || 'upload-attachment' !== $_POST['action'] ) { return; } // Duplicate core functionality. wp_die(); } -
* * Uploads from the media library are handled *
by `async-upload.php`. * We can't override the hook so intercept `admin_init`. */ function ajax_upload_attachment() { // Only intercept the upload-attachment action. if ( ! isset( $_POST['action'] ) || 'upload-attachment' !== $_POST['action'] ) { return; } // Duplicate core functionality. } -
{ 'altText': '', 'description': '', 'caption': '', 'credit': '', 'keywords':
'', 'sha1': '7e51b009bf0e9097a1fd6ba339a78b6181c 'source': '', 'source_system_name': 'wordpress', 'fileDataURI': 'data:image/jpeg;base64,/9j/4AAQSkZJ } -
} // Duplicate core functionality. $schema = Image_Schema\get_image_schema( $image, true
); wp_remote_request( 'https://api-media/v0/images', [ 'method' => 'POST', 'headers' => [ 'content-type' => 'application/json', ], 'body' => $schema, 'timeout' => 10, ] ); -
wp_remote_request( 'https://api-media/v0/images', [ 'method' => 'POST', 'headers' => [ 'content-type'
=> 'application/json', ], 'body' => $schema, 'timeout' => 10, ] ); wp_delete_post( $image_id, true ); wp_die(); } -
{ "success": true, "data": [ { "id": 4424 /* ...
*/ }, { "id": 4333 /* ... */ }, { "id": 4332 /* ... */ }, { "id": 4330 /* ... */ }, { "id": 4327 /* ... */ }, { "id": 4323 /* ... */ }, { "id": 4321 /* ... */ }, { "id": 4317 /* ... */ }, { "id": 4315 /* ... */ }, { "id": 4312 /* ... */ } ] } /wp-admin/admin-ajax.php?action=query-attachments -
{ "id": 4424, "filename": "deh-logo.jpg", "url": "https://pwcc.cc/wp-content/uploads/2018/02/deh-logo.jpg "alt": "", "description":
"", "caption": "", "name": "deh-logo", "dateFormatted": "February 8, 2018", "mime": "image/jpeg", "type": "image", "subtype": "jpeg", "sizes": { "thumbnail": {}, "medium": {}, "large": {}, -
{ "altText": "Plaster casts from Dear Evan Hansen.", "caption": "The
props department creates a new plaster cast for Dear "dateCreated": "2018-02-07T23:07:57.191Z", "credit": "Internet", "description": "Plaster casts Evan wears in Dear Evan Hansen.", "id": "78b576d29756c0f06ca5a1c450f4cf84bb69e8de", "keywords": "", "source": "Internet" } -
/** * Bootstrap the library replacement. */ function bootstrap() {
add_action( 'wp_ajax_query-attachments', 'ajax_query_attachments', 0 ); add_action( 'wp_ajax_get-attachment', 'ajax_get_attachment', 0 ); } -
add_image_size( 'square1x1', 200, 200, true ); add_image_size( 'landscape3x2', 300, 200,
true ); add_image_size( 'landscape16x9', 357, 201, true ); add_image_size( 'portrait2x3', 200, 300, true ); -
/** * Retrieve attachment meta field for attachment ID. *
* This matches the signature of `wp_get_attachment_metadata()` * modified for use with the Media API. * * @param string $attachment_id Attachment ID. Default ''. * @param bool $unfiltered True: filters are not run. * Default false. * @return mixed Attachment meta field. * False on failure. */ function get_attachment_metadata( /* ... */ ) { } -
> var_dump( wp_get_attachment_metadata() ); Array( [width] => 2400, [height] =>
1559, [file] => '2018/02/you-will-be-found.jpg', [sizes] => Array( [square1x1] => Array(width, height, file), [landscape3x2] => Array(width, height, file), [landscape16x9] => Array(width, height, file), [portrait2x3] => Array(width, height, file), [etc] => Array(width, height, file), ) ) -
> var_dump( API_Media\get_attachment_metadata() ); Array( [width] => 2400, [height] =>
1559, [file] => 'bd0d64a85c59655b815776ae46c3d14be7a6098e', [url] => 'http://static.ffx.io/bd0d64a85c59655b81…98e', [sizes] => Array( [square1x1] => Array(width, height, file, url), [landscape3x2] => Array(width, height, file, url), [landscape16x9] => Array(width, height, file, url), [portrait2x3] => Array(width, height, file, url), [etc] => Array(width, height, file, url), ) ) -
{ "id": "bd0d64a85c59655b815776ae46c3d14be7a6098e", "filename": "bd0d64a85c59655b815776ae46c3d14be7a6098e", "url": "https://static.ffx.io/bd0d64a85c59655b815776ae46c3d14be "alt": "The Dear
Evan Hansen cast perform You Will Be Found", "description": "Dear Evan Hansen cast perform You Will Be Found, the em "caption": "Dear Evan Hansen cast perform You Will Be Found, the em "name": "bd0d64a85c59655b815776ae46c3d14be7a6098e", "dateFormatted": "February 8, 2018 09:02am", "mime": "image/jpeg", "type": "image", "subtype": "jpeg", "sizes": { "square1x1": {}, "landscape3x2": {}, "landscape16x9": {}, -
{ "id": "bd0d64a85c59655b815776ae46c3d14be7a6098e", "filename": "bd0d64a85c59655b815776ae46c3d14be7a6098e", "url": "https://static.ffx.io/bd0d64a85c59655b815776ae46c3d14be "alt": "The Dear
Evan Hansen cast perform You Will Be Found", "description": "Dear Evan Hansen cast perform You Will Be Found, the em "caption": "Dear Evan Hansen cast perform You Will Be Found, the em "name": "bd0d64a85c59655b815776ae46c3d14be7a6098e", "dateFormatted": "February 8, 2018 09:02am", "mime": "image/jpeg", "type": "image", "subtype": "jpeg", "sizes": { “thumbnail": {}, "landscape3x2": {}, "landscape16x9": {}, Not numeric That’s new These names have changed -
wp.media.view ◦ Attachment ◦ AttachmentCompat ◦ AttachmentFilters ◦ Attachments ◦
AttachmentsBrowser ◦ AudioDetails ◦ Button ◦ ButtonGroup ◦ Cropper ◦ DateFilter ◦ EditImage ◦ EditorUploader ◦ Embed ◦ EmbedImage ◦ EmbedLink ◦ EmbedUrl ◦ FocusManager ◦ Frame ◦ Iframe ◦ ImageDetails ◦ Label ◦ MediaDetails ◦ MediaFrame ◦ Menu ◦ MenuItem ◦ Modal ◦ PriorityList ◦ Router ◦ RouterItem ◦ Search ◦ Selection ◦ Settings ◦ Sidebar ◦ SiteIconCropper ◦ SiteIconPreview ◦ Spinner ◦ Toolbar ◦ UploaderInline ◦ UploaderStatus ◦ UploaderStatusError ◦ UploaderWindow ◦ VideoDetails -
Inherited from WordPress ◦ 42 views ◦ 6 models ◦
19 collections -
Inherited from WordPress ◦ 42 views ◦ 6 models ◦
19 collections # Underscore # Backbone $ jQuery -
/* Models */ wp.media.model.Attachment = require( './models/attachment' ); wp.media.model.Attachments =
require( './models/attachments' ); /* Views */ wp.media.view.Attachment.Library = require( './views/attachment/library' ); wp.media.view.Attachment.Details = require( './views/attachment/details' ); wp.media.view.Attachment.Selection = require( './views/attachment/selection wp.media.view.Settings.AttachmentDisplay = require( './views/settings/attac wp.media.view.MediaFrame.Post = require( './views/frame/post' ); /* Misc */ wp.media.query = require( './query' ); -
/* Models */ wp.media.model.Attachment = require( './models/attachment' ); wp.media.model.Attachments =
require( './models/attachments' ); /* Views */ wp.media.view.Attachment.Library = require( './views/attachment/library' ); wp.media.view.Attachment.Details = require( './views/attachment/details' ); wp.media.view.Attachment.Selection = require( './views/attachment/selection wp.media.view.Settings.AttachmentDisplay = require( './views/settings/attac wp.media.view.MediaFrame.Post = require( './views/frame/post' ); /* Misc */ wp.media.query = require( './query' ); -
/* Models */ wp.media.model.Attachment = require( './models/attachment' ); wp.media.model.Attachments =
require( './models/attachments' ); /* Views */ wp.media.view.Attachment.Library = require( './views/attachment/library' ); wp.media.view.Attachment.Details = require( './views/attachment/details' ); wp.media.view.Attachment.Selection = require( './views/attachment/selection wp.media.view.Settings.AttachmentDisplay = require( './views/settings/attac wp.media.view.MediaFrame.Post = require( './views/frame/post' ); /* Misc */ wp.media.query = require( './query' ); -
/* Models */ wp.media.model.Attachment = require( './models/attachment' ); wp.media.model.Attachments =
require( './models/attachments' ); /* Views */ wp.media.view.Attachment.Library = require( './views/attachment/library' ); wp.media.view.Attachment.Details = require( './views/attachment/details' ); wp.media.view.Attachment.Selection = require( './views/attachment/selection wp.media.view.Settings.AttachmentDisplay = require( './views/settings/attac wp.media.view.MediaFrame.Post = require( './views/frame/post' ); /* Misc */ wp.media.query = require( './query' ); -
/* Models */ wp.media.model.Attachment = require( './models/attachment' ); wp.media.model.Attachments =
require( './models/attachments' ); /* Views */ wp.media.view.Attachment.Library = require( './views/attachment/library' ); wp.media.view.Attachment.Details = require( './views/attachment/details' ); wp.media.view.Attachment.Selection = require( './views/attachment/selection wp.media.view.Settings.AttachmentDisplay = require( './views/settings/attac wp.media.view.MediaFrame.Post = require( './views/frame/post' ); /* Misc */ wp.media.query = require( './query' ); -
/** * wp.media.query * * We're overriding this because we
need to use our custom * Attachment model and collection. */ module.exports = function ( props = {} ) { return new Attachments( null, { props: _.extend( _.defaults( props, { orderby: 'date', order: 'DESC' } ), { query: true } ) } ); }; -
/** * wp.media.query * * We're overriding this because we
need to use our custom * Attachment model and collection. */ module.exports = function ( props = {} ) { return new Attachments( null, { props: _.extend( _.defaults( props, { orderby: 'date', order: 'DESC' } ), { query: true } ) } ); }; -
/** * wp.media.view.Attachment.Library * * We're overriding this to use
our custom template for images. */ module.exports = Library.extend( { template: function () { const prefix = ( this.model.get( 'type' ) === 'image' ) ? 'ffx-' : ''; const template = wp.template( `${prefix}attachment` ); return template.apply( this, arguments ); } } ); -
/** * wp.media.view.Attachment.Library * * We're overriding this to use
our custom template for images. */ module.exports = Library.extend( { template: function () { const prefix = ( this.model.get( 'type' ) === 'image' ) ? 'ffx-' : ''; const template = wp.template( `${prefix}attachment` ); return template.apply( this, arguments ); } } ); -
/** * CropPreview Model * * @class * @augments Backbone.Model
*/ module.exports = Backbone.Model.extend( { defaults: { id: '', url: '', attachment_id: '', autoCrop: true, fileName: '', aspect: '', originalWidth: 0, cropWidth: 0, // Attributes below should not saved. -
[img id="f23d41a8ebf536a52eca254e1bb44d996cf21d25" altText="..." caption="..." credit="..." source="..." description="..." aspect="1.5" cropWidth="300" autoCrop="false"
offsetX="-374.3478" offsetY="-85.9782" zoom="0.3062"][/img] -
// We don't need this, we have // the Publish
Box of the Future™! remove_meta_box( 'submitdiv', 'post', 'side' ); -
// The Publish Box of the Future™! add_meta_box( 'ffx-submitdiv', __(
'Save & Publish', 'ffx' ), __NAMESPACE__ . '\\the_loading_icon', [ 'post' ], 'side', 'high' ); -
register_rest_field( 'post', 'ffx_writeoff', [ 'get_callback' => __NAMESPACE__ . '\\get_writeoff', 'update_callback'
=> __NAMESPACE__ . '\\set_writeoff', 'schema' => [ 'description' => __( 'Article writeoff', 'ffx' ), 'type' => 'string', ], ] ); -
register_rest_field( 'post', 'ffx_writeoff', [ 'get_callback' => __NAMESPACE__ . '\\get_writeoff', 'update_callback'
=> __NAMESPACE__ . '\\set_writeoff', 'schema' => [ 'description' => __( 'Article writeoff', 'ffx' ), 'type' => 'string', ], ] ); -
register_rest_field( 'post', 'ffx_private', [ 'get_callback' => __NAMESPACE__ . '\\get_privacy', 'update_callback'
=> __NAMESPACE__ . '\\set_privacy', 'schema' => [ 'description' => __( 'Fairfax Visibility', 'ffx' ), 'type' => 'boolean', ], ] ); -
Inherited from WordPress # Underscore # Backbone $ jQuery %
WordPress REST API client library -
The Post model ◦ author ◦ categories ◦ comment_status ◦
content ◦ date ◦ date_gmt ◦ excerpt ◦ featured_media ◦ ffx-legal-status ◦ ffx-post-state ◦ ffx-sources ◦ ffx-tags ◦ ffx_advertisements ◦ ffx_advertiser_logo ◦ ffx_advertiser_name ◦ ffx_article_tool ◦ ffx_authors ◦ ffx_bespoke_url ◦ ffx_brief ◦ ffx_collab_authors ◦ ffx_collab_editor ◦ ffx_collab_watchers ◦ ffx_comments ◦ ffx_comments_open ◦ ffx_commercial_content_ty pe ◦ ffx_correction ◦ ffx_correction_text ◦ ffx_format ◦ ffx_identifier ◦ ffx_in_numbers ◦ ffx_in_numbers_title ◦ ffx_index_headline ◦ ffx_intro ◦ ffx_label ◦ ffx_last_updated ◦ ffx_major_update ◦ ffx_misc_update ◦ ffx_off_time ◦ ffx_primary_tag ◦ ffx_private ◦ ffx_seo_description ◦ ffx_seo_news_keywords ◦ ffx_seo_noindex ◦ ffx_seo_title ◦ ffx_slack_channel ◦ ffx_sponsor ◦ ffx_sports_score ◦ ffx_syndication ◦ ffx_talking_points ◦ ffx_talking_points_live_title ◦ ffx_talking_points_title ◦ ffx_url ◦ ffx_url_content ◦ ffx_url_slug ◦ ffx_why_it_matters ◦ ffx_writeoff ◦ format ◦ id ◦ meta ◦ password ◦ ping_status ◦ slug ◦ status ◦ sticky ◦ template ◦ title -
wp_insert_post ◦ update post content % create new revision ◦
update taxonomies ◦ update meta data -
Update via REST API ◦ update post content & create
new revision ◦ update taxonomies ◦ update meta data -
add_filter( 'rest_pre_dispatch', 'move_revision_callback', 10, 3 ); /** Move the 'wp_save_post_revision'
callback for REST requests. */ function move_revision_callback( $result, $unused, $request ) { /* SNIP: Check for post update request */ // Move default `wp_save_post_revision` callback. remove_action( 'post_updated', 'wp_save_post_revision', 10 ); add_action( 'rest_request_after_callbacks', 'wp_save_post_revision'); return $result; // Support other filters. } -
add_filter( 'rest_pre_dispatch', 'move_revision_callback', 10, 3 ); /** Move the 'wp_save_post_revision'
callback for REST requests. */ function move_revision_callback( $result, $unused, $request ) { /* SNIP: Check for post update request */ // Move default `wp_save_post_revision` callback. remove_action( 'post_updated', 'wp_save_post_revision', 10 ); add_action( 'rest_request_after_callbacks', 'wp_save_post_revision'); return $result; // Support other filters. } -
add_filter( 'rest_request_after_callbacks', 'reset_revision_cb' ); /** Reset 'wp_save_post_revision' after REST requests.
*/ function reset_revision_cb( $response ) { // Move default `wp_save_post_revision` callback. add_action( 'post_updated', 'wp_save_post_revision', 10 ); return $response; // Support other filters. } -
[img id="9550846e3098113e9fe16878fcbc26e23580e8ea" altTex "body": "<x-placeholder id='2c62…d2'></x-placeholder>", "bodyPlaceholders": { "2c62…d2": {
"type": "image", "data": { "id": "9550846e3098113e9fe16878fcbc26e23 "caption": "Lin-Manuel Miranda in Hamilton th "credit": "Production, Hamilton the Musical" "aspect": 1.5, -
[img id="9550846e3098113e9fe16878fcbc26e23580e8ea" altTex "body": "<x-placeholder id='2c62…d2'></x-placeholder>", "bodyPlaceholders": { "2c62…d2": {
"type": "image", "data": { "id": "9550846e3098113e9fe16878fcbc26e23 "caption": "Lin-Manuel Miranda in Hamilton th "credit": "Production, Hamilton the Musical" "aspect": 1.5, -
[img id="9550846e3098113e9fe16878fcbc26e23580e8ea" altTex "body": "<x-placeholder id='2c62…d2'></x-placeholder>", "bodyPlaceholders": { "2c62…d2": {
"type": "image", "data": { "id": "9550846e3098113e9fe16878fcbc26e23 "caption": "Lin-Manuel Miranda in Hamilton th "credit": "Production, Hamilton the Musical" "aspect": 1.5, -
“ My job is code review and fooling myself that
today I really will pick up a ticket. Me