File "Sync.php"
Full Path: /home/warrior1/public_html/languages/wp-content/plugins/facebook-for-woocommerce/includes/ProductSets/Sync.php
File size: 11.27 KB
MIME-type: text/x-php
Charset: utf-8
<?php
// phpcs:ignoreFile
/**
* Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved
*
* This source code is licensed under the license found in the
* LICENSE file in the root directory of this source tree.
*
* @package FacebookCommerce
*/
namespace SkyVerge\WooCommerce\Facebook\ProductSets;
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* The product set sync handler.
*
* @since 2.3.0
*/
class Sync {
/**
* Update action name
*
* @var string
*/
const ACTION_UPDATE = 'UPDATE';
/**
* Delete action name
*
* @var string
*/
const ACTION_DELETE = 'DELETE';
/**
* Requests array for sync schedule
*
* @var array
*/
protected $requests = array();
/**
* Product's Category Previous List
*
* @since 2.3.0
*
* @var array
*/
protected static $prev_product_cat = array();
/**
* Product's Category New List
*
* @since 2.3.0
*
* @var array
*/
protected static $new_product_cat = array();
/**
* Product's Product Set Previous List
*
* @since 2.3.0
*
* @var array
*/
protected static $prev_product_set = array();
/**
* Product's Product Set New List
*
* @since 2.3.0
*
* @var array
*/
protected static $new_product_set = array();
/**
* Categories field name
*
* @since 2.3.0
*
* @var string
*/
protected $categories_field = '';
/**
* Sync constructor.
*
* @since 2.3.0
*/
public function __construct() {
$this->categories_field = \WC_Facebookcommerce::PRODUCT_SET_META;
$this->add_hooks();
}
/**
* Adds needed hooks to support product set sync.
*
* @since 2.3.0
*/
public function add_hooks() {
// product hooks, compare taxonomies the lists before and after saving product to see if must sync
add_filter( 'wp_insert_post_data', array( $this, 'check_product_data_before_save' ), 99, 2 );
add_action( 'save_post', array( $this, 'check_product_data_after_save' ), 99, 2 );
// product hooks, sync product's product set when deleting or restoring product
add_action( 'trashed_post', array( $this, 'sync_product_product_sets' ), 99 );
add_action( 'before_delete_post', array( $this, 'sync_product_product_sets' ), 99 );
add_action( 'untrashed_post', array( $this, 'sync_product_product_sets' ), 99 );
// product set hooks, compare taxonomies the lists before and after saving product to see if must sync
add_action( 'created_fb_product_set', array( $this, 'fb_product_set_hook_before' ), 1 );
add_action( 'created_fb_product_set', array( $this, 'fb_product_set_hook_after' ), 99 );
add_action( 'edited_fb_product_set', array( $this, 'fb_product_set_hook_before' ), 1 );
add_action( 'edited_fb_product_set', array( $this, 'fb_product_set_hook_after' ), 99 );
// product cat and product set delete hooks, remove or check if must remove any product set
add_action( 'pre_delete_term', array( $this, 'sync_remove_product_set' ), 1, 2 );
add_action( 'delete_product_cat', array( $this, 'maybe_sync_product_set_on_product_cat_remove' ), 99 );
}
/** Hook methods *******************************************************************************************/
/**
* Stores the list of categories and product set of a product to compare later on 'save_post' hook.
*
* @since 2.3.0
*
* @param array $data Post Data.
* @param array $post Post.
*/
public function check_product_data_before_save( $data, $post ) {
// gets product's current categories IDs
if ( ! empty( $post ) && 'product' === $post['post_type'] ) {
self::$prev_product_cat = wc_get_product_cat_ids( $post['ID'] );
self::$prev_product_set = wc_get_product_term_ids( $post['ID'], 'fb_product_set' );
}
return $data;
}
/**
* Sync Product's Product Sets based on its Categories
*
* @param int $post_id Post ID.
*/
public function sync_product_product_sets( $post_id ) {
if ( 'product' !== get_post_type( $post_id ) ) {
return;
}
// get product's categories and sets
$product_cats = wc_get_product_cat_ids( $post_id );
$product_sets = wc_get_product_term_ids( $post_id, 'fb_product_set' );
$this->maybe_sync_product_sets( $product_cats, $product_sets );
}
/**
* Stores the list of categories and product set of a product to compare with the previous
*
* @since 2.3.0
*
* @param int $post_id Post ID.
* @param WP_Post $post Post Object.
*/
public function check_product_data_after_save( $post_id, $post = '' ) {
if ( 'product' !== $post->post_type ) {
return;
}
// gets product's new categories IDs to compare if there are differences to sync
self::$new_product_cat = wc_get_product_cat_ids( $post_id );
self::$new_product_set = wc_get_product_term_ids( $post_id, 'fb_product_set' );
// get differences
$product_cat_diffs = $this->get_all_diff( 'product_cat' );
$product_set_diffs = $this->get_all_diff( 'product_set' );
if ( ! $product_cat_diffs && ! $product_set_diffs ) {
return;
}
$this->maybe_sync_product_sets( $product_cat_diffs, $product_set_diffs );
}
/**
* Check if must sync Product Sets from given lists
*
* @since 2.3.0
*
* @param array $product_cats Product Category Term IDs.
* @param array $product_sets Product Set Term IDs.
*/
public function maybe_sync_product_sets( $product_cats, $product_sets ) {
if ( empty( $product_sets ) || ! is_array( $product_sets ) ) {
$product_sets = array();
}
$product_set_term_ids = array_merge( array(), $product_sets );
// check if product cat belongs to a product_set
foreach ( $product_cats as $product_cat_id ) {
$cat_product_sets = $this->get_product_cat_sets( $product_cat_id );
if ( ! empty( $cat_product_sets ) ) {
$product_set_term_ids = array_merge( $product_set_term_ids, $cat_product_sets );
}
}
foreach ( $product_set_term_ids as $product_set_id ) {
$this->maybe_sync_product_set( $product_set_id );
}
}
/**
* Stores the list of categories of a product set to compare later.
*
* @since 2.3.0
*
* @param int $term_id Term ID.
*/
public function fb_product_set_hook_before( $term_id ) {
self::$prev_product_cat = get_term_meta( $term_id, $this->categories_field, true );
}
/**
* Stores the list of categories of a product set to compare with the previous and check if must sync
*
* @since 2.3.0
*
* @param int $term_id Term ID.
*/
public function fb_product_set_hook_after( $term_id ) {
self::$new_product_cat = get_term_meta( $term_id, $this->categories_field, true );
if ( ! empty( $this->get_all_diff( 'product_cat' ) ) ) {
$this->maybe_sync_product_set( $term_id );
}
}
/**
* Check if must sync Product Set from FB when removing Product Cat
*
* @since 2.3.0
*
* @param int $term_id Product Cat Term ID.
*/
public function maybe_sync_product_set_on_product_cat_remove( $term_id ) {
$product_sets = $this->get_product_cat_sets( $term_id );
if ( empty( $product_sets ) ) {
return;
}
foreach ( $product_sets as $product_set_id ) {
$this->maybe_sync_product_set( $product_set_id );
}
}
/**
* Call API to remove Product Set from FB
*
* @since 2.3.0
*
* @param int $product_set_term_id Product Set Term ID.
*/
public function sync_remove_product_set( $product_set_term_id, $taxonomy ) {
if ( 'fb_product_set' !== $taxonomy ) {
return;
}
// get product set FB ID
$fb_product_set_id = get_term_meta( $product_set_term_id, \WC_Facebookcommerce_Integration::FB_PRODUCT_SET_ID, true );
if ( empty( $fb_product_set_id ) ) {
return;
}
do_action( 'fb_wc_product_set_delete', $fb_product_set_id );
}
/** Utility methods *******************************************************************************************/
/**
* Maybe sync product set
*
* @since 2.3.0
*
* @param int $product_set_id Facebook Product Set Term ID.
*/
public function maybe_sync_product_set( $product_set_id ) {
// get Product Set
$term = get_term( $product_set_id );
if ( empty( $term ) ) {
return;
}
// get categories
$product_cat_ids = get_term_meta( $product_set_id, $this->categories_field, true );
// get products for the taxonomies
$products = array();
$products_args = array(
'fields' => 'ids',
'post_type' => 'product',
'post_status' => 'publish',
'posts_per_page' => -1,
'tax_query' => array(
'relation' => 'OR',
array(
'taxonomy' => 'fb_product_set',
'field' => 'term_taxonomy_id',
'terms' => array( $product_set_id ),
'operator' => 'IN',
),
array(
'taxonomy' => 'product_cat',
'field' => 'term_taxonomy_id',
'terms' => $product_cat_ids,
'operator' => 'IN',
),
),
);
$product_ids = get_posts( $products_args );
// Removes the Product Set if it doesn't have products.
if ( empty( $product_ids ) ) {
$fb_product_set_id = get_term_meta( $product_set_id, \WC_Facebookcommerce_Integration::FB_PRODUCT_SET_ID, true );
update_term_meta( $product_set_id, \WC_Facebookcommerce_Integration::FB_PRODUCT_SET_ID, '' );
do_action( 'fb_wc_product_set_delete', $fb_product_set_id );
return;
}
// gets products variations
global $wpdb;
$sql = sprintf(
"SELECT ID FROM $wpdb->posts WHERE post_type = 'product_variation' AND post_parent IN (%s) ",
implode( ', ', array_map( 'intval', $product_ids ) )
);
$variation_ids = $wpdb->get_results( $sql );
if ( ! empty( $variation_ids ) ) {
// product_variations: add retailer id to the products filter
foreach ( $variation_ids as $variation_id ) {
$product = new \WC_Product_Variation( $variation_id->ID );
$fb_retailer_id = \WC_Facebookcommerce_Utils::get_fb_retailer_id( $product );
array_push(
$products,
array( 'retailer_id' => array( 'eq' => $fb_retailer_id ) )
);
}
}
// products: add retailer id to the products filter
foreach ( $product_ids as $product_id ) {
$product = new \WC_Product( $product_id );
$fb_retailer_id = \WC_Facebookcommerce_Utils::get_fb_retailer_id( $product );
array_push(
$products,
array( 'retailer_id' => array( 'eq' => $fb_retailer_id ) )
);
}
$data = array(
'name' => $term->name,
'filter' => wp_json_encode( array( 'or' => $products ) ),
'metadata' => wp_json_encode( array( 'description' => $term->description ) ),
);
do_action( 'fb_wc_product_set_sync', $data, $product_set_id );
}
/**
* Return the list of product sets of a given product category term
*
* @since 2.3.0
*
* @param string $product_cat_id product cat Term ID.
*
* @return array
*/
protected function get_product_cat_sets( $product_cat_id ) {
$args = array(
'fields' => 'ids',
'taxonomy' => 'fb_product_set',
'hide_empty' => false,
'meta_query' => array(
array(
'key' => \WC_Facebookcommerce::PRODUCT_SET_META,
'value' => sprintf( ':%d;', $product_cat_id ),
'compare' => 'LIKE',
),
),
);
return get_terms( $args );
}
/**
* Return the list of differences between two list of terms
*
* @since 2.3.0
*
* @param string $taxonomy Taxonomy slug.
*
* @return array
*/
protected function get_all_diff( $taxonomy = 'product_cat' ) {
$prev = empty( self::${ 'prev_' . $taxonomy } ) ? array() : self::${ 'prev_' . $taxonomy };
$new = empty( self::${ 'new_' . $taxonomy } ) ? array() : self::${ 'new_' . $taxonomy };
$removed = array_diff( $prev, $new );
$added = array_diff( $new, $prev );
return array_merge( $removed, $added );
}
}