PluginProbe
WCPOS – Point of Sale (POS) plugin for WooCommerce / 1.10.18
WCPOS – Point of Sale (POS) plugin for WooCommerce v1.10.18
1.10.19 1.10.18 1.10.17 1.10.16 1.10.15 1.10.13 1.10.14 1.10.12 1.10.11 1.10.10 1.10.9 1.10.8 untagged-3d9b7ccddc54df87c672 1.10.7 1.10.6 1.10.5 1.10.3 1.10.4 1.10.2 1.10.1 1.10.0 1.9.17 1.9.15 1.9.16 1.9.14 All 163 releases
← All changes | includes/API/V2/Write_Controller.php +8 -56 1.10.31.10.18 View file →
@@ -7,8 +7,9 @@
7 7
8 8 namespace WCPOS\WooCommercePOS\API\V2;
9 9
10 10 use WCPOS\WooCommercePOS\API\V2\Writers\Collection_Writer_Resolver;
11 +use WCPOS\WooCommercePOS\Services\Permission_Rules;
11 12 use WCPOS\WooCommercePOS\Services\Tax_Id_Types;
12 13 use WCPOS\WooCommercePOS\Sync\Api;
13 14 use WCPOS\WooCommercePOS\Sync\Collections;
14 15 use WCPOS\WooCommercePOS\Sync\Endpoint_Permissions;
@@ -43,8 +44,9 @@
43 44 * live in an injected mutation store, so the apply logic is unit-testable with a
44 45 * fake store + a stubbed `rest_do_request`.
45 46 */
46 47 class Write_Controller extends WP_REST_Controller {
48 +
47 49 // Our gate (capability + F13 health); forwarded writes scope the client-tier grant below.
48 50 use Endpoint_Permissions;
49 51
50 52
@@ -591,13 +593,13 @@
591 593 *
592 594 * @param int $id The order id.
593 595 */
594 596 private function can_forward_delete( int $id ): bool {
595 - add_filter( 'woocommerce_rest_check_permissions', array( $this, 'wcpos_check_permissions' ), 10, 4 );
597 + Permission_Rules::install_wc_filter();
596 598 try {
597 599 return (bool) wc_rest_check_post_permissions( 'shop_order', 'delete', $id );
598 600 } finally {
599 - remove_filter( 'woocommerce_rest_check_permissions', array( $this, 'wcpos_check_permissions' ), 10 );
601 + Permission_Rules::uninstall_wc_filter();
600 602 }
601 603 }
602 604
603 605 private function checkpoint_and_finalize( string $mutation_id, int $remote_id, int $response_status ) {
@@ -743,9 +745,9 @@
743 745 */
744 746 private function dispatch_write( WP_REST_Request $request ) {
745 747 // Stamp here so direct callers (notably deletes) carry the scope too.
746 748 Store_Scope::stamp( $request );
747 - add_filter( 'woocommerce_rest_check_permissions', array( $this, 'wcpos_check_permissions' ), 10, 4 );
749 + Permission_Rules::install_wc_filter();
748 750 try {
749 751 // Marked as OUR traffic for the duration of the forward, so a consumer
750 752 // keyed on store scope can act on a till write without also claiming
751 753 // every stock wc/v3 product write on the site (pro#425 review).
@@ -754,65 +756,15 @@
754 756 return rest_do_request( $request );
755 757 }
756 758 );
757 759 } finally {
758 - remove_filter( 'woocommerce_rest_check_permissions', array( $this, 'wcpos_check_permissions' ), 10 );
760 + Permission_Rules::uninstall_wc_filter();
759 761 }
760 762 }
761 763
762 - /**
763 - * Authorize proxied catalog mutations for POS users.
764 - *
765 - * This filter is attached only while a sync push is forwarded to wc/v3, so
766 - * direct WooCommerce requests keep their normal permission checks.
767 - *
768 - * @param bool $permission The current permission.
769 - * @param string $context The request context.
770 - * @param int $object_id The object ID.
771 - * @param string $post_type The object type passed by WooCommerce.
772 - *
773 - * @return bool
774 - */
764 + /** @deprecated Use Permission_Rules::wc_filter(). */
775 765 public function wcpos_check_permissions( $permission, $context, $object_id, $post_type ) {
776 - // Catalog and coupon WRITES require the user's real WooCommerce
777 - // capabilities — no POS-tier widening. The cashier role is deliberately
778 - // read-only on catalog (Activator), and a blanket grant here handed
779 - // every POS user product deletion and coupon minting. Product decision
780 - // 2026-08-06: strict wc/v3 parity for catalog mutations; only the
781 - // HPOS placeholder remap below (orders) adjusts anything, and it never
782 - // grants beyond the user's own role caps.
783 -
784 - // Orders: with HPOS enabled (sync off), get_post() yields shop_order_placehold
785 - // (map_meta_cap = false, no capability_type), so WooCommerce's REST check maps
786 - // to the generic edit_post/delete_post caps that cashier-tier roles lack —
787 - // even though they hold the real shop_orders caps. Re-check the capability the
788 - // mapping SHOULD have produced, mirroring V1\Orders_Controller's
789 - // update_item_permissions_check fix. No grant beyond the user's own role caps.
790 - if ( ! $permission && 'shop_order' === $post_type ) {
791 - $order_caps = array(
792 - 'read' => 'read_private_shop_orders',
793 - 'create' => 'publish_shop_orders',
794 - 'delete' => 'delete_shop_orders',
795 - );
796 - $order_cap = $order_caps[ $context ] ?? null;
797 - // edit and delete are ownership-sensitive: the base *_shop_orders cap only
798 - // authorizes acting on the user's OWN orders. Touching another user's order
799 - // additionally requires the *_others_shop_orders cap, mirroring WooCommerce's
800 - // own meta-cap map. Without this, a cashier with delete_shop_orders (but not
801 - // delete_others_shop_orders) could delete/void orders they do not own.
802 - if ( \in_array( $context, array( 'edit', 'delete' ), true ) ) {
803 - $order_post = get_post( $object_id );
804 - if ( $order_post ) {
805 - $owns_order = get_current_user_id() === (int) $order_post->post_author;
806 - $order_cap = $owns_order ? "{$context}_shop_orders" : "{$context}_others_shop_orders";
807 - }
808 - }
809 - if ( $order_cap && current_user_can( $order_cap ) ) {
810 - $permission = true;
811 - }
812 - }
813 -
814 - return $permission;
766 + return Permission_Rules::wc_filter( $permission, $context, $object_id, $post_type, 'writes' );
815 767 }
816 768
817 769 /**
818 770 * Read this collection's document for one record, through its writer.