├── includes ├── arial.ttf ├── class-extending-wp-rest-api-admin-ajax.php ├── class-pn-date-progress-chart.php └── class-extending-wp-rest-api-controller.php ├── admin ├── admin-hello-world.php ├── admin-hello-world.js └── class-extending-wp-rest-api-admin.php ├── plugin.php └── README.md /includes/arial.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/petenelson/extending-wp-rest-api/HEAD/includes/arial.ttf -------------------------------------------------------------------------------- /admin/admin-hello-world.php: -------------------------------------------------------------------------------- 1 |
2 | 3 |

4 | 7 |

8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |

16 |

17 |

Response

18 |
19 |
20 | 21 |

22 | 23 | 24 |
25 | 26 | -------------------------------------------------------------------------------- /plugin.php: -------------------------------------------------------------------------------- 1 | show_in_rest = is_user_logged_in();``` 15 | * Disabled media endpoint: ```rest_dispatch_request``` filter 16 | 17 | -------------------------------------------------------------------------------- /includes/class-extending-wp-rest-api-admin-ajax.php: -------------------------------------------------------------------------------- 1 | 'post' ) ); 20 | wp_send_json( $query->posts ); 21 | } 22 | 23 | public function ajax_hello_world() { 24 | 25 | $response = new stdClass(); 26 | $response->hello = 'world'; 27 | $response->time = current_time( 'mysql' ); 28 | 29 | wp_send_json( $response ); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /admin/admin-hello-world.js: -------------------------------------------------------------------------------- 1 | ( function( $ ) { 2 | 3 | 'use strict'; 4 | 5 | $.extend( { 6 | 7 | extend_rest_api: { 8 | 9 | bind_events: function() { 10 | 11 | $( '.options-form' ).submit( function ( e ) { 12 | e.preventDefault(); 13 | }); 14 | 15 | $('.button-get').click( function( e ) { 16 | $.extend_rest_api.send_get(); 17 | }); 18 | 19 | $('.button-post').click( function( e ) { 20 | $.extend_rest_api.send_post(); 21 | }); 22 | 23 | $('.button-delete').click( function( e ) { 24 | $.extend_rest_api.send_delete(); 25 | }); 26 | }, 27 | 28 | display_response: function( response ) { 29 | $('.postbox pre code').text( JSON.stringify( response, null, 2 ) ).each( function( i, block ) { 30 | hljs.highlightBlock( block ); 31 | }); 32 | }, 33 | 34 | send_get: function() { 35 | $.get( ExtendingRESTAPI.endpoints.hello_world, {}, function( response ) { 36 | } ).always( function ( response ) { 37 | $.extend_rest_api.display_response( response ); 38 | }); 39 | }, 40 | 41 | send_post: function() { 42 | $.post( ExtendingRESTAPI.endpoints.hello_world, { my_number:$('.extend-my-number').val() }, function() { 43 | } ).always( function ( response ) { 44 | $.extend_rest_api.display_response( response ); 45 | }); 46 | }, 47 | 48 | send_delete: function() { 49 | $.ajax( { 50 | url: ExtendingRESTAPI.endpoints.hello_world, 51 | data: { }, 52 | type: 'DELETE', 53 | success: function() { 54 | } 55 | } ).always( function ( response ) { 56 | $.extend_rest_api.display_response( response ); 57 | }); 58 | 59 | } 60 | 61 | 62 | 63 | } 64 | } ); 65 | 66 | // send nonce to the WP API 67 | $( document ).ajaxSend( function( event, xhr ) { 68 | // you can also send _wp_rest_nonce in the GET or POST params 69 | xhr.setRequestHeader( 'X-WP-Nonce', wpApiSettings.nonce ); 70 | }); 71 | 72 | $(document).ready( function() { 73 | $.extend_rest_api.bind_events(); 74 | }); 75 | 76 | 77 | })( jQuery ); 78 | -------------------------------------------------------------------------------- /includes/class-pn-date-progress-chart.php: -------------------------------------------------------------------------------- 1 | font = plugin_dir_path( __FILE__ ) . $this->font; 27 | 28 | $this->bar_max_width = $this->bar_end - $this->bar_start; 29 | 30 | // create image resource 31 | $this->im = imagecreate($this->width, $this->height); 32 | 33 | //background 34 | $bg = imagecolorallocate($this->im, 246, 246, 247); 35 | 36 | // grey text 37 | $this->textcolor = imagecolorallocate($this->im, 103, 103, 103); 38 | 39 | // blue progress bar 40 | $this->bluebar = imagecolorallocate($this->im, 26, 117, 187); 41 | 42 | // lines and ticks 43 | $this->greyline = imagecolorallocate($this->im, 175, 175, 175); 44 | 45 | } 46 | 47 | 48 | function draw_date($date, $text_center) { 49 | $date_string = date($this->month_year, date_timestamp_get( $date ) ); 50 | $box = imagettfbbox($this->font_size, 0, $this->font, $date_string); 51 | $text_width = abs($box[4] - $box[0]); 52 | $text_height = abs($box[5] - $box[1]); 53 | $text_start = $text_center - ($text_width / 2); 54 | imagettftext($this->im, $this->font_size, 0, $text_start, $this->bottom_line_y + $text_height + $this->tick_height + $this->text_top_padding, $this->textcolor, $this->font, $date_string); 55 | } 56 | 57 | function draw_line($from_x, $from_y, $to_x, $to_y) { 58 | imageline($this->im, $from_x, $from_y, $to_x, $to_y, $this->greyline); 59 | } 60 | 61 | function draw_progress_bar($percent_progress) { 62 | $bar_width = ceil($this->bar_max_width * $percent_progress); 63 | imagefilledrectangle($this->im, $this->bar_start, $this->bar_top_x, $this->bar_start + $bar_width, $this->bar_top_x + $this->bar_height, $this->bluebar); 64 | } 65 | 66 | 67 | } -------------------------------------------------------------------------------- /admin/class-extending-wp-rest-api-admin.php: -------------------------------------------------------------------------------- 1 | register_general_settings(); 35 | $this->register_hello_world(); 36 | } 37 | 38 | 39 | private function register_general_settings() { 40 | $key = $this->settings_key_general; 41 | $this->plugin_settings_tabs[ $key ] = esc_html__( 'General', 'extending-wp-rest-api' ); 42 | 43 | register_setting( $key, $key ); 44 | 45 | $section = 'general'; 46 | 47 | add_settings_section( $section, '', array( $this, 'section_header' ), $key ); 48 | 49 | add_settings_field( 'add-revision-count', esc_html__( 'Add Revision Count to Posts', 'extending-wp-rest-api' ), array( $this, 'settings_yes_no' ), $key, $section, 50 | array( 'key' => $key, 'name' => 'add-revision-count', ) ); 51 | 52 | add_settings_field( 'add-featured-image', esc_html__( 'Add Featured Image to Posts', 'extending-wp-rest-api' ), array( $this, 'settings_yes_no' ), $key, $section, 53 | array( 'key' => $key, 'name' => 'add-featured-image', ) ); 54 | 55 | add_settings_field( 'determine-current-user', esc_html__( 'Determine Current User Demo', 'extending-wp-rest-api' ), array( $this, 'settings_yes_no' ), $key, $section, 56 | array( 'key' => $key, 'name' => 'determine-current-user', ) ); 57 | 58 | add_settings_field( 'disallow-non-ssl', esc_html__( 'Disallow non-SSL', 'extending-wp-rest-api' ), array( $this, 'settings_yes_no' ), $key, $section, 59 | array( 'key' => $key, 'name' => 'disallow-non-ssl', ) ); 60 | 61 | add_settings_field( 'force-ssl-endpoint', esc_html__( 'Force SSL Endpoint in Link Header', 'extending-wp-rest-api' ), array( $this, 'settings_yes_no' ), $key, $section, 62 | array( 'key' => $key, 'name' => 'force-ssl-endpoint', ) ); 63 | 64 | add_settings_field( 'change-url-prefix', esc_html__( 'Change Endpoint Prefix (/awesome-api)', 'extending-wp-rest-api' ), array( $this, 'settings_yes_no' ), $key, $section, 65 | array( 'key' => $key, 'name' => 'change-url-prefix', ) ); 66 | 67 | add_settings_field( 'restrict-media-endpoint', esc_html__( 'Hide Media Endpoint from Non-authenticated users', 'extending-wp-rest-api' ), array( $this, 'settings_yes_no' ), $key, $section, 68 | array( 'key' => $key, 'name' => 'restrict-media-endpoint', ) ); 69 | 70 | add_settings_field( 'disable-media-endpoint', esc_html__( 'Disable Media Endpoint', 'extending-wp-rest-api' ), array( $this, 'settings_yes_no' ), $key, $section, 71 | array( 'key' => $key, 'name' => 'disable-media-endpoint', ) ); 72 | 73 | add_settings_field( 'remove-wordpess-core', esc_html__( 'Remove WordPress Core', 'extending-wp-rest-api' ), array( $this, 'settings_yes_no' ), $key, $section, 74 | array( 'key' => $key, 'name' => 'remove-wordpress-core', ) ); 75 | 76 | } 77 | 78 | private function register_hello_world() { 79 | $key = $this->settings_key_hello_world; 80 | $this->plugin_settings_tabs[ $key ] = esc_html__( 'Hello World', 'extending-wp-rest-api' ); 81 | 82 | register_setting( $key, $key ); 83 | 84 | $section = 'hello-world'; 85 | 86 | add_settings_section( $section, '', array( $this, 'section_header' ), $key ); 87 | 88 | } 89 | 90 | 91 | public function setting_is_enabled( $enabled, $key, $setting ) { 92 | return '1' === $this->setting_get( '0', $key, $setting ); 93 | } 94 | 95 | 96 | public function setting_get( $value, $key, $setting ) { 97 | 98 | $args = wp_parse_args( get_option( $key ), 99 | array( 100 | $setting => $value, 101 | ) 102 | ); 103 | 104 | return $args[$setting]; 105 | } 106 | 107 | 108 | public function settings_yes_no( $args ) { 109 | 110 | $args = wp_parse_args( $args, 111 | array( 112 | 'name' => '', 113 | 'key' => '', 114 | 'after' => '', 115 | ) 116 | ); 117 | 118 | $name = $args['name']; 119 | $key = $args['key']; 120 | 121 | $option = get_option( $key ); 122 | $value = isset( $option[$name] ) ? esc_attr( $option[$name] ) : ''; 123 | 124 | if ( empty( $value ) ) 125 | $value = '0'; 126 | 127 | $name = esc_attr( $name ); 128 | $key = esc_attr( $key ); 129 | 130 | echo '
'; 131 | echo " "; 132 | echo " "; 133 | echo '
'; 134 | 135 | if ( !empty( $args['after'] ) ) 136 | echo '
' . esc_html( $args['after'] ) . '
'; 137 | } 138 | 139 | 140 | public function admin_menu() { 141 | add_options_page( esc_html__( 'Extending REST API Settings', 'extending-wp-rest-api' ), esc_html__( 'Extending REST API', 'extending-wp-rest-api' ), 'manage_options', $this->settings_page, array( $this, 'options_page' ), 30 ); 142 | } 143 | 144 | 145 | public function options_page() { 146 | 147 | $tab = $this->current_tab(); ?> 148 |
149 | plugin_options_tabs(); ?> 150 |
151 | 152 | 153 | 154 |
155 |
156 | settings_key_general : $current_tab; 169 | } 170 | 171 | 172 | private function plugin_options_tabs() { 173 | $current_tab = $this->current_tab(); 174 | echo '

' . esc_html__( 'Extending WP REST API Settings', 'extending-wp-rest-api' ) . '

'; 188 | } 189 | 190 | 191 | public function section_header( $args ) { 192 | 193 | switch ( $args['id'] ) { 194 | case 'hello-world'; 195 | include_once 'admin-hello-world.php'; 196 | wp_enqueue_script( 'extending-wp-rest-api', plugin_dir_url( __FILE__ ) . '/admin-hello-world.js', 'jquery', time(), true ); 197 | 198 | // https://highlightjs.org/ 199 | wp_enqueue_script( 'extending-highlight-js', '//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/highlight.min.js' ); 200 | wp_enqueue_style( 'extending-highlight-js', '//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/styles/default.min.css' ); 201 | 202 | $data = array( 203 | 'endpoints' => array( 204 | 'hello_world' => rest_url( '/api-extend/v1/hello-world' ), 205 | ) 206 | ); 207 | 208 | wp_localize_script( 'extending-wp-rest-api', 'ExtendingRESTAPI', $data ); 209 | 210 | break; 211 | } 212 | } 213 | } 214 | } -------------------------------------------------------------------------------- /includes/class-extending-wp-rest-api-controller.php: -------------------------------------------------------------------------------- 1 | register_routes(); 12 | 13 | if ( extending_wp_rest_api_setting_enabled( 'add-revision-count' ) ) { 14 | $this->add_revision_count_to_posts(); 15 | } 16 | } 17 | 18 | 19 | public function plugins_loaded() { 20 | 21 | // enqueue WP_API_Settings script 22 | add_action( 'wp_print_scripts', function() { 23 | wp_enqueue_script( 'wp-api' ); 24 | } ); 25 | 26 | if ( extending_wp_rest_api_setting_enabled( 'add-featured-image' ) ) { 27 | add_filter( 'rest_prepare_post', array( $this, 'add_featured_image_link' ), 10, 3 ); 28 | } 29 | 30 | if ( extending_wp_rest_api_setting_enabled( 'disallow-non-ssl' ) ) { 31 | add_filter( 'rest_pre_dispatch', array( $this, 'disallow_non_ssl' ) ); 32 | } 33 | 34 | if ( extending_wp_rest_api_setting_enabled( 'disable-media-endpoint' ) ) { 35 | add_filter( 'rest_dispatch_request', array( $this, 'disable_media_endpoint' ), 10, 2 ); 36 | } 37 | 38 | if ( extending_wp_rest_api_setting_enabled( 'restrict-media-endpoint' ) ) { 39 | add_filter( 'rest_pre_dispatch', array( $this, 'restrict_media_endpoint' ), 10, 3 ); 40 | } 41 | 42 | if ( extending_wp_rest_api_setting_enabled( 'remove-wordpress-core' ) ) { 43 | add_filter( 'rest_endpoints', array( $this, 'remove_wordpress_core_endpoints' ), 10, 1 ); 44 | } 45 | 46 | if ( extending_wp_rest_api_setting_enabled( 'determine-current-user' ) ) { 47 | add_filter( 'determine_current_user', array( $this, 'determine_current_user' ), 50 ); 48 | } 49 | 50 | // You can ignore the extending_wp_rest_api_setting_enabled() 51 | // calls, it's just for the code demo. 52 | 53 | add_filter( 'rest_url_prefix', function( $endpoint ) { 54 | 55 | if ( extending_wp_rest_api_setting_enabled( 'change-url-prefix' ) ) { 56 | // if you're changing the endpoint, you'll also need to call flush_rewrite_rules 57 | // be sure to cache the custom endpoint and only flush the rules if it is changed 58 | $endpoint = 'awesome-api'; 59 | } 60 | 61 | if ( $endpoint !== get_option( 'extend_api_endpoint' ) ) { 62 | flush_rewrite_rules(); 63 | update_option( 'extend_api_endpoint', $endpoint ); 64 | } 65 | 66 | return $endpoint; 67 | } ); 68 | 69 | add_filter( 'rest_pre_serve_request', array( $this, 'multiformat_rest_pre_serve_request' ), 10, 4 ); 70 | 71 | 72 | if ( extending_wp_rest_api_setting_enabled( 'force-ssl-endpoint' ) ) { 73 | add_filter( 'rest_url', array( $this, 'force_https_rest_url'), 10, 4 ); 74 | } 75 | } 76 | 77 | 78 | 79 | public function register_routes() { 80 | 81 | $namespace = 'api-extend'; // base endpoint for our custom API 82 | 83 | // creating a new route for our hello world exaple 84 | register_rest_route( $namespace, '/v1/hello-world', array( 85 | 'methods' => WP_REST_Server::READABLE, 86 | 'callback' => array( $this, 'get_hello_world' ), 87 | 'args' => array( 88 | 'format' => array( 89 | 'sanitize_callback' => 'sanitize_key', 90 | ) 91 | ), 92 | ) ); 93 | 94 | // creating a new route editable route for our hello world exaple 95 | // the sanitize and validate callback functions are passed the value, the request, 96 | // and the name of the parameter ( $value, $request, $key ) 97 | register_rest_route( $namespace, '/v1/hello-world', array( 98 | 'methods' => WP_REST_Server::EDITABLE, 99 | 'callback' => array( $this, 'update_hello_world' ), 100 | 'permission_callback' => array( $this, 'update_hello_world_permission_check' ), 101 | 'args' => array( 102 | 'my_number' => array( 103 | 'required' => true, 104 | 'default' => 10, 105 | 'sanitize_callback' => 'absint', 106 | 'validate_callback' => array( $this, 'number_is_greater_than_10' ), 107 | ), 108 | ) 109 | ) ); 110 | 111 | 112 | // creating a new route for our hello world exaple 113 | // versioning example 114 | register_rest_route( $namespace, '/v2/hello-world', array( 115 | 'methods' => WP_REST_Server::READABLE, 116 | 'callback' => array( $this, 'get_hello_world_v2' ), 117 | 'args' => array( 118 | 'format' => array( 119 | 'required' => false, 120 | 'default' => 'json', 121 | 'sanitize_callback' => 'sanitize_key', 122 | ) 123 | ), 124 | ) ); 125 | 126 | 127 | // creating a new route editable route for our hello world exaple 128 | // the sanitize and validate callbacks are passed the value, the request, and the name of the parameter ( $value, $request, $key ) 129 | register_rest_route( $namespace, '/v1/hello-world', array( 130 | 'methods' => WP_REST_Server::DELETABLE, 131 | 'callback' => array( $this, 'delete_hello_world' ), 132 | 'permission_callback' => array( $this, 'update_hello_world_permission_check' ), 133 | ) ); 134 | 135 | 136 | // creating a new route for our custom authentication exaple 137 | register_rest_route( $namespace, '/whoami', array( 138 | 'methods' => array( WP_REST_Server::READABLE ), 139 | 'callback' => array( $this, 'get_whoami' ), 140 | ) ); 141 | 142 | 143 | // creating a new route for our custom authentication exaple 144 | register_rest_route( 'wp/v2', '/cron', array( 145 | 'methods' => array( WP_REST_Server::READABLE ), 146 | 'callback' => array( $this, 'get_crons' ), 147 | ) ); 148 | 149 | 150 | register_rest_route( $namespace, '/itsec-lockout', array( 151 | 'methods' => array( WP_REST_Server::READABLE ), 152 | 'callback' => array( $this, 'get_itsec_lockouts' ), 153 | ) ); 154 | 155 | register_rest_route( $namespace, '/itsec-lockout/(?P[\d]+)', array( 156 | 'methods' => array( WP_REST_Server::READABLE ), 157 | 'callback' => array( $this, 'get_itsec_lockouts' ), 158 | 'args' => array( 159 | 'id' => array( 160 | 'default' => 0, 161 | 'sanitize_callback' => 'absint', 162 | ), 163 | ), 164 | ) ); 165 | 166 | 167 | // sample for dynamically generating an image and returning it via the REST API 168 | register_rest_route( $namespace, '/billing-period-chart', array( 169 | 'methods' => array( WP_REST_Server::READABLE ), 170 | 'callback' => array( $this, 'get_chart' ), 171 | 'args' => array( 172 | 'start' => array( 173 | 'required' => true, 174 | 'sanitize_callback' => array( $this, 'to_date_time' ), 175 | ), 176 | 'end' => array( 177 | 'required' => true, 178 | 'sanitize_callback' => array( $this, 'to_date_time' ), 179 | ), 180 | 'current' => array( 181 | 'required' => true, 182 | 'sanitize_callback' => array( $this, 'to_date_time' ), 183 | ), 184 | ) 185 | ) ); 186 | 187 | register_rest_route( $namespace, '/remote-sizes', array( 188 | 'methods' => array( WP_REST_Server::READABLE ), 189 | 'callback' => array( $this, 'get_remote_sizes' ), 190 | ) 191 | ); 192 | 193 | } 194 | 195 | 196 | public function disallow_non_ssl( $response ) { 197 | 198 | if ( ! is_ssl() ) { 199 | $response = new WP_Error( 'rest_forbidden', __( "SSL is required to access the REST API." ), array( 'status' => 403 ) ); 200 | } 201 | 202 | return $response; 203 | } 204 | 205 | public function restrict_media_endpoint( $response, $server, $request ) { 206 | 207 | // See if this is the media endpoint and the user is logged in. 208 | if ( false !== stripos( $request->get_route(), '/wp/v2/media' ) && ! is_user_logged_in() ) { 209 | $response = new WP_Error( 210 | 'rest_forbidden', 211 | __( "Authentication is required to access the media endpoint." ), 212 | array( 'status' => 403 ) 213 | ); 214 | } 215 | 216 | return $response; 217 | } 218 | 219 | 220 | public function force_https_rest_url( $url, $path, $blog_id, $scheme ) { 221 | return set_url_scheme( $url, 'https' ); // force the Link header to be https 222 | } 223 | 224 | 225 | public function disable_media_endpoint( $response, $request ) { 226 | 227 | if ( false !== stripos( $request->get_route(), 'wp/v2/media' ) ) { 228 | $response = new WP_Error( 'rest_forbidden', __( "Sorry, the media endpoint is temporarily disabled." ), 229 | array( 'status' => 403 ) ); 230 | } 231 | 232 | return $response; 233 | } 234 | 235 | 236 | public function get_hello_world( WP_REST_Request $request ) { 237 | 238 | $response = new stdClass(); 239 | $response->hello = 'world'; 240 | $response->time = current_time( 'mysql' ); 241 | $response->my_number = absint( get_option( '_extending_my_number' ) ); 242 | 243 | $response->some_html = 'Hello World'; 244 | 245 | return rest_ensure_response( $response ); 246 | } 247 | 248 | 249 | public function get_hello_world_v2( WP_REST_Request $request ) { 250 | 251 | $response = new stdClass(); 252 | $response->hello = 'This is the new and improved endpoint!'; 253 | $response->my_number = absint( get_option( '_extending_my_number' ) ); 254 | 255 | return rest_ensure_response( $response ); 256 | } 257 | 258 | 259 | public function update_hello_world_permission_check( WP_REST_Request $request ) { 260 | $cap = 'manage_options'; 261 | if ( ! current_user_can( $cap ) ) { 262 | // can return false or a custom WP_Error 263 | return new WP_Error( 'rest_forbidden', 264 | sprintf( 'current user must have %s permissions', $cap ), array( 'status' => 403 ) ); 265 | } else { 266 | return true; 267 | } 268 | } 269 | 270 | 271 | public function number_is_greater_than_10( $value, $request, $key ) { 272 | if ( $value <= 10 ) { 273 | // can return false or a custom WP_Error 274 | return new WP_Error( 'rest_invalid_param', 275 | sprintf( '%s %d must be greater than 10', $key, $value ), array( 'status' => 400 ) ); 276 | } else { 277 | return true; 278 | } 279 | } 280 | 281 | 282 | public function update_hello_world( WP_REST_Request $request ) { 283 | 284 | // because permissions, sanitation, and validation have already been taken care of, 285 | // we can start working with our data right away 286 | 287 | // update our example with whatever was passed by the user 288 | update_option( '_extending_my_number', $request['my_number'] ); 289 | 290 | // return the updated object 291 | return $this->get_hello_world( $request ); 292 | 293 | } 294 | 295 | 296 | public function delete_hello_world( WP_REST_Request $request ) { 297 | 298 | delete_option( '_extending_my_number' ); 299 | 300 | // return the updated object 301 | return $this->get_hello_world( $request ); 302 | 303 | } 304 | 305 | 306 | public function add_revision_count_to_posts() { 307 | 308 | $schema = array( 309 | 'type' => 'integer', 310 | 'description' => 'number of revisions', 311 | 'context' => array( 'view' ), 312 | ); 313 | 314 | register_rest_field( 'post', 'number_of_revisions', array( 315 | 'schema' => $schema, 316 | 'get_callback' => array( $this, 'get_number_of_revisions' ), 317 | ) ); 318 | } 319 | 320 | 321 | public function get_number_of_revisions( $post ) { 322 | return absint( count( wp_get_post_revisions( $post->ID ) ) ); 323 | } 324 | 325 | 326 | public function add_featured_image_link( $result, $post, $request ) { 327 | 328 | if ( has_post_thumbnail( $post->ID ) ) { 329 | $featured_image = wp_get_attachment_image_src( get_post_thumbnail_id( $post->ID ), 'full' ); 330 | 331 | if ( is_array( $featured_image ) && ! empty( $featured_image ) ) { 332 | $result->add_link( 'featured_image', 333 | $featured_image[0], 334 | array( 335 | 'width' => absint( $featured_image[1] ), 336 | 'height' => absint( $featured_image[2] ) 337 | ) 338 | ); 339 | } 340 | } 341 | 342 | return $result; 343 | } 344 | 345 | 346 | public function get_whoami( WP_REST_Request $request ) { 347 | 348 | $response = new stdClass(); 349 | $response->current_user = null; 350 | 351 | // Runs the determine_current_user filter. 352 | $user = wp_get_current_user(); 353 | if ( ! empty( $user ) ) { 354 | $response->current_user = new stdClass(); 355 | $response->current_user->ID = $user->ID; 356 | $response->current_user->login = $user->user_login; 357 | $response->current_user->email = $user->user_email; 358 | $response->current_user->capabilities = $user->allcaps; 359 | } 360 | 361 | return rest_ensure_response( $response ); 362 | } 363 | 364 | 365 | public function determine_current_user( $user_id ) { 366 | 367 | $uri = filter_input( INPUT_SERVER, 'REQUEST_URI', FILTER_SANITIZE_STRING ); 368 | $api_key = filter_input( INPUT_GET, 'api-key', FILTER_SANITIZE_STRING ); 369 | $login = filter_input( INPUT_GET, 'login', FILTER_SANITIZE_STRING ); 370 | 371 | // Make sure this is only for our whoami demo. 372 | // Only for a specific API key. 373 | // Verify login was passed. 374 | if ( false !== stripos( $uri, '/api-extend/whoami' ) && 'helloworld' === $api_key && ! empty( $login ) ) { 375 | 376 | // this request is allowed to impersonate anyone 377 | $user = get_user_by( 'login', $login ); 378 | if ( ! empty( $user ) ) { 379 | $user_id = $user->ID; 380 | } 381 | } 382 | 383 | return $user_id; 384 | } 385 | 386 | 387 | public function get_crons( WP_REST_Request $request ) { 388 | $response = new stdClass(); 389 | $response->cron_jobs = _get_cron_array(); 390 | $response->schedules = wp_get_schedules(); 391 | return rest_ensure_response( $response ); 392 | } 393 | 394 | 395 | public function get_itsec_lockouts( WP_REST_Request $request ) { 396 | 397 | // itsec_lockouts 398 | global $wpdb; 399 | 400 | $sql = "select * from {$wpdb->prefix}itsec_lockouts where 1"; 401 | 402 | if ( ! empty( $request['id'] ) ) { 403 | $sql .= $wpdb->prepare( ' and lockout_id = %d' , $request['id'] ); 404 | } 405 | 406 | $response = new stdClass(); 407 | $response->lockouts = array(); 408 | 409 | $lockouts = $wpdb->get_results( $sql ); 410 | 411 | foreach ( $lockouts as $lockout ) { 412 | 413 | // add a link to the individual entry 414 | $lockout->_links = array( 'self' => array( 'href' => rest_url( '/api-extend/itsec-lockout/' . absint( $lockout->lockout_id ) ) ) ); 415 | $response->lockouts[] = $lockout; 416 | 417 | } 418 | 419 | return rest_ensure_response( $response ); 420 | 421 | } 422 | 423 | 424 | public function multiformat_rest_pre_serve_request( $served, $result, $request, $server ) { 425 | 426 | if ( in_array( $request->get_route(), array( '/api-extend/v1/hello-world', '/api-extend/v2/hello-world' ) ) ) { 427 | 428 | // this coud also be accomplished with an Accepts header 429 | switch ( $request['format'] ) { 430 | 431 | case 'text': 432 | // if you needed a CSV, this is where you'd do it 433 | header( 'Content-Type: text/plain; charset=' . get_option( 'blog_charset' ) ); 434 | echo $result->data->hello . ' '; 435 | echo $result->data->time . ' '; 436 | echo $result->data->my_number; 437 | $served = true; // tells the WP-API that we sent the response already 438 | break; 439 | 440 | case 'xml': // I guess if you really need to 441 | header( 'Content-Type: application/xml; charset=' . get_option( 'blog_charset' ) ); 442 | 443 | $xmlDoc = new DOMDocument(); 444 | $response = $xmlDoc->appendChild( $xmlDoc->createElement( 'Response' ) ); 445 | $response->appendChild( $xmlDoc->createElement( 'Hello', $result->data->hello ) ); 446 | $response->appendChild( $xmlDoc->createElement( 'Time', $result->data->time ) ); 447 | $response->appendChild( $xmlDoc->createElement( 'My_Number', $result->data->my_number ) ); 448 | 449 | echo $xmlDoc->saveXML(); 450 | $served = true; 451 | break; 452 | 453 | } 454 | 455 | } 456 | 457 | 458 | if ( '/api-extend/billing-period-chart' === $request->get_route() ) { 459 | 460 | // because we returned the image generator class to the API, we can access the 461 | // image it generated and return it to the browser 462 | header('Content-type: image/png'); 463 | imagepng($result->data->im); 464 | imagedestroy($result->data->im); 465 | 466 | $served = true; 467 | 468 | } 469 | 470 | 471 | return $served; 472 | } 473 | 474 | 475 | public function to_date_time( $value ) { 476 | return new DateTime( $value ); 477 | } 478 | 479 | 480 | public function get_chart( WP_REST_Request $request ) { 481 | 482 | // https://www.greenmountainenergy.com/api/?api-action=billing-period-chart&s=2014-11-13&e=2014-12-15&c=2014-11-25 483 | // http://local.baconipsum.dev/wp-json/api-extend/chart?start=2015-02-01&end=2015-04-25¤t=2015-03-09 484 | 485 | require_once 'class-pn-date-progress-chart.php'; 486 | 487 | $start = $request['start']; 488 | $end = $request['end']; 489 | $current = $request['current']; 490 | 491 | $dateChart = new pn_date_progress_chart(); 492 | $dateChart->init(); 493 | 494 | 495 | // vertical grey line to the left of the blue bar 496 | $dateChart->draw_line($dateChart->bar_start-1, 1, $dateChart->bar_start-1, $dateChart->bottom_line_y); 497 | 498 | // horizontal grey line to the bottom of the blue bar 499 | $dateChart->draw_line($dateChart->bar_start-1, $dateChart->bottom_line_y, $dateChart->bar_end, $dateChart->bottom_line_y); 500 | 501 | // start date tick 502 | $dateChart->draw_line($dateChart->bar_start-1, $dateChart->bottom_line_y, $dateChart->bar_start-1, $dateChart->bottom_line_y + $dateChart->tick_height); 503 | 504 | 505 | // end date tick 506 | $dateChart->draw_line($dateChart->bar_end, $dateChart->bottom_line_y, $dateChart->bar_end, $dateChart->bottom_line_y + $dateChart->tick_height); 507 | 508 | 509 | // draw start date 510 | $dateChart->draw_date($start, $dateChart->bar_start-1); 511 | 512 | // draw end date 513 | $dateChart->draw_date($end, $dateChart->bar_end); 514 | 515 | // figure out how far into the date range we are and draw a progress bar accordingly 516 | $total_days = date_diff($start, $end)->days; 517 | $days_into_range = date_diff($start, $current)->days; 518 | $percent_into_range = $days_into_range / $total_days; 519 | 520 | // draw ticks at 25%, 50%, 75% 521 | $percent_ticks_x = []; 522 | for ($i = .25; $i <= .75 ; $i += .25) 523 | $percent_ticks_x[] = $dateChart->bar_start + floor($dateChart->bar_max_width * $i); 524 | 525 | 526 | 527 | foreach ($percent_ticks_x as $p) 528 | $dateChart->draw_line($p, $dateChart->bottom_line_y, $p, $dateChart->bottom_line_y + $dateChart->tick_height); 529 | 530 | 531 | // create dates for 25%, 50% and 75% 532 | $percent_date = []; 533 | for ($i = .25; $i <= .75 ; $i += .25) { 534 | $percent_date[] = date_add(clone $start, new DateInterval('P' . floor($total_days * $i) . 'D')); 535 | } 536 | 537 | 538 | // draw dates at 25%, 50%, 75% 539 | for ($i=0; $i < 3; $i++) 540 | $dateChart->draw_date($percent_date[$i], $percent_ticks_x[$i]); 541 | 542 | $dateChart->draw_progress_bar($percent_into_range); 543 | 544 | return $dateChart; 545 | 546 | 547 | } 548 | 549 | 550 | /** 551 | * Unsets all core WP endpoints registered by the WordPress REST API (via rest_endpoints filter) 552 | * @param array $endpoints registered endpoints 553 | * @return array 554 | */ 555 | public function remove_wordpress_core_endpoints( $endpoints ) { 556 | 557 | foreach ( array_keys( $endpoints ) as $endpoint ) { 558 | if ( stripos( $endpoint, '/wp/v2' ) === 0 ) { 559 | unset( $endpoints[ $endpoint ] ); 560 | } 561 | } 562 | 563 | return $endpoints; 564 | } 565 | 566 | public function get_remote_sizes() { 567 | 568 | // a basic example of logging results from API requests to other servers 569 | 570 | $args = array( 571 | 'time' => current_time( 'mysql' ), 572 | 'ip_address' => filter_input( INPUT_SERVER, 'REMOTE_ADDR', FILTER_SANITIZE_STRING ), 573 | 'route' => '/wp-json/dashboard-directory-size/v1/sizes', 574 | 'source' => 'petenelson.io REST API', 575 | 'method' => 'GET', 576 | 'status' => 0, 577 | 'request' => array( 578 | 'body' => '', 579 | ), 580 | 'response' => array( 581 | 'body' => '', 582 | ), 583 | 'milliseconds' => 0, 584 | ); 585 | 586 | $remote_results = wp_remote_get( 'https://petenelson.io/wp-json/dashboard-directory-size/v1/sizes' ); 587 | 588 | $args['response']['headers'] = wp_remote_retrieve_headers( $remote_results ); 589 | $args['status'] = wp_remote_retrieve_response_code( $remote_results ); 590 | 591 | $data = json_decode( wp_remote_retrieve_body( $remote_results ) ); 592 | 593 | $args['response']['body'] = $data; 594 | 595 | do_action( 'wp-rest-api-log-insert', $args ); 596 | 597 | $data = wp_list_pluck( $data, 'path' ); 598 | 599 | return rest_ensure_response( $data ); 600 | 601 | } 602 | 603 | } 604 | 605 | 606 | } 607 | --------------------------------------------------------------------------------