-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathwp-dope-api.php
More file actions
224 lines (188 loc) · 7.49 KB
/
wp-dope-api.php
File metadata and controls
224 lines (188 loc) · 7.49 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
<?php
/*
Plugin Name: WP Dope API
Plugin URI: http://www.blairwilliams.com/
Description: A dope example of creating a WordPress based API bro
Version: 0.0.2
Author: Blair Williams
Author URI: http://blairwilliams.com/
Text Domain: wp-dope-api
Copyright: 2004-2013, Blair Williams
*/
if(!defined('ABSPATH')) {die('You are not allowed to call this page directly.');}
// These can be overriden in wp-config.php for now
// These can be moved to a wp-admin page
if(!defined('DAPI_URL_SLUG')) { define('DAPI_URL_SLUG', 'api'); }
if(!defined('DAPI_AUTH_METHOD')) { define('DAPI_AUTH_METHOD', 'basic'); }
if(!defined('DAPI_DEBUG')) { define('DAPI_DEBUG',true); }
define('DAPI_PLUGIN_SLUG',plugin_basename(__FILE__));
define('DAPI_PLUGIN_NAME',dirname(DAPI_PLUGIN_SLUG));
define('DAPI_PATH',WP_PLUGIN_DIR.'/'.DAPI_PLUGIN_NAME);
define('DAPI_LIB_PATH',DAPI_PATH.'/lib');
define('DAPI_CONTROLLERS_PATH',DAPI_PATH.'/controllers');
/** This class sets everything up ... from rewrites, to autoloading, and routes **/
class WpDopeApi {
public $slug;
public $auth;
public $routes;
public $regexes;
public $query_vars;
public $rules;
public function __construct() {
// This could easily be configured from the wp-admin
$this->slug = DAPI_URL_SLUG; // This is the base slug that the api will be accessible from
$this->auth = DAPI_AUTH_METHOD; // This is the type of authentication we'll be using
$this->routes = array(); // initialize the routes array
$this->query_vars = array( 'plugin', 'action', 'format' );
$this->rules = array();
}
public function load_hooks() {
add_action('init', array($this,'init'));
add_filter('template_include', array($this,'route'));
add_filter('query_vars', array($this, 'query_vars'));
add_filter('redirect_canonical', array($this, 'unslashit'), 10, 2);
}
public function controller_dirs() {
return apply_filters('dapi-controller-dirs',array(DAPI_CONTROLLERS_PATH));
}
// Autoload all the requisite classes
public function autoloader($class_name) {
if(preg_match('/^Dapi.+$/', $class_name)) {
if( $class_name != 'DapiBaseController' and
preg_match('/Controller$/',$class_name) ) {
foreach($this->controller_dirs() as $dir) {
$filepath = $dir . "/{$class_name}.php";
if(file_exists($filepath)) { require_once($filepath); }
}
}
else {
$filepath = DAPI_LIB_PATH . "/{$class_name}.php";
if(file_exists($filepath)) { require_once($filepath); }
}
}
}
// This just adds the rule in the case that the rules are flushed
public function init() {
add_filter('rewrite_rules_array', array($this,'rewrites'));
}
// WordPress' built in query mechanism won't detect the custom
// variables for these added rules unless we add them here
public function query_vars($vars) {
return array_merge( $this->query_vars, $vars );
}
// This is where the new rewrite rules are added to WordPress'
// built-in rewrite rules mechanism to be parsed out accordingly
public function rewrites($wp_rules) {
if(empty($this->slug)) { return $wp_rules; }
return array_merge($this->rules, $wp_rules);
}
// We don't want the url to be redirected to the "slashed" version
public function unslashit($redirect_url, $requested_url) {
global $wp_query, $wp, $wp_rewrite;
if( $this->is_valid_route() )
return false;
return $redirect_url;
}
// We use the query here to make sure we're processing a valid route
private function is_valid_route() {
global $wp_query;
$req_method = strtolower( $_SERVER['REQUEST_METHOD'] );
return ( isset($wp_query->query) and isset($wp_query->query['plugin']) and
$wp_query->query['plugin']=='dapi' and isset($wp_query->query['action']) and
in_array($wp_query->query['action'],array_keys($this->routes)) and
isset($this->routes[$wp_query->query['action']][$req_method]) );
}
// Route the api routes based one wordpress' query system
public function route($template) {
global $wp_query;
if( $this->is_valid_route() ) {
$action = $wp_query->query['action'];
$req_method = strtolower($_SERVER['REQUEST_METHOD']);
@call_user_func($this->routes[$action][$req_method]);
exit;
}
else if( isset($wp_query->query) and
isset($wp_query->query['plugin']) and
$wp_query->query['plugin']=='dapi' ) {
return get_404_template();
}
return $template;
}
// Add custom rules and flush them on activation
public function activation() {
// Add the rewrite rule on activation
global $wp_rewrite;
add_filter('rewrite_rules_array', array($this,'rewrites'));
$wp_rewrite->flush_rules();
}
// Remove custom rules and flush them on deactivation
public function deactivation() {
// Remove the rewrite rule on deactivation
global $wp_rewrite;
$wp_rewrite->flush_rules();
}
// This registers the api route with Wp Dope API
public function register_route($method, $action, $callback) {
$method = strtolower($method);
$slug = $this->action_slug($action);
if(!isset($this->routes[$slug])) {
$this->routes[$slug] = array();
$this->compile_action($action);
}
$this->routes[$slug][$method] = $callback;
}
protected function action_slug($action) {
$regex = preg_replace('!/:([^/]+)!','/([^/]+)',$action);
return md5($regex);
}
// Sets up the query args and rules for each route
protected function compile_action($action) {
$slug = $this->action_slug($action);
preg_match_all('!/:([^/]+)!',$action,$matches);
// Add these variables directly to query_vars for WP to process accordingly
if(isset($matches[1])) {
$this->query_vars = array_merge( $this->query_vars, $matches[1] );
$match_count = count($matches[1]);
}
else
$match_count = 0;
// Refactor matches to build query string
$query_str = '';
for( $i = 0; $i < $match_count; $i++ ) {
$mi = $i+1;
$query_str .= "&{$matches[1][$i]}=\$matches[{$mi}]";
}
// Match index for the format string
$format_index = ( $match_count + 1 );
// figure out regexes for our new rules
$regex = preg_replace('!/:([^/]+)!','/([^/]+)',$action);
$this->rules = array_merge( $this->rules, array(
"{$this->slug}{$regex}\.([^/]+)\$" => "index.php?plugin=dapi&action={$slug}{$query_str}&format=\$matches[{$format_index}]",
"{$this->slug}{$regex}\$" => "index.php?plugin=dapi&action={$slug}{$query_str}&format=json" ) );
}
}
// This is where the magic happens
$dapi = new WpDopeApi();
// Take care of autoloading classes using WpDopeApi::autoloader
if( is_array(spl_autoload_functions()) and
in_array('__autoload', spl_autoload_functions()) ) {
spl_autoload_register('__autoload');
}
spl_autoload_register( array( $dapi, 'autoloader' ) );
// Dynamically load the controllers ... other than the BaseController
foreach($dapi->controller_dirs() as $dir) {
$controllers = @glob( $dir . '/Dapi*Controller.php', GLOB_NOSORT );
foreach( $controllers as $controller ) {
$classname = preg_replace( '#\.php#', '', basename($controller) );
if( preg_match( '#Dapi.*Controller#', $classname ) ) {
include_once($controller);
$rc = new ReflectionClass($classname);
$obj = $rc->newInstanceArgs(array($dapi));
$obj->routes();
}
}
}
$dapi->load_hooks();
// Hook up the activation / deactivation hooks
register_activation_hook(DAPI_PLUGIN_SLUG, array($dapi,'activation'));
register_deactivation_hook(DAPI_PLUGIN_SLUG, array($dapi,'deactivation'));