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 | * Creates CMB2 objects/fields endpoint for WordPres REST API. |
||
| 4 | * Allows access to fields registered to a specific post type and more. |
||
| 5 | * |
||
| 6 | * @todo Add better documentation. |
||
| 7 | * @todo Research proper schema. |
||
| 8 | * |
||
| 9 | * @since 2.2.0 |
||
| 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 { |
||
|
0 ignored issues
–
show
|
|||
| 18 | |||
| 19 | /** |
||
| 20 | * CMB2 Instance |
||
| 21 | * |
||
| 22 | * @var CMB2_REST |
||
| 23 | */ |
||
| 24 | protected $rest_box; |
||
| 25 | |||
| 26 | /** |
||
| 27 | * Register the routes for the objects of the controller. |
||
| 28 | * |
||
| 29 | * @since 2.2.0 |
||
| 30 | */ |
||
| 31 | View Code Duplication | public function register_routes() { |
|
|
0 ignored issues
–
show
This method seems to be duplicated in 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...
|
|||
| 32 | // Returns specific box's fields. |
||
| 33 | register_rest_route( CMB2_REST::BASE, '/boxes/(?P<cmb_id>[\w-]+)/fields/', array( |
||
| 34 | array( |
||
| 35 | 'methods' => WP_REST_Server::READABLE, |
||
| 36 | 'callback' => array( $this, 'get_items' ), |
||
| 37 | 'permission_callback' => array( $this, 'get_item_permissions_check' ), |
||
| 38 | ), |
||
| 39 | 'schema' => array( $this, 'get_item_schema' ), |
||
| 40 | ) ); |
||
| 41 | |||
| 42 | // Returns specific field data. |
||
| 43 | register_rest_route( CMB2_REST::BASE, '/boxes/(?P<cmb_id>[\w-]+)/fields/(?P<field_id>[\w-]+)', array( |
||
| 44 | array( |
||
| 45 | 'methods' => WP_REST_Server::READABLE, |
||
| 46 | 'callback' => array( $this, 'get_item' ), |
||
| 47 | 'permission_callback' => array( $this, 'get_item_permissions_check' ), |
||
| 48 | ), |
||
| 49 | 'schema' => array( $this, 'get_item_schema' ), |
||
| 50 | ) ); |
||
| 51 | } |
||
| 52 | |||
| 53 | /** |
||
| 54 | * Get all box fields |
||
| 55 | * |
||
| 56 | * @since 2.2.0 |
||
| 57 | * |
||
| 58 | * @param WP_REST_Request $request The API request object. |
||
| 59 | * @return array |
||
| 60 | */ |
||
| 61 | public function get_items( $request ) { |
||
|
0 ignored issues
–
show
get_items uses the super-global variable $_GET which is generally not recommended.
Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable: // Bad
class Router
{
public function generate($path)
{
return $_SERVER['HOST'].$path;
}
}
// Better
class Router
{
private $host;
public function __construct($host)
{
$this->host = $host;
}
public function generate($path)
{
return $this->host.$path;
}
}
class Controller
{
public function myAction(Request $request)
{
// Instead of
$page = isset($_GET['page']) ? intval($_GET['page']) : 1;
// Better (assuming you use the Symfony2 request)
$page = $request->query->get('page', 1);
}
}
Loading history...
|
|||
| 62 | $this->initiate_rest_read_box( $request, 'fields_read' ); |
||
| 63 | |||
| 64 | if ( is_wp_error( $this->rest_box ) ) { |
||
| 65 | 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...
|
|||
| 66 | } |
||
| 67 | |||
| 68 | $fields = array(); |
||
| 69 | foreach ( $this->rest_box->cmb->prop( 'fields', array() ) as $field ) { |
||
| 70 | $field_id = $field['id']; |
||
| 71 | $rest_field = $this->get_rest_field( $field_id ); |
||
| 72 | |||
| 73 | if ( ! is_wp_error( $rest_field ) ) { |
||
| 74 | $fields[ $field_id ] = $this->server->response_to_data( $rest_field, isset( $_GET['_embed'] ) ); |
||
| 75 | } else { |
||
| 76 | $fields[ $field_id ] = array( 'error' => $rest_field->get_error_message() ); |
||
| 77 | } |
||
| 78 | } |
||
| 79 | |||
| 80 | return $this->prepare_item( $fields ); |
||
| 81 | } |
||
| 82 | |||
| 83 | /** |
||
| 84 | * Get a specific field |
||
| 85 | * |
||
| 86 | * @since 2.2.0 |
||
| 87 | * |
||
| 88 | * @param WP_REST_Request $request The API request object. |
||
| 89 | * @return array|WP_Error |
||
| 90 | */ |
||
| 91 | public function get_item( $request ) { |
||
| 92 | $this->initiate_rest_read_box( $request, 'field_read' ); |
||
| 93 | |||
| 94 | if ( is_wp_error( $this->rest_box ) ) { |
||
| 95 | 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...
|
|||
| 96 | } |
||
| 97 | |||
| 98 | $field = $this->get_rest_field( $this->request->get_param( 'field_id' ) ); |
||
| 99 | |||
| 100 | if ( is_wp_error( $field ) ) { |
||
| 101 | return $this->prepare_item( array( 'error' => $field->get_error_message() ) ); |
||
| 102 | } |
||
| 103 | |||
| 104 | return $this->prepare_item( $field ); |
||
| 105 | } |
||
| 106 | |||
| 107 | /** |
||
| 108 | * Get a specific field |
||
| 109 | * |
||
| 110 | * @since 2.2.0 |
||
| 111 | * |
||
| 112 | * @param string Field id |
||
| 113 | * @return array|WP_Error |
||
| 114 | */ |
||
| 115 | public function get_rest_field( $field_id ) { |
||
| 116 | $field = $this->rest_box->field_can_read( $field_id, true ); |
||
| 117 | |||
| 118 | if ( ! $field ) { |
||
| 119 | return new WP_Error( 'cmb2_rest_error', __( 'No field found by that id.', 'cmb2' ) ); |
||
| 120 | } |
||
| 121 | |||
| 122 | $field_data = $this->prepare_field_data( $field ); |
||
| 123 | $response = rest_ensure_response( $field_data ); |
||
| 124 | |||
| 125 | $response->add_links( $this->prepare_links( $field ) ); |
||
| 126 | |||
| 127 | return $response; |
||
| 128 | } |
||
| 129 | |||
| 130 | protected function prepare_field_data( CMB2_Field $field ) { |
||
|
0 ignored issues
–
show
prepare_field_data uses the super-global variable $_REQUEST which is generally not recommended.
Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable: // Bad
class Router
{
public function generate($path)
{
return $_SERVER['HOST'].$path;
}
}
// Better
class Router
{
private $host;
public function __construct($host)
{
$this->host = $host;
}
public function generate($path)
{
return $this->host.$path;
}
}
class Controller
{
public function myAction(Request $request)
{
// Instead of
$page = isset($_GET['page']) ? intval($_GET['page']) : 1;
// Better (assuming you use the Symfony2 request)
$page = $request->query->get('page', 1);
}
}
Loading history...
|
|||
| 131 | $field_data = array(); |
||
| 132 | $params_to_ignore = array( 'show_on_cb', 'show_in_rest', 'options' ); |
||
| 133 | $params_to_rename = array( |
||
| 134 | 'label_cb' => 'label', |
||
| 135 | 'options_cb' => 'options', |
||
| 136 | ); |
||
| 137 | |||
| 138 | // Run this first so the js_dependencies arg is populated. |
||
| 139 | $rendered = ( $cb = $field->maybe_callback( 'render_row_cb' ) ) |
||
| 140 | // Ok, callback is good, let's run it. |
||
| 141 | ? $this->get_cb_results( $cb, $field->args(), $field ) |
||
| 142 | : false; |
||
| 143 | |||
| 144 | foreach ( $field->args() as $key => $value ) { |
||
| 145 | if ( in_array( $key, $params_to_ignore, true ) ) { |
||
| 146 | continue; |
||
| 147 | } |
||
| 148 | |||
| 149 | if ( 'render_row_cb' === $key ) { |
||
| 150 | continue; |
||
| 151 | } |
||
| 152 | |||
| 153 | if ( 'options_cb' === $key ) { |
||
| 154 | $value = $field->options(); |
||
| 155 | } elseif ( in_array( $key, CMB2_Field::$callable_fields ) ) { |
||
| 156 | $value = $field->get_param_callback_result( $key ); |
||
| 157 | } |
||
| 158 | |||
| 159 | $key = isset( $params_to_rename[ $key ] ) ? $params_to_rename[ $key ] : $key; |
||
| 160 | |||
| 161 | if ( empty( $value ) || is_scalar( $value ) || is_array( $value ) ) { |
||
| 162 | $field_data[ $key ] = $value; |
||
| 163 | } else { |
||
| 164 | $field_data[ $key ] = __( 'Value Error', 'cmb2' ); |
||
| 165 | } |
||
| 166 | } |
||
| 167 | |||
| 168 | if ( isset( $_REQUEST['_rendered'] ) ) { |
||
| 169 | $field_data['rendered'] = $rendered; |
||
| 170 | } |
||
| 171 | |||
| 172 | $field_data['value'] = $field->get_data(); |
||
| 173 | |||
| 174 | return $field_data; |
||
| 175 | } |
||
| 176 | |||
| 177 | protected function prepare_links( $field ) { |
||
| 178 | $boxbase = CMB2_REST::BASE . '/boxes/' . $this->rest_box->cmb->cmb_id; |
||
| 179 | |||
| 180 | $links = array( |
||
| 181 | 'self' => array( |
||
| 182 | 'href' => rest_url( trailingslashit( $boxbase ) . 'fields/' . $field->_id() ), |
||
| 183 | ), |
||
| 184 | 'collection' => array( |
||
| 185 | 'href' => rest_url( trailingslashit( $boxbase ) . 'fields' ), |
||
| 186 | ), |
||
| 187 | 'up' => array( |
||
| 188 | 'href' => rest_url( $boxbase ), |
||
| 189 | ), |
||
| 190 | ); |
||
| 191 | |||
| 192 | // TODO ? |
||
| 193 | error_log( '$this->request[context]: '. print_r( $this->request['context'], true ) ); |
||
| 194 | error_log( 'CMB2_REST_Controller::get_intial_route(): '. print_r( CMB2_REST_Controller::get_intial_route(), true ) ); |
||
| 195 | error_log( '$match: '. print_r( 'box_read' === CMB2_REST_Controller::get_intial_request_type(), true ) ); |
||
| 196 | |||
| 197 | |||
| 198 | // Don't embed boxes when looking at boxes route. |
||
| 199 | if ( '/cmb2/v1/boxes' !== CMB2_REST_Controller::get_intial_route() ) { |
||
| 200 | $links['up']['embeddable'] = true; |
||
| 201 | } |
||
| 202 | |||
| 203 | return $links; |
||
| 204 | } |
||
| 205 | |||
| 206 | } |
||
| 207 |
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.