SlideShare a Scribd company logo
WORDPRESS REST API HACKING
WORDPRESS : IT’S A BLOG
LONG AGO
WORDPRESS : IT’S NOT JUST A BLOG
THE PAST
WORDPRESS : IT’S NOT JUST CMS
PRESENT
WORDPRESS : IT’S AN APPLICATION FRAMEWORK
FUTURE?
BECAUSE OF THE WP REST API
NO TODAY!
RESOURCE BASED STATELESS COMMUNICATION
REPRESENTATIONAL STATE TRANSFER
TO GAIN ACCESS TO (A COMPUTER) ILLEGALLY
TO ALTER (A COMPUTER PROGRAM)
/HĂK/·ING
/00 ALTER THE REST API
WHAT YOU NEED TO KNOW FIRST..
INFRASTRUCTURE IS IN CORE
IMPLEMENTATION IN THE REST-API PLUGIN
2 PARTS
IN CORE
├── rest-api
│   ├── class-wp-rest-request.php
│   ├── class-wp-rest-response.php
│   └── class-wp-rest-server.php
├── rest-api.php
IN PLUGIN
├── class-wp-rest-attachments-controller.php
├── class-wp-rest-comments-controller.php
├── class-wp-rest-controller.php
├── class-wp-rest-post-statuses-controller.php
├── class-wp-rest-post-types-controller.php
├── class-wp-rest-posts-controller.php
├── class-wp-rest-revisions-controller.php
├── class-wp-rest-settings-controller.php
├── class-wp-rest-taxonomies-controller.php
├── class-wp-rest-terms-controller.php
└── class-wp-rest-users-controller.php
YOU KNOW HOW TO CREATE A PLUGIN?
EXTENDING THE API
MY PLUGIN.PHP SETUP
<?php
/*
Plugin Name: My REST API extension
Plugin URI: https://www.a-wp-site.com/
Description: WordPress REST API extension
Version: 1.0.0
Author: Enrise
Author URI: https://www.enrise.com
*/
require_once('src/Bootstrap.php');
new Bootstrap::getInstance();
WHEN TO TRIGGER YOUR CODE
public static function getInstance() {
if ( ! ( self::$instance instanceof self ) ) {
self::$instance = new self();
}
return self::$instance;
}
protected function __construct() {
add_action( 'plugins_loaded', [ $this, 'initServer' ], 100 );
}
public function initServer() {
}
/01 DISABLE THE API
LET’S START EASY!
public function initServer() {
add_filter( 'rest_enabled', [ $this, 'disableApi' ] );
}
public function disableApi( $isEnabled ) {
if ( $isEnabled == true ) {
return false;
}
return $isEnabled;
}
/02 CHANGE THE ROOT URL
CHANGE WP-JSON INTO …
public function initServer() {
if ( ! defined( 'REST_API_VERSION' ) ) {
// return early if WP API versions do not exist
add_action( 'all_admin_notices', [ $this, 'showError' ] );
return;
}
add_filter( 'rest_url_prefix', [ $this, 'changeApiBase' ] );
}
public function changeApiBase( $prefix ) {
if ($prefix === 'wp-json') {
return 'api';
}
return $prefix;
}
/03 CHANGE EXPOSURE
register_post_type( $post_type, $args );
register_taxonomy( $taxonomy, $object_type, $args );
ACCESS POST TYPE & TAXONOMY
public function initServer() {
add_action( 'rest_api_init', [ $this, 'updateExposure' ], 12 );
}
public function updateExposure() {
global $wp_post_types, $wp_taxonomies;
$wp_post_types['customposttype']->show_in_rest = true;
$wp_taxonomies['customtaxonomy']->show_in_rest = true;
}
/04 CHANGE CUSTOM POST
TYPE HANDLING
EXTEND API CONTROLLERS
public function updateExposure() {
global $wp_post_types, $wp_taxonomies;
$wp_post_types['customposttype']->show_in_rest = true;
$wp_post_types['customposttype']->rest_base = 'customposttype';
$wp_post_types['customposttype']->rest_controller_class =
'EnriseApiEndpointCustomType';
$wp_taxonomies['customtaxonomy']->show_in_rest = true;
$wp_taxonomies['customtaxonomy']->rest_base = 'customtaxonomy';
$wp_taxonomies['customtaxonomy']->rest_controller_class =
'EnriseApiEndpointCustomTaxonomy';
}
class CustomType extends WP_REST_Posts_Controller {}
class CustomTaxonomy extends WP_REST_Terms_Controller {}
EXTEND THE INPUT / OUTPUT
register_rest_field( 'customposttype', 'custommetafield', [
'schema' => [
'type' => 'integer',
'context' => [ 'view', 'edit' ],
],
'get_callback' => [ $this, 'getMetaField' ],
'update_callback' => [ $this, 'saveMetaField' ]
] );
public function getMetaField( $post, $key, $request ) {
return get_post_meta( $post['id'], $key, true );
}
public function saveMetaField( $value, $post, $key ) {
return update_post_meta( $post->ID, $key, $value );
}
EXTEND THE INPUT / OUTPUT
register_rest_field( 'customposttype', 'custommetafield', [
'schema' => [
'type' => 'integer',
'context' => [ 'view', 'edit' ],
],
'get_callback' => [ $this, 'getMetaField' ],
'update_callback' => [ $this, 'saveMetaField' ]
] );
public function getMetaField( $post, $key, $request ) {
return get_post_meta( $post['id'], $key, true );
}
public function saveMetaField( $value, $post, $key ) {
return update_post_meta( $post->ID, $key, $value );
}
REST API 2.0 BETA 15
$args =[
'sanitize_callback' => 'sanitize_my_meta_key',
'auth_callback' => 'authorize_my_meta_key',
'type' => 'string',
'description' => 'My registered meta key',
'single' => true,
'show_in_rest' => true,
];
register_meta( 'post', 'my_meta_key', $args );
/05 ROLL YOUR OWN
ENDPOINT
WP_REST_Controller
WP_REST_Posts_Controller
STANDARD IMPLEMENTATION
WP_REST_Controller
Your_Extended_Controller
OPTION #1
register_rest_route( 'enrise', '/version/(?P<os>[a-z]{3,7})', [
[
'methods' => WP_REST_Server::READABLE,
'callback' => [ $this, 'getVersion' ],
'permission_callback' => [ $this, 'checkAccess' ],
'args' => [
'os' => [
'validate_callback' => [ $this, 'isOS' ],
'sanitize_callback' => [ $this, 'filterOS' ],
'required' => true,
],
],
],
] );
OPTION #2
/06 OVERRIDE DEFAULT
FUNCTIONALITY
ANNOTATE AND VALIDATE JSON DOCUMENTS
JSON-SCHEMA.ORG
public function get_item_schema() {
$schema = [
'$schema' => 'http://json-schema.org/draft-04/schema#',
'title' => $this->post_type,
'type' => 'object',
/*
* Base properties for every Post.
*/
'properties' => [
'date' => [
'description' => __( "The date the object was published, in the
site's timezone." ),
'type' => 'string',
'format' => 'date-time',
'context' => [ 'view', 'edit', 'embed' ],
],
...
];
}
JSON SCHEMA DEFINITION
global $wp_rest_additional_fields;
GLOBAL AGAIN…
register_rest_field( 'user', 'first_name', [
'schema' => [
'description' => __( 'First name for the resource.' ),
'type' => 'string',
'context' => [ 'edit', 'embed', 'view' ],
'arg_options' => [
'sanitize_callback' => 'sanitize_text_field',
],
],
] );
register_rest_field( 'user', 'last_name', [
'schema' => [
'description' => __( 'Last name for the resource.' ),
'type' => 'string',
'context' => [ 'edit', 'embed', 'view' ],
'arg_options' => [
'sanitize_callback' => 'sanitize_text_field',
],
],
] );
OVERRIDE DEFAULT CONFIGURATION
/07 APPLY SOME FILTERING
public function initServer() {
add_filter('rest_customposttype_query', [ $this, 'filterbyMetaField' ], 10, 2);
}
/**
* @param $args
* @param $request WP_REST_Request
*/
public function filterByMetaField($args, $request) {
$filter = [];
$filter['meta_key'] = 'custommetafield';
$filter['meta_value'] = 1476896350;
$filter['meta_type'] = 'DECIMAL';
$filter['meta_compare'] = '>=';
return array_merge($args, $filter);
}
CHANGE THE QUERY BEHAVIOUR
/08 FILE UPLOADS
xhr.onload = function() {
var attachment = JSON.parse(this.responseText);
$.current.set('featured_image', attachment.id);
saveCustompost();
};
xhr.open('POST', '/wp-json/wp/v2/media');
xhr.setRequestHeader('Content-Type', 'image/jpeg');
xhr.setRequestHeader('Content-Disposition',
'attachment; filename=filename.jpg');
xhr.send(image.read());
UPLOAD A FILE
public function initServer() {
add_filter('wp_handle_sideload_prefilter', [ $this, 'autoRotate' ]);
add_filter('rest_insert_customposttype', [$this, 'saveAttachment'], 10, 3);
}
/**
* @param $post WP_Post
* @param $request WP_REST_Request
* @param $create bool
*/
public function saveAttachment($post, $request, $create) {
if ($create === true && isset( $request['featured_image'] )) {
set_post_thumbnail( $post->ID, $request['featured_image'] );
}
}
HANDLE THE ATTACHMENT
/09 CACHE REQUESTS
add_filter( 'rest_pre_dispatch', [ $this, 'lastUpdate' ], 10, 3 );
public function lastUpdate( $response, $server, $request ) {
$since = $request->get_header( 'if_modified_since' );
if ( $since === null ) {
return $response;
}
if ( $response !== null || $response->get_route() !==
'/wp/v2/customposttype' ) {
return $response;
}
$lastrequest = DateTime::createFromFormat( DateTime::RFC1123, $since );
$lastpost = DateTime::createFromFormat( 'Y-m-d H:i:s',
get_lastpostmodified( 'gmt', 'customposttype' ) );
if ( $lastrequest >= $lastpost ) {
return new WP_REST_Response( null, 304 );
}
return $response;
}
LET THE CLIENT CACHE…
/10 AUTHENTICATION
add_filter( 'determine_current_user', [ $this, 'authenticate' ] );
add_filter( 'rest_authentication_errors', [ $this, 'getErrors' ] );
public function authenticate( $user ) { | public function getErrors( $value ) {
// method run/used multiple times | // already overrided
if ($user instanceof WP_User) { | if ( $value !== null ) {
return $user; | return $value;
} | }
// roll your own authentication here | // WP_Error|null|bool(!?)
if (false) { | return $this->status;
$this->status = new WP_Error(); | }
return null; |
} |
$this->status = true; |
return $user->ID; |
} |
TRY TO DEBUG THIS…
IMPLEMENTATIONS
WORDPRESS.ORG/PLUGINS/OAUTH2-PROVIDER
WORDPRESS.ORG/PLUGINS/JWT-AUTHENTICATION-FOR-WP-REST-API
WORDPRESS.ORG/PLUGINS/REST-API-OAUTH1
/11 CHANGE ALL OUTPUT!
add_filter( 'rest_pre_serve_request', [ $this, 'changeResponse' ], 10, 4 );
public function changeResponse( $served, $response, $request, $server ) {
$route = $response->get_matched_route();
if ( $served || $route !== '/wp/v2/customposttype' ) {
return false;
}
if ( 'HEAD' === $request->get_method() ) {
return null;
}
$result = $server->response_to_data( $response, true );
$transform = new Transformer( $result );
echo wp_json_encode( iterator_to_array( $transform ) );
return true;
}
THIS SHOULDN’T BE NECESSARY…
class Transformer extends ArrayIterator {
public function current() {
$item = parent::current();
$item = $this->modify( $item );
return $item;
}
private function modify( array $data ) {
// modify the data in any way
return $data;
}
}
THIS SHOULDN’T BE NECESSARY…
add_filter('rest_prepare_customposttype', 'beforeOutput', 10, 3);
add_filter('rest_pre_insert_customposttype', 'beforeInsertInDb', 10, 2);
add_filter('rest_insert_customposttype', 'afterInsertInDb', 10, 3);
add_filter('rest_query_vars', 'filterQueryVars', 10, 1);
OTHER INTERESTING HOOKS
MORE HOOKS?
V2.WP-API.ORG/EXTENDING/HOOKS
WordPress REST API hacking

More Related Content

What's hot (20)

PDF
ColdFusion for Penetration Testers
Chris Gates
 
PPTX
Php with mysql ppt
Rajamanickam Gomathijayam
 
PDF
Introduction to burp suite
Utkarsh Bhargava
 
PPTX
Attacking thru HTTP Host header
Sergey Belov
 
PPT
A Brief Introduction in SQL Injection
Sina Manavi
 
PDF
Modern JavaScript Frameworks: Angular, React & Vue.js
Jonas Bandi
 
PDF
IPV6 Hands on Lab
Cisco Canada
 
PPTX
Basics of Server Side Template Injection
Vandana Verma
 
PDF
A5-Security misconfiguration-OWASP 2013
Sorina Chirilă
 
PPT
SQL Injection
Adhoura Academy
 
PPT
Cross Site Request Forgery
Tony Bibbs
 
PPTX
Injection flaws
DANISH INAMDAR
 
PPTX
WAF Bypass Techniques - Using HTTP Standard and Web Servers’ Behaviour
Soroush Dalili
 
PPT
OWASP Serbia - A6 security misconfiguration
Nikola Milosevic
 
PDF
The Secret Life of a Bug Bounty Hunter – Frans Rosén @ Security Fest 2016
Frans Rosén
 
PPTX
Sql injection
Nuruzzaman Milon
 
PPTX
Sql injection
Zidh
 
PDF
Bug Bounty - Hackers Job
Arbin Godar
 
PPTX
Security misconfiguration
Micho Hayek
 
PPTX
OWASP Top 10 2021 What's New
Michael Furman
 
ColdFusion for Penetration Testers
Chris Gates
 
Php with mysql ppt
Rajamanickam Gomathijayam
 
Introduction to burp suite
Utkarsh Bhargava
 
Attacking thru HTTP Host header
Sergey Belov
 
A Brief Introduction in SQL Injection
Sina Manavi
 
Modern JavaScript Frameworks: Angular, React & Vue.js
Jonas Bandi
 
IPV6 Hands on Lab
Cisco Canada
 
Basics of Server Side Template Injection
Vandana Verma
 
A5-Security misconfiguration-OWASP 2013
Sorina Chirilă
 
SQL Injection
Adhoura Academy
 
Cross Site Request Forgery
Tony Bibbs
 
Injection flaws
DANISH INAMDAR
 
WAF Bypass Techniques - Using HTTP Standard and Web Servers’ Behaviour
Soroush Dalili
 
OWASP Serbia - A6 security misconfiguration
Nikola Milosevic
 
The Secret Life of a Bug Bounty Hunter – Frans Rosén @ Security Fest 2016
Frans Rosén
 
Sql injection
Nuruzzaman Milon
 
Sql injection
Zidh
 
Bug Bounty - Hackers Job
Arbin Godar
 
Security misconfiguration
Micho Hayek
 
OWASP Top 10 2021 What's New
Michael Furman
 

Viewers also liked (20)

PDF
WordPress REST API hacking
Jeroen van Dijk
 
PPTX
Conduction
Sonal Upadhyay
 
PPTX
Webinar - Maximize Your Library Technology - 2016-05-24
TechSoup
 
PPTX
Designing Interactive Learning Spaces
Brian Pichman
 
PPTX
Webinar - QuickBooks Online for Newer Nonprofit Users - 2016-07-21
TechSoup
 
DOC
Pgs 506 class-notes_
Mahesh Kumar
 
PPTX
Programming Ideas in Makerspaces
Brian Pichman
 
PPTX
Día internacional de la mujer
Nicolas Rojas
 
PPT
Prezentacija Blog
fizicarke2
 
PPTX
Disputation: Von Open Access zu Open Science: Zum Wandel digitaler Kulturen d...
Christian Heise
 
PPTX
Dia internacional de la mujer
alejandro serrano
 
PPTX
Signal flow graph
Chandresh Suthar
 
PPTX
Programming ideas
Brian Pichman
 
DOCX
Cписок сотрудников "Золотой ключик"
Parusnik55
 
PPT
Презентация Центр ПМСС
Parusnik55
 
PPTX
Carnaval
Emília Fernandes
 
PDF
Citylogistics in Amsterdam's Oude Pijp
Walther Ploos van Amstel
 
PPTX
Filmska umjetnost
aco bojic
 
PPSX
PowerPoint 8 de marzo de 2016. Día Internacional de la Mujer
María López
 
PPT
Likovna kultura 2
aco bojic
 
WordPress REST API hacking
Jeroen van Dijk
 
Conduction
Sonal Upadhyay
 
Webinar - Maximize Your Library Technology - 2016-05-24
TechSoup
 
Designing Interactive Learning Spaces
Brian Pichman
 
Webinar - QuickBooks Online for Newer Nonprofit Users - 2016-07-21
TechSoup
 
Pgs 506 class-notes_
Mahesh Kumar
 
Programming Ideas in Makerspaces
Brian Pichman
 
Día internacional de la mujer
Nicolas Rojas
 
Prezentacija Blog
fizicarke2
 
Disputation: Von Open Access zu Open Science: Zum Wandel digitaler Kulturen d...
Christian Heise
 
Dia internacional de la mujer
alejandro serrano
 
Signal flow graph
Chandresh Suthar
 
Programming ideas
Brian Pichman
 
Cписок сотрудников "Золотой ключик"
Parusnik55
 
Презентация Центр ПМСС
Parusnik55
 
Citylogistics in Amsterdam's Oude Pijp
Walther Ploos van Amstel
 
Filmska umjetnost
aco bojic
 
PowerPoint 8 de marzo de 2016. Día Internacional de la Mujer
María López
 
Likovna kultura 2
aco bojic
 

Similar to WordPress REST API hacking (20)

PDF
Teaming up WordPress API with Backbone.js in Titanium
Jeroen van Dijk
 
PDF
Extending the WordPress REST API - Josh Pollock
Caldera Labs
 
PDF
JSON REST API for WordPress
Taylor Lovett
 
PDF
Old WP REST API, New Tricks
WordPress Community Montreal
 
PPTX
The JSON REST API for WordPress
Taylor Lovett
 
PPTX
WordPress Rest API
Brian Layman
 
PDF
WORDPRESS_REST_API_WORDPRESS_REST_API.pdf
Angy668409
 
PDF
JSON REST API for WordPress
Taylor Lovett
 
PDF
WP REST API - Adding Your Own Endpoint
Keanan Koppenhaver
 
PPTX
Word press rest api sudarshan shrestha
Sudarshan Shrestha
 
PDF
Teaming up WordPress API with Backbone.js in Titanium
Jeroen van Dijk
 
PDF
Building a mini-theme with WordPress REST API
Anthony Montalbano
 
PDF
Introduction to WordPress Rest API
kishore sahoo
 
PDF
WordCamp Birmingham 2016 - WP API, What is it good for? Absolutely Everything!
Evan Mullins
 
PPTX
Using WordPress as your application stack
Paul Bearne
 
KEY
Representation state transfer and some other important stuff
Joshua Thijssen
 
PDF
WordCamp Raleigh 2016 - WP API, What is it good for? Absolutely Everything!
Evan Mullins
 
PPTX
Let's code_ WP REST API - custom routes and endpoints.pptx
Jonathan Bossenger
 
PDF
Caldera Learn - LoopConf WP API + Angular FTW Workshop
CalderaLearn
 
PDF
2019 WordCamp Orange County - An Introduction to the WordPress REST API
vegasgeek
 
Teaming up WordPress API with Backbone.js in Titanium
Jeroen van Dijk
 
Extending the WordPress REST API - Josh Pollock
Caldera Labs
 
JSON REST API for WordPress
Taylor Lovett
 
Old WP REST API, New Tricks
WordPress Community Montreal
 
The JSON REST API for WordPress
Taylor Lovett
 
WordPress Rest API
Brian Layman
 
WORDPRESS_REST_API_WORDPRESS_REST_API.pdf
Angy668409
 
JSON REST API for WordPress
Taylor Lovett
 
WP REST API - Adding Your Own Endpoint
Keanan Koppenhaver
 
Word press rest api sudarshan shrestha
Sudarshan Shrestha
 
Teaming up WordPress API with Backbone.js in Titanium
Jeroen van Dijk
 
Building a mini-theme with WordPress REST API
Anthony Montalbano
 
Introduction to WordPress Rest API
kishore sahoo
 
WordCamp Birmingham 2016 - WP API, What is it good for? Absolutely Everything!
Evan Mullins
 
Using WordPress as your application stack
Paul Bearne
 
Representation state transfer and some other important stuff
Joshua Thijssen
 
WordCamp Raleigh 2016 - WP API, What is it good for? Absolutely Everything!
Evan Mullins
 
Let's code_ WP REST API - custom routes and endpoints.pptx
Jonathan Bossenger
 
Caldera Learn - LoopConf WP API + Angular FTW Workshop
CalderaLearn
 
2019 WordCamp Orange County - An Introduction to the WordPress REST API
vegasgeek
 

More from Jeroen van Dijk (13)

PDF
The Enterprise Wor/d/thy/Press
Jeroen van Dijk
 
PDF
The Enterprise Wor/d/thy/Press
Jeroen van Dijk
 
PDF
Beacons in Appcelerator Titanium
Jeroen van Dijk
 
PDF
An app on the shoulders of giants
Jeroen van Dijk
 
PDF
Zend Server: Not just a PHP stack
Jeroen van Dijk
 
PDF
Refactoring using Codeception
Jeroen van Dijk
 
PDF
Liking Relevance - PHP North East 2014
Jeroen van Dijk
 
PDF
To SQL or No(t)SQL - PHPNW12
Jeroen van Dijk
 
PDF
To SQL or No(t)SQL - PFCongres 2012
Jeroen van Dijk
 
PDF
Socializing a world of travel
Jeroen van Dijk
 
PDF
Varnish, the high performance valhalla?
Jeroen van Dijk
 
PPTX
Varnish, the high performance valhalla?
Jeroen van Dijk
 
PPTX
Edge Side Includes in Zend Framework without Varnish
Jeroen van Dijk
 
The Enterprise Wor/d/thy/Press
Jeroen van Dijk
 
The Enterprise Wor/d/thy/Press
Jeroen van Dijk
 
Beacons in Appcelerator Titanium
Jeroen van Dijk
 
An app on the shoulders of giants
Jeroen van Dijk
 
Zend Server: Not just a PHP stack
Jeroen van Dijk
 
Refactoring using Codeception
Jeroen van Dijk
 
Liking Relevance - PHP North East 2014
Jeroen van Dijk
 
To SQL or No(t)SQL - PHPNW12
Jeroen van Dijk
 
To SQL or No(t)SQL - PFCongres 2012
Jeroen van Dijk
 
Socializing a world of travel
Jeroen van Dijk
 
Varnish, the high performance valhalla?
Jeroen van Dijk
 
Varnish, the high performance valhalla?
Jeroen van Dijk
 
Edge Side Includes in Zend Framework without Varnish
Jeroen van Dijk
 

Recently uploaded (20)

PDF
Using FME to Develop Self-Service CAD Applications for a Major UK Police Force
Safe Software
 
PDF
Chris Elwell Woburn, MA - Passionate About IT Innovation
Chris Elwell Woburn, MA
 
PDF
HubSpot Main Hub: A Unified Growth Platform
Jaswinder Singh
 
PPTX
MSP360 Backup Scheduling and Retention Best Practices.pptx
MSP360
 
PDF
Windsurf Meetup Ottawa 2025-07-12 - Planning Mode at Reliza.pdf
Pavel Shukhman
 
PDF
NewMind AI Journal - Weekly Chronicles - July'25 Week II
NewMind AI
 
PDF
Log-Based Anomaly Detection: Enhancing System Reliability with Machine Learning
Mohammed BEKKOUCHE
 
PDF
Fl Studio 24.2.2 Build 4597 Crack for Windows Free Download 2025
faizk77g
 
PPTX
UiPath Academic Alliance Educator Panels: Session 2 - Business Analyst Content
DianaGray10
 
PDF
The Builder’s Playbook - 2025 State of AI Report.pdf
jeroen339954
 
PDF
Building Real-Time Digital Twins with IBM Maximo & ArcGIS Indoors
Safe Software
 
PDF
July Patch Tuesday
Ivanti
 
PDF
LLMs.txt: Easily Control How AI Crawls Your Site
Keploy
 
PDF
New from BookNet Canada for 2025: BNC BiblioShare - Tech Forum 2025
BookNet Canada
 
PDF
CIFDAQ Token Spotlight for 9th July 2025
CIFDAQ
 
PPT
Interview paper part 3, It is based on Interview Prep
SoumyadeepGhosh39
 
PDF
Human-centred design in online workplace learning and relationship to engagem...
Tracy Tang
 
PDF
Why Orbit Edge Tech is a Top Next JS Development Company in 2025
mahendraalaska08
 
PDF
Blockchain Transactions Explained For Everyone
CIFDAQ
 
PDF
Empower Inclusion Through Accessible Java Applications
Ana-Maria Mihalceanu
 
Using FME to Develop Self-Service CAD Applications for a Major UK Police Force
Safe Software
 
Chris Elwell Woburn, MA - Passionate About IT Innovation
Chris Elwell Woburn, MA
 
HubSpot Main Hub: A Unified Growth Platform
Jaswinder Singh
 
MSP360 Backup Scheduling and Retention Best Practices.pptx
MSP360
 
Windsurf Meetup Ottawa 2025-07-12 - Planning Mode at Reliza.pdf
Pavel Shukhman
 
NewMind AI Journal - Weekly Chronicles - July'25 Week II
NewMind AI
 
Log-Based Anomaly Detection: Enhancing System Reliability with Machine Learning
Mohammed BEKKOUCHE
 
Fl Studio 24.2.2 Build 4597 Crack for Windows Free Download 2025
faizk77g
 
UiPath Academic Alliance Educator Panels: Session 2 - Business Analyst Content
DianaGray10
 
The Builder’s Playbook - 2025 State of AI Report.pdf
jeroen339954
 
Building Real-Time Digital Twins with IBM Maximo & ArcGIS Indoors
Safe Software
 
July Patch Tuesday
Ivanti
 
LLMs.txt: Easily Control How AI Crawls Your Site
Keploy
 
New from BookNet Canada for 2025: BNC BiblioShare - Tech Forum 2025
BookNet Canada
 
CIFDAQ Token Spotlight for 9th July 2025
CIFDAQ
 
Interview paper part 3, It is based on Interview Prep
SoumyadeepGhosh39
 
Human-centred design in online workplace learning and relationship to engagem...
Tracy Tang
 
Why Orbit Edge Tech is a Top Next JS Development Company in 2025
mahendraalaska08
 
Blockchain Transactions Explained For Everyone
CIFDAQ
 
Empower Inclusion Through Accessible Java Applications
Ana-Maria Mihalceanu
 

WordPress REST API hacking

  • 2. WORDPRESS : IT’S A BLOG LONG AGO
  • 3. WORDPRESS : IT’S NOT JUST A BLOG THE PAST
  • 4. WORDPRESS : IT’S NOT JUST CMS PRESENT
  • 5. WORDPRESS : IT’S AN APPLICATION FRAMEWORK FUTURE?
  • 6. BECAUSE OF THE WP REST API NO TODAY!
  • 7. RESOURCE BASED STATELESS COMMUNICATION REPRESENTATIONAL STATE TRANSFER
  • 8. TO GAIN ACCESS TO (A COMPUTER) ILLEGALLY TO ALTER (A COMPUTER PROGRAM) /HĂK/·ING
  • 9. /00 ALTER THE REST API WHAT YOU NEED TO KNOW FIRST..
  • 10. INFRASTRUCTURE IS IN CORE IMPLEMENTATION IN THE REST-API PLUGIN 2 PARTS
  • 11. IN CORE ├── rest-api │   ├── class-wp-rest-request.php │   ├── class-wp-rest-response.php │   └── class-wp-rest-server.php ├── rest-api.php
  • 12. IN PLUGIN ├── class-wp-rest-attachments-controller.php ├── class-wp-rest-comments-controller.php ├── class-wp-rest-controller.php ├── class-wp-rest-post-statuses-controller.php ├── class-wp-rest-post-types-controller.php ├── class-wp-rest-posts-controller.php ├── class-wp-rest-revisions-controller.php ├── class-wp-rest-settings-controller.php ├── class-wp-rest-taxonomies-controller.php ├── class-wp-rest-terms-controller.php └── class-wp-rest-users-controller.php
  • 13. YOU KNOW HOW TO CREATE A PLUGIN? EXTENDING THE API
  • 14. MY PLUGIN.PHP SETUP <?php /* Plugin Name: My REST API extension Plugin URI: https://www.a-wp-site.com/ Description: WordPress REST API extension Version: 1.0.0 Author: Enrise Author URI: https://www.enrise.com */ require_once('src/Bootstrap.php'); new Bootstrap::getInstance();
  • 15. WHEN TO TRIGGER YOUR CODE public static function getInstance() { if ( ! ( self::$instance instanceof self ) ) { self::$instance = new self(); } return self::$instance; } protected function __construct() { add_action( 'plugins_loaded', [ $this, 'initServer' ], 100 ); } public function initServer() { }
  • 17. LET’S START EASY! public function initServer() { add_filter( 'rest_enabled', [ $this, 'disableApi' ] ); } public function disableApi( $isEnabled ) { if ( $isEnabled == true ) { return false; } return $isEnabled; }
  • 18. /02 CHANGE THE ROOT URL
  • 19. CHANGE WP-JSON INTO … public function initServer() { if ( ! defined( 'REST_API_VERSION' ) ) { // return early if WP API versions do not exist add_action( 'all_admin_notices', [ $this, 'showError' ] ); return; } add_filter( 'rest_url_prefix', [ $this, 'changeApiBase' ] ); } public function changeApiBase( $prefix ) { if ($prefix === 'wp-json') { return 'api'; } return $prefix; }
  • 21. register_post_type( $post_type, $args ); register_taxonomy( $taxonomy, $object_type, $args );
  • 22. ACCESS POST TYPE & TAXONOMY public function initServer() { add_action( 'rest_api_init', [ $this, 'updateExposure' ], 12 ); } public function updateExposure() { global $wp_post_types, $wp_taxonomies; $wp_post_types['customposttype']->show_in_rest = true; $wp_taxonomies['customtaxonomy']->show_in_rest = true; }
  • 23. /04 CHANGE CUSTOM POST TYPE HANDLING
  • 24. EXTEND API CONTROLLERS public function updateExposure() { global $wp_post_types, $wp_taxonomies; $wp_post_types['customposttype']->show_in_rest = true; $wp_post_types['customposttype']->rest_base = 'customposttype'; $wp_post_types['customposttype']->rest_controller_class = 'EnriseApiEndpointCustomType'; $wp_taxonomies['customtaxonomy']->show_in_rest = true; $wp_taxonomies['customtaxonomy']->rest_base = 'customtaxonomy'; $wp_taxonomies['customtaxonomy']->rest_controller_class = 'EnriseApiEndpointCustomTaxonomy'; } class CustomType extends WP_REST_Posts_Controller {} class CustomTaxonomy extends WP_REST_Terms_Controller {}
  • 25. EXTEND THE INPUT / OUTPUT register_rest_field( 'customposttype', 'custommetafield', [ 'schema' => [ 'type' => 'integer', 'context' => [ 'view', 'edit' ], ], 'get_callback' => [ $this, 'getMetaField' ], 'update_callback' => [ $this, 'saveMetaField' ] ] ); public function getMetaField( $post, $key, $request ) { return get_post_meta( $post['id'], $key, true ); } public function saveMetaField( $value, $post, $key ) { return update_post_meta( $post->ID, $key, $value ); }
  • 26. EXTEND THE INPUT / OUTPUT register_rest_field( 'customposttype', 'custommetafield', [ 'schema' => [ 'type' => 'integer', 'context' => [ 'view', 'edit' ], ], 'get_callback' => [ $this, 'getMetaField' ], 'update_callback' => [ $this, 'saveMetaField' ] ] ); public function getMetaField( $post, $key, $request ) { return get_post_meta( $post['id'], $key, true ); } public function saveMetaField( $value, $post, $key ) { return update_post_meta( $post->ID, $key, $value ); }
  • 27. REST API 2.0 BETA 15 $args =[ 'sanitize_callback' => 'sanitize_my_meta_key', 'auth_callback' => 'authorize_my_meta_key', 'type' => 'string', 'description' => 'My registered meta key', 'single' => true, 'show_in_rest' => true, ]; register_meta( 'post', 'my_meta_key', $args );
  • 28. /05 ROLL YOUR OWN ENDPOINT
  • 31. register_rest_route( 'enrise', '/version/(?P<os>[a-z]{3,7})', [ [ 'methods' => WP_REST_Server::READABLE, 'callback' => [ $this, 'getVersion' ], 'permission_callback' => [ $this, 'checkAccess' ], 'args' => [ 'os' => [ 'validate_callback' => [ $this, 'isOS' ], 'sanitize_callback' => [ $this, 'filterOS' ], 'required' => true, ], ], ], ] ); OPTION #2
  • 33. ANNOTATE AND VALIDATE JSON DOCUMENTS JSON-SCHEMA.ORG
  • 34. public function get_item_schema() { $schema = [ '$schema' => 'http://json-schema.org/draft-04/schema#', 'title' => $this->post_type, 'type' => 'object', /* * Base properties for every Post. */ 'properties' => [ 'date' => [ 'description' => __( "The date the object was published, in the site's timezone." ), 'type' => 'string', 'format' => 'date-time', 'context' => [ 'view', 'edit', 'embed' ], ], ... ]; } JSON SCHEMA DEFINITION
  • 36. register_rest_field( 'user', 'first_name', [ 'schema' => [ 'description' => __( 'First name for the resource.' ), 'type' => 'string', 'context' => [ 'edit', 'embed', 'view' ], 'arg_options' => [ 'sanitize_callback' => 'sanitize_text_field', ], ], ] ); register_rest_field( 'user', 'last_name', [ 'schema' => [ 'description' => __( 'Last name for the resource.' ), 'type' => 'string', 'context' => [ 'edit', 'embed', 'view' ], 'arg_options' => [ 'sanitize_callback' => 'sanitize_text_field', ], ], ] ); OVERRIDE DEFAULT CONFIGURATION
  • 37. /07 APPLY SOME FILTERING
  • 38. public function initServer() { add_filter('rest_customposttype_query', [ $this, 'filterbyMetaField' ], 10, 2); } /** * @param $args * @param $request WP_REST_Request */ public function filterByMetaField($args, $request) { $filter = []; $filter['meta_key'] = 'custommetafield'; $filter['meta_value'] = 1476896350; $filter['meta_type'] = 'DECIMAL'; $filter['meta_compare'] = '>='; return array_merge($args, $filter); } CHANGE THE QUERY BEHAVIOUR
  • 40. xhr.onload = function() { var attachment = JSON.parse(this.responseText); $.current.set('featured_image', attachment.id); saveCustompost(); }; xhr.open('POST', '/wp-json/wp/v2/media'); xhr.setRequestHeader('Content-Type', 'image/jpeg'); xhr.setRequestHeader('Content-Disposition', 'attachment; filename=filename.jpg'); xhr.send(image.read()); UPLOAD A FILE
  • 41. public function initServer() { add_filter('wp_handle_sideload_prefilter', [ $this, 'autoRotate' ]); add_filter('rest_insert_customposttype', [$this, 'saveAttachment'], 10, 3); } /** * @param $post WP_Post * @param $request WP_REST_Request * @param $create bool */ public function saveAttachment($post, $request, $create) { if ($create === true && isset( $request['featured_image'] )) { set_post_thumbnail( $post->ID, $request['featured_image'] ); } } HANDLE THE ATTACHMENT
  • 43. add_filter( 'rest_pre_dispatch', [ $this, 'lastUpdate' ], 10, 3 ); public function lastUpdate( $response, $server, $request ) { $since = $request->get_header( 'if_modified_since' ); if ( $since === null ) { return $response; } if ( $response !== null || $response->get_route() !== '/wp/v2/customposttype' ) { return $response; } $lastrequest = DateTime::createFromFormat( DateTime::RFC1123, $since ); $lastpost = DateTime::createFromFormat( 'Y-m-d H:i:s', get_lastpostmodified( 'gmt', 'customposttype' ) ); if ( $lastrequest >= $lastpost ) { return new WP_REST_Response( null, 304 ); } return $response; } LET THE CLIENT CACHE…
  • 45. add_filter( 'determine_current_user', [ $this, 'authenticate' ] ); add_filter( 'rest_authentication_errors', [ $this, 'getErrors' ] ); public function authenticate( $user ) { | public function getErrors( $value ) { // method run/used multiple times | // already overrided if ($user instanceof WP_User) { | if ( $value !== null ) { return $user; | return $value; } | } // roll your own authentication here | // WP_Error|null|bool(!?) if (false) { | return $this->status; $this->status = new WP_Error(); | } return null; | } | $this->status = true; | return $user->ID; | } | TRY TO DEBUG THIS…
  • 47. /11 CHANGE ALL OUTPUT!
  • 48. add_filter( 'rest_pre_serve_request', [ $this, 'changeResponse' ], 10, 4 ); public function changeResponse( $served, $response, $request, $server ) { $route = $response->get_matched_route(); if ( $served || $route !== '/wp/v2/customposttype' ) { return false; } if ( 'HEAD' === $request->get_method() ) { return null; } $result = $server->response_to_data( $response, true ); $transform = new Transformer( $result ); echo wp_json_encode( iterator_to_array( $transform ) ); return true; } THIS SHOULDN’T BE NECESSARY…
  • 49. class Transformer extends ArrayIterator { public function current() { $item = parent::current(); $item = $this->modify( $item ); return $item; } private function modify( array $data ) { // modify the data in any way return $data; } } THIS SHOULDN’T BE NECESSARY…
  • 50. add_filter('rest_prepare_customposttype', 'beforeOutput', 10, 3); add_filter('rest_pre_insert_customposttype', 'beforeInsertInDb', 10, 2); add_filter('rest_insert_customposttype', 'afterInsertInDb', 10, 3); add_filter('rest_query_vars', 'filterQueryVars', 10, 1); OTHER INTERESTING HOOKS