wordpress for the 99%
TRANSCRIPT
W O R D P R E S S F OR T H E 9 9 %A O NE -S I ZE - F I T S - M O S T W P A A S C AS E S T U DY
Stephanie Learystephanieleary.com@sleary
S TE P H AN I E LE A RY. C OM @S LE ARY
W O R K E D W IT H …
T H E S E T W O …
S A M E P R O BL E M S , S A M E S OLU T I ON
W E G O T 9 9 P R OB L E M S
• No acceptable central campus solution
• No past oversight or control
• No idea what has been built independently
• Rogue servers
• Itinerant workers
W E G O T 9 9 P R OB L E M S
• Poor code
• No updates
• No branding
• Insecure, unprofessional sites
• Tiny staff
• 100s of migration and new site requests
SO LU T I O N
• One-size-fits-most WordPress template & plugin suite
• Managed WordPress hosting
• Backups
• Security monitoring
• Automatic critical updates
• Support
• Free to campus users*
BRA N DE D TH E M E SO LUT I O N
• Flexible
• 6 layout options
• logo toggles
• several color schemes
• Responsive
• Accessible
C O M M O N E L E M E N T S
• WP Engine
• Genesis child theme
• Custom post types & taxonomies
• Advanced Custom Fields plugin
• Gravity Forms plugin
• CAS Maestro plugin
• GitHub Updater WP Pusher plugin
W H Y W P E N G I N E ?
• Existing campus contract
• Daily backups & one-button restore feature
• Staging copies
• Automatic security updates
• Optimized for performance
• Sucuri remediation of security incidents
W P E N G I N E C AV E AT S
• Price jumps after 100 installs
• Solution: Multisite
• Bandwidth / visitor limitations (vs storage)
• Restore points include entire multisite network
• Solution: Migrate DB Pro plugin
W H Y G E N E S I S ?
• Built-in…
• Layout options
• Color schemes
• SEO features
• plugins for slider, grid loops, multi-column text
• featured content widgets
• package of professional child themes
G E N E S I S C AV E AT S
• No grandchild themes
• Solution: JP Custom CSS plugin
• Obscure to new developers
• Solutions:
• Visual Hook Guide
• StudioPress snippet library
• StudioPress theme documentation
PSE U DO - G RA N D C H I L D T H E M E S
• Theme option: site-specific directory name
• If filled in, and if it exists…
• Enqueue style.css
• Include functions.php
C A S M A E S T R O C AV E AT S
• Minimal payload; no tailored onboarding
• WP login back door not visible
• No mobile app support
• or any other app relying on XML-RPC
• WP usernames must match CAS
• Character limits are not the same*
S IT E S E T U P W IZ A R DI F YO U AR E NO T U S ING CA S , C ON S I DER …
N E T W O R K-AC T I VATE D PLU G I N S• Advanced Custom Fields
• BE Subpages Widget
• CAS Maestro
• Display Posts Shortcode
• Enable Media Replace
• Genesis Grid
• Gravity Forms
• Image Widget
• JP Custom CSS
• JP Widget Visibility
• Menu Social Icons
• My Eyes Are Up Here
• Related Posts By Taxonomy
• Safe Redirect Manager
• Seamless Sticky Custom Post Types
• Simple Page Ordering
• Term Management Tools
• WCAG Fields for Gravity Forms
• WP Post Type Archive Links
• WP Editor Widget
• WP Help
• WP REST API
• WP REST API Custom Fields
• WP101
PLU G I N C AV E AT S
• Is it maintained?
• Can we maintain it?
• Should we rewrite it?
• Can we hook into it?
• Licensing
J E T PAC K SU BS T I T U TE S
• Users shouldn’t have to maintain wordpress.com accounts; Jetpack disconnects every few weeks
• Developer mode doesn’t actually work very well
• JP Widget Visibility
• JP Carousel
• JP Custom CSS
SPE C I A LT Y PLU G I N S
• Download Monitor
• Document Revisions
• The Events Calendar Pro (Modern Tribe)
• WP LaTeX
• Visualizer
SE A RC H PLU G I N S
• Relevanssi Premium
• SearchWP
• Google CSE
C U S T O M C O D E
F E ATU R E S
• People directories (faculty, staff, student, combined)
• Simple course catalog
• Building / equipment directory
• Publication lists
• Research project profiles
E D I T I N G F E AT U R E S
• Widget style chooser
• Pull quotes
• Editor toolbar changes
• Rich text footer option
• Centrally managed footer links
F R O N T E N D F E AT U R E S
• Branding options
• Color schemes
• Custom widgets
• Readability-style template for long documents
A D M I N F E ATU R E S
• Dashboard widgets
• Screen option defaults
• Edit screen columns
• Microtext changes
• Posts page warning
N E T W O R K A D M I N F E ATU R E S
• Logins go through main network site (CAS whitelist)
• Default network role for subsite users
• Main site login redirect for subsite users
• Sortable Sites column for upload file usage
C O N T E N T M O D E LPeopleSubject AreasOrganizationsPeople Type(Committees)(Groups)
CoursesSubject Areas
Organizations
PublicationsSubject Areas
ResearchSubject Areas
FacilitiesSubject
AreasFacility Type
C U S T O M F I E L D S & E D I T S C R E E N SFOR AL L F I VE C U ST OM P OST T YP ES
AC F F I E L DS F O R PE O P L E
ACF F I ELDS FOR COU R S ES
AC F F I E LDS FOR PUBL I CAT ION S
ACF F I E L D S F O R FAC I L I T I E S
Requirements often describe structure:“separate”
“search by…”“sort”“filter”
“We need a way to separate events bios
productscourses
etc. from our posts and pages.”
POST TYPE
“We want to display _____ alongside the description.”
FIELD OR TAXONOMY
“We want to sort by X and Y as well as by title and date.”
FIELD*
“This text input should be a controlled list.”
TAXONOMY… PROBABLY
R E Q U IR E M E N T S
AC F F I E L D T Y P E S
CON TEN T M ODE L IN G QU EST IONS• What things are you writing about? How are
they related? How are they grouped?
• How detailed can we get and keep the editing process sustainable?
• Should different groups of people have permission to edit different things?
C U S TO M F I E L D Q U E S T I O N S• What are the parts that make up each thing?
• Which of those fit the fields the CMS provides, and which do we need to create?
• What should the editing experience be for each part?
TA XO N O M Y Q U E S T I O N S• Do we have any groups in which several kinds
of categories are mixed? Can these be separated into more clearly delineated groups?
• Do our authors understand the differences between each group?
• Should items in different groups have completely different sets of fields? (Maybe a post type is better.)
F I E LD O R TA XO N O M Y ?
What is the format of this data?
Should the input be a controlled list?
Should duplicates be avoided? FIELDTAXONOMY
NoYes
Text Anything Else
A DVA N C E D C U S TO M F I E L D S
G E N E RAT E W PO R
C P T U I
+
RA P I D PR OT O T Y PE S
PO ST T Y PE S A N D TA XO N O M I E S
DE S I G N C O N T E N T I N C O N T E XT
• Single page views
• Date-based archives
• Taxonomy-based archives
• Site search results
• Specialized search results
• Home page features
I T E RAT E .
C O U R SE C O R R E C T I O N I S E A SY• Post Type Switcher
• Term Management Tools
• WP All Export / WP All Import
P O S T T Y P E S W I TC H E R
TE R M M G M T T OOL S : ME R G E
T E R M M G M T T O O L S : CH A NG E
F I E L D T O TA XO N O M YWP A L L E XP O RT
W P A RC H I V E S U S U A L LY I N C LU D E …
• Content or excerpts
• All post types in taxonomy archives
• All subcategories’ posts in parent archives
GE NE S I S G R I D LOOP SE TT I NG S
GE NE S I S G R I D LOOP SE TT I NG S
G E N E S I S TA B L E LO O PS
function scl_loop_table_headers( $headers ) {$headerrow = '';foreach ( $headers as $header ) {
$headerrow .= sprintf( "<th>%s</th>\n", $header );}
return sprintf( '<div class="loop"><table cellspacing="0" class="responsive">
<thead><tr>
%s </tr>
</thead><tbody>'."\n", $headerrow );
}
G E N E S I S TA B L E LO O PS
function scl_loop_table_cells( $data ) {$datarow = '';$rowindex = 1;foreach ( $data as $title => $field ) {
$class = '';if ( empty( trim ( $field ) ) )
$class = ' class="empty"';$tag = 'td';if ( 1 == $rowindex )
$tag = 'th';$datarow .= sprintf( '<%s title="%s" %s>%s</%1$s>'."\n", $tag,
$title, $class, $field );$rowindex++;
}
return sprintf( "<tr id='post-%d' %s>\n %s \n </tr>\n", get_the_ID(), genesis_attr( 'entry' ), $datarow );
}
G E N E S I S TA B L E LO O PS
remove_action( 'genesis_loop', 'genesis_do_loop' );add_action( 'genesis_loop', 'scl_course_table_loop', 10 );function scl_course_table_loop() {
if ( have_posts() ) :
$headers = array( esc_html__('Course'), esc_html__('Number'), esc_html__('Instructor(s)'), esc_html__('Time') );
echo scl_loop_table_headers( $headers );
while ( have_posts() ) : the_post();$data = array(
sprintf( '<a href="%s" title="%s">%s</a>', esc_url( get_permalink() ), the_title_attribute( 'echo=0' ), get_the_title() ),
get_field( 'course_number' ),get_field( 'instructors' )
);echo scl_loop_table_cells( array_combine( $headers, $data ) );
endwhile; //* end of one postscl_loop_table_footer();
endif; //* end loop}
TA B LE LO O P C AV E AT S
• No settings interface
• Will override Grid Loop settings—user confusion?
L I S T C H I L D PAG E S
L I ST C H I L D PAG E S
function scl_append_child_pages( $content = '' ) { $type = get_post_type(); if ( is_post_type_hierarchical( $type ) && empty( $content ) ) { $args = array( 'echo' => 0, 'depth' => 1, 'title_li' => '', 'child_of' => get_the_ID(), 'post_type' => $type ); $content .= '<ul class="childpages">' . wp_list_pages( $args ) . '</ul>'; } return $content;}
L I ST C H I L D PAG E S
function scl_child_pages_shortcode() { return scl_append_child_pages();}
add_shortcode( 'child-pages', 'scl_child_pages_shortcode' );add_shortcode( 'subpages', 'scl_child_pages_shortcode' );
add_filter( 'the_content', 'scl_append_child_pages' );
C PT A RC H I V E T E R M D I V I S I O N S
• Archives settings option
• Divide posts by selected taxonomy
• Further subdivide by child terms? (depth)
D E E P TA XO N O M Y T E R M A RC H I V E S
SH A R E D TA XO N O M Y A RC H I V E S
• Titles and breadcrumbs reflect only one term
• Post types all mixed together
• post_type not set
SH A R E D TA XO N O M Y T I T LE S
https://gist.github.com/sillybean/ae00bea06ff1513d48ed1fd9cbaca3eb
https://gist.github.com/sillybean/4f592e462ea51866082a099b11c6309d
S H A R E D TA XO N O M Y BR E A D C R U M BS
F I N D _ PO ST _ T YP E ( )
function scl_find_post_type() {$type = get_query_var( 'post_type' );
if(( !isset( $type ) || empty( $type )) && is_tax()) {$current_term = get_queried_object();$tax_obj = get_taxonomy( $current_term-
>taxonomy );
if ( count( $tax_obj->object_type ) == 1 )$type = $tax_obj->object_type[0];
}
return $type;}
R E P L AC E LO O P W I T H P O S T T Y P E L I S T
R E P L AC E LO O P W I T H P O S T T Y P E L I S T
add_action( 'genesis_meta', 'scl_taxonomy_loop_switch' );
function scl_taxonomy_loop_switch() {if ( function_exists( 'scl_find_post_type' ) )
$type = scl_find_post_type();else
$type = get_query_var( 'post_type' );
if ( empty( $type ) || 'any' == $type || is_array( $type ) ) {remove_action( 'genesis_loop', 'genesis_do_loop' );add_action( 'genesis_loop',
'scl_list_taxonomy_post_types', 1 );}
}
A D D PO ST TY P E A R G U M E N T
add_filter( 'term_link', 'tax_link_for_post_type', 10, 3 );
function tax_link_for_post_type($termlink, $term, $taxonomy){
$tax_obj = get_taxonomy( $taxonomy );// if this is not a shared taxonomy, bailif ( count( $tax_obj->object_type ) == 1 )
return $termlink;
$post_type = scl_find_post_type();if ( !isset( $post_type ) || 'any' == $post_type )
return $termlink;
return add_query_arg( 'post_type', $post_type, $termlink );}
PE R- PO S T-T Y PE S I D E B A R S
add_action( 'get_header', 'scl_cpt_switch_sidebar' );
function scl_cpt_switch_sidebar() {remove_action( 'genesis_sidebar', 'genesis_do_sidebar' ); add_action( 'genesis_sidebar', 'scl_do_sidebar' );
}
PE R- PO S T-T Y PE S I D E B A R S *
function scl_do_sidebar() {
if ( is_home() && !is_front_page() )$type = 'post';
else$type = scl_find_post_type();
if ( is_active_sidebar( $type ) )dynamic_sidebar( $type );
elsegenesis_do_sidebar();
}
W I DG E T V I S I B I L I T Y PLU G I N
R E Q U IR E D L I N K S
SY N C E D F O O T E R L I N K S
add_action( 'genesis_footer', 'scl_footer_required_links' );
function scl_footer_required_links() {if ( false === ( $links = get_transient( 'scl_footer_required_links' ) ) ) {
$response = wp_remote_get( 'http://example.com/wp-json/wp/v2/pages/2' );
if ( wp_remote_retrieve_response_code( $response ) == 200 && ! is_wp_error( $response ) ) {
$body = json_decode( wp_remote_retrieve_body( $response ), true );
$links = wp_kses_post( $body['content']['rendered'] );}
set_transient( 'scl_footer_required_links', $links, 12 * HOUR_IN_SECONDS );}echo apply_filters( 'scl_footer_required_links', $links );
}
FOOT ER T EXT CUS TOMIZER F I EL Dadd_action( 'customize_register', 'scl_customizer_sections' );function scl_customizer_sections( $wp_customize ) {
$wp_customize->add_section( 'scl_footer', array('title' => 'Footer Text','priority' => 105,'capability' => 'edit_pages',
) );
$wp_customize->add_setting( 'scl_footer_text', array('default' => '','sanitize_callback' => 'scl_sanitize_footer_text','transport' => 'postMessage',
) );
$wp_customize->add_control( 'scl_footer_text', array('label' => 'Footer text (copyright, etc.)','section' => 'scl_footer','type' => 'text',
) );}
FOOT ER T EXT CUS TOMIZER F I EL D
remove_action( 'genesis_footer', 'genesis_do_footer' );add_action( 'genesis_footer', 'scl_custom_footer' );
function scl_custom_footer() {echo get_theme_mod( 'scl_footer_text', '© ' . get_option( 'blogname' ) );
}
function scl_sanitize_footer_text( $input ) { return wp_kses_post( force_balance_tags( $input ) );}
F O O T E R R I C H T E XT O PT I O N
remove_action( 'genesis_footer', 'genesis_do_footer' );add_action( 'genesis_footer', 'scl_custom_footer' );
function scl_custom_footer() {echo '<div class="footer-content">';echo do_shortcode( get_field( 'footer_text', 'option' ) );echo '</div><!-- end .footer-content -->';
}
C M S US E R SE N D U SE R S +
If content authors can’t or won’t use the CMS, it’s game
over.
US E R S I G N U P P R O C E SS
• Site request form:
• contact info
• desired URL
• Offsite delegation
• Font licensing (&^#*@)
• Copy template blog
• Add user to blog
DE FA U LT N E T W O R K S I TE R O L E
function tees_default_roles( $user_id ) {if ( is_main_site() && !is_user_member_of_blog( $user_id ) )
add_user_to_blog( get_current_blog_id(), $user_id, 'subscriber' );
}
add_action( 'wpmu_activate_user', 'tees_default_roles', 10, 1 );add_action( 'wpmu_new_user', 'tees_default_roles', 10, 1 );add_action( 'user_register', ‘tees_default_roles', 10, 1 );
CAS U S E RNAM E RE S TR IC T IONS
DA S H BOA R D W I D G E T S
• My Sites
• Way finder: CPTs and taxonomies
• Way finder: Options page content
• Link to support form
LO G I N R E D I R E C T S : N E T W O R K
add_filter( 'login_redirect', 'tees_subsite_login_redirect', 100, 3 );
function tees_subsite_login_redirect( $redirect_to, $request_redirect_to, $user ) {
if ( !is_user_member_of_blog( $user->ID ) ) { // this is the main network site. Stupid name.
global $current_site; return get_site_url( $current_site, '', 'admin' );
}
return $redirect_to; }
C H A N G E T H E A D M I N U I
• Hide unneeded features
• Make everything on the screen relevant
• Change placeholders and labels
• Add toolbar options for pattern library elements
• Add inline help
• Document in the CMS
H I DE U N NE E DE D F E AT U R E S
TU R N OF F SC R E E N OP T I O N S<?php
add_filter( 'default_hidden_meta_boxes', 'my_default_hidden_screen_options', 10, 2 );
function my_default_hidden_screen_options( $hidden, $screen ) {
$hide_these = array( 'dashboard_primary','postcustom','trackbacksdiv',
);
return array_merge( $hidden, $hide_these );}
TU R N O N S C R E E N O P T I O N S
add_filter( 'default_hidden_meta_boxes', 'scl_toggle_meta_boxes', 10, 2 );function scl_toggle_meta_boxes( $hidden, $screen ) { $hide_these = array( ... );
if ( $screen->base == 'nav-menus' ) {$show_these = array(
'add-post-type-course','add-post-type-people','add-post-type-publication','add-post-type-facility','add-post-type-research','add-people_type','add-organization','add-subject_area','add-facility_type','add-publication_type',
);$hidden = array_diff( $hidden, $show_these );
}
return array_merge( $hidden, $hide_these );}
M AK E E VE RY T H I N G R E LE VA NT
ADMIN CO LU MNS
M AK E E VE RY T H I N G R E LE VA NT
ADMIN CO LU MNS
M AK E E VE RY T H I N G R E LE VA NT
ADMIN CO LU MNS
C H A N G E P L AC E H OL D E R S
C H A N G E P L AC E H OL D E R S
<?phpadd_filter( 'enter_title_here', 'my_title_placeholders' );function my_title_placeholders( $placeholder ){ $screen = get_current_screen();
switch ( $screen->post_type ) {case 'people':
$placeholder = 'Enter full name';break;
case 'course':$placeholder = 'Enter course title';break;
case 'facility':$placeholder = 'Enter building name and number';break;
default: break;
} return $placeholder;}
C H A N G E P L AC E H OL D E R S
C H A N G E L A B E L SFE AT U R E D I MAG ES
C H A N G E L A B E L SFE AT U R E D I MAG ES
C H A N G E L A B E L S
<?phpremove_meta_box( 'postexcerpt', 'post', 'side' );
add_meta_box('postexcerpt', __( 'Plain Text Summary' ), 'post_excerpt_meta_box', 'post', 'normal', 'high');
N E W E XC E R P T L A B E L
A DD I N L I N E H E L PADVAN CED CU ST O M F IE L DS (MES S AGE F IE L D)
A DD I N L I N E H E L PADVAN CED CU ST O M F IE L DS (MES S AGE F IE L D)
C H A N G E IN L IN E H E L P
C H A N G E I N L I N E H E L P
<?phpremove_meta_box( 'postexcerpt', 'post', 'side' );add_meta_box( 'postexcerpt', __( 'Plain Text Summary' ),
'custom_post_excerpt_meta_box', 'post', 'normal', ‘high’ );
function custom_post_excerpt_meta_box( $post ) { ?><label class="screen-reader-text" for="excerpt"><?php _e( 'Plain Text
Summary' ) ?></label><textarea rows="1" cols="40" name="excerpt" id="excerpt"> <?php echo $post->post_excerpt; // textarea_escaped ?></textarea><p><?php
__( 'The plain text summary will appear on archive pages (e.g. lists of posts by category) and in search results.' );
?></p><?php}
C H A N G E I N L I N E H E L P
<?phpremove_meta_box( 'postexcerpt', 'post', 'side' );add_meta_box( 'postexcerpt', __( 'Plain Text Summary' ),
'custom_post_excerpt_meta_box', 'post', 'normal', ‘high’ );
function custom_post_excerpt_meta_box( $post ) { ?><label class="screen-reader-text" for="excerpt"><?php _e( 'Plain Text
Summary' ) ?></label><textarea rows="1" cols="40" name="excerpt" id="excerpt"> <?php echo $post->post_excerpt; // textarea_escaped ?></textarea><p><?php
__( 'The plain text summary will appear on archive pages (e.g. lists of posts by category) and in search results.' );
?></p><?php}
N E W E XC E R P T BOX
PO ST S PAG E M E SS AG E
add_action( 'admin_notices', 'scl_postspage_print_notices' );
function scl_postspage_print_notices() {$screen = get_current_screen();if ( $screen->parent_base != 'edit' || $screen->base != 'post' || $_REQUEST['action'] != 'edit' )
return;
$posts_page = get_option( 'page_for_posts' );if ( !$posts_page )
return; if ( $_REQUEST['post'] == $posts_page ) echo '<div class="error"><p>This page is a container for the most recent
posts. It should always be empty, and you should never edit this page. To add a news item, go to <a href="post-new.php">Posts -- Add New</a>.<p></div>';
}
W P E D I T O R W I D G E T S T YL E S
PATT E R N L I BRA RY I N T O O L BA R
A D D T O O L B A R S T Y L E S & B U TT O N S
ADVAN CED T IN Y MCE
A D D T O O L B A R S T Y L E S & B U TT O N S
ADVAN CED T IN Y MCE
A D D T O O L B A R S T Y L E S & B U TT O N S
ADVAN CED T IN Y MCE
A D D T O O L B A R S T Y L E S & B U TT O N S
ADVAN CED T IN Y MCE
R E M OV I N G T O OL B A R BU TTO N S
function scl_mce_buttons( $buttons ) {$remove = array( 'underline', 'alignjustify' );return array_diff( $buttons, $remove );
}
add_filter( 'mce_buttons_2', 'scl_mce_buttons' );
A D D T O O L B A R S T Y L E S & B U TT O N S
SH ORTCA K E U I
A D D T O O L B A R S T Y L E S & B U TT O N S
SH ORTCA K E U I
A D D T O O L B A R S T Y L E S & B U TT O N S
SH ORTCA K E U I
A D D T O O L B A R S T Y L E S & B U TT O N S
SH ORTCA K E U I
BLOC K QUOTE + C I TE BU TT ON
BLOC K QUOTE + C I TE BU TT ON
BLOC K QUOTE + C I TE BU TT ON
BLO C K Q U O TE + C I T E BU TT O N
function scl_pullquote_mce_button() {if ( 'true' == get_user_option( 'rich_editing' ) ) {
add_filter( 'mce_external_plugins', 'scl_pullquote_add_tinymce_plugin' );add_filter( 'mce_buttons', 'scl_pullquote_register_mce_button' );
}}add_action('admin_head', 'scl_pullquote_mce_button');
function scl_pullquote_add_tinymce_plugin( $plugin_array ) {$plugin_array['blockquote_cite'] = get_stylesheet_directory_uri() .'/js/mce-buttons.js';return $plugin_array;
}
function scl_pullquote_register_mce_button( $buttons ) {return array_push( $buttons, 'blockquote_cite' );
}
DO C U M E N TAT IO N
W P 1 0 1V I DE O T UT O R I AL S I N T H E DA S HBOA R D
ADD HEL P L I BRARY I N T HE CMS
WP H EL P
W P H E LP
• Synchronized
• Managed like pages
• Set up sync source install or use main network site
• Use relative links
TE C H N I C A L H O W-T O
• Writing style guide
• Links to brand guide, photo libraries, etc.
L IS T E N .
DO NO T AC C E P T T H E D E FA U LT.
“Well, that’s how the CMS does it.”
“Well, that’s how the CMS does it.”
“Well, that’s how we made the CMS do it.”
MOR E CON T EN T STRAT EGY STU FF• More code
• A content inventory plugin
• Videos
• A book
• http://stephanieleary.com/tag/content-strategy/
I MP ORT AN YT H I N G TO WORDP RE S S
Y ET A NOT H ER P R ES E NTAT I O N