wishlist = (array) $wishlist; $this->_name = $plugin_name; $this->table = sprintf( '%s%s_%s', $wpdb->prefix, $this->_name, 'items' ); $this->user = $this->wishlist_author(); if ( empty( $this->user ) ) { $user = wp_get_current_user(); if ( $user->exists() ) { $this->user = $user->ID; } } add_filter( 'tinvwl_addtowishlist_add_form', array( $this, 'clean_meta' ), 10, 1 ); } /** * Get wishlist id * * @return int */ function wishlist_id() { if ( is_array( $this->wishlist ) && array_key_exists( 'ID', $this->wishlist ) ) { return $this->wishlist['ID']; } return 0; } /** * Get author wishlist * * @return int */ function wishlist_author() { if ( is_array( $this->wishlist ) && array_key_exists( 'author', $this->wishlist ) ) { return $this->wishlist['author']; } return 0; } /** * Add\Update product * * @param array $data Object product. * @param array $meta Object meta form data. * * @return boolean */ function add_product( $data = array(), $meta = array() ) { $_data = filter_var_array( $data, array( 'product_id' => FILTER_VALIDATE_INT, 'variation_id' => FILTER_VALIDATE_INT, 'wishlist_id' => FILTER_VALIDATE_INT, 'quantity' => FILTER_VALIDATE_INT, ) ); if ( empty( $_data['quantity'] ) ) { $_data['quantity'] = 1; } if ( empty( $_data['wishlist_id'] ) ) { $_data['wishlist_id'] = $this->wishlist_id(); } $product_data = $this->check_product( $_data['product_id'], $_data['variation_id'], $_data['wishlist_id'], $meta ); if ( false === $product_data ) { return false; } if ( $product_data ) { return $this->update( $data, $meta, $product_data['ID'] ); } else { return $this->add( $data, $meta ); } } /** * Add product * * @param array $data Object product. * @param array $meta Object meta form data. * * @return boolean * @global wpdb $wpdb * */ function add( $data = array(), $meta = array() ) { $default = array( 'wishlist_id' => $this->wishlist_id(), 'product_id' => 0, 'variation_id' => 0, 'formdata' => '', 'author' => $this->user, 'date' => current_time( 'Y-m-d H:i:s' ), 'quantity' => 1, 'price' => 0, 'in_stock' => 1, ); $data = apply_filters( 'tinvwl_wishlist_product_add_field', filter_var_array( $data, array( 'author' => FILTER_VALIDATE_INT, 'product_id' => FILTER_VALIDATE_INT, 'quantity' => FILTER_VALIDATE_INT, 'variation_id' => FILTER_VALIDATE_INT, 'wishlist_id' => FILTER_VALIDATE_INT, ) ) ); $data = array_filter( $data ); $data = tinv_array_merge( $default, $data ); if ( empty( $data['wishlist_id'] ) || empty( $data['product_id'] ) ) { return false; } $product_data = $this->product_data( $data['product_id'], $data['variation_id'] ); if ( $data['quantity'] <= 0 || ! $product_data ) { return false; } if ( $product_data->is_sold_individually() ) { $data['quantity'] = 1; } $data = apply_filters( 'tinvwl_wishlist_product_add', $data ); $data['in_stock'] = $product_data->is_in_stock(); $data['formdata'] = $this->prepare_save_meta( $meta, $data['product_id'], $data['variation_id'] ); if ( $product_data->is_type( 'variable' ) ) { $data['price'] = filter_var( $product_data->get_variation_price( 'max', false ), FILTER_VALIDATE_FLOAT ); } else { $data['price'] = filter_var( ( $product_data->get_price() ), FILTER_VALIDATE_FLOAT ); } global $wpdb; if ( $wpdb->insert( $this->table, $data ) ) { // @codingStandardsIgnoreLine WordPress.VIP.DirectDatabaseQuery.DirectQuery $id = $wpdb->insert_id; /* Run a 3rd party code when product added to a wishlist. * * @param array $data product data including author and wishlist IDs. * */ do_action( 'tinvwl_product_added', $data ); $wla = new TInvWL_Analytics( $this->wishlist ); $wla->cart_product( $data['product_id'], $data['variation_id'] ); return $id; } return false; } /** * Get products by wishlist * * @param array $data Request. * * @return array */ function get_wishlist( $data = array(), $count = false ) { if ( ! array_key_exists( 'wishlist_id', $data ) ) { $data['wishlist_id'] = $this->wishlist_id(); } if ( empty( $data['wishlist_id'] ) ) { return array(); } return $this->get( $data, $count ); } /** * Check existing product * * @param integer $product_id Product id. * @param integer $variation_id Product variaton id. * @param integer $wishlist_id If exist wishlist object, you can put 0. * @param array $meta Object meta form data. * * @return mixed */ function check_product( $product_id, $variation_id = 0, $wishlist_id = 0, $meta = array() ) { $product_id = absint( $product_id ); $variation_id = absint( $variation_id ); $wishlist_id = absint( $wishlist_id ); if ( empty( $wishlist_id ) ) { $wishlist_id = $this->wishlist_id(); } if ( empty( $wishlist_id ) || empty( $product_id ) ) { return false; } $product_data = $this->product_data( $product_id, $variation_id ); if ( ! $product_data ) { return false; } $product_id = $product_data->is_type( 'variation' ) ? $product_data->get_parent_id() : $product_data->get_id(); $variation_id = $product_data->is_type( 'variation' ) ? $product_data->get_id() : 0; $products = $this->get( array( 'product_id' => $product_id, 'variation_id' => $variation_id, 'wishlist_id' => $wishlist_id, 'formdata' => $this->prepare_save_meta( $meta, $product_id, $variation_id ), 'count' => 1, 'external' => false, ) ); return array_shift( $products ); } /** * Get products * * @param array $data Request. * @param bool $count COUNT QUERY. * * @return array * @global wpdb $wpdb * */ function get( $data = array(), $count = false ) { global $wpdb; $default = array( 'count' => 10, 'field' => null, 'offset' => 0, 'order' => 'DESC', 'order_by' => 'date', 'external' => true, 'sql' => '', ); foreach ( $default as $_k => $_v ) { if ( array_key_exists( $_k, $data ) ) { $default[ $_k ] = $data[ $_k ]; unset( $data[ $_k ] ); } } $default['offset'] = absint( $default['offset'] ); $default['count'] = absint( $default['count'] ); if ( is_array( $default['field'] ) ) { $default['field'] = '`' . implode( '`,`', $default['field'] ) . '`'; } elseif ( is_string( $default['field'] ) ) { $default['field'] = array( 'ID', $default['field'] ); $default['field'] = '`' . implode( '`,`', $default['field'] ) . '`'; } else { $default['field'] = '*'; } if ( $count ) { $default['field'] = 'COUNT(`ID`) as `count`'; } $sql = "SELECT {$default[ 'field' ]} FROM `{$this->table}`"; $where = '1'; if ( ! empty( $data ) && is_array( $data ) ) { if ( array_key_exists( 'meta', $data ) ) { unset( $data['meta'] ); } foreach ( $data as $f => $v ) { $s = is_array( $v ) ? ' IN ' : '='; if ( is_array( $v ) ) { foreach ( $v as $_f => $_v ) { $v[ $_f ] = $wpdb->prepare( '%s', $_v ); } $v = implode( ',', $v ); $v = "($v)"; } else { $v = $wpdb->prepare( '%s', $v ); } $data[ $f ] = sprintf( '`%s`%s%s', $f, $s, $v ); } $where = implode( ' AND ', $data ); $sql .= ' WHERE ' . $where; } $sql .= sprintf( ' ORDER BY `%s` %s LIMIT %d,%d;', $default['order_by'], $default['order'], $default['offset'], $default['count'] ); if ( ! empty( $default['sql'] ) ) { $replacer = $replace = array(); $replace[0] = '{table}'; $replacer[0] = $this->table; $replace[1] = '{where}'; $replacer[1] = $where; foreach ( $default as $key => $value ) { $i = count( $replace ); $replace[ $i ] = '{' . $key . '}'; $replacer[ $i ] = $value; } $sql = str_replace( $replace, $replacer, $default['sql'] ); } $products = $wpdb->get_results( $sql, ARRAY_A ); // WPCS: db call ok; no-cache ok; unprepared SQL ok. if ( empty( $products ) || is_wp_error( $products ) ) { return array(); } if ( $count ) { return $products[0]['count']; } $ids = array(); foreach ( $products as $k => $product ) { if ( empty( $default['sql'] ) ) { $product = filter_var_array( $product, array( 'ID' => FILTER_VALIDATE_INT, 'wishlist_id' => FILTER_VALIDATE_INT, 'product_id' => FILTER_VALIDATE_INT, 'variation_id' => FILTER_VALIDATE_INT, 'author' => FILTER_VALIDATE_INT, 'date' => FILTER_DEFAULT, 'formdata' => FILTER_DEFAULT, 'quantity' => FILTER_VALIDATE_INT, 'price' => FILTER_SANITIZE_NUMBER_FLOAT | FILTER_FLAG_ALLOW_FRACTION, 'in_stock' => FILTER_VALIDATE_BOOLEAN, ) ); $product['quantity'] = 1; } if ( $default['external'] ) { if ( isset( $product['product_id'] ) ) { $ids[] = ( apply_filters( 'wpml_object_id', $product['product_id'], 'product', false ) ) ? apply_filters( 'wpml_object_id', $product['product_id'], 'product', false ) : $product['product_id']; } } $product['meta'] = array(); if ( array_key_exists( 'formdata', $product ) ) { $meta = $product['formdata']; unset( $product['formdata'] ); $product['meta'] = $this->prepare_retrun_meta( $meta, $product['product_id'], $product['variation_id'], $product['quantity'] ); } $products[ $k ] = apply_filters( 'tinvwl_wishlist_product_get', $product ); } if ( ! empty( $ids ) ) { $args = array( 'include' => $ids, 'limit' => count( $ids ), ); $_products = wc_get_products( $args ); foreach ( $_products as $_product ) { foreach ( $products as $key => $wlproduct ) { if ( ! isset( $wlproduct['product_id'] ) ) { continue; } if ( $_product->get_id() === absint( ( apply_filters( 'wpml_object_id', $wlproduct['product_id'], 'product', false ) ) ? apply_filters( 'wpml_object_id', $wlproduct['product_id'], 'product', false ) : $wlproduct['product_id'] ) ) { if ( in_array( $_product->get_type(), array( 'variable', 'grouped' ) ) ) { $use_original_id = false; if ( function_exists( 'pll_is_translated_post_type' ) ) { $use_original_id = true; } if ( function_exists( 'wpml_get_current_language' ) ) { global $sitepress; if ( $sitepress && $sitepress instanceof SitePress ) { $wpml_settings = $sitepress->get_settings(); if ( isset( $wpml_settings['custom_posts_sync_option'] ) && isset( $wpml_settings['custom_posts_sync_option']['product_variation'] ) && in_array( $wpml_settings['custom_posts_sync_option']['product_variation'], array( 1, 2, ) ) ) { $use_original_id = true; } } } $products[ $key ]['data'] = $wlproduct['variation_id'] ? wc_get_product( apply_filters( 'wpml_object_id', $wlproduct['variation_id'], 'product_variation', $use_original_id ) ) : $_product; } else { $products[ $key ]['data'] = $_product; } } } } // remove deleted products from database if ( $default['external'] && ! function_exists( 'wpml_get_current_language' ) ) { foreach ( $products as $key => $product ) { if ( empty( $product['data'] ) ) { unset( $products[ $key ] ); $this->remove( $product ); } } } } // Filter wishlist products $products = apply_filters( 'tinvwl_wishlist_get_products', $products, $this ); return $products; } /** * Get product info * * @param integer $product_id Product id. * @param integer $variation_id Product variation id. * * @return mixed */ function product_data( $product_id, $variation_id = 0 ) { $product_id = absint( $product_id ); $variation_id = absint( $variation_id ); $product_data = apply_filters( 'tinvwl_product_data', wc_get_product( $variation_id ? $variation_id : $product_id ), $product_id, $variation_id ); if ( ! $product_data || 'trash' === get_post( $product_data->get_id() )->post_status ) { return null; } $product_data->variation_id = absint( ( $product_data->is_type( 'variation' ) ? $product_data->get_id() : 0 ) ); return $product_data; } /** * Update product * * @param array $data Object product. * @param array $meta Object meta form data. * @param int $id Wishlist item ID. * * @return boolean * @global wpdb $wpdb * */ function update( $data = array(), $meta = array(), $id = 0 ) { if ( empty( $meta ) && array_key_exists( 'meta', $data ) && ! empty( $data['meta'] ) ) { $meta = $data['meta']; } $data = filter_var_array( $data, apply_filters( 'tinvwl_wishlist_product_update_field', array( 'product_id' => FILTER_VALIDATE_INT, 'quantity' => FILTER_VALIDATE_INT, 'variation_id' => FILTER_VALIDATE_INT, 'wishlist_id' => FILTER_VALIDATE_INT, 'author' => FILTER_VALIDATE_INT, ) ) ); $data = array_filter( $data ); if ( ! array_key_exists( 'wishlist_id', $data ) ) { $data['wishlist_id'] = $this->wishlist_id(); } if ( ! array_key_exists( 'variation_id', $data ) ) { $data['variation_id'] = 0; } if ( empty( $data['wishlist_id'] ) || empty( $data['product_id'] ) ) { return false; } $product_data = $this->product_data( $data['product_id'], $data['variation_id'] ); if ( ! $product_data ) { return false; } if ( $product_data->is_sold_individually() ) { $data['quantity'] = 1; } $data = apply_filters( 'tinvwl_wishlist_product_update', $data ); $data['in_stock'] = $product_data->is_in_stock(); if ( $product_data->is_type( 'variable' ) ) { $data['price'] = filter_var( $product_data->get_variation_price( 'max', false ), FILTER_VALIDATE_FLOAT ); } else { $data['price'] = filter_var( $product_data->get_price(), FILTER_VALIDATE_FLOAT ); } global $wpdb; $res_update = $wpdb->update( $this->table, $data, array( 'product_id' => $data['product_id'], 'variation_id' => $data['variation_id'], 'wishlist_id' => $data['wishlist_id'], 'formdata' => $this->prepare_save_meta( $meta, $data['product_id'], $data['variation_id'] ), ) ); if ( $res_update !== false ) { // @codingStandardsIgnoreLine WordPress.VIP.DirectDatabaseQuery.DirectQuery /* Run a 3rd party code when product updated on a wishlist. * * @param array $data product data including author and wishlist IDs. * */ do_action( 'tinvwl_product_updated', $data ); return ( $id ) ? $id : true; } return false; } /** * Remove product from wishlist. * * @param int $wishlist_id If exist wishlist object, you can put 0. * @param int $product_id Product ID. * @param int $variation_id Product variation ID. * @param array $meta Object meta form data. * * @return bool */ function remove_product_from_wl( int $wishlist_id = 0, int $product_id = 0, int $variation_id = 0, array $meta = [] ): bool { global $wpdb; if ( empty( $wishlist_id ) ) { $wishlist_id = $this->wishlist_id(); } if ( empty( $wishlist_id ) ) { return false; } if ( empty( $product_id ) ) { return false !== $wpdb->delete( $this->table, [ 'wishlist_id' => $wishlist_id ] ); // WPCS: db call ok; no-cache ok; unprepared SQL ok. } $original_meta = $meta; if ( ! empty( $meta ) && array_key_exists( 'tinvwl-hidden-fields', $meta ) ) { unset( $meta['tinvwl-hidden-fields'] ); } $data = [ 'wishlist_id' => $wishlist_id, 'product_id' => $product_id, 'variation_id' => $variation_id, ]; $data['formdata'] = $this->prepare_save_meta( $meta, $data['product_id'], $data['variation_id'] ); $data['original_meta'] = $this->prepare_save_meta( $original_meta, $data['product_id'], $data['variation_id'] ); $sql = "DELETE FROM $this->table WHERE `wishlist_id` = %d AND `product_id` = %d AND `variation_id` = %d"; $args = [ $data['wishlist_id'], $data['product_id'], $data['variation_id'] ]; if ( ! empty( $meta ) ) { $sql .= " AND (`formdata` = %s OR `formdata` = %s OR `formdata` = %s OR `formdata` = %s)"; $args[] = $data['formdata']; $args[] = $data['original_meta']; $args[] = '{"tinvwl-hidden-fields":"[]"}'; $args[] = ''; } $prepared_sql = $wpdb->prepare( $sql, $args ); $result = $wpdb->query( $prepared_sql ); if ( $result ) { do_action( 'tinvwl_wishlist_product_removed_from_wishlist', $wishlist_id, $product_id, $variation_id ); } return (bool) $result; } /** * Remove product * * @param integer $product_id Product id. * * @return boolean * @global wpdb $wpdb * */ function remove_product( $product_id = 0 ) { if ( empty( $product_id ) ) { return false; } global $wpdb; $result = false !== $wpdb->delete( $this->table, array( 'product_id' => $product_id ) ); // WPCS: db call ok; no-cache ok; unprepared SQL ok. if ( $result ) { do_action( 'tinvwl_wishlist_product_removed_by_product', $product_id ); } return $result; } /** * Get wishlist data by product from wishlist * * @param integer $product_id Product id. * * @return bool|array * @global wpdb $wpdb * */ function get_wishlist_by_product_id( $product_id = 0 ) { if ( empty( $product_id ) ) { return false; } global $wpdb; $sql = "SELECT `wishlist_id` FROM `{$this->table}` WHERE `ID`={$product_id}"; $result = $wpdb->get_results( $sql, ARRAY_A ); if ( ! $result ) { return false; } $wl = new TInvWL_Wishlist(); return $wl->get_by_id( $result[0]['wishlist_id'] ); } /** * Remove product by ID * * @param array $data Product data. * * @return boolean * @global wpdb $wpdb * */ function remove( $data ) { if ( ! isset( $data['ID'] ) || empty( $data['ID'] ) ) { return false; } global $wpdb; $result = false !== $wpdb->delete( $this->table, array( 'ID' => $data['ID'] ) ); // WPCS: db call ok; no-cache ok; unprepared SQL ok. if ( $result ) { /* Run a 3rd party code when product removed from a wishlist. * * @param array $data product data including author and wishlist IDs. * */ do_action( 'tinvwl_product_removed', $data ); } return $result; } /** * Clean meta from default values. * * @param array $meta Meta array. * * @return array */ function clean_meta( $meta ) { foreach ( array( 'add-to-cart', 'product_id', 'variation_id', 'quantity', 'undefined', 'product_sku', ) as $field ) { if ( array_key_exists( $field, $meta ) ) { unset( $meta[ $field ] ); } } $meta = array_filter( $meta ); return $meta; } /** * Prepare to save meta in database * * @param array $meta Meta array. * @param int $product_id Woocommerce product ID. * @param int $variation_id Woocommerce product variation ID. * * @return string */ function prepare_save_meta( $meta = array(), $product_id = 0, $variation_id = 0 ) { if ( ! is_array( $meta ) ) { $meta = array(); } $meta = apply_filters( 'tinvwl_product_prepare_meta', $meta, $product_id, $variation_id ); foreach ( array( 'add-to-cart', 'product_id', 'variation_id', 'quantity', 'undefined', 'product_sku', ) as $field ) { if ( array_key_exists( $field, $meta ) ) { unset( $meta[ $field ] ); } } $meta = array_filter( $meta ); if ( empty( $meta ) ) { return ''; } return json_encode( $meta ); } /** * Convert meta string to array * * @param string $meta Meta array. * @param integer $product_id Product ID. * @param integer $variation_id Variation product ID. * @param integer $quantity Quantity product. * * @return array */ function prepare_retrun_meta( $meta = '', $product_id = 0, $variation_id = 0, $quantity = 1 ) { if ( empty( $meta ) ) { return array(); } $meta = @json_decode( $meta, true ); if ( empty( $meta ) || ! is_array( $meta ) ) { return array(); } if ( ! empty( $product_id ) ) { $meta['add-to-cart'] = $product_id; $meta['product_id'] = $product_id; $meta['quantity'] = $quantity; if ( ! empty( $variation_id ) ) { $meta['variation_id'] = $variation_id; } } return apply_filters( 'tinvwl_wishlist_product_unprepare_meta', $meta ); } }