├── .gitignore ├── docs ├── _config.yml └── index.md ├── index.php ├── classes ├── index.php ├── requirements-check.php ├── admin.php ├── helpers.php └── disable-rest-api.php ├── languages └── index.php ├── uninstall.php ├── js ├── admin-header.js └── admin-footer.js ├── css └── admin.css ├── admin.php ├── disable-json-api.php ├── README.md └── readme.txt /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | \.idea/ 3 | -------------------------------------------------------------------------------- /docs/_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-dinky -------------------------------------------------------------------------------- /index.php: -------------------------------------------------------------------------------- 1 | { 3 | el.addEventListener( 'click', () => { 4 | el.style.display = new_display; 5 | }); 6 | }); 7 | } 8 | 9 | function dra_maybe_show_routes() { 10 | let manage = document.querySelector('input[name=default_allow]:checked').value.toString(); 11 | if ( '0' === manage ) { 12 | dra_set_route_display( 'block' ); 13 | } else { 14 | dra_set_route_display( 'none' ); 15 | } 16 | } 17 | 18 | document.addEventListener( 'DOMContentLoaded', () => { 19 | 20 | dra_maybe_show_routes(); 21 | 22 | document.getElementById('dra-role').addEventListener( 'change', function() { 23 | window.location.href = window.location.origin + window.location.pathname + '?page=disable_rest_api_settings&role=' + this.value; 24 | }); 25 | 26 | document.querySelectorAll('input[name=default_allow]').forEach( el => { 27 | el.addEventListener( 'change', () => { 28 | dra_maybe_show_routes(); 29 | }); 30 | }); 31 | 32 | }); 33 | -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | ## Welcome to GitHub Pages FRONT END MEETING 2 | 3 | You can use the [editor on GitHub](https://github.com/dmchale/disable-json-api/edit/master/docs/index.md) to maintain and preview the content for your website in Markdown files. 4 | 5 | Whenever you commit to this repository, GitHub Pages will run [Jekyll](https://jekyllrb.com/) to rebuild the pages in your site, from the content in your Markdown files. 6 | 7 | ### Markdown 8 | 9 | Markdown is a lightweight and easy-to-use syntax for styling your writing. It includes conventions for 10 | 11 | ```markdown 12 | Syntax highlighted code block 13 | 14 | # Header 1 15 | ## Header 2 16 | ### Header 3 17 | 18 | - Bulleted 19 | - List 20 | 21 | 1. Numbered 22 | 2. List 23 | 24 | **Bold** and _Italic_ and `Code` text 25 | 26 | [Link](url) and  27 | ``` 28 | 29 | For more details see [Basic writing and formatting syntax](https://docs.github.com/en/github/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax). 30 | 31 | ### Jekyll Themes 32 | 33 | Your Pages site will use the layout and styles from the Jekyll theme you have selected in your [repository settings](https://github.com/dmchale/disable-json-api/settings/pages). The name of this theme is saved in the Jekyll `_config.yml` configuration file. 34 | 35 | ### Support or Contact 36 | 37 | Having trouble with Pages? Check out our [documentation](https://docs.github.com/categories/github-pages-basics/) or [contact support](https://support.github.com/contact) and we’ll help you sort it out. 38 | -------------------------------------------------------------------------------- /admin.php: -------------------------------------------------------------------------------- 1 |
7 | 8 |
9 | 10 |The “" . esc_html( $this->title ) . "” plugin cannot run on PHP versions older than " . $this->php . '. Please contact your host and ask them to upgrade.
'; 55 | echo 'The “" . esc_html( $this->title ) . "” plugin cannot run on WordPress versions older than " . $this->wp . '. Please update WordPress.
'; 75 | echo '81 | '; 84 | echo esc_html__( 'If you choose to manage access for a user role, you will have to come back and add permissions for any new routes later.', 'disable-json-api' ); 85 | ?> 86 |
87 | 88 | 89 | 90 | Add New' page in your WordPress admin area 29 | 1. Activate the plugin through the 'Plugins' menu in WordPress 30 | 31 | == Frequently Asked Questions == 32 | 33 | = How do I know if this plugin is working? = 34 | 35 | While logged into WordPress as any user, the REST API will function as intended. Because of this, you must use a new browser - or Chrome's incognito mode - to test your website with a clean session. Go to yourdomain.com/wp-json/ (or yourdomain.com/?rest_route=/ if you have pretty permalinks disabled) while NOT LOGGED IN to test the results. You will see an authentication error returned if the plugin is active. "DRA: Only authenticated users can access the REST API." 36 | 37 | = Does this plugin disable every REST API that is installed on my site? = 38 | 39 | This plugin is ONLY meant to disable endpoints accessible via the core REST API that is part of WordPress itself. If a plugin or theme has implemented their own REST API (not to be confused with implementing their own endpoints within the WordPress API) this plugin will have no effect. 40 | 41 | == Screenshots == 42 | 43 | 1. The JSON returned by a website with the API disabled via filters (WP versions 4.4, 4.5, 4.6) 44 | 2. The JSON returned by a website with the API disabled via authentication methods (WP versions 4.7+) 45 | 3. The Settings page lets you selectively whitelist endpoints registered with the REST API, on a per-user-role basis. 46 | 47 | == Changelog == 48 | 49 | = 1.8 = 50 | * Tested up to WP v6.3 51 | * Added `dra_error_message` filter so devs can customize the access error message 52 | * Fixed bug that caused fatal errors if activating plugin on installations running the LearnPress plugin 53 | * Changed minimum requirements to PHP 5.6 (up from 5.3) and WordPress 4.9 (up from 4.4). Adding docblock comments to support minimums. 54 | 55 | = 1.7 = 56 | * Tested up to WP v5.8 57 | * Replace use of filemtime() with plugin version number for static file enqueues. Props @tangrufus for bringing this up! 58 | * Fixed logic bug for role-based default_allow rules. Props @msp1974 for the report! 59 | * Few small code-style updates 60 | 61 | = 1.6 = 62 | * Tested up to WP v5.6 63 | * Added support for managing endpoint access on a per-user-role basis 64 | * Soooooooo many small changes behind the scenes to support the above 65 | 66 | = 1.5.1 = 67 | * Tested up to WP v5.5 68 | 69 | = 1.5 = 70 | * Tested up to WP v5.3 71 | * Added enforcement for WordPress and PHP minimum version requirements 72 | * Fixed minor bug to prevent unintended empty routes 73 | * Minor text updates and adding textdomain to translation functions that didn't have them 74 | 75 | = 1.4.3 = 76 | * Added `load_plugin_textdomain()` for i18n 77 | 78 | = 1.4.2 = 79 | * Fixed issue causing unintentional unlocking of endpoints when another WP_Error existed before this plugin did its job 80 | 81 | = 1.4.1 = 82 | * Fixed echo of text URL to primary Plugins page in WP Dashboard 83 | 84 | = 1.4 = 85 | * Tested for WP v4.8 86 | * Tested for PHP 5.3+ 87 | * Added settings screen 88 | * Site Admins may now whitelist routes that they wish to allow unauthenticated access to 89 | * Added `dra_allow_rest_api` filter to the is_logged_in() check, so developers can get more granular with permissions 90 | * Props to @tangrufus for all of the help that went into this release 91 | 92 | = 1.3 = 93 | * Tested for WP v4.7 94 | * Adding new functionality to raise authentication errors in 4.7+ for non-logged-in users 95 | 96 | = 1.2 = 97 | * Tested for WP v4.5 98 | * Removal of actions which publish REST info to the head and header 99 | 100 | = 1.1 = 101 | * Updated to support the new filters created in the 2.0 beta API 102 | 103 | = 1.0 = 104 | * Initial Release 105 | 106 | == Upgrade Notice == 107 | 108 | = 1.8 = 109 | * Improved UI/UX of admin settings page to better manage routes 110 | 111 | = 1.6 = 112 | * By popular request... now with User Role support! 113 | 114 | = 1.4 = 115 | * Adds support to optionally whitelist individual routes of the REST API via Settings page. 116 | 117 | = 1.1 = 118 | * Now with support for the 2.0 beta API filters 119 | 120 | = 1.0 = 121 | * Initial Release 122 | -------------------------------------------------------------------------------- /classes/helpers.php: -------------------------------------------------------------------------------- 1 | get_routes() ); 14 | } 15 | 16 | 17 | /** 18 | * Make sure this is called after wp-settings.php is loaded, or the `rest_get_server()` will throw 500's 19 | * 20 | * @return string[] 21 | */ 22 | static function get_all_rest_namespaces() { 23 | $wp_rest_server = rest_get_server(); 24 | 25 | return $wp_rest_server->get_namespaces(); 26 | } 27 | 28 | 29 | /** 30 | * Make sure this is called after wp-settings.php is loaded, or the `self::get_all_rest_routes()` will throw 500's 31 | * 32 | * @param $allowed_routes 33 | * 34 | * @return array 35 | */ 36 | static function build_routes_rule( $allowed_routes ) { 37 | 38 | // The full list of all routes in the system 39 | $all_routes = self::get_all_rest_routes(); 40 | 41 | // Initialize our new rules 42 | $new_rules = array(); 43 | 44 | // Loop through ALL routes, find out if any exist in the previously-existing rules. If so, they SHOULD be allowed. Default for everyone is false 45 | foreach ( $all_routes as $route ) { 46 | $new_value = false; 47 | if ( ! empty( $allowed_routes ) && in_array( $route, $allowed_routes ) ) { 48 | $new_value = true; 49 | } 50 | $new_rules[ esc_html( $route ) ] = $new_value; 51 | } 52 | 53 | // Return full list of all known routes, with true/false values for whether they are allowed 54 | return $new_rules; 55 | } 56 | 57 | 58 | /** 59 | * Make sure this is called after wp-settings.php is loaded, or the `self::get_all_rest_routes()` will throw 500's 60 | * 61 | * @param bool $default_value 62 | * 63 | * @return array 64 | */ 65 | static function build_routes_rule_for_all( $default_value = true ) { 66 | // The full list of all routes in the system 67 | $all_routes = self::get_all_rest_routes(); 68 | 69 | // Initialize our new rules 70 | $new_rules = array(); 71 | 72 | // Loop through ALL routes, set all to the desired value 73 | foreach ( $all_routes as $route ) { 74 | $new_rules[ esc_html( $route ) ] = $default_value; 75 | } 76 | 77 | // Return full list of all known routes with values defined 78 | return $new_rules; 79 | } 80 | 81 | 82 | /** 83 | * Confirms if the passed value is either 'none' or another role defined in the system 84 | * 85 | * @param $role 86 | * 87 | * @return bool 88 | */ 89 | static function is_valid_role( $role ) { 90 | 91 | // If we requested 'none', we know it's okay 92 | if ( 'none' == $role ) { 93 | return true; 94 | } 95 | 96 | // Get all roles from the system. Loop through and see if one of them is the one we're asking about 97 | $editable_roles = get_editable_roles(); 98 | foreach ( $editable_roles as $editable_role => $details ) { 99 | if ( $role == $editable_role ) { 100 | return true; 101 | } 102 | } 103 | 104 | // If we got here, we're trying to ask for an invalid user role 105 | return false; 106 | } 107 | 108 | 109 | /** 110 | * Check the WP Option for our stored values of which routes should be allowed based on the supplied role 111 | * 112 | * @param $role 113 | * @param bool $get_allowed 114 | * 115 | * @return array 116 | */ 117 | static function get_allowed_routes( $role, $get_allowed = true ) { 118 | $arr_option = get_option( 'disable_rest_api_options', array() ); 119 | 120 | // If we have an empty array, just return that 121 | if ( empty( $arr_option ) ) { 122 | return $arr_option; 123 | } 124 | 125 | $option_rules = array(); 126 | $allowed_rules = array(); 127 | 128 | if ( 'none' == $role && ! isset( $arr_option['roles']['none'] ) ) { 129 | 130 | // This helps us bridge the gap from plugin version <=1.5.1 to >=1.6. 131 | // We didn't use to store results based on role, but we want to return the values for "unauthenticated users" if we have recently upgraded 132 | $option_rules = ( array ) DRA_Helpers::build_routes_rule( $arr_option ); 133 | 134 | } elseif ( isset( $arr_option['roles'][ $role ]['allow_list'] ) ) { 135 | 136 | // If we have a definition for the currently requested role, return it 137 | $option_rules = ( array ) $arr_option['roles'][ $role ]['allow_list']; 138 | 139 | } else { 140 | 141 | // If we failed all the way down to here, return a default array since we're asking for a role we don't have a definition for yet 142 | $option_rules = ( array ) DRA_Helpers::build_routes_rule_for_all( true ); 143 | 144 | } 145 | 146 | // Loop through and only save the keys that have a value pairing of true 147 | foreach ( $option_rules as $key => $value ) { 148 | if ( $get_allowed === $value ) { 149 | $allowed_rules[] = $key; 150 | } 151 | } 152 | 153 | // Get rid of < and > before doing our comparisons 154 | $allowed_rules = array_map( 'htmlspecialchars_decode', $allowed_rules ); 155 | 156 | // Return our array of allowed rules 157 | return $allowed_rules; 158 | 159 | } 160 | 161 | 162 | /** 163 | * Return the setting for what the default route behavior is for a specified role 164 | * 165 | * @param $role 166 | * 167 | * @return bool 168 | */ 169 | static function get_default_allow_for_role( $role ) { 170 | $arr_option = get_option( 'disable_rest_api_options', array() ); 171 | 172 | // If we have an empty array, return false so we deny access 173 | if ( empty( $arr_option ) ) { 174 | return false; 175 | } 176 | 177 | // Unauthorized users default to DONT ALLOW, authorized users default to DO ALLOW 178 | $default_allow = ( 'none' == $role ) ? false : true; 179 | 180 | if ( isset( $arr_option['roles'][ $role ]['default_allow'] ) ) { 181 | $default_allow = $arr_option['roles'][ $role ]['default_allow']; 182 | } 183 | 184 | // Return our default rule 185 | return ( bool ) $default_allow; 186 | 187 | } 188 | 189 | 190 | /** 191 | * Returns the translated name of the role based on provided role slug 192 | * 193 | * @param $role 194 | * 195 | * @return string 196 | */ 197 | static function get_role_name( $role ) { 198 | 199 | if ( 'none' == $role ) { 200 | return __( 'Unauthenticated', 'disable-json-api' ); 201 | } 202 | 203 | $editable_roles = get_editable_roles(); 204 | if ( isset( $editable_roles[ $role ] ) ) { 205 | return translate_user_role( $editable_roles[ $role ]['name'] ); 206 | } 207 | 208 | return ''; 209 | 210 | } 211 | 212 | } 213 | -------------------------------------------------------------------------------- /classes/disable-rest-api.php: -------------------------------------------------------------------------------- 1 | base_file_path = plugin_basename( $path ); 30 | 31 | // Do logic for upgrading to 1.6 from versions less than 1.6 32 | add_action( 'wp_loaded', array( &$this, 'option_check' ) ); 33 | 34 | // Set up admin page for plugin settings 35 | add_action( 'admin_menu', array( &$this, 'define_admin_link' ) ); 36 | 37 | // This actually does everything in this plugin 38 | add_filter( 'rest_authentication_errors', array( &$this, 'you_shall_not_pass' ), 20 ); 39 | 40 | } 41 | 42 | 43 | /** 44 | * Checks for a current route being requested, and processes the allowlist 45 | * 46 | * @param $access 47 | * 48 | * @return WP_Error|null|boolean 49 | */ 50 | public function you_shall_not_pass( $access ) { 51 | 52 | // Return current value of $access and skip all plugin functionality 53 | if ( $this->allow_rest_api() ) { 54 | return $access; 55 | } 56 | 57 | $current_route = $this->get_current_route(); 58 | 59 | if ( ! $this->is_route_allowed( $current_route ) ) { 60 | return $this->get_wp_error( $access ); 61 | } 62 | 63 | // If we got all the way here, return the unmodified $access response 64 | return $access; 65 | 66 | } 67 | 68 | 69 | /** 70 | * Current REST route getter. 71 | * 72 | * @return string 73 | */ 74 | private function get_current_route() { 75 | $rest_route = isset( $GLOBALS['wp']->query_vars['rest_route'] ) ? 76 | $GLOBALS['wp']->query_vars['rest_route'] : 77 | ''; 78 | 79 | return ( empty( $rest_route ) || '/' == $rest_route ) ? 80 | $rest_route : 81 | untrailingslashit( $rest_route ); 82 | } 83 | 84 | 85 | /** 86 | * Checks a route for whether it belongs to the list of allowed routes 87 | * 88 | * @param $currentRoute 89 | * 90 | * @return boolean 91 | */ 92 | private function is_route_allowed( $currentRoute ) { 93 | 94 | $current_options = get_option( 'disable_rest_api_options', array() ); 95 | $current_user_roles = $this->get_current_user_roles(); 96 | 97 | // Loop through user roles belonging to the current user 98 | foreach ( $current_user_roles as $role ) { 99 | 100 | // If we have a definition for the current user's role 101 | if ( isset( $current_options['roles'][ $role ] ) ) { 102 | 103 | // If any role for this user is set to Allow Full REST API Access, return true automatically 104 | if ( true === $current_options['roles'][ $role ]['default_allow'] ) { 105 | return true; 106 | } 107 | 108 | // See if this route is specifically allowed 109 | $is_currentRoute_allowed = array_reduce( DRA_Helpers::get_allowed_routes( $role ), function ( $isMatched, $pattern ) use ( $currentRoute ) { 110 | return $isMatched || (bool) preg_match( '@^' . htmlspecialchars_decode( $pattern ) . '$@i', $currentRoute ); 111 | }, false ); 112 | if ( $is_currentRoute_allowed ) { 113 | return true; 114 | } 115 | 116 | // See if this route is specifically disallowed 117 | $is_currentRoute_disallowed = array_reduce( DRA_Helpers::get_allowed_routes( $role, false ), function ( $isMatched, $pattern ) use ( $currentRoute ) { 118 | return $isMatched || (bool) preg_match( '@^' . htmlspecialchars_decode( $pattern ) . '$@i', $currentRoute ); 119 | }, false ); 120 | if ( $is_currentRoute_disallowed ) { 121 | return false; 122 | } 123 | 124 | } 125 | 126 | } 127 | 128 | // If we got all the way here, we didn't find any rules that matched the route and none of the user roles had a "default unknowns to true" rule. 129 | // Most likely, we're here because the request is from a user role we don't have a definition for. 130 | // Return the plugin-global setting for what should be done in the case of something we don't know what to do with. 131 | // As of this writing in v1.6, this is "allow" by default since we want new User Roles to be ALLOWED access to everything until an admin chooses to take that right away. 132 | return $current_options['default_allow']; 133 | 134 | } 135 | 136 | 137 | /** 138 | * Add a menu 139 | * 140 | * @return void 141 | */ 142 | public function define_admin_link() { 143 | 144 | add_options_page( 145 | esc_html__( 'Disable REST API Settings', 'disable-json-api' ), 146 | esc_html__( 'Disable REST API', 'disable-json-api' ), 147 | self::CAPABILITY, 148 | self::MENU_SLUG, 149 | array( &$this, 'settings_page' ) 150 | ); 151 | add_filter( "plugin_action_links_$this->base_file_path", array( &$this, 'settings_link' ) ); 152 | add_action( 'admin_enqueue_scripts', array( &$this, 'admin_enqueues' ) ); 153 | 154 | } 155 | 156 | 157 | /** 158 | * Add Settings Link to plugins page 159 | * 160 | * @param $links 161 | * 162 | * @return array 163 | */ 164 | public function settings_link( $links ) { 165 | 166 | $settings_url = menu_page_url( self::MENU_SLUG, false ); 167 | $settings_link = "" . esc_html__( "Settings", "disable-json-api" ) . ""; 168 | array_unshift( $links, $settings_link ); 169 | 170 | return $links; 171 | } 172 | 173 | 174 | /** 175 | * Menu Callback 176 | * 177 | * @return void 178 | */ 179 | public function settings_page() { 180 | 181 | $this->maybe_process_settings_form(); 182 | 183 | // Render the settings template 184 | include( __DIR__ . "/../admin.php" ); 185 | 186 | } 187 | 188 | /** 189 | * Enqueues for adding CSS and JavaScript to the admin settings page 190 | */ 191 | public function admin_enqueues( $hook_suffix ) { 192 | if ( $hook_suffix == 'settings_page_' . self::MENU_SLUG ) { 193 | wp_enqueue_style( 'dra-admin-css', plugins_url( 'css/admin.css', $this->base_file_path ), array(), DISABLE_REST_API_PLUGIN_VER, 'all' ); 194 | wp_enqueue_script( 'dra-admin-header', plugins_url( 'js/admin-header.js', $this->base_file_path ), array( 'jquery' ), DISABLE_REST_API_PLUGIN_VER, false ); 195 | wp_enqueue_script( 'dra-admin-footer', plugins_url( 'js/admin-footer.js', $this->base_file_path ), array( 'jquery' ), DISABLE_REST_API_PLUGIN_VER, true ); 196 | } 197 | } 198 | 199 | 200 | /** 201 | * Process the admin page settings form submission 202 | * 203 | * @return void 204 | */ 205 | private function maybe_process_settings_form() { 206 | 207 | if ( ! ( isset( $_POST['_wpnonce'] ) && check_admin_referer( 'DRA_admin_nonce' ) ) ) { 208 | return; 209 | } 210 | 211 | if ( ! current_user_can( self::CAPABILITY ) ) { 212 | return; 213 | } 214 | 215 | // Confirm a valid role has been passed 216 | $role = ( isset( $_POST['role'] ) ) ? $_POST['role'] : 'dra-undefined'; 217 | if ( ! DRA_Helpers::is_valid_role( $role ) ) { 218 | add_settings_error( 'DRA-notices', esc_attr( 'settings_updated' ), esc_html__( 'Invalid user role detected when processing form. No updates have been made.', 'disable-json-api' ), 'error' ); 219 | 220 | return; 221 | } 222 | 223 | // Catch the `default_allow` value for this role 224 | $default_allow = ( isset( $_POST['default_allow'] ) && "1" == $_POST['default_allow'] ) ? true : false; 225 | 226 | // Catch the routes that should be allowed 227 | $rest_routes = ( isset( $_POST['rest_routes'] ) ) ? wp_unslash( $_POST['rest_routes'] ) : array(); 228 | 229 | // Retrieve all current rules for all roles 230 | $arr_option = get_option( 'disable_rest_api_options' ); 231 | 232 | // If resetting or allowlist is empty, clear the option and exit the function 233 | if ( empty( $rest_routes ) || isset( $_POST['reset'] ) ) { 234 | 235 | // Unauthorized users default to no routes allowed. All other user roles default to allowing all routes 236 | $rest_routes_for_setting = DRA_Helpers::build_routes_rule_for_all( $default_allow ); 237 | $msg = esc_html__( 'All allowlists have been reset for this user role.', 'disable-json-api' ); 238 | 239 | } else { 240 | 241 | // Get back the full list of true/false routes based on the posted routes allowed 242 | $rest_routes_for_setting = DRA_Helpers::build_routes_rule( $rest_routes ); 243 | $msg = esc_html__( 'Allowlist settings saved for this user role.', 'disable-json-api' ); 244 | 245 | } 246 | 247 | // Save only the rules for this role back to itself 248 | $arr_option['roles'][ $role ] = array( 249 | 'default_allow' => $default_allow, 250 | 'allow_list' => $rest_routes_for_setting, 251 | ); 252 | 253 | // Save allowlist to the Options table and return with message for user 254 | update_option( 'disable_rest_api_options', $arr_option ); 255 | add_settings_error( 'DRA-notices', esc_attr( 'settings_updated' ), $msg, 'updated' ); 256 | 257 | } 258 | 259 | 260 | /** 261 | * Allow carte blanche access for logged-in users (or allow override via filter) 262 | * 263 | * @return bool 264 | */ 265 | private function allow_rest_api() { 266 | return (bool) apply_filters( 'dra_allow_rest_api', false ); 267 | } 268 | 269 | 270 | /** 271 | * If $access is already a WP_Error object, add our error to the list 272 | * Otherwise return a new one 273 | * 274 | * @param $access 275 | * 276 | * @return WP_Error 277 | */ 278 | private function get_wp_error( $access ) { 279 | $dra_error_message = apply_filters( 'dra_error_message', 'DRA: Only authenticated users can access the REST API.', $access ); 280 | $error_message = esc_html__( $dra_error_message, 'disable-json-api' ); 281 | 282 | if ( is_wp_error( $access ) ) { 283 | $access->add( 'rest_cannot_access', $error_message, array( 'status' => rest_authorization_required_code() ) ); 284 | 285 | return $access; 286 | } 287 | 288 | return new WP_Error( 'rest_cannot_access', $error_message, array( 'status' => rest_authorization_required_code() ) ); 289 | } 290 | 291 | 292 | /** 293 | * Helper function to migrate from pre-version-1.6 to the new option 294 | */ 295 | public function option_check() { 296 | 297 | // If our new option already exists, we can bail 298 | if ( get_option( 'disable_rest_api_options' ) ) { 299 | return; 300 | } 301 | 302 | // Make sure we have a default option defined 303 | $this->create_settings_option(); 304 | 305 | } 306 | 307 | 308 | /** 309 | * Create settings option for the plugin 310 | */ 311 | private function create_settings_option() { 312 | 313 | // Define the basic structure of our new option 314 | $arr_option = array( 315 | 'version' => DISABLE_REST_API_PLUGIN_VER, // the current version of this plugin 316 | 'default_allow' => true, // if a role is not specifically defined in the settings, should the default be to ALLOW the route or not? 317 | 'roles' => array(), // array of the user roles in this install of wordpress 318 | ); 319 | 320 | // Default list of allowed routes. By default, nothing is allowed because we're checking for our pre-v1.6 option here for migration purposes 321 | $pre_1_6_allowed_routes = get_option( 'DRA_route_whitelist', array() ); 322 | 323 | // Decode the html encoding before passing to the function that builds the new routes. They'll get re-encoded later 324 | $pre_1_6_allowed_routes = array_map( 'html_entity_decode', $pre_1_6_allowed_routes ); 325 | 326 | // Build the rules for this role based on the merge with the previously allowed rules (if any) 327 | $new_unauthenticated_rules = DRA_Helpers::build_routes_rule( $pre_1_6_allowed_routes ); 328 | 329 | // Define the "unauthenticated" rules based on the old option value (or default value of "nothing") 330 | $arr_option['roles']['none'] = array( 331 | 'default_allow' => false, 332 | 'allow_list' => $new_unauthenticated_rules, 333 | ); 334 | 335 | // Save new option 336 | update_option( 'disable_rest_api_options', $arr_option ); 337 | 338 | // delete the old option if applicable 339 | if ( ! empty( $pre_1_6_allowed_routes ) ) { 340 | delete_option( 'DRA_route_whitelist' ); 341 | } 342 | 343 | } 344 | 345 | 346 | /** 347 | * Return array with list of roles the current user belongs to 348 | * 349 | * @return array 350 | */ 351 | private function get_current_user_roles() { 352 | if ( ! is_user_logged_in() ) { 353 | return array( 354 | 'name' => 'none', 355 | ); 356 | } 357 | 358 | $user = wp_get_current_user(); 359 | 360 | return ( array ) $user->roles; 361 | 362 | } 363 | 364 | } 365 | --------------------------------------------------------------------------------