PluginProbe
WCPOS – Point of Sale (POS) plugin for WooCommerce / 1.10.21
WCPOS – Point of Sale (POS) plugin for WooCommerce v1.10.21
1.10.23 1.10.22 1.10.21 1.10.20 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 All 167 releases
← All changes | includes/Sync/Digest_Index.php +53 -37 1.10.11 → 1.10.21 View file →
@@ -418,15 +418,15 @@
418 418 $live_rows = isset( $row['digest']['live_rows'] ) ? (string) $row['digest']['live_rows'] : '';
419 419 // Products are the one collection whose servability is NARROWER than a live
420 420 // row: POS visibility and the readable-catalog scope both apply, so the
421 421 // richer reader owns them. Every other id-space is exactly its live row.
422 - $products = 'products' === $collection;
423 - if ( ! $products && ( '' === $live_rows || ! method_exists( $this, $live_rows ) ) ) {
422 + $servable = $row['digest']['servable'] ?? null;
423 + if ( null === $servable && ( '' === $live_rows || ! method_exists( $this, $live_rows ) ) ) {
424 424 return $ids;
425 425 }
426 426 $wpdb->last_error = '';
427 - if ( $products ) {
428 - $servable_ids = $this->servable_product_ids( $ids, true );
427 + if ( null !== $servable ) {
428 + $servable_ids = $this->$servable( $ids, true );
429 429 } else {
430 430 $predicate = (string) \call_user_func( array( $this, $live_rows ), 'requested.id' );
431 431 $requested = implode( ' UNION ALL ', array_fill( 0, \count( $ids ), 'SELECT %d AS id' ) );
432 432 $servable_ids = $wpdb->get_col(
@@ -536,18 +536,18 @@
536 536 global $wpdb;
537 537 $bucket_size = max( 1, (int) ( $range['bucket_size'] ?? 1 ) );
538 538 $window_start = max( 0, (int) ( $range['start'] ?? 0 ) );
539 539 $window_end = max( 0, (int) ( $range['end'] ?? 0 ) );
540 - $publish = 'products' === $collection && 'publish' === ( $filters['status'] ?? '' );
541 - $object_types = self::OBJECT_TYPES_SQL;
542 - $current_sql = $this->row_digest_select_sql( 'p.ID >= %d AND p.ID < %d' );
543 - if ( 'customers' === $collection ) {
544 - $object_types = "('customer')";
545 - $current_sql = $this->customer_digest_select_sql( 'u.ID >= %d AND u.ID < %d' );
546 - } elseif ( 'orders' === $collection ) {
547 - $object_types = "('order')";
548 - $current_sql = $this->order_digest_select_sql( '{id} >= %d AND {id} < %d' );
540 + $digest = Collections::row( $collection )['digest'] ?? null;
541 + if ( null === $digest ) {
542 + return array(
543 + 'buckets' => array(),
544 + 'max_id' => 0,
545 + );
549 546 }
547 + $publish = isset( Collections::row( $collection )['digest']['published_ids'] ) && 'publish' === ( $filters['status'] ?? '' );
548 + $object_types = "('" . implode( "','", $digest['object_types'] ) . "')";
549 + $current_sql = $this->{$digest['select']}( $digest['id_column'] . ' >= %d AND ' . $digest['id_column'] . ' < %d' );
550 550 $current_scope = $publish ? $this->product_servable_predicate_sql( 't.id', true ) : array(
551 551 'sql' => '',
552 552 'args' => array(),
553 553 );
@@ -655,8 +655,9 @@
655 655 public function bucket_drift( array $range ): array {
656 656 global $wpdb;
657 657 $range_start = max( 0, (int) ( $range['start'] ?? 0 ) );
658 658 $range_end = max( 0, (int) ( $range['end'] ?? 0 ) );
659 + $digest = Collections::row( 'products' )['digest'];
659 660 $table = $this->table_name();
660 661
661 662 // Same-formula invariant: the current side must digest identically to the stored side.
662 663 $this->raise_group_concat_max_len();
@@ -664,17 +665,17 @@
664 665 $wpdb->prepare(
665 666 'SELECT cur.id AS id,'
666 667 . " CASE WHEN d.digest IS NULL THEN 'missing_stored' ELSE 'changed' END AS status,"
667 668 . ' d.digest AS stored_digest, cur.crc AS current_digest, cur.object_type AS object_type'
668 - . ' FROM (' . $this->row_digest_select_sql( 'p.ID >= %d AND p.ID < %d' ) . ') cur'
669 + . ' FROM (' . $this->{$digest['select']}( $digest['id_column'] . ' >= %d AND ' . $digest['id_column'] . ' < %d' ) . ') cur'
669 670 . " LEFT JOIN {$table} d ON d.object_id = cur.id AND d.object_type = cur.object_type"
670 671 . ' WHERE d.digest IS NULL OR d.digest <> cur.crc'
671 672 . ' UNION ALL'
672 673 . " SELECT d.object_id AS id, 'deleted' AS status, d.digest AS stored_digest, NULL AS current_digest, d.object_type AS object_type"
673 674 . " FROM {$table} d"
674 - . ' WHERE d.object_type IN ' . self::OBJECT_TYPES_SQL
675 + . ' WHERE d.object_type IN ' . "('" . implode( "','", $digest['object_types'] ) . "')"
675 676 . ' AND d.object_id >= %d AND d.object_id < %d'
676 - . ' AND NOT ' . $this->live_row_exists_sql( 'd.object_id' )
677 + . ' AND NOT ' . $this->{$digest['live_rows']}( 'd.object_id' )
677 678 . ' ORDER BY id ASC',
678 679 $range_start,
679 680 $range_end,
680 681 $range_start,
@@ -725,15 +726,14 @@
725 726
726 727 $servable_join = '';
727 728 $servable_filter = '';
728 729 $servable_args = array();
729 - if ( 'customers' === $collection ) {
730 - $inner_sql = $this->customer_digest_select_sql( 'u.ID >= %d AND u.ID < %d' );
731 - } elseif ( 'orders' === $collection ) {
732 - // Orders bucket over their own id-space (HPOS o.id / CPT p.ID) via the {id} placeholder.
733 - $inner_sql = $this->order_digest_select_sql( '{id} >= %d AND {id} < %d' );
734 - } else {
735 - $inner_sql = $this->row_digest_select_sql( 'p.ID >= %d AND p.ID < %d' );
730 + $digest = Collections::row( $collection )['digest'] ?? null;
731 + if ( null === $digest ) {
732 + return array();
733 + }
734 + $inner_sql = $this->{$digest['select']}( $digest['id_column'] . ' >= %d AND ' . $digest['id_column'] . ' < %d' );
735 + if ( isset( $digest['servable'] ) ) {
736 736 $servable_join = " INNER JOIN {$wpdb->posts} catalog_post ON catalog_post.ID = cur.id";
737 737 if ( 'publish' === ( $filters['status'] ?? '' ) ) {
738 738 $servable_join .= " LEFT JOIN {$wpdb->posts} parent_product ON parent_product.ID = catalog_post.post_parent"
739 739 . " AND catalog_post.post_type = 'product_variation'";
@@ -838,11 +838,12 @@
838 838 }
839 839
840 840 /**
841 841 * The readable-catalog predicate over a post alias and its parent alias — a published product,
842 - * or a variation whose parent product is published. One home for the rule.
842 + * or a variation whose parent product is published. One home for the rule. The wcpos/v2 products
843 + * ID fast path ({@see \WCPOS\WooCommercePOS\API\V2\Proxy\Products_Proxy_Behavior::fast_response()}) calls it too.
843 844 */
844 - private function published_product_predicate_sql( string $post_alias, string $parent_alias ): string {
845 + public static function published_product_predicate_sql( string $post_alias, string $parent_alias ): string {
845 846 return "(({$post_alias}.post_type = 'product' AND {$post_alias}.post_status = 'publish')"
846 847 . " OR ({$post_alias}.post_type = 'product_variation' AND {$parent_alias}.post_type = 'product'"
847 848 . " AND {$parent_alias}.post_status = 'publish'))";
848 849 }
@@ -904,28 +905,43 @@
904 905 *
905 906 * @return array{sql: string, args: array<int, int>}
906 907 */
907 908 private function live_max_id_sql( string $collection, bool $publish ): array {
908 - global $wpdb;
909 - if ( 'customers' === $collection ) {
909 + $digest = Collections::row( $collection )['digest'] ?? null;
910 + if ( null === $digest ) {
910 911 return array(
911 - 'sql' => "SELECT MAX(u.ID) FROM {$wpdb->users} u",
912 + 'sql' => 'SELECT NULL WHERE 1 = 0',
912 913 'args' => array(),
913 914 );
914 915 }
915 - if ( 'orders' === $collection ) {
916 - if ( $this->orders_are_hpos() ) {
917 - $orders_table = $wpdb->prefix . 'wc_orders';
918 - return array(
919 - 'sql' => "SELECT MAX(o.id) FROM {$orders_table} o WHERE " . $this->live_order_predicate_sql( 'o' ),
920 - 'args' => array(),
921 - );
922 - }
916 + return $this->{$digest['live_max']}( $publish );
917 + }
918 +
919 + private function customer_live_max_id_sql(): array {
920 + global $wpdb;
921 + return array(
922 + 'sql' => "SELECT MAX(u.ID) FROM {$wpdb->users} u",
923 + 'args' => array(),
924 + );
925 + }
926 +
927 + private function order_live_max_id_sql(): array {
928 + global $wpdb;
929 + if ( $this->orders_are_hpos() ) {
930 + $orders_table = $wpdb->prefix . 'wc_orders';
923 931 return array(
924 - 'sql' => "SELECT MAX(p.ID) FROM {$wpdb->posts} p WHERE " . $this->live_order_predicate_sql( 'p' ),
932 + 'sql' => "SELECT MAX(o.id) FROM {$orders_table} o WHERE " . $this->live_order_predicate_sql( 'o' ),
925 933 'args' => array(),
926 934 );
927 935 }
936 + return array(
937 + 'sql' => "SELECT MAX(p.ID) FROM {$wpdb->posts} p WHERE " . $this->live_order_predicate_sql( 'p' ),
938 + 'args' => array(),
939 + );
940 + }
941 +
942 + private function product_live_max_id_sql( bool $publish ): array {
943 + global $wpdb;
928 944 if ( ! $publish ) {
929 945 return array(
930 946 'sql' => "SELECT MAX(p.ID) FROM {$wpdb->posts} p WHERE " . $this->live_product_predicate_sql( 'p' ),
931 947 'args' => array(),