WebDevStudios /
CMB2
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
| 1 | <?php |
||
| 2 | /** |
||
| 3 | * CMB2 objects/fields endpoint for WordPres REST API. |
||
| 4 | * Allows access to fields registered to a specific box. |
||
| 5 | * |
||
| 6 | * @todo Add better documentation. |
||
| 7 | * @todo Research proper schema. |
||
| 8 | * |
||
| 9 | * @since 2.2.4 |
||
| 10 | * |
||
| 11 | * @category WordPress_Plugin |
||
| 12 | * @package CMB2 |
||
| 13 | * @author WebDevStudios |
||
| 14 | * @license GPL-2.0+ |
||
| 15 | * @link http://webdevstudios.com |
||
| 16 | */ |
||
| 17 | class CMB2_REST_Controller_Fields extends CMB2_REST_Controller_Boxes { |
||
|
0 ignored issues
–
show
|
|||
| 18 | |||
| 19 | /** |
||
| 20 | * Register the routes for the objects of the controller. |
||
| 21 | * |
||
| 22 | * @since 2.2.4 |
||
| 23 | */ |
||
| 24 | public function register_routes() { |
||
| 25 | |||
| 26 | // Returns specific box's fields. |
||
| 27 | register_rest_route( $this->namespace, '/' . $this->rest_base . '/(?P<cmb_id>[\w-]+)/fields/', array( |
||
| 28 | array( |
||
| 29 | 'methods' => WP_REST_Server::READABLE, |
||
| 30 | 'callback' => array( $this, 'get_items' ), |
||
| 31 | 'permission_callback' => array( $this, 'get_items_permissions_check' ), |
||
| 32 | ), |
||
| 33 | 'schema' => array( $this, 'get_item_schema' ), |
||
| 34 | ) ); |
||
| 35 | |||
| 36 | // Returns specific field data. |
||
| 37 | register_rest_route( $this->namespace, '/' . $this->rest_base . '/(?P<cmb_id>[\w-]+)/fields/(?P<field_id>[\w-]+)', array( |
||
| 38 | array( |
||
| 39 | 'methods' => WP_REST_Server::READABLE, |
||
| 40 | 'callback' => array( $this, 'get_item' ), |
||
| 41 | 'permission_callback' => array( $this, 'get_item_permissions_check' ), |
||
| 42 | ), |
||
| 43 | array( |
||
| 44 | 'methods' => WP_REST_Server::EDITABLE, |
||
| 45 | 'callback' => array( $this, 'update_field_value' ), |
||
| 46 | 'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ), |
||
| 47 | 'permission_callback' => array( $this, 'update_field_value_permissions_check' ), |
||
| 48 | ), |
||
| 49 | array( |
||
| 50 | 'methods' => WP_REST_Server::DELETABLE, |
||
| 51 | 'callback' => array( $this, 'delete_field_value' ), |
||
| 52 | 'permission_callback' => array( $this, 'delete_field_value_permissions_check' ), |
||
| 53 | ), |
||
| 54 | 'schema' => array( $this, 'get_item_schema' ), |
||
| 55 | ) ); |
||
| 56 | } |
||
| 57 | |||
| 58 | /** |
||
| 59 | * Get all public CMB2 box fields. |
||
| 60 | * |
||
| 61 | * @since 2.2.4 |
||
| 62 | * |
||
| 63 | * @param WP_REST_Request $request Full data about the request. |
||
| 64 | * @return WP_Error|WP_REST_Response |
||
| 65 | */ |
||
| 66 | public function get_items( $request ) { |
||
| 67 | $this->initiate_rest_read_box( $request, 'fields_read' ); |
||
| 68 | |||
| 69 | if ( is_wp_error( $this->rest_box ) ) { |
||
| 70 | return $this->prepare_item( array( 'error' => $this->rest_box->get_error_message() ) ); |
||
|
0 ignored issues
–
show
The method
get_error_message() does not seem to exist on object<CMB2_REST>.
This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces. This is most likely a typographical error or the method has been renamed. Loading history...
|
|||
| 71 | } |
||
| 72 | |||
| 73 | $fields = array(); |
||
| 74 | foreach ( $this->rest_box->cmb->prop( 'fields', array() ) as $field ) { |
||
| 75 | $field_id = $field['id']; |
||
| 76 | $rest_field = $this->get_rest_field( $field_id ); |
||
| 77 | |||
| 78 | if ( ! is_wp_error( $rest_field ) ) { |
||
| 79 | $fields[ $field_id ] = $this->server->response_to_data( $rest_field, isset( $this->request['_embed'] ) ); |
||
| 80 | } else { |
||
| 81 | $fields[ $field_id ] = array( 'error' => $rest_field->get_error_message() ); |
||
| 82 | } |
||
| 83 | } |
||
| 84 | |||
| 85 | return $this->prepare_item( $fields ); |
||
| 86 | } |
||
| 87 | |||
| 88 | /** |
||
| 89 | * Get one CMB2 field from the collection. |
||
| 90 | * |
||
| 91 | * @since 2.2.4 |
||
| 92 | * |
||
| 93 | * @param WP_REST_Request $request Full data about the request. |
||
| 94 | * @return WP_Error|WP_REST_Response |
||
| 95 | */ |
||
| 96 | public function get_item( $request ) { |
||
| 97 | $this->initiate_rest_read_box( $request, 'field_read' ); |
||
| 98 | |||
| 99 | if ( is_wp_error( $this->rest_box ) ) { |
||
| 100 | return $this->prepare_item( array( 'error' => $this->rest_box->get_error_message() ) ); |
||
|
0 ignored issues
–
show
The method
get_error_message() does not seem to exist on object<CMB2_REST>.
This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces. This is most likely a typographical error or the method has been renamed. Loading history...
|
|||
| 101 | } |
||
| 102 | |||
| 103 | $field = $this->get_rest_field( $this->request->get_param( 'field_id' ) ); |
||
| 104 | |||
| 105 | if ( is_wp_error( $field ) ) { |
||
| 106 | return $this->prepare_item( array( 'error' => $field->get_error_message() ) ); |
||
| 107 | } |
||
| 108 | |||
| 109 | return $this->prepare_item( $field ); |
||
| 110 | } |
||
| 111 | |||
| 112 | /** |
||
| 113 | * Update CMB2 field value. |
||
| 114 | * |
||
| 115 | * @since 2.2.4 |
||
| 116 | * |
||
| 117 | * @param WP_REST_Request $request Full data about the request. |
||
| 118 | * @return WP_Error|WP_REST_Response |
||
| 119 | */ |
||
| 120 | public function update_field_value( $request ) { |
||
| 121 | $this->initiate_rest_read_box( $request, 'field_value_update' ); |
||
| 122 | |||
| 123 | View Code Duplication | if ( ! $this->request['object_id'] && ! $this->request['object_type'] ) { |
|
|
0 ignored issues
–
show
This code seems to be duplicated across your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. Loading history...
|
|||
| 124 | return $this->prepare_item( array( 'error' => __( 'CMB2 Field value cannot be updated without the object_id and object_type parameters specified.', 'cmb2' ) ) ); |
||
| 125 | } |
||
| 126 | |||
| 127 | if ( ! $this->request['value'] ) { |
||
| 128 | return $this->prepare_item( array( 'error' => __( 'CMB2 Field value cannot be updated without the value parameter specified.', 'cmb2' ) ) ); |
||
| 129 | } |
||
| 130 | |||
| 131 | if ( is_wp_error( $this->rest_box ) ) { |
||
| 132 | return $this->prepare_item( array( 'error' => $this->rest_box->get_error_message() ) ); |
||
|
0 ignored issues
–
show
The method
get_error_message() does not seem to exist on object<CMB2_REST>.
This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces. This is most likely a typographical error or the method has been renamed. Loading history...
|
|||
| 133 | } |
||
| 134 | |||
| 135 | $field = $this->rest_box->field_can_write( $this->request->get_param( 'field_id' ), true ); |
||
| 136 | |||
| 137 | if ( ! $field ) { |
||
| 138 | return new WP_Error( 'cmb2_rest_error', __( 'No field found by that id.', 'cmb2' ) ); |
||
| 139 | } |
||
| 140 | |||
| 141 | $field->args['value_updated'] = (bool) $field->save_field( $this->request['value'] ); |
||
| 142 | |||
| 143 | $field_data = $this->get_rest_field( $field ); |
||
| 144 | |||
| 145 | if ( is_wp_error( $field_data ) ) { |
||
| 146 | return $this->prepare_item( array( 'error' => $field_data->get_error_message() ) ); |
||
| 147 | } |
||
| 148 | |||
| 149 | return $this->prepare_item( $field_data ); |
||
| 150 | } |
||
| 151 | |||
| 152 | /** |
||
| 153 | * Update CMB2 field value. |
||
| 154 | * |
||
| 155 | * @since 2.2.4 |
||
| 156 | * |
||
| 157 | * @param WP_REST_Request $request Full data about the request. |
||
| 158 | * @return WP_Error|WP_REST_Response |
||
| 159 | */ |
||
| 160 | public function delete_field_value( $request ) { |
||
| 161 | $this->initiate_rest_read_box( $request, 'field_value_delete' ); |
||
| 162 | |||
| 163 | View Code Duplication | if ( ! $this->request['object_id'] && ! $this->request['object_type'] ) { |
|
|
0 ignored issues
–
show
This code seems to be duplicated across your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. Loading history...
|
|||
| 164 | return $this->prepare_item( array( 'error' => __( 'CMB2 Field value cannot be deleted without the object_id and object_type parameters specified.', 'cmb2' ) ) ); |
||
| 165 | } |
||
| 166 | |||
| 167 | if ( is_wp_error( $this->rest_box ) ) { |
||
| 168 | return $this->prepare_item( array( 'error' => $this->rest_box->get_error_message() ) ); |
||
|
0 ignored issues
–
show
The method
get_error_message() does not seem to exist on object<CMB2_REST>.
This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces. This is most likely a typographical error or the method has been renamed. Loading history...
|
|||
| 169 | } |
||
| 170 | |||
| 171 | $field = $this->rest_box->field_can_write( $this->request->get_param( 'field_id' ), true ); |
||
| 172 | |||
| 173 | if ( ! $field ) { |
||
| 174 | return new WP_Error( 'cmb2_rest_error', __( 'No field found by that id.', 'cmb2' ) ); |
||
| 175 | } |
||
| 176 | |||
| 177 | $field->args['value_deleted'] = (bool) $field->remove_data(); |
||
| 178 | |||
| 179 | $field_data = $this->get_rest_field( $field ); |
||
| 180 | |||
| 181 | if ( is_wp_error( $field_data ) ) { |
||
| 182 | return $this->prepare_item( array( 'error' => $field_data->get_error_message() ) ); |
||
| 183 | } |
||
| 184 | |||
| 185 | return $this->prepare_item( $field_data ); |
||
| 186 | } |
||
| 187 | |||
| 188 | /** |
||
| 189 | * Get a specific field |
||
| 190 | * |
||
| 191 | * @since 2.2.4 |
||
| 192 | * |
||
| 193 | * @param string Field id |
||
| 194 | * @return array|WP_Error |
||
| 195 | */ |
||
| 196 | public function get_rest_field( $field_id ) { |
||
| 197 | $field = $field_id instanceof CMB2_Field ? $field_id : $this->rest_box->field_can_read( $field_id, true ); |
||
| 198 | |||
| 199 | if ( ! $field ) { |
||
| 200 | return new WP_Error( 'cmb2_rest_error', __( 'No field found by that id.', 'cmb2' ) ); |
||
| 201 | } |
||
| 202 | |||
| 203 | $field_data = $this->prepare_field_data( $field ); |
||
|
0 ignored issues
–
show
It seems like
$field defined by $field_id instanceof \CM...n_read($field_id, true) on line 197 can also be of type boolean; however, CMB2_REST_Controller_Fields::prepare_field_data() does only seem to accept object<CMB2_Field>, maybe add an additional type check?
If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check: /**
* @return array|string
*/
function returnsDifferentValues($x) {
if ($x) {
return 'foo';
}
return array();
}
$x = returnsDifferentValues($y);
if (is_array($x)) {
// $x is an array.
}
If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue. Loading history...
|
|||
| 204 | $response = rest_ensure_response( $field_data ); |
||
| 205 | |||
| 206 | $response->add_links( $this->prepare_links( $field ) ); |
||
|
0 ignored issues
–
show
It seems like
$field defined by $field_id instanceof \CM...n_read($field_id, true) on line 197 can also be of type boolean; however, CMB2_REST_Controller_Fields::prepare_links() does only seem to accept object<CMB2_Field>, maybe add an additional type check?
If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check: /**
* @return array|string
*/
function returnsDifferentValues($x) {
if ($x) {
return 'foo';
}
return array();
}
$x = returnsDifferentValues($y);
if (is_array($x)) {
// $x is an array.
}
If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue. Loading history...
|
|||
| 207 | |||
| 208 | return $response; |
||
| 209 | } |
||
| 210 | |||
| 211 | /** |
||
| 212 | * Prepare the field data array for JSON. |
||
| 213 | * |
||
| 214 | * @since 2.2.4 |
||
| 215 | * |
||
| 216 | * @param CMB2_Field $field field object. |
||
| 217 | * |
||
| 218 | * @return array Array of field data. |
||
| 219 | */ |
||
| 220 | protected function prepare_field_data( CMB2_Field $field ) { |
||
| 221 | $field_data = array(); |
||
| 222 | $params_to_ignore = array( 'show_in_rest', 'options' ); |
||
| 223 | $params_to_rename = array( |
||
| 224 | 'label_cb' => 'label', |
||
| 225 | 'options_cb' => 'options', |
||
| 226 | ); |
||
| 227 | |||
| 228 | // Run this first so the js_dependencies arg is populated. |
||
| 229 | $rendered = ( $cb = $field->maybe_callback( 'render_row_cb' ) ) |
||
| 230 | // Ok, callback is good, let's run it. |
||
| 231 | ? $this->get_cb_results( $cb, $field->args(), $field ) |
||
| 232 | : false; |
||
| 233 | |||
| 234 | $field_args = $field->args(); |
||
| 235 | |||
| 236 | foreach ( $field_args as $key => $value ) { |
||
| 237 | if ( in_array( $key, $params_to_ignore, true ) ) { |
||
| 238 | continue; |
||
| 239 | } |
||
| 240 | |||
| 241 | if ( 'options_cb' === $key ) { |
||
| 242 | $value = $field->options(); |
||
| 243 | } elseif ( in_array( $key, CMB2_Field::$callable_fields, true ) ) { |
||
| 244 | |||
| 245 | if ( isset( $this->request['_rendered'] ) ) { |
||
| 246 | $value = $key === 'render_row_cb' ? $rendered : $field->get_param_callback_result( $key ); |
||
| 247 | } elseif ( is_array( $value ) ) { |
||
| 248 | // We need to rewrite callbacks as string as they will cause |
||
| 249 | // JSON recursion errors. |
||
| 250 | $class = is_string( $value[0] ) ? $value[0] : get_class( $value[0] ); |
||
| 251 | $value = $class . '::' . $value[1]; |
||
| 252 | } |
||
| 253 | } |
||
| 254 | |||
| 255 | $key = isset( $params_to_rename[ $key ] ) ? $params_to_rename[ $key ] : $key; |
||
| 256 | |||
| 257 | if ( empty( $value ) || is_scalar( $value ) || is_array( $value ) ) { |
||
| 258 | $field_data[ $key ] = $value; |
||
| 259 | } else { |
||
| 260 | $field_data[ $key ] = sprintf( __( 'Value Error for %s', 'cmb2' ), $key ); |
||
| 261 | } |
||
| 262 | } |
||
| 263 | |||
| 264 | if ( $this->request['object_id'] && $this->request['object_type'] ) { |
||
| 265 | $field_data['value'] = $field->get_data(); |
||
| 266 | } |
||
| 267 | |||
| 268 | return $field_data; |
||
| 269 | } |
||
| 270 | |||
| 271 | /** |
||
| 272 | * Return an array of contextual links for field/fields. |
||
| 273 | * |
||
| 274 | * @since 2.2.4 |
||
| 275 | * |
||
| 276 | * @param CMB2_Field $field Field object to build links from. |
||
| 277 | * |
||
| 278 | * @return array Array of links |
||
| 279 | */ |
||
| 280 | protected function prepare_links( $field ) { |
||
| 281 | $boxbase = $this->namespace_base . '/' . $this->rest_box->cmb->cmb_id; |
||
| 282 | $query_string = $this->get_query_string(); |
||
| 283 | |||
| 284 | $links = array( |
||
| 285 | 'self' => array( |
||
| 286 | 'href' => rest_url( trailingslashit( $boxbase ) . 'fields/' . $field->_id() . $query_string ), |
||
| 287 | ), |
||
| 288 | 'collection' => array( |
||
| 289 | 'href' => rest_url( trailingslashit( $boxbase ) . 'fields' . $query_string ), |
||
| 290 | ), |
||
| 291 | 'up' => array( |
||
| 292 | 'href' => rest_url( $boxbase . $query_string ), |
||
| 293 | ), |
||
| 294 | ); |
||
| 295 | |||
| 296 | // Don't embed boxes when looking at boxes route. |
||
| 297 | if ( '/cmb2/v1/boxes' !== CMB2_REST_Controller::get_intial_route() ) { |
||
| 298 | $links['up']['embeddable'] = true; |
||
| 299 | } |
||
| 300 | |||
| 301 | return $links; |
||
| 302 | } |
||
| 303 | |||
| 304 | } |
||
| 305 |
You can fix this by adding a namespace to your class:
When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.