settings = $settings; } public function register(): void { \add_action( 'woocommerce_new_product', [ $this, 'onProductSaved' ], 10, 1 ); \add_action( 'woocommerce_update_product', [ $this, 'onProductSaved' ], 10, 1 ); \add_action( 'woocommerce_new_product_variation', [ $this, 'onProductSaved' ], 10, 1 ); \add_action( 'woocommerce_update_product_variation', [ $this, 'onProductSaved' ], 10, 1 ); \add_action( 'transition_post_status', [ $this, 'onTransitionStatus' ], 10, 3 ); \add_action( 'before_delete_post', [ $this, 'onBeforeDelete' ], 10, 2 ); } public function onProductSaved( int $productId ): void { if ( ! $this->settings->hasApiKey() ) { return; } $parentId = $this->resolveParentId( $productId ); if ( $parentId === null ) { return; } $op = $this->isInSelectedCategories( $parentId ) ? self::OP_UPSERT : self::OP_DELETE; $this->enqueue( $parentId, $op ); } /** * @param mixed $post */ public function onTransitionStatus( string $newStatus, string $oldStatus, $post ): void { if ( ! $this->settings->hasApiKey() ) { return; } if ( ! is_object( $post ) || ! isset( $post->post_type, $post->ID ) ) { return; } if ( ! in_array( $post->post_type, [ 'product', 'product_variation' ], true ) ) { return; } if ( $newStatus === $oldStatus ) { return; } $id = (int) $post->ID; $parentId = $this->resolveParentId( $id ); if ( $parentId === null ) { return; } if ( $newStatus === 'publish' ) { $op = $this->isInSelectedCategories( $parentId ) ? self::OP_UPSERT : self::OP_DELETE; $this->enqueue( $parentId, $op ); return; } if ( $oldStatus === 'publish' ) { if ( $post->post_type === 'product_variation' ) { $this->enqueue( $parentId, self::OP_UPSERT ); return; } $this->enqueue( $parentId, self::OP_DELETE ); } } /** * @param mixed $post */ public function onBeforeDelete( int $postId, $post = null ): void { if ( ! $this->settings->hasApiKey() ) { return; } if ( ! is_object( $post ) || ! isset( $post->post_type ) ) { $post = \get_post( $postId ); if ( ! $post ) { return; } } if ( ! in_array( $post->post_type, [ 'product', 'product_variation' ], true ) ) { return; } if ( $post->post_type === 'product_variation' ) { $parentId = (int) $post->post_parent; if ( $parentId > 0 ) { $this->enqueue( $parentId, self::OP_UPSERT ); } return; } $this->enqueue( $postId, self::OP_DELETE ); } private function isInSelectedCategories( int $parentId ): bool { $selected = $this->settings->syncCategories(); if ( $selected === [] ) { return true; } $termIds = \wp_get_post_terms( $parentId, 'product_cat', [ 'fields' => 'ids' ] ); if ( ! is_array( $termIds ) || $termIds === [] ) { return false; } return array_intersect( array_map( 'intval', $termIds ), $selected ) !== []; } private function resolveParentId( int $id ): ?int { $post = \get_post( $id ); if ( ! $post ) { return null; } if ( $post->post_type === 'product_variation' ) { $parentId = (int) $post->post_parent; return $parentId > 0 ? $parentId : null; } if ( $post->post_type === 'product' ) { return $id; } return null; } private function enqueue( int $productId, string $op ): void { if ( ! \function_exists( 'as_enqueue_async_action' ) || $this->hasPendingSync( $productId ) ) { return; } $args = [ 'product_id' => $productId, 'op' => $op, ]; \as_enqueue_async_action( self::SYNC_HOOK, $args, self::ACTION_GROUP ); } private function hasPendingSync( int $productId ): bool { if ( ! \function_exists( 'as_get_scheduled_actions' ) ) { return false; } foreach ( [ self::OP_UPSERT, self::OP_DELETE ] as $op ) { $pending = \as_get_scheduled_actions( [ 'hook' => self::SYNC_HOOK, 'args' => [ 'product_id' => $productId, 'op' => $op, ], 'group' => self::ACTION_GROUP, 'status' => 'pending', 'per_page' => 1, ], 'ids' ); if ( is_array( $pending ) && $pending !== [] ) { return true; } } return false; } }