Skip to content

Commit

Permalink
parse all meta_data before sending response
Browse files Browse the repository at this point in the history
  • Loading branch information
kilbot committed Jun 28, 2023
1 parent d075594 commit 6e93c31
Show file tree
Hide file tree
Showing 11 changed files with 518 additions and 514 deletions.
67 changes: 67 additions & 0 deletions includes/API/Abstracts/WC_Rest_API_Modifier.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
<?php

namespace WCPOS\WooCommercePOS\API\Abstracts;

use WC_Data;
use WCPOS\WooCommercePOS\Logger;
use WP_Error;
use WP_REST_Request;
use WP_REST_Response;

abstract class WC_Rest_API_Modifier {

/**
* @var WP_REST_Request store the request object
*/
protected $request;


/**
* @param array $fields
* @return array|WP_Error
*/
abstract public function get_all_posts( array $fields = array() ): array;


/**
* @param string $id
* @return object
*/
protected function format_id( string $id ): object {
return (object) array( 'id' => (int) $id );
}

/**
* BUG FIX: some servers are not returning the correct meta_data if it is left as WC_Meta_Data objects
* NOTE: it only seems to effect some versions of PHP, or some plugins are adding weird meta_data types
* The result is mata_data: [{}, {}, {}] ie: empty objects, I think json_encode can't handle the WC_Meta_Data objects
*
* @TODO - I need to find out why this is happening
*
* @param WC_Data $object
* @return array
*/
protected function parse_meta_data( WC_Data $object ): array {
return array_map( function( $meta_data ) {
return $meta_data->get_data();
}, $object->get_meta_data());
}

/**
* BUG FIX: the response for some records can be huge, eg:
* - product descriptions with lots of HTML,
* - I've seen products with 1800+ meta_data objects
*
* This is just a helper function to try and alert us to these large responses
*
* @param WP_REST_Response $response
* @param WC_Data $object
*/
protected function log_large_rest_response( WP_REST_Response $response, WC_Data $object ) {
$response_size = strlen( serialize( $response->data ) );
$max_response_size = 100000;
if ( $response_size > $max_response_size ) {
Logger::log( "Object ID {$object->get_id()} has a response size of {$response_size} bytes, exceeding the limit of {$max_response_size} bytes." );
}
}
}
95 changes: 41 additions & 54 deletions includes/API/Customers.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,14 @@
use Ramsey\Uuid\Uuid;
use WC_Customer;
use WCPOS\WooCommercePOS\Logger;
use WP_Error;
use WP_REST_Request;
use WP_REST_Response;
use WP_User;
use WP_User_Query;
use WP_Meta_Query;

class Customers {
private $request;
class Customers extends Abstracts\WC_Rest_API_Modifier {
use Traits\Uuid_Handler;

/**
* Customers constructor.
Expand All @@ -22,6 +22,7 @@ class Customers {
*/
public function __construct( WP_REST_Request $request ) {
$this->request = $request;
$this->uuids = $this->get_all_usermeta_uuids();

add_filter( 'rest_request_before_callbacks', array( $this, 'rest_request_before_callbacks' ), 10, 3 );
add_filter( 'woocommerce_rest_customer_query', array( $this, 'customer_query' ), 10, 2 );
Expand Down Expand Up @@ -96,43 +97,30 @@ public function rest_request_before_callbacks( $response, $handler, $request ) {
public function customer_response( WP_REST_Response $response, WP_User $user_data, WP_REST_Request $request ): WP_REST_Response {
$data = $response->get_data();

/**
* Make sure the customer has a uuid
*/
$uuid = get_user_meta( $user_data->ID, '_woocommerce_pos_uuid', true );
if ( ! $uuid ) {
$uuid = Uuid::uuid4()->toString();
update_user_meta( $user_data->ID, '_woocommerce_pos_uuid', $uuid );
try {
$customer = new WC_Customer( $user_data->ID );
$data['meta_data'] = $customer->get_meta_data();
} catch ( Exception $e ) {
Logger::log( 'Error getting customer meta data: ' . $e->getMessage() );
}
}

/**
* In the WC REST Customers Controller -> get_formatted_item_data_core function, the customer's
* meta_data is only added for administrators. I assume this is for privacy/security reasons.
*
* Cashiers are not always administrators so we need to add the meta_data for uuids.
* @TODO - are there any other meta_data we need to add?
*/
if ( empty( $data['meta_data'] ) ) {
try {
$customer = new WC_Customer( $user_data->ID );
$data['meta_data'] = array_values( array_filter( $customer->get_meta_data(), function ( $meta ) {
return '_woocommerce_pos_uuid' === $meta->key;
}));
} catch ( Exception $e ) {
Logger::log( 'Error getting customer meta data: ' . $e->getMessage() );
}
}

/**
* Reset the new response data
*/
$response->set_data( $data );
// Add the uuid to the response
$this->maybe_add_user_uuid( $user_data );

/**
* Add the customer meta data to the response
*
* In the WC REST Customers Controller -> get_formatted_item_data_core function, the customer's
* meta_data is only added for administrators. I assume this is for privacy/security reasons.
*
* NOTE: for now we are only adding the uuid meta_data
* @TODO - are there any other meta_data we need to add?
*/
try {
$customer = new WC_Customer( $user_data->ID );
$data['meta_data'] = array_values( array_filter( $customer->get_meta_data(), function ( $meta ) {
return '_woocommerce_pos_uuid' === $meta->key;
}));
} catch ( Exception $e ) {
Logger::log( 'Error getting customer meta data: ' . $e->getMessage() );
}

// Set any changes to the response data
$response->set_data( $data );
$this->log_large_rest_response( $response, $product );

return $response;
}
Expand Down Expand Up @@ -262,9 +250,9 @@ public function modify_user_query( $user_query ) {
*
* @param array $fields
*
* @return array|void
* @return array|WP_Error
*/
public function get_all_posts( array $fields = array() ) {
public function get_all_posts( array $fields = array() ): array {
$args = array(
'fields' => 'ID', // Only return user IDs
);
Expand All @@ -275,18 +263,17 @@ public function get_all_posts( array $fields = array() ) {
}

$user_query = new WP_User_Query( $args );
$user_ids = $user_query->get_results();

// wpdb returns id as string, we need int
return array_map( array( $this, 'format_id' ), $user_ids );
}

/**
* @param int $user_id
*
* @return object
*/
private function format_id( $user_id ): object {
return (object) array( 'id' => (int) $user_id );
try {
$user_ids = $user_query->get_results();
return array_map( array( $this, 'format_id' ), $user_ids );
} catch ( Exception $e ) {
Logger::log( 'Error fetching order IDs: ' . $e->getMessage() );
return new WP_Error(
'woocommerce_pos_rest_cannot_fetch',
'Error fetching customer IDs.',
array( 'status' => 500 )
);
}
}
}
72 changes: 26 additions & 46 deletions includes/API/Orders.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
use WC_Order_Item;
use WC_Product_Variation;
use WCPOS\WooCommercePOS\Logger;
use WP_Error;
use WP_HTTP_Response;
use WP_REST_Request;
use WP_REST_Response;
use function in_array;
Expand All @@ -18,8 +20,8 @@
use WC_Order_Query;
use WP_Query;

class Orders {
private $request;
class Orders extends Abstracts\WC_Rest_API_Modifier {
use Traits\Uuid_Handler;

private $posted;

Expand All @@ -31,6 +33,7 @@ class Orders {
public function __construct( WP_REST_Request $request ) {
$this->request = $request;
$this->posted = $this->request->get_json_params();
$this->uuids = $this->get_all_postmeta_uuids();

if ( 'POST' == $request->get_method() ) {
$this->incoming_shop_order();
Expand Down Expand Up @@ -218,38 +221,30 @@ public function pre_insert_shop_order_object( $order, $request, $creating ) {
public function order_response( WP_REST_Response $response, WC_Order $order, WP_REST_Request $request ): WP_REST_Response {
$data = $response->get_data();

/**
* make sure the order has a uuid
*/
$uuid = $order->get_meta( '_woocommerce_pos_uuid' );
if ( ! $uuid ) {
$uuid = Uuid::uuid4()->toString();
$order->update_meta_data( '_woocommerce_pos_uuid', $uuid );
$order->save_meta_data();
$data['meta_data'] = $order->get_meta_data();
}

/**
* reset the new response data
*/
$response->set_data( $data );
// Add UUID to order
$this->maybe_add_post_uuid( $order );

/**
* Add link for order payment.
*/
// Add payment link to the order.
$pos_payment_url = add_query_arg(array(
'pay_for_order' => true,
'key' => $order->get_order_key(),
), get_home_url( null, '/wcpos-checkout/order-pay/' . $order->get_id() ));

$response->add_link( 'payment', $pos_payment_url, array( 'foo' => 'bar' ) );

/**
* Add link for order receipt.
*/
// Add receipt link to the order.
$pos_receipt_url = get_home_url( null, '/wcpos-checkout/wcpos-receipt/' . $order->get_id() );
$response->add_link( 'receipt', $pos_receipt_url );

/**
* Make sure we parse the meta data before returning the response
*/
$order->save_meta_data(); // make sure the meta data is saved
$data['meta_data'] = $this->parse_meta_data( $order );

$response->set_data( $data );
$this->log_large_rest_response( $response, $order );

return $response;
}

Expand All @@ -261,15 +256,7 @@ public function order_response( WP_REST_Response $response, WC_Order $order, WP_
*/
public function order_get_items( array $items, WC_Order $order, array $item_type ): array {
foreach ( $items as $item ) {
/**
* make sure the cart items have a uuid
*/
$uuid = $item->get_meta( '_woocommerce_pos_uuid' );
if ( ! $uuid ) {
$uuid = Uuid::uuid4()->toString();
$item->update_meta_data( '_woocommerce_pos_uuid', $uuid );
$item->save_meta_data();
}
$this->maybe_add_order_item_uuid( $item );
}

return $items;
Expand Down Expand Up @@ -428,7 +415,7 @@ public function orderby_additions( array $clauses, WP_Query $wp_query ): array {
*
* @param array $fields
*
* @return array
* @return array|WP_Error
*/
public function get_all_posts( array $fields = array() ): array {
$args = array(
Expand All @@ -441,21 +428,14 @@ public function get_all_posts( array $fields = array() ): array {

try {
$order_ids = $order_query->get_orders();
return array_map( array( $this, 'format_id' ), $order_ids );
} catch ( Exception $e ) {
Logger::log( 'Error fetching order IDs: ' . $e->getMessage() );
return array(); // Return an empty array in case of an error
return new WP_Error(
'woocommerce_pos_rest_cannot_fetch',
'Error fetching order IDs.',
array( 'status' => 500 )
);
}

// wpdb returns id as string, we need int
return array_map( array( $this, 'format_id' ), $order_ids );
}

/**
* @param string $order_id
*
* @return object
*/
private function format_id( string $order_id ): object {
return (object) array( 'id' => (int) $order_id );
}
}
Loading

0 comments on commit 6e93c31

Please sign in to comment.