Connecting with customers on their mobile device– especially through the use of a branded, mobile application– is considered the holy grail of customer engagementPeople live on their phones these days. So store owners, naturally, want to be where their customers live for many stores.
In this topic, we’ll examine the example of a Product Review App.
If you prefer, you can jump to the Knowledge check to see what you already know
In this example, we’ll customize the API to accommodate requests from a Mobile App limited to the following requirements:
It’s worth noting, up front, that this is a “toy” example and a full fledged production app would have many additional considerations.
For many portions of the application, default REST functionality can be used. However, for full functionality, we will need custom code to implement some of the use cases:
Use Case | Approach |
---|---|
AuthenticationBy default, WooCommerce does not permit customer level authentication to obtain API keys | Permit specific user capabilities during authentication requests |
Retrieving Customer Orders Because orders are a post type, the REST API only permits access to those with view_others_private_orders capability | Custom REST Controller that extends default Woo functionality |
Creating a Product Review By default only accessible to those with moderate_comments capability | Custom REST Controller that extends default Woo functionality |
WooCommerce allows remote Apps, that are logged in as a site user, to to create and obtain API keys.
However, as a security measure, this capability is limited to the users that have the ‘manage_woocommerce’ capability.
In order to have a useful, personalized experience in the mobile app, Without allowing each customer to obtain his own API key, WooCommerce won’t be able to individually identify each userwe will need to modify this behavior.
add_filter("user_has_cap", "cwpdev_wc_app_athunetication", 15, 3);
function cwpdev_wc_app_athunetication($allcaps, $cap, $args){
//bail if not doing a WC Auth Request
global $wp;
if( !isset($wp->query_vars['wc-auth-route']) || !isset( $wp->query_vars['wc-auth-version'] ) ){
return $allcaps;
}
//validate the app return url and callback url
if(!cwpdev_custom_validate_app_url($_REQUEST['callback_url']) ){
return $allcaps;
}
//bail for those who can already manage_woocommerce or if not asking about woocommerce
if( $allcaps['manage_woocommerce'] || 'manage_woocommerce' !== $args[0]){
return $allcaps;
}
//we're only going to allow one key per customer
global $wpdb;
$user_id=get_current_user_id();
if( 0 < $wpdb->get_var( $wpdb->prepare(
"SELECT COUNT(*) FROM {$wpdb->prefix}woocommerce_api_keys WHERE `user_id`=%d", $user_id) )
){
return $allcaps;
}
//now that we've cleared all gaurd statments
$allcaps[ 'manage_woocommerce' ]=true;
return $allcaps;
}
For mobile apps to obtain API keys, we will cautiously allow customers to manage_woocommerce Note the large amount of guard statements in this example code. Here’s an example filter for user_has_cap:
In this example, we’ll focus on two requests from the mobile app:
Here are two examples of these requests (modified from the REST API Docs We’re omitting fields that Customers shouldn’t have access to, such as user_id and reviewer_id) using the npm library.
const data = {
product_id: 22,
review: "Nice album!",
rating: 5
};
WooCommerce.post("products/reviews", data)
.then((response) => {
console.log(response.data);
})
.catch((error) => {
console.log(error.response.data);
});
WooCommerce.get("orders")
.then((response) => {
console.log(response.data);
})
.catch((error) => {
console.log(error.response.data);
});
In order to select a product for review, the App will need to be able to see what products the customer has purchased.
So we’ll need to open the up the permissions, but restrict customers to their own ordersLine 17 accomplishes this by overriding the customer_id parameter with the authenticated user id
class Cwpdev_REST_Order_Controller extends WC_REST_Orders_Controller{
public function get_items_permissions_check( $request ){
if( wc_rest_check_post_permissions( $this->post_type, 'read' ) ){
return true;
}
if( in_array('customer', $wp_get_current_user()->roles)){
return true;
}
return new WP_Error( 'woocommerce_rest_cannot_view', __( 'Sorry, you cannot list resources.', 'woocommerce' ), array( 'status' => rest_authorization_required_code() ) );
}
public function get_items($request){
//if user cannot normally read order, add controls
if( !wc_rest_check_post_permissions( $this->post_type, 'read' ) ){
$request['customer_id']=get_current_user_id();
}
return parent::get_items($request);
}
}
The default product reviews controller, bases access on the ability of a user to manage_comments.
We’ll need to open it up for customer, but restrict their ability to only review products that they’ve purchasedThe wc_customer_bought_product function is a nice check for this (Line 11)
class Cwpdev_REST_Product_Review_Controller extends WC_REST_Product_Reviews_Controller{
public function create_item_permissions_check( $request ) {
//if they can normally create a review, let 'em
if ( wc_rest_check_product_reviews_permissions( 'create' ) ) {
return true;
}
//check if user bought the product
$user=wp_get_current_user();
if( wc_customer_bought_product($user->user_email,$user->ID, (int) $request['product_id']) ){
return true;
}
return new WP_Error( 'woocommerce_rest_cannot_edit', __( 'Sorry, you cannot edit this resource.', 'woocommerce' ), array( 'status' => rest_authorization_required_code() ) );
}
public function create_item($request){
//If they don't "moderate_comments" put some controlled values in.
if ( !wc_rest_check_product_reviews_permissions( 'create' ) ) {
$user=get_current_user();
$request['status'] = 'hold';
$request['reviewer'] = $user->user_nicename;
$request['reviewer_email']= $user->user_email;
$request['verified']=true;
}
return parent::create_item($request);
}
// Additional Methods can be added for controlling
// the updating of product reviews, as well
}
Finally, be sure to hook your custom controllers into WooCommerce’s rest namespaces.
add_filter('woocommerce_rest_api_get_rest_namespaces', function($namespaces){
$namespaces['wc/v3']['product-reviews']="Cwpdev_REST_Product_Review_Controller";
$namespaces['wc/v3']['orders']="Cwpdev_REST_Order_Controller";
return $namespaces;
});
You now have a general overview of some of the techniques you can use to bend the REST API to your will.
In a general sense, the Woo REST API is extremely capable, yet fairly restrictiveThis helps to put security at the forefront. when it comes to user permissions. For many use cases, you will likely need to open up the controllers default permissions, and then restrict the data that specific user types can access.
This concludes the topic and the lesson! Be sure to, check your knowledge before you go. Remember this course is designed to be searchable, nimble, and is continuously updated, so keep this material in your back pocket and use it to breeze through your next WooCommerce project!
Hint: All the custom code in the lesson has been prefixed with “cwpdev”. Use CTRL+Shift+F to search this snippet to quickly jump to the examples.
0 of 2 Questions completed
Questions:
You have already completed the quiz before. Hence you can not start it again.
Quiz is loading…
You must sign in or sign up to start the quiz.
You must first complete the following:
0 of 2 Questions answered correctly
Your time:
Time has elapsed
You have reached 0 of 0 point(s), (0)
Earned Point(s): 0 of 0, (0)
0 Essay(s) Pending (Possible Point(s): 0)
What permission do users need to have to obtain an API key from the WooCommerce Authentication Endpoint?
How can we modify the data that users see based on custom logic?