Disable REST API - Version v1.6

Version Description

Download this release

Release Info

Developer dmchale
Plugin Icon 128x128 Disable REST API
Version v1.6
Comparing to
See all releases

Code changes from version v1.5.1 to v1.6

admin.php CHANGED
@@ -1,95 +1,48 @@
1
- <style>
2
- #DRA_container ul li {
3
- padding-left: 20px;
4
- }
5
-
6
- #DRA_container em {
7
- font-size: 0.8em;
8
- }
9
- </style>
10
-
11
- <script>
12
- function dra_namespace_click(namespace, id) {
13
- if (jQuery('#dra_namespace_' + id).is(":checked")) {
14
- jQuery("input[data-namespace='" + namespace + "']").prop('checked', true);
15
- } else {
16
- jQuery("input[data-namespace='" + namespace + "']").prop('checked', false);
17
- }
18
- };
19
- </script>
20
-
21
  <div class="wrap">
22
  <h1><?php echo esc_html__( "Disable REST API", "disable-json-api" ); ?></h1>
23
  <?php settings_errors( 'DRA-notices' ); ?>
 
24
  <p><?php echo esc_html__( "By default, this plugin ensures that the entire REST API is protected from non-authenticated users. You may use this page to specify which endpoints should be allowed to behave as normal.", "disable-json-api" ); ?></p>
25
  <p>
26
  <strong><?php echo esc_html__( "IMPORTANT NOTE:", "disable-json-api" ); ?></strong> <?php echo esc_html__( "Checking a box merely restores default functionality to an endpoint. Other authentication and/or permissions may still be required for access, or other themes/plugins may also affect access to those endpoints.", "disable-json-api" ); ?>
27
  </p>
28
 
29
- <form method="post" action="" id="DRA_form">
30
- <?php wp_nonce_field( 'DRA_admin_nonce' ); ?>
31
-
32
- <div id="DRA_container"><?php DRA_display_route_checkboxes(); ?></div>
33
-
34
- <?php submit_button(); ?>
35
- <input type="submit" name="reset"
36
- value="<?php echo esc_attr__( "Reset Whitelisted Routes", "disable-json-api" ); ?>"
37
- onclick="return confirm('<?php echo esc_attr__( "Are you sure you wish to clear all whitelisted routes?", "disable-json-api" ); ?>');">
38
- </form>
39
- </div>
40
-
41
- <?php
42
- /**
43
- * Loop through all routes returned by the REST API and display them on-screen
44
- *
45
- */
46
- function DRA_display_route_checkboxes() {
47
- $wp_rest_server = rest_get_server();
48
- $all_namespaces = $wp_rest_server->get_namespaces();
49
- $all_routes = array_keys( $wp_rest_server->get_routes() );
50
- $whitelisted_routes = is_array( get_option( 'DRA_route_whitelist' ) ) ? get_option( 'DRA_route_whitelist' ) : array();
51
-
52
- $loopCounter = 0;
53
- $current_namespace = '';
54
 
55
- foreach ( $all_routes as $route ) {
56
- $is_route_namespace = in_array( ltrim( $route, "/" ), $all_namespaces );
57
- $checkedProp = DRA_get_route_checked_prop( $route, $whitelisted_routes );
 
 
 
 
 
 
58
 
59
- if ( $is_route_namespace || "/" == $route ) {
60
- $current_namespace = $route;
61
- if ( 0 != $loopCounter ) {
62
- echo "</ul>";
63
- }
64
 
65
- $route_for_display = ( "/" == $route ) ? "/ <em>" . esc_html__( "REST API ROOT", "disable-json-api" ) . "</em>" : esc_html( $route );
66
- echo "<h2><label><input name='rest_routes[]' value='$route' type='checkbox' id='dra_namespace_$loopCounter' onclick='dra_namespace_click(\"$route\", $loopCounter)' $checkedProp>&nbsp;$route_for_display</label></h2><ul>";
 
67
 
68
- if ( "/" == $route ) {
69
- echo "<li>" . sprintf( esc_html__( "On this website, the REST API root is %s", "disable-json-api" ), "<strong>" . rest_url() . "</strong>" ) . "</li>";
70
- }
71
 
72
- } else {
73
- echo "<li><label><input name='rest_routes[]' value='$route' type='checkbox' data-namespace='$current_namespace' $checkedProp>&nbsp;" . esc_html( $route ) . "</label></li>";
74
- }
75
 
76
- $loopCounter ++;
77
- }
78
- echo "</ul>";
79
- }
80
 
 
 
 
 
 
 
81
 
82
- /**
83
- * During comparison, encode the route being requested in the same fashion that it's stored in the database option
84
- * Encoding during save happens in Disable_REST_API::maybe_process_settings_form()
85
- *
86
- * @param $route
87
- * @param $whitelisted_routes
88
- *
89
- * @return string
90
- */
91
- function DRA_get_route_checked_prop( $route, $whitelisted_routes ) {
92
- $is_route_checked = in_array( esc_html( $route ), $whitelisted_routes, true );
93
 
94
- return checked( $is_route_checked, true, false );
95
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  <div class="wrap">
2
  <h1><?php echo esc_html__( "Disable REST API", "disable-json-api" ); ?></h1>
3
  <?php settings_errors( 'DRA-notices' ); ?>
4
+
5
  <p><?php echo esc_html__( "By default, this plugin ensures that the entire REST API is protected from non-authenticated users. You may use this page to specify which endpoints should be allowed to behave as normal.", "disable-json-api" ); ?></p>
6
  <p>
7
  <strong><?php echo esc_html__( "IMPORTANT NOTE:", "disable-json-api" ); ?></strong> <?php echo esc_html__( "Checking a box merely restores default functionality to an endpoint. Other authentication and/or permissions may still be required for access, or other themes/plugins may also affect access to those endpoints.", "disable-json-api" ); ?>
8
  </p>
9
 
10
+ <hr />
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
11
 
12
+ <div id="select-container">
13
+ <?php echo esc_html__( "Rules for", "disable-json-api" ); ?>: <select name="role" id="dra-role">
14
+ <option value="none"><?php echo esc_html__( "Unauthenticated Users", "disable-json-api" ); ?></option>
15
+ <?php
16
+ $role = ( isset( $_GET['role'] ) ) ? $_GET['role'] : 'none';
17
+ wp_dropdown_roles( $role );
18
+ ?>
19
+ </select>
20
+ </div>
21
 
22
+ <hr />
 
 
 
 
23
 
24
+ <form method="post" action="" id="DRA_form">
25
+ <?php wp_nonce_field( 'DRA_admin_nonce' ); ?>
26
+ <input type="hidden" name="role" value="<?php echo esc_attr( $role ); ?>">
27
 
28
+ <div id="default-allow-container">
29
+ <?php DRA_Admin::display_role_default_allow( $role ); ?>
30
+ </div>
31
 
32
+ <hr />
 
 
33
 
34
+ <div id="route-container">
35
+ <?php DRA_Admin::display_route_checkboxes( $role ); ?>
36
+ <hr />
37
+ </div>
38
 
39
+ <div id="button-container">
40
+ <?php submit_button(); ?>
41
+ <input type="submit" name="reset" id="dra-reset-button"
42
+ value="<?php echo esc_attr__( "Reset Allowed List of Routes", "disable-json-api" ); ?>"
43
+ onclick="return confirm('<?php echo esc_attr__( "Are you sure you wish to reset all allowed routes for this user role?", "disable-json-api" ); ?>');">
44
+ </div>
45
 
46
+ </form>
 
 
 
 
 
 
 
 
 
 
47
 
48
+ </div>
 
classes/admin.php ADDED
@@ -0,0 +1,93 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class DRA_Admin {
3
+
4
+ /**
5
+ * Loop through all routes returned by the REST API and display them on-screen
6
+ *
7
+ * @param string $role
8
+ */
9
+ static function display_route_checkboxes( $role = 'none' ) {
10
+ $all_namespaces = DRA_Helpers::get_all_rest_namespaces();
11
+ $all_routes = DRA_Helpers::get_all_rest_routes();
12
+ $allowed_routes = DRA_Helpers::get_allowed_routes( $role );
13
+
14
+ $loopCounter = 0;
15
+ $current_namespace = '';
16
+
17
+ foreach ( $all_routes as $route ) {
18
+ $is_route_namespace = in_array( ltrim( $route, "/" ), $all_namespaces );
19
+ $checkedProp = self::get_route_checked_prop( $route, $allowed_routes );
20
+
21
+ if ( $is_route_namespace || "/" == $route ) {
22
+ $current_namespace = $route;
23
+ if ( 0 != $loopCounter ) {
24
+ echo "</ul>";
25
+ }
26
+
27
+ $route_for_display = ( "/" == $route ) ? "/ <em>" . esc_html__( "REST API ROOT", "disable-json-api" ) . "</em>" : esc_html( $route );
28
+ echo "<label class='switch'><input name='rest_routes[]' value='$route' type='checkbox' id='dra_namespace_$loopCounter' onclick='dra_namespace_click(\"$route\", $loopCounter)' $checkedProp><span class='slider'></span></label><h2><label for='dra_namespace_$loopCounter'>&nbsp;$route_for_display</label></h2><ul>";
29
+
30
+ if ( "/" == $route ) {
31
+ echo "<li>" . sprintf( esc_html__( "On this website, the REST API root is %s", "disable-json-api" ), "<strong>" . rest_url() . "</strong>" ) . "</li>";
32
+ }
33
+
34
+ } else {
35
+ echo "<li><label class='switch'><input name='rest_routes[]' id='dra_namespace_$loopCounter' value='$route' type='checkbox' data-namespace='$current_namespace' $checkedProp><span class='slider'></span></label><label for='dra_namespace_$loopCounter'>&nbsp;" . esc_html( $route ) . "</label></li>";
36
+ }
37
+
38
+ $loopCounter ++;
39
+ }
40
+ echo "</ul>";
41
+ }
42
+
43
+
44
+ /**
45
+ * During comparison, encode the route being requested in the same fashion that it's stored in the database option
46
+ * Encoding during save happens in Disable_REST_API::maybe_process_settings_form()
47
+ *
48
+ * @param $route
49
+ * @param $allowed_routes
50
+ *
51
+ * @return string
52
+ */
53
+ static function get_route_checked_prop( $route, $allowed_routes ) {
54
+ $is_route_checked = in_array( esc_html( $route ), array_map( 'esc_html', $allowed_routes ), true );
55
+
56
+ return checked( $is_route_checked, true, false );
57
+ }
58
+
59
+
60
+ /**
61
+ * Displays setting for default role on admin page
62
+ *
63
+ * @param $role
64
+ */
65
+ static function display_role_default_allow( $role ) {
66
+ $default_allow_true_checked = '';
67
+ $default_allow_false_checked = '';
68
+
69
+ $role_default_allow = DRA_Helpers::get_default_allow_for_role( $role );
70
+ if ( $role_default_allow ) {
71
+ $default_allow_true_checked = ' checked="checked"';
72
+ } else {
73
+ $default_allow_false_checked = ' checked="checked"';
74
+ }
75
+
76
+ /* translators: name of user role */
77
+ echo sprintf( '<h2>%s</h2>', sprintf( esc_html__( 'Manage Rules for %s Users', 'disable-json-api' ), DRA_Helpers::get_role_name( $role ) ) );
78
+ ?>
79
+ <p style="font-style:italic;">
80
+ <?php
81
+ echo esc_html__( 'NOTE: New routes may be added in the future by plugins, themes, or WordPress itself.', 'disable-json-api' );
82
+ echo '<br />';
83
+ 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' );
84
+ ?>
85
+ </p>
86
+ <label><input type="radio" name="default_allow" value="0" <?php echo $default_allow_false_checked; ?>>&nbsp;<?php echo esc_html__( 'Manage REST API Access', 'disable-json-api' ); ?></label>
87
+ &nbsp;&nbsp;&nbsp;
88
+ <label><input type="radio" name="default_allow" value="1" <?php echo $default_allow_true_checked; ?>>&nbsp;<?php echo esc_html__( 'Allow Full REST API Access', 'disable-json-api' ); ?></label>
89
+ <?php
90
+ }
91
+
92
+
93
+ }
classes/disable-rest-api.php CHANGED
@@ -1,5 +1,4 @@
1
  <?php
2
-
3
  /**
4
  * Disable_REST_API class
5
  *
@@ -9,6 +8,7 @@ class Disable_REST_API {
9
 
10
  const MENU_SLUG = 'disable_rest_api_settings';
11
  const CAPABILITY = 'manage_options';
 
12
 
13
  /**
14
  * Stores 'disable-json-api/disable-json-api.php' typically
@@ -28,21 +28,26 @@ class Disable_REST_API {
28
  // Set variable so the class knows how to reference the plugin
29
  $this->base_file_path = plugin_basename( $path );
30
 
 
 
 
 
31
  add_action( 'admin_menu', array( &$this, 'define_admin_link' ) );
32
 
33
- add_filter( 'rest_authentication_errors', array( &$this, 'whitelist_routes' ), 20 );
 
34
 
35
  }
36
 
37
 
38
  /**
39
- * Checks for a current route being requested, and processes the whitelist
40
  *
41
  * @param $access
42
  *
43
  * @return WP_Error|null|boolean
44
  */
45
- public function whitelist_routes( $access ) {
46
 
47
  // Return current value of $access and skip all plugin functionality
48
  if ( $this->allow_rest_api() ) {
@@ -51,10 +56,11 @@ class Disable_REST_API {
51
 
52
  $current_route = $this->get_current_route();
53
 
54
- if ( ! $this->is_whitelisted( $current_route ) ) {
55
  return $this->get_wp_error( $access );
56
  }
57
 
 
58
  return $access;
59
 
60
  }
@@ -75,29 +81,53 @@ class Disable_REST_API {
75
 
76
 
77
  /**
78
- * Checks a route for whether it belongs to the whitelist
79
  *
80
  * @param $currentRoute
81
  *
82
  * @return boolean
83
  */
84
- private function is_whitelisted( $currentRoute ) {
85
 
86
- return array_reduce( $this->get_route_whitelist_option(), function ( $isMatched, $pattern ) use ( $currentRoute ) {
87
- return $isMatched || (bool) preg_match( '@^' . htmlspecialchars_decode( $pattern ) . '$@i', $currentRoute );
88
- }, false );
89
 
90
- }
 
91
 
 
 
92
 
93
- /**
94
- * Get `DRA_route_whitelist` option array from database
95
- *
96
- * @return array
97
- */
98
- private function get_route_whitelist_option() {
 
 
 
 
 
 
 
 
 
99
 
100
- return (array) get_option( 'DRA_route_whitelist', array() );
 
 
 
 
 
 
 
 
 
 
 
 
 
101
 
102
  }
103
 
@@ -109,11 +139,15 @@ class Disable_REST_API {
109
  */
110
  public function define_admin_link() {
111
 
112
- add_options_page( esc_html__( 'Disable REST API Settings', 'disable-json-api' ), esc_html__( 'Disable REST API', 'disable-json-api' ), self::CAPABILITY, self::MENU_SLUG, array(
113
- &$this,
114
- 'settings_page'
115
- ) );
 
 
 
116
  add_filter( "plugin_action_links_$this->base_file_path", array( &$this, 'settings_link' ) );
 
117
 
118
  }
119
 
@@ -149,6 +183,18 @@ class Disable_REST_API {
149
 
150
  }
151
 
 
 
 
 
 
 
 
 
 
 
 
 
152
 
153
  /**
154
  * Process the admin page settings form submission
@@ -165,22 +211,46 @@ class Disable_REST_API {
165
  return;
166
  }
167
 
168
- // Catch the routes that should be whitelisted
169
- $rest_routes = ( isset( $_POST['rest_routes'] ) ) ?
170
- array_map( 'esc_html', wp_unslash( $_POST['rest_routes'] ) ) :
171
- null;
 
 
 
 
 
172
 
173
- // If resetting or whitelist is empty, clear the option and exit the function
 
 
 
 
 
 
174
  if ( empty( $rest_routes ) || isset( $_POST['reset'] ) ) {
175
- delete_option( 'DRA_route_whitelist' );
176
- add_settings_error( 'DRA-notices', esc_attr( 'settings_updated' ), esc_html__( 'All whitelists have been removed.', 'disable-json-api' ), 'updated' );
177
 
178
- return;
 
 
 
 
 
 
 
 
 
179
  }
180
 
181
- // Save whitelist to the Options table
182
- update_option( 'DRA_route_whitelist', $rest_routes );
183
- add_settings_error( 'DRA-notices', esc_attr( 'settings_updated' ), esc_html__( 'Whitelist settings saved.', 'disable-json-api' ), 'updated' );
 
 
 
 
 
 
184
 
185
  }
186
 
@@ -191,7 +261,7 @@ class Disable_REST_API {
191
  * @return bool
192
  */
193
  private function allow_rest_api() {
194
- return (bool) apply_filters( 'dra_allow_rest_api', is_user_logged_in() );
195
  }
196
 
197
 
@@ -215,4 +285,76 @@ class Disable_REST_API {
215
  return new WP_Error( 'rest_cannot_access', $error_message, array( 'status' => rest_authorization_required_code() ) );
216
  }
217
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
218
  }
1
  <?php
 
2
  /**
3
  * Disable_REST_API class
4
  *
8
 
9
  const MENU_SLUG = 'disable_rest_api_settings';
10
  const CAPABILITY = 'manage_options';
11
+ const VERSION = '1.6';
12
 
13
  /**
14
  * Stores 'disable-json-api/disable-json-api.php' typically
28
  // Set variable so the class knows how to reference the plugin
29
  $this->base_file_path = plugin_basename( $path );
30
 
31
+ // Do logic for upgrading to 1.6 from versions less than 1.6
32
+ add_action( 'init', 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() ) {
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
  }
81
 
82
 
83
  /**
84
+ * Checks a route for whether it belongs to the list of allowed routes
85
  *
86
  * @param $currentRoute
87
  *
88
  * @return boolean
89
  */
90
+ private function is_route_allowed( $currentRoute ) {
91
 
92
+ $current_options = get_option( 'disable_rest_api_options', array() );
93
+ $current_user_roles = $this->get_current_user_roles();
 
94
 
95
+ // Loop through user roles belonging to the current user
96
+ foreach ( $current_user_roles as $role ) {
97
 
98
+ // If we have a definition for the current user's role
99
+ if ( isset( $current_options['roles'][$role] ) ) {
100
 
101
+ // See if this route is specifically allowed
102
+ $is_currentRoute_allowed = array_reduce( DRA_Helpers::get_allowed_routes( $role ), function ( $isMatched, $pattern ) use ( $currentRoute ) {
103
+ return $isMatched || (bool) preg_match( '@^' . htmlspecialchars_decode( $pattern ) . '$@i', $currentRoute );
104
+ }, false );
105
+ if ( $is_currentRoute_allowed ) {
106
+ return true;
107
+ }
108
+
109
+ // See if this route is specifically disallowed
110
+ $is_currentRoute_disallowed = array_reduce( DRA_Helpers::get_allowed_routes( $role, false ), function ( $isMatched, $pattern ) use ( $currentRoute ) {
111
+ return $isMatched || (bool) preg_match( '@^' . htmlspecialchars_decode( $pattern ) . '$@i', $currentRoute );
112
+ }, false );
113
+ if ( $is_currentRoute_disallowed ) {
114
+ return false;
115
+ }
116
 
117
+ // If the route has no definition, see if the role is set to allow unknown routes by default
118
+ if ( true === $current_options['roles'][$role]['default_allow'] ) {
119
+ return true;
120
+ }
121
+
122
+ }
123
+
124
+ }
125
+
126
+ // 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.
127
+ // Most likely, we're here because the request is from a user role we don't have a definition for.
128
+ // Return the plugin-global setting for what should be done in the case of something we don't know what to do with.
129
+ // 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.
130
+ return $current_options['default_allow'];
131
 
132
  }
133
 
139
  */
140
  public function define_admin_link() {
141
 
142
+ add_options_page(
143
+ esc_html__( 'Disable REST API Settings', 'disable-json-api' ),
144
+ esc_html__( 'Disable REST API', 'disable-json-api' ),
145
+ self::CAPABILITY,
146
+ self::MENU_SLUG,
147
+ array( &$this, 'settings_page' )
148
+ );
149
  add_filter( "plugin_action_links_$this->base_file_path", array( &$this, 'settings_link' ) );
150
+ add_action( 'admin_enqueue_scripts', array( &$this, 'admin_enqueues' ) );
151
 
152
  }
153
 
183
 
184
  }
185
 
186
+ /**
187
+ * Enqueues for adding CSS and JavaScript to the admin settings page
188
+ */
189
+ public function admin_enqueues( $hook_suffix ) {
190
+ if ( $hook_suffix == 'settings_page_' . self::MENU_SLUG ) {
191
+ $enqueue_file_base = WP_PLUGIN_DIR . '/' . plugin_dir_path( $this->base_file_path );
192
+ wp_enqueue_style( 'dra-admin-css', plugins_url( 'css/admin.css', $this->base_file_path ), array(), filemtime( $enqueue_file_base . 'css/admin.css' ), 'all' );
193
+ wp_enqueue_script( 'dra-admin-header', plugins_url( 'js/admin-header.js', $this->base_file_path ), array( 'jquery' ), filemtime( $enqueue_file_base . 'js/admin-header.js' ), false );
194
+ wp_enqueue_script( 'dra-admin-footer', plugins_url( 'js/admin-footer.js', $this->base_file_path ), array( 'jquery' ), filemtime( $enqueue_file_base . 'js/admin-footer.js' ), true );
195
+ }
196
+ }
197
+
198
 
199
  /**
200
  * Process the admin page settings form submission
211
  return;
212
  }
213
 
214
+ // Confirm a valid role has been passed
215
+ $role = ( isset( $_POST['role'] ) ) ? $_POST['role'] : 'dra-undefined';
216
+ if ( ! DRA_Helpers::is_valid_role( $role ) ) {
217
+ 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' );
218
+ return;
219
+ }
220
+
221
+ // Catch the `default_allow` value for this role
222
+ $default_allow = ( isset( $_POST['default_allow'] ) && "1" == $_POST['default_allow'] ) ? true : false;
223
 
224
+ // Catch the routes that should be allowed
225
+ $rest_routes = ( isset( $_POST['rest_routes'] ) ) ? wp_unslash( $_POST['rest_routes'] ) : array();
226
+
227
+ // Retrieve all current rules for all roles
228
+ $arr_option = get_option( 'disable_rest_api_options' );
229
+
230
+ // If resetting or allowlist is empty, clear the option and exit the function
231
  if ( empty( $rest_routes ) || isset( $_POST['reset'] ) ) {
 
 
232
 
233
+ // Unauthorized users default to no routes allowed. All other user roles default to allowing all routes
234
+ $rest_routes_for_setting = DRA_Helpers::build_routes_rule_for_all( $default_allow );
235
+ $msg = esc_html__( 'All allowlists have been reset for this user role.', 'disable-json-api' );
236
+
237
+ } else {
238
+
239
+ // Get back the full list of true/false routes based on the posted routes allowed
240
+ $rest_routes_for_setting = DRA_Helpers::build_routes_rule( $rest_routes );
241
+ $msg = esc_html__( 'Allowlist settings saved for this user role.', 'disable-json-api' );
242
+
243
  }
244
 
245
+ // Save only the rules for this role back to itself
246
+ $arr_option['roles'][$role] = array(
247
+ 'default_allow' => $default_allow,
248
+ 'allow_list' => $rest_routes_for_setting,
249
+ );
250
+
251
+ // Save allowlist to the Options table and return with message for user
252
+ update_option( 'disable_rest_api_options', $arr_option );
253
+ add_settings_error( 'DRA-notices', esc_attr( 'settings_updated' ), $msg, 'updated' );
254
 
255
  }
256
 
261
  * @return bool
262
  */
263
  private function allow_rest_api() {
264
+ return (bool) apply_filters( 'dra_allow_rest_api', false );
265
  }
266
 
267
 
285
  return new WP_Error( 'rest_cannot_access', $error_message, array( 'status' => rest_authorization_required_code() ) );
286
  }
287
 
288
+
289
+ /**
290
+ * Helper function to migrate from pre-version-1.6 to the new option
291
+ */
292
+ public function option_check() {
293
+
294
+ // If our new option already exists, we can bail
295
+ if ( get_option( 'disable_rest_api_options') ) {
296
+ return;
297
+ }
298
+
299
+ // Make sure we have a default option defined
300
+ $this->create_settings_option();
301
+
302
+ }
303
+
304
+
305
+ /**
306
+ * Create settings option for the plugin
307
+ */
308
+ private function create_settings_option() {
309
+
310
+ // Define the basic structure of our new option
311
+ $arr_option = array(
312
+ 'version' => self::VERSION, // the current version of this plugin
313
+ 'default_allow' => true, // if a role is not specifically defined in the settings, should the default be to ALLOW the route or not?
314
+ 'roles' => array(), // array of the user roles in this install of wordpress
315
+ );
316
+
317
+ // Default list of allowed routes. By default, nothing is allowed because we're checking for our pre-v1.6 option here for migration purposes
318
+ $pre_1_6_allowed_routes = get_option( 'DRA_route_whitelist', array() );
319
+
320
+ // Decode the html encoding before passing to the function that builds the new routes. They'll get re-encoded later
321
+ $pre_1_6_allowed_routes = array_map( 'html_entity_decode', $pre_1_6_allowed_routes );
322
+
323
+ // Build the rules for this role based on the merge with the previously allowed rules (if any)
324
+ $new_unauthenticated_rules = DRA_Helpers::build_routes_rule( $pre_1_6_allowed_routes );
325
+
326
+ // Define the "unauthenticated" rules based on the old option value (or default value of "nothing")
327
+ $arr_option['roles']['none'] = array(
328
+ 'default_allow' => false,
329
+ 'allow_list' => $new_unauthenticated_rules,
330
+ );
331
+
332
+ // Save new option
333
+ update_option( 'disable_rest_api_options', $arr_option );
334
+
335
+ // delete the old option if applicable
336
+ if ( ! empty( $pre_1_6_allowed_routes ) ) {
337
+ delete_option( 'DRA_route_whitelist' );
338
+ }
339
+
340
+ }
341
+
342
+
343
+ /**
344
+ * Return array with list of roles the current user belongs to
345
+ *
346
+ * @return array
347
+ */
348
+ private function get_current_user_roles() {
349
+ if ( ! is_user_logged_in() ) {
350
+ return array(
351
+ 'name' => 'none',
352
+ );
353
+ }
354
+
355
+ $user = wp_get_current_user();
356
+ return ( array ) $user->roles;
357
+
358
+ }
359
+
360
  }
classes/helpers.php ADDED
@@ -0,0 +1,209 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class DRA_Helpers {
3
+
4
+ /**
5
+ * Make sure this is called after wp-settings.php is loaded, or the `rest_get_server()` will throw 500's
6
+ *
7
+ * @return array
8
+ */
9
+ static function get_all_rest_routes() {
10
+ $wp_rest_server = rest_get_server();
11
+ return array_keys( $wp_rest_server->get_routes() );
12
+ }
13
+
14
+
15
+ /**
16
+ * Make sure this is called after wp-settings.php is loaded, or the `rest_get_server()` will throw 500's
17
+ *
18
+ * @return string[]
19
+ */
20
+ static function get_all_rest_namespaces() {
21
+ $wp_rest_server = rest_get_server();
22
+ return $wp_rest_server->get_namespaces();
23
+ }
24
+
25
+
26
+ /**
27
+ * Make sure this is called after wp-settings.php is loaded, or the `self::get_all_rest_routes()` will throw 500's
28
+ *
29
+ * @param $allowed_routes
30
+ *
31
+ * @return array
32
+ */
33
+ static function build_routes_rule( $allowed_routes ) {
34
+
35
+ // The full list of all routes in the system
36
+ $all_routes = self::get_all_rest_routes();
37
+
38
+ // Initialize our new rules
39
+ $new_rules = array();
40
+
41
+ // 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
42
+ foreach ( $all_routes as $route ) {
43
+ $new_value = false;
44
+ if ( ! empty( $allowed_routes ) && in_array( $route, $allowed_routes ) ) {
45
+ $new_value = true;
46
+ }
47
+ $new_rules[esc_html($route)] = $new_value;
48
+ }
49
+
50
+ // Return full list of all known routes, with true/false values for whether they are allowed
51
+ return $new_rules;
52
+ }
53
+
54
+
55
+ /**
56
+ * Make sure this is called after wp-settings.php is loaded, or the `self::get_all_rest_routes()` will throw 500's
57
+ *
58
+ * @param bool $default_value
59
+ *
60
+ * @return array
61
+ */
62
+ static function build_routes_rule_for_all( $default_value = true ) {
63
+ // The full list of all routes in the system
64
+ $all_routes = self::get_all_rest_routes();
65
+
66
+ // Initialize our new rules
67
+ $new_rules = array();
68
+
69
+ // Loop through ALL routes, set all to the desired value
70
+ foreach ( $all_routes as $route ) {
71
+ $new_rules[esc_html($route)] = $default_value;
72
+ }
73
+
74
+ // Return full list of all known routes with values defined
75
+ return $new_rules;
76
+ }
77
+
78
+
79
+ /**
80
+ * Confirms if the passed value is either 'none' or another role defined in the system
81
+ *
82
+ * @param $role
83
+ *
84
+ * @return bool
85
+ */
86
+ static function is_valid_role( $role ) {
87
+
88
+ // If we requested 'none', we know it's okay
89
+ if ( 'none' == $role ) {
90
+ return true;
91
+ }
92
+
93
+ // Get all roles from the system. Loop through and see if one of them is the one we're asking about
94
+ $editable_roles = get_editable_roles();
95
+ foreach ( $editable_roles as $editable_role => $details ) {
96
+ if ( $role == $editable_role ) {
97
+ return true;
98
+ }
99
+ }
100
+
101
+ // If we got here, we're trying to ask for an invalid user role
102
+ return false;
103
+ }
104
+
105
+
106
+ /**
107
+ * Check the WP Option for our stored values of which routes should be allowed based on the supplied role
108
+ *
109
+ * @param $role
110
+ * @param bool $get_allowed
111
+ *
112
+ * @return array
113
+ */
114
+ static function get_allowed_routes( $role, $get_allowed = true ) {
115
+ $arr_option = get_option( 'disable_rest_api_options', array() );
116
+
117
+ // If we have an empty array, just return that
118
+ if ( empty( $arr_option ) ) {
119
+ return $arr_option;
120
+ }
121
+
122
+ $option_rules = array();
123
+ $allowed_rules = array();
124
+
125
+ if ( 'none' == $role && ! isset( $arr_option['roles']['none'] ) ) {
126
+
127
+ // This helps us bridge the gap from plugin version <=1.5.1 to >=1.6.
128
+ // 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
129
+ $option_rules = ( array ) DRA_Helpers::build_routes_rule( $arr_option );
130
+
131
+ } elseif ( isset( $arr_option['roles'][$role]['allow_list'] ) ) {
132
+
133
+ // If we have a definition for the currently requested role, return it
134
+ $option_rules = ( array ) $arr_option['roles'][$role]['allow_list'];
135
+
136
+ } else {
137
+
138
+ // 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
139
+ $option_rules = ( array ) DRA_Helpers::build_routes_rule_for_all( true );
140
+
141
+ }
142
+
143
+ // Loop through and only save the keys that have a value pairing of true
144
+ foreach ( $option_rules as $key => $value ) {
145
+ if ( $get_allowed === $value ) {
146
+ $allowed_rules[] = $key;
147
+ }
148
+ }
149
+
150
+ // Get rid of &lt; and &gt; before doing our comparisons
151
+ $allowed_rules = array_map( 'htmlspecialchars_decode', $allowed_rules );
152
+
153
+ // Return our array of allowed rules
154
+ return $allowed_rules;
155
+
156
+ }
157
+
158
+
159
+ /**
160
+ * Return the setting for what the default route behavior is for a specified role
161
+ *
162
+ * @param $role
163
+ *
164
+ * @return bool
165
+ */
166
+ static function get_default_allow_for_role( $role ) {
167
+ $arr_option = get_option( 'disable_rest_api_options', array() );
168
+
169
+ // If we have an empty array, return false so we deny access
170
+ if ( empty( $arr_option ) ) {
171
+ return false;
172
+ }
173
+
174
+ // Unauthorized users default to DONT ALLOW, authorized users default to DO ALLOW
175
+ $default_allow = ( 'none' == $role ) ? false : true;
176
+
177
+ if ( isset( $arr_option['roles'][$role]['default_allow'] ) ) {
178
+ $default_allow = $arr_option['roles'][$role]['default_allow'];
179
+ }
180
+
181
+ // Return our default rule
182
+ return ( bool ) $default_allow;
183
+
184
+ }
185
+
186
+
187
+ /**
188
+ * Returns the translated name of the role based on provided role slug
189
+ *
190
+ * @param $role
191
+ *
192
+ * @return string
193
+ */
194
+ static function get_role_name( $role ) {
195
+
196
+ if ( 'none' == $role ) {
197
+ return __( 'Unauthenticated', 'disable-json-api' );
198
+ }
199
+
200
+ $editable_roles = get_editable_roles();
201
+ if ( isset( $editable_roles[$role] ) ) {
202
+ return translate_user_role( $editable_roles[$role]['name'] );
203
+ }
204
+
205
+ return '';
206
+
207
+ }
208
+
209
+ }
classes/requirements-check.php CHANGED
@@ -6,7 +6,7 @@
6
  *
7
  */
8
 
9
- class Disable_REST_API_Requirements_Check {
10
  private $title = '';
11
  private $php = '5.2.4';
12
  private $wp = '3.8';
@@ -71,4 +71,4 @@ class Disable_REST_API_Requirements_Check {
71
  echo "<p>The &#8220;" . esc_html( $this->title ) . "&#8221; plugin cannot run on WordPress versions older than " . $this->wp . '. Please update WordPress.</p>';
72
  echo '</div>';
73
  }
74
- }
6
  *
7
  */
8
 
9
+ class DRA_Requirements_Check {
10
  private $title = '';
11
  private $php = '5.2.4';
12
  private $wp = '3.8';
71
  echo "<p>The &#8220;" . esc_html( $this->title ) . "&#8221; plugin cannot run on WordPress versions older than " . $this->wp . '. Please update WordPress.</p>';
72
  echo '</div>';
73
  }
74
+ }
css/admin.css ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ h2 { display: inline; }
2
+ #route-container ul li { padding-left: 20px; }
3
+ #route-container em { font-size: 0.8em; }
4
+ .switch { position: relative; display: inline-block; width: 38px; height: 20px; margin-right: 0.4em; }
5
+ .switch input { opacity: 0; width: 0; height: 0; }
6
+ .slider { position: absolute; cursor: pointer; top: 0; left: 0; right: 0; bottom: 0; background-color: #ccc; -webkit-transition: .4s; transition: .4s; border-radius: 18px; display:inline; }
7
+ .slider:before { position: absolute; content: ""; height: 14px; width: 14px; left: 4px; bottom: 3px; background-color: #fff; -webkit-transition: .4s; transition: .4s; border-radius: 50%; }
8
+ input:checked + .slider { background-color: #2196F3; }
9
+ input:focus + .slider { box-shadow: 0 0 1px #2196F3; }
10
+ input:checked + .slider:before { -webkit-transform: translateX(16px); -ms-transform: translateX(16px); transform: translateX(16px); }
11
+ div#select-container, div#default-allow-container, div#route-container { padding: 1em 0 1em 0; }
12
+ div#route-container { display: none; }
13
+ input#dra-reset-button { display: none; }
disable-json-api.php CHANGED
@@ -2,8 +2,8 @@
2
  /**
3
  * Plugin Name: Disable REST API
4
  * Plugin URI: http://www.binarytemplar.com/disable-json-api
5
- * Description: Disable the use of the REST API on your website to anonymous users
6
- * Version: 1.5.1
7
  * Author: Dave McHale
8
  * Author URI: http://www.binarytemplar.com
9
  * Text Domain: disable-json-api
@@ -25,7 +25,7 @@ function disable_rest_api_load_textdomain() {
25
  // Requirements check, to cleanly handle failure of WP/PHP version requirements
26
  include( dirname( __FILE__ ) . '/classes/requirements-check.php' );
27
 
28
- $dra_requirements_check = new Disable_REST_API_Requirements_Check( array(
29
  'title' => 'Disable REST API',
30
  'php' => '5.3',
31
  'wp' => '4.4',
@@ -43,8 +43,19 @@ if ( $dra_requirements_check->passes() ) {
43
  // WordPress 4.7+ disables the REST API via authentication short-circuit.
44
  // For versions of WordPress < 4.7, disable the REST API via filters
45
  if ( version_compare( get_bloginfo( 'version' ), '4.7', '>=' ) ) {
 
 
 
 
 
 
 
 
 
 
46
  require_once( plugin_dir_path( __FILE__ ) . 'classes/disable-rest-api.php' );
47
  new Disable_REST_API( __FILE__ );
 
48
  } else {
49
  require_once( plugin_dir_path( __FILE__ ) . 'functions/legacy.php' );
50
  DRA_Disable_Via_Filters();
2
  /**
3
  * Plugin Name: Disable REST API
4
  * Plugin URI: http://www.binarytemplar.com/disable-json-api
5
+ * Description: Disable the use of the REST API on your website to anonymous users. You can optionally enable select endpoints if you wish. Now with support for User Roles!
6
+ * Version: 1.6
7
  * Author: Dave McHale
8
  * Author URI: http://www.binarytemplar.com
9
  * Text Domain: disable-json-api
25
  // Requirements check, to cleanly handle failure of WP/PHP version requirements
26
  include( dirname( __FILE__ ) . '/classes/requirements-check.php' );
27
 
28
+ $dra_requirements_check = new DRA_Requirements_Check( array(
29
  'title' => 'Disable REST API',
30
  'php' => '5.3',
31
  'wp' => '4.4',
43
  // WordPress 4.7+ disables the REST API via authentication short-circuit.
44
  // For versions of WordPress < 4.7, disable the REST API via filters
45
  if ( version_compare( get_bloginfo( 'version' ), '4.7', '>=' ) ) {
46
+
47
+ // Load in extra classes
48
+ require_once( plugin_dir_path( __FILE__ ) . 'classes/helpers.php' );
49
+
50
+ // Only load admin classes if in admin area
51
+ if ( is_admin() ) {
52
+ require_once( plugin_dir_path( __FILE__ ) . 'classes/admin.php' );
53
+ }
54
+
55
+ // Load the primary Disable_REST_API class
56
  require_once( plugin_dir_path( __FILE__ ) . 'classes/disable-rest-api.php' );
57
  new Disable_REST_API( __FILE__ );
58
+
59
  } else {
60
  require_once( plugin_dir_path( __FILE__ ) . 'functions/legacy.php' );
61
  DRA_Disable_Via_Filters();
js/admin-footer.js ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ function maybe_show_dra_routes() {
2
+ let manage = jQuery('input[name=default_allow]:checked').val().toString();
3
+ if ( '0' === manage ) {
4
+ jQuery('div#route-container, input#dra-reset-button').css( 'display', 'block' );
5
+ } else {
6
+ jQuery('div#route-container, input#dra-reset-button').css( 'display', 'none' );
7
+ }
8
+ }
9
+
10
+ jQuery( function() {
11
+
12
+ maybe_show_dra_routes();
13
+
14
+ jQuery('select#dra-role').change( function() {
15
+ window.location.href = window.location.origin + window.location.pathname + '?page=disable_rest_api_settings&role=' + jQuery(this).val();
16
+ });
17
+
18
+ jQuery('input[name=default_allow]').change( function() {
19
+ maybe_show_dra_routes();
20
+ });
21
+
22
+ });
js/admin-header.js ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
1
+ function dra_namespace_click(namespace, id) {
2
+ if (jQuery('#dra_namespace_' + id).is(":checked")) {
3
+ jQuery("#route-container input[data-namespace='" + namespace + "']").prop('checked', true);
4
+ } else {
5
+ jQuery("#route-container input[data-namespace='" + namespace + "']").prop('checked', false);
6
+ }
7
+ }
readme.txt CHANGED
@@ -3,24 +3,24 @@ Contributors: dmchale, tangrufus
3
  Tags: admin, api, json, REST, rest-api, disable
4
  Requires at least: 4.4
5
  Requires PHP: 5.6
6
- Tested up to: 5.5
7
- Stable tag: 1.5.1
8
  License: GPLv2 or later
9
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
10
 
11
- Disable the use of the REST API on your website to unauthenticated users.
12
 
13
  == Description ==
14
 
15
  The most comprehensive plugin for controlling access to the WordPress REST API!
16
 
17
- Works as a "set it and forget it" install. Just upload and activate, and the entire REST API will be inaccessible to your site visitors. Or if you have a plugin or theme installed which needs some of its endpoints to be accessible to site visitors, you can do that too. Go to the Settings page and you can quickly whitelist individual endpoints - or entire branches of endpoints - registered with the REST API.
18
 
19
- The engine for the API has existed in WordPress since v4.4 and additional functionality and endpoints are a continual project. While this is very exciting news for many reasons, it is also not functionality that every site admin wants enabled on their website if not necessary.
20
 
21
- As of WordPress 4.7, the filters provided for disabling the REST API were removed. To compensate, this plugin will forcibly return an authentication error to any API requests from sources who are not logged into your website, which will effectively still prevent unauthorized requests from using the REST API to get information from your website.
22
 
23
- For WordPress versions 4.4, 4.5 and 4.6, this plugin makes use of the `rest_enabled` filter provided by the API to disable the API functionality. However, it is strongly recommended that all site owners run the most recent version of WordPress except where absolutely necessary.
24
 
25
  == Installation ==
26
 
@@ -34,18 +34,23 @@ For WordPress versions 4.4, 4.5 and 4.6, this plugin makes use of the `rest_enab
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 all REST API's installed? =
38
 
39
- This plugin is ONLY meant to disable endpoints accessible via the default REST API that is part of WordPress itself. If a plugin or theme chooses to register its namespace with the core REST API, its endpoints will - by default - by disabled so long as this plugin is active. Namespaces and routes may be whitelisted via this plugin's Settings page.
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.
46
 
47
  == Changelog ==
48
 
 
 
 
 
 
49
  = 1.5.1 =
50
  * Tested up to WP v5.5
51
 
@@ -88,6 +93,9 @@ This plugin is ONLY meant to disable endpoints accessible via the default REST A
88
 
89
  == Upgrade Notice ==
90
 
 
 
 
91
  = 1.4 =
92
  * Adds support to optionally whitelist individual routes of the REST API via Settings page.
93
 
3
  Tags: admin, api, json, REST, rest-api, disable
4
  Requires at least: 4.4
5
  Requires PHP: 5.6
6
+ Tested up to: 5.6
7
+ Stable tag: 1.6
8
  License: GPLv2 or later
9
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
10
 
11
+ Disable the use of the REST API on your website to site users. Now with User Role support!
12
 
13
  == Description ==
14
 
15
  The most comprehensive plugin for controlling access to the WordPress REST API!
16
 
17
+ Works as a "set it and forget it" install. Just upload and activate, and the entire REST API will be inaccessible to your general site visitors.
18
 
19
+ But if you do need to grant access to some endpoints, you can do that too. Go to the Settings page and you can quickly whitelist individual endpoints (or entire branches of endpoints) in the REST API.
20
 
21
+ You can even do this on a per-user-role basis, so your unauthenticated users have one set of rules while WooCommerce customers have another while Subscribers and Editors and Admins all have their own. NOTE: Out of the box, all defined user roles will still be granted full access to the REST API until you choose to manage those settings.
22
 
23
+ For most versions of WordPress, this plugin will return an authentication error if a user is not allowed to access an endpoint. For legacy support, WordPress 4.4, 4.5, and 4.6 use the provided `rest_enabled` filter to disable the entire REST API.
24
 
25
  == Installation ==
26
 
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.6 =
50
+ * Tested up to WP v5.6
51
+ * Added support for managing endpoint access on a per-user-role basis
52
+ * Soooooooo many small changes behind the scenes to support the above
53
+
54
  = 1.5.1 =
55
  * Tested up to WP v5.5
56
 
93
 
94
  == Upgrade Notice ==
95
 
96
+ = 1.6 =
97
+ * By popular request... now with User Role support!
98
+
99
  = 1.4 =
100
  * Adds support to optionally whitelist individual routes of the REST API via Settings page.
101
 
uninstall.php CHANGED
@@ -10,9 +10,4 @@ if ( ! defined( 'WP_UNINSTALL_PLUGIN' ) ) {
10
  die;
11
  }
12
 
13
- $option_name = 'DRA_route_whitelist';
14
-
15
- delete_option( $option_name );
16
-
17
- // for site options in Multisite
18
- delete_site_option( $option_name );
10
  die;
11
  }
12
 
13
+ delete_option( 'disable_rest_api_options' );