EXTENDING
WORDPRESS AS
A PRO
Marko Heijnen

WordSesh December 2014
MARKO HEIJNEN
• Founder  of  CodeKitchen  
• Working  for  1&1  
• Lead  developer  of  GlotPress  
• Core  contributor  for  WordPress  
• Plugin  developer  
• Organizer  for  WordCamp  Belgrade

http://2015.belgrade.wordcamp.org/
WORDPRESS DEVELOPER
The Netherlands
TODAY’S

TOPICS
• Current ways to extend WordPress

• Expect the unexpectable

• Demo wpcentral.io

• Build for the future

• Look at new technologies

• Demo opensesh.org

• Questions
EXTENDING
WORDPRESS
HOOKS
• Hooks are a way for one piece of code to interact
with and modify another piece of code. They make
up the foundation for how plugins and themes
interact with WordPress Core, but they’re also
used extensively by Core itself

• Two types of hooks: Actions and Filters
DROP-INS
Single site
• advanced-cache.php

• object-cache.php

• db.php

• db-error.php

• install.php

• maintenance.php

Multisite
• sunrise.php

• blog-deleted.php

• blog-inactive.php

• blog-suspended.php
PLUGGABLE FUNCTIONS
• These functions let you override certain core
functions via plugins

• Pluggable functions are no longer being added to
WordPress core

• All new functions instead use filters on their output
to allow for similar overriding of their functionality

• See http://codex.wordpress.org/Pluggable_Functions
PLUGGABLE CLASSES
• Using a filter to replace the class that should be
loaded like session_token_manager

• Be able to add your class to be loaded like
wp_image_editors filter
EXPECT THE
UNEXPECTABLE
Check out: http://wpcentral.io/
WP CENTRAL

WHAT IS IT?
• Showing download history

• Showing version usage history

• List all locales and their current state

• Showing contributors data (currently API only)

• Collects history of locale progress
11
12
13
14
WP CENTRAL

HOW IT WORKS
• A lot of data handling by wp_remote_get

• Scrapping profiles.WordPress.org to read data

• Bugs

• Storing 0 values

• Storing invalid data after failed wp_remote_get
requests

• Not checking HTML output from

DOMDocument / DomXPath
WP CENTRAL
CACHING STRATEGY
• Expensive query result caching

• Cron job to retrieve download counts and version
usage

• 24 hour cache per locale on request with a max of
5 locales per time

• Using WP CLI to run it command line

• Creating contributor data on request of the API
BUILD FOR
THE FUTURE
BUILD FOR THE FUTURE
• When writing code, keep the changes you want to
make in mind

• Future proofing is making sure you can easily add
code/features without breaking existing
functionality

• Make the code robust against unexpected problem
situations allowing for graceful recovery or fail-fast,
but do not write code for possible future uses.
LOOK AT NEW
TECHNOLOGIES
http://opensesh.org
20
NODE.JS
NODEJS.ORG
• JavaScript platform

• Uses an event-driven, non-blocking I/O model

• Lightweight and efficient

• Ideal for real time application

• Lot’s of modules you can use

• Manage with NPM - https://www.npmjs.org
OPENSESH
OPENSESH.ORG
• A platform for conferences like WordSesh

• Community driven project for the open source community

• Node.js lets you push new sessions

• This with the help of Socket.IO

• When the session is over, you can simply replace it

• Be able to use YouTube files as wait music

• Possible other ideas:

• Create a hangout through WordPress

• Have a personal schedule
THE SITE
MANAGING CHANNELS
BREAK TIME
CONNECTING TO WORDPRESS
• Node.js checks cookie data to indicate if user is logged in

• Validates over JSON API and retrieve more user data

• Returns a WP_User object

• Has basic capability check support
BASIC CONFIGURATION
var config = {}, channels = [], clients = [];

config.port = 9000;

config.application_host = ‘http://opensesh.com’;

config.application_port = 80;

var app = require('http').createServer(handler),

	 io = require('socket.io').listen(app),

	 wordpress = require("wordpress-utils");

app.listen(config.port);

wordpress.set_siteurl( config.application_host );
SERVER HANDLER (PART 1)
function handler(req, res) {

if (req.url == "/status") {

res.writeHead( 200 );

res.end();

return;

}

var wp_user = wordpress.connect( req.headers.cookie, req.headers['x-token'] );

if ( wp_user ) { // More code to come }

res.end();

}
SOCKET CONNECTION
io.on('connection', function (socket) {

clients[socket.id] = socket;

socket.wp_user = wordpress.connect( socket.handshake.headers.cookie,
socket.handshake.query.token );

socket.on('disconnect', function() {

delete clients[socket.id]

});

var channel_id = parseInt(socket.handshake.query.channel);

socket.emit('publish', { channel : channel_id, url :channels[ channel_id ].url });

});
SERVER HANDLER (PART 2)
wp_user.on('wp_connected', function ( data ) {

if ( ! wp_user.can('manage_options') ) {

res.writeHead(403); res.end(); return;

}

var fullBody = ‘';

req.on('data', function(chunk) {

fullBody += chunk.toString();

});

req.on('end', function() { // Access to JSON data }

}
SERVER HANDLER (PART 3)
if (req.url == "/publish") {

var json = JSON.parse(fullBody);

if ( json.channel && json.url ) {

if ( ! channels[ json.channel ] ) {

channels[ json.channel ] = {};

}

channels[ json.channel ].url = json.url;

io.sockets.emit( 'publish', { channel : json.channel, url : json.url } );

}

else { res.writeHead(404); }

res.end();

}
SERVER HANDLER (PART 4)
else if (req.url == "/channels") {

res.writeHead( 200, {'Content-Type': ‘application/json’} );

res.end( JSON.stringify(channels) );

}

res.end();
THANK YOU FOR
LISTENING

QUESTIONS?

@markoheijnen - markoheijnen.com

Extending WordPress as a pro

  • 1.
    EXTENDING WORDPRESS AS A PRO MarkoHeijnen WordSesh December 2014
  • 2.
    MARKO HEIJNEN • Founder of  CodeKitchen   • Working  for  1&1   • Lead  developer  of  GlotPress   • Core  contributor  for  WordPress   • Plugin  developer   • Organizer  for  WordCamp  Belgrade
 http://2015.belgrade.wordcamp.org/ WORDPRESS DEVELOPER The Netherlands
  • 3.
    TODAY’S
 TOPICS • Current waysto extend WordPress • Expect the unexpectable • Demo wpcentral.io • Build for the future • Look at new technologies • Demo opensesh.org • Questions
  • 4.
  • 5.
    HOOKS • Hooks area way for one piece of code to interact with and modify another piece of code. They make up the foundation for how plugins and themes interact with WordPress Core, but they’re also used extensively by Core itself • Two types of hooks: Actions and Filters
  • 6.
    DROP-INS Single site • advanced-cache.php •object-cache.php • db.php • db-error.php • install.php • maintenance.php Multisite • sunrise.php • blog-deleted.php • blog-inactive.php • blog-suspended.php
  • 7.
    PLUGGABLE FUNCTIONS • Thesefunctions let you override certain core functions via plugins • Pluggable functions are no longer being added to WordPress core • All new functions instead use filters on their output to allow for similar overriding of their functionality • See http://codex.wordpress.org/Pluggable_Functions
  • 8.
    PLUGGABLE CLASSES • Usinga filter to replace the class that should be loaded like session_token_manager • Be able to add your class to be loaded like wp_image_editors filter
  • 9.
  • 10.
    WP CENTRAL
 WHAT ISIT? • Showing download history • Showing version usage history • List all locales and their current state • Showing contributors data (currently API only) • Collects history of locale progress
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
    WP CENTRAL
 HOW ITWORKS • A lot of data handling by wp_remote_get • Scrapping profiles.WordPress.org to read data • Bugs • Storing 0 values • Storing invalid data after failed wp_remote_get requests • Not checking HTML output from
 DOMDocument / DomXPath
  • 16.
    WP CENTRAL CACHING STRATEGY •Expensive query result caching • Cron job to retrieve download counts and version usage • 24 hour cache per locale on request with a max of 5 locales per time • Using WP CLI to run it command line • Creating contributor data on request of the API
  • 17.
  • 18.
    BUILD FOR THEFUTURE • When writing code, keep the changes you want to make in mind • Future proofing is making sure you can easily add code/features without breaking existing functionality • Make the code robust against unexpected problem situations allowing for graceful recovery or fail-fast, but do not write code for possible future uses.
  • 19.
  • 20.
  • 21.
    NODE.JS NODEJS.ORG • JavaScript platform •Uses an event-driven, non-blocking I/O model • Lightweight and efficient • Ideal for real time application • Lot’s of modules you can use • Manage with NPM - https://www.npmjs.org
  • 22.
  • 23.
    OPENSESH.ORG • A platformfor conferences like WordSesh • Community driven project for the open source community • Node.js lets you push new sessions • This with the help of Socket.IO • When the session is over, you can simply replace it • Be able to use YouTube files as wait music • Possible other ideas: • Create a hangout through WordPress • Have a personal schedule
  • 24.
  • 25.
  • 26.
  • 27.
    CONNECTING TO WORDPRESS •Node.js checks cookie data to indicate if user is logged in • Validates over JSON API and retrieve more user data • Returns a WP_User object • Has basic capability check support
  • 28.
    BASIC CONFIGURATION var config= {}, channels = [], clients = []; config.port = 9000; config.application_host = ‘http://opensesh.com’; config.application_port = 80; var app = require('http').createServer(handler), io = require('socket.io').listen(app), wordpress = require("wordpress-utils"); app.listen(config.port); wordpress.set_siteurl( config.application_host );
  • 29.
    SERVER HANDLER (PART1) function handler(req, res) { if (req.url == "/status") { res.writeHead( 200 ); res.end(); return; } var wp_user = wordpress.connect( req.headers.cookie, req.headers['x-token'] ); if ( wp_user ) { // More code to come } res.end(); }
  • 30.
    SOCKET CONNECTION io.on('connection', function(socket) { clients[socket.id] = socket; socket.wp_user = wordpress.connect( socket.handshake.headers.cookie, socket.handshake.query.token ); socket.on('disconnect', function() { delete clients[socket.id] }); var channel_id = parseInt(socket.handshake.query.channel); socket.emit('publish', { channel : channel_id, url :channels[ channel_id ].url }); });
  • 31.
    SERVER HANDLER (PART2) wp_user.on('wp_connected', function ( data ) { if ( ! wp_user.can('manage_options') ) { res.writeHead(403); res.end(); return; } var fullBody = ‘'; req.on('data', function(chunk) { fullBody += chunk.toString(); }); req.on('end', function() { // Access to JSON data } }
  • 32.
    SERVER HANDLER (PART3) if (req.url == "/publish") { var json = JSON.parse(fullBody); if ( json.channel && json.url ) { if ( ! channels[ json.channel ] ) { channels[ json.channel ] = {}; } channels[ json.channel ].url = json.url; io.sockets.emit( 'publish', { channel : json.channel, url : json.url } ); } else { res.writeHead(404); } res.end(); }
  • 33.
    SERVER HANDLER (PART4) else if (req.url == "/channels") { res.writeHead( 200, {'Content-Type': ‘application/json’} ); res.end( JSON.stringify(channels) ); } res.end();
  • 34.