get_transient_version() 공개 정적인 메소드

When using transients with unpredictable names, e.g. those containing an md5. hash in the name, we need a way to invalidate them all at once. When using default WP transients we're able to do this with a DB query to. delete transients manually. With external cache however, this isn't possible. Instead, this function is used. to append a unique string (based on time()) to each transient. When transients. are invalidated, the transient version will increment and data will be regenerated. Raised in issue https://github.com/woocommerce/woocommerce/issues/5777. Adapted from ideas in http://tollmanz.com/invalidation-schemes/.
public static get_transient_version ( string $group, boolean $refresh = false ) : string
$group string Name for the group of transients we need to invalidate
$refresh boolean true to force a new version
리턴 string transient version based on time(), 10 digits
예제 #1
0
 /**
  * Clear the product/shop transients cache.
  *
  * ## EXAMPLES
  *
  *     wp wc tool clear_transients
  *
  * @since 2.5.0
  */
 public function clear_transients($args, $assoc_args)
 {
     wc_delete_product_transients();
     wc_delete_shop_order_transients();
     WC_Cache_Helper::get_transient_version('shipping', true);
     WP_CLI::success('Product transients and shop order transients were cleared.');
 }
 /**
  * Delete the simple flat rate.
  *
  * @since 2.3
  */
 public static function delete_simple_flat_rate()
 {
     delete_option('woocommerce_flat_rate_settings');
     delete_option('woocommerce_flat_rate');
     WC_Cache_Helper::get_transient_version('shipping', true);
     WC()->shipping->unregister_shipping_methods();
 }
 /**
  * Cancel a booking.
  */
 public static function cancel_booking()
 {
     if (isset($_GET['cancel_booking']) && isset($_GET['booking_id'])) {
         $booking_id = absint($_GET['booking_id']);
         $booking = get_wc_booking($booking_id);
         $booking_can_cancel = $booking->has_status(apply_filters('woocommerce_valid_booking_statuses_for_cancel', array('unpaid', 'pending-confirmation', 'confirmed', 'paid')));
         $redirect = $_GET['redirect'];
         if ($booking->has_status('cancelled')) {
             // Already cancelled - take no action
         } elseif ($booking_can_cancel && $booking->id == $booking_id && isset($_GET['_wpnonce']) && wp_verify_nonce($_GET['_wpnonce'], 'woocommerce-bookings-cancel_booking')) {
             // Cancel the booking
             $booking->update_status('cancelled');
             WC_Cache_Helper::get_transient_version('bookings', true);
             // Message
             wc_add_notice(apply_filters('woocommerce_booking_cancelled_notice', __('Your booking was cancelled.', 'woocommerce-bookings')), apply_filters('woocommerce_booking_cancelled_notice_type', 'notice'));
             do_action('woocommerce_bookings_cancelled_booking', $booking->id);
         } elseif (!$booking_can_cancel) {
             wc_add_notice(__('Your booking can no longer be cancelled. Please contact us if you need assistance.', 'woocommerce-bookings'), 'error');
         } else {
             wc_add_notice(__('Invalid booking.', 'woocommerce-bookings'), 'error');
         }
         if ($redirect) {
             wp_safe_redirect($redirect);
             exit;
         }
     }
 }
예제 #4
0
 /**
  * Delete product view transients when needed e.g. when post status changes, or visibility/stock status is modified.
  */
 public static function delete_product_query_transients()
 {
     // Increments the transient version to invalidate cache
     WC_Cache_Helper::get_transient_version('product_query', true);
     // If not using an external caching system, we can clear the transients out manually and avoid filling our DB
     if (!wp_using_ext_object_cache()) {
         global $wpdb;
         $wpdb->query("\n\t\t\t\tDELETE FROM `{$wpdb->options}`\n\t\t\t\tWHERE `option_name` LIKE ('\\_transient\\_wc\\_uf\\_pid\\_%')\n\t\t\t\tOR `option_name` LIKE ('\\_transient\\_timeout\\_wc\\_uf\\_pid\\_%')\n\t\t\t\tOR `option_name` LIKE ('\\_transient\\_wc\\_products\\_will\\_display\\_%')\n\t\t\t\tOR `option_name` LIKE ('\\_transient\\_timeout\\_wc\\_products\\_will\\_display\\_%')\n\t\t\t");
     }
 }
    /**
     * Loop over found products.
     * @param  array $query_args
     * @param  array $atts
     * @param  string $loop_name
     * @return string
     */
    private static function product_loop($query_args, $atts, $loop_name)
    {
        global $woocommerce_loop;
        $columns = absint($atts['columns']);
        $woocommerce_loop['columns'] = $columns;
        $woocommerce_loop['name'] = $loop_name;
        $transient_name = 'wc_loop' . substr(md5(json_encode($query_args) . $loop_name), 28) . WC_Cache_Helper::get_transient_version('product_query');
        $products = get_transient($transient_name);
        if (false === $products || !is_a($products, 'WP_Query')) {
            $products = new WP_Query(apply_filters('woocommerce_shortcode_products_query', $query_args, $atts, $loop_name));
            set_transient($transient_name, $products, DAY_IN_SECONDS * 30);
        }
        ob_start();
        if ($products->have_posts()) {
            ?>

			<?php 
            do_action("woocommerce_shortcode_before_{$loop_name}_loop", $atts);
            ?>

			<?php 
            woocommerce_product_loop_start();
            ?>

				<?php 
            while ($products->have_posts()) {
                $products->the_post();
                ?>

					<?php 
                wc_get_template_part('content', 'product');
                ?>

				<?php 
            }
            // end of the loop.
            ?>

			<?php 
            woocommerce_product_loop_end();
            ?>

			<?php 
            do_action("woocommerce_shortcode_after_{$loop_name}_loop", $atts);
            ?>

			<?php 
        } else {
            do_action("woocommerce_shortcode_{$loop_name}_loop_no_results", $atts);
        }
        woocommerce_reset_loop();
        wp_reset_postdata();
        return '<div class="woocommerce columns-' . $columns . '">' . ob_get_clean() . '</div>';
    }
 /**
  * Update zone in the database.
  *
  * @since 2.7.0
  * @param WC_Shipping_Zone
  */
 public function update(&$zone)
 {
     global $wpdb;
     if ($zone->get_id()) {
         $wpdb->update($wpdb->prefix . 'woocommerce_shipping_zones', array('zone_name' => $zone->get_zone_name(), 'zone_order' => $zone->get_zone_order()), array('zone_id' => $zone->get_id()));
     }
     $zone->save_meta_data();
     $this->save_locations($zone);
     $zone->apply_changes();
     WC_Cache_Helper::incr_cache_prefix('shipping_zones');
     WC_Cache_Helper::get_transient_version('shipping', true);
 }
 /**
  * Gets bookings for product ids and resource ids
  * @param  array  $ids
  * @param  array  $status
  * @return array of WC_Booking objects
  */
 public static function get_bookings_for_objects($ids = array(), $status = array('confirmed', 'paid'))
 {
     $transient_name = 'book_fo_' . md5(http_build_query(array($ids, $status, WC_Cache_Helper::get_transient_version('bookings'))));
     if (false === ($booking_ids = get_transient($transient_name))) {
         $booking_ids = self::get_bookings_for_objects_query($ids, $status);
         set_transient($transient_name, $booking_ids, DAY_IN_SECONDS * 30);
     }
     $bookings = array();
     foreach ($booking_ids as $booking_id) {
         $bookings[] = get_wc_booking($booking_id);
     }
     return $bookings;
 }
예제 #8
0
 /**
  * Return the products children posts.
  *
  * @access public
  * @return array
  */
 public function get_children()
 {
     if (!is_array($this->children) || empty($this->children)) {
         $transient_name = 'wc_product_children_ids_' . $this->id . WC_Cache_Helper::get_transient_version('product');
         $this->children = get_transient($transient_name);
         if (empty($this->children)) {
             $args = apply_filters('woocommerce_grouped_children_args', array('post_parent' => $this->id, 'post_type' => 'product', 'orderby' => 'menu_order', 'order' => 'ASC', 'fields' => 'ids', 'post_status' => 'publish', 'numberposts' => -1));
             $this->children = get_posts($args);
             set_transient($transient_name, $this->children, YEAR_IN_SECONDS);
         }
     }
     return (array) $this->children;
 }
 /**
  * Get total stock.
  *
  * This is the stock of parent and children combined.
  *
  * @access public
  * @return int
  */
 public function get_total_stock()
 {
     if (empty($this->total_stock)) {
         $transient_name = 'wc_product_total_stock_' . $this->id . WC_Cache_Helper::get_transient_version('product');
         if (false === ($this->total_stock = get_transient($transient_name))) {
             $this->total_stock = $this->stock;
             if (sizeof($this->get_children()) > 0) {
                 foreach ($this->get_children() as $child_id) {
                     $stock = get_post_meta($child_id, '_stock', true);
                     if ($stock != '') {
                         $this->total_stock += wc_stock_amount($stock);
                     }
                 }
             }
             set_transient($transient_name, $this->total_stock, DAY_IN_SECONDS * 30);
         }
     }
     return wc_stock_amount($this->total_stock);
 }
예제 #10
0
 /**
  * Returns array that conintains ids of related tours.
  *
  * @param  int   $limit
  * @return array
  */
 public function get_related($limit = 5)
 {
     $transient_name = 'wc_related_' . $limit . '_' . $this->id . WC_Cache_Helper::get_transient_version('product');
     if (false === ($related_posts = get_transient($transient_name))) {
         global $wpdb;
         // Related products are found from category and tag
         $tags_array = $this->get_related_terms('product_tag');
         $tour_cats_array = $this->get_related_terms('tour_category');
         // Don't bother if none are set
         if (sizeof($tour_cats_array) == 1 && sizeof($tags_array) == 1) {
             $related_posts = array();
         } else {
             // Sanitize
             $exclude_ids = array_map('absint', array_merge(array(0, $this->id), $this->get_upsells()));
             // Generate query
             $query = $this->build_related_tours_query($tour_cats_array, $tags_array, $exclude_ids, $limit);
             // Get the posts
             $related_posts = $wpdb->get_col(implode(' ', $query));
         }
         set_transient($transient_name, $related_posts, DAY_IN_SECONDS * 30);
     }
     shuffle($related_posts);
     return $related_posts;
 }
 /**
  * Get an array of all sale and regular prices from all variations. This is used for example when displaying the price range at variable product level or seeing if the variable product is on sale.
  *
  * Can be filtered by plugins which modify costs, but otherwise will include the raw meta costs unlike get_price() which runs costs through the woocommerce_get_price filter.
  * This is to ensure modified prices are not cached, unless intended.
  *
  * @since  2.7.0
  * @param  WC_Product
  * @param  bool $include_taxes If taxes should be calculated or not.
  */
 private function read_price_data(&$product, $include_taxes = false)
 {
     global $wp_filter;
     /**
      * Transient name for storing prices for this product (note: Max transient length is 45)
      * @since 2.5.0 a single transient is used per product for all prices, rather than many transients per product.
      */
     $transient_name = 'wc_var_prices_' . $product->get_id();
     /**
      * Create unique cache key based on the tax location (affects displayed/cached prices), product version and active price filters.
      * DEVELOPERS should filter this hash if offering conditonal pricing to keep it unique.
      * @var string
      */
     $price_hash = $include_taxes ? array(get_option('woocommerce_tax_display_shop', 'excl'), WC_Tax::get_rates()) : array(false);
     $filter_names = array('woocommerce_variation_prices_price', 'woocommerce_variation_prices_regular_price', 'woocommerce_variation_prices_sale_price');
     foreach ($filter_names as $filter_name) {
         if (!empty($wp_filter[$filter_name])) {
             $price_hash[$filter_name] = array();
             foreach ($wp_filter[$filter_name] as $priority => $callbacks) {
                 $price_hash[$filter_name][] = array_values(wp_list_pluck($callbacks, 'function'));
             }
         }
     }
     $price_hash[] = WC_Cache_Helper::get_transient_version('product');
     $price_hash = md5(json_encode(apply_filters('woocommerce_get_variation_prices_hash', $price_hash, $product, $include_taxes)));
     /**
      * $this->prices_array is an array of values which may have been modified from what is stored in transients - this may not match $transient_cached_prices_array.
      * If the value has already been generated, we don't need to grab the values again so just return them. They are already filtered.
      */
     if (!empty($this->prices_array[$price_hash])) {
         if ($include_taxes) {
             $product->set_variation_prices_including_taxes($this->prices_array[$price_hash]);
         } else {
             $product->set_variation_prices($this->prices_array[$price_hash]);
         }
         /**
          * No locally cached value? Get the data from the transient or generate it.
          */
     } else {
         // Get value of transient
         $transient_cached_prices_array = array_filter((array) json_decode(strval(get_transient($transient_name)), true));
         // If the product version has changed since the transient was last saved, reset the transient cache.
         if (empty($transient_cached_prices_array['version']) || WC_Cache_Helper::get_transient_version('product') !== $transient_cached_prices_array['version']) {
             $transient_cached_prices_array = array('version' => WC_Cache_Helper::get_transient_version('product'));
         }
         // If the prices are not stored for this hash, generate them and add to the transient.
         if (empty($transient_cached_prices_array[$price_hash])) {
             $prices = array();
             $regular_prices = array();
             $sale_prices = array();
             $variation_ids = $product->get_visible_children();
             foreach ($variation_ids as $variation_id) {
                 if ($variation = wc_get_product($variation_id)) {
                     $price = apply_filters('woocommerce_variation_prices_price', $variation->get_price('edit'), $variation, $product);
                     $regular_price = apply_filters('woocommerce_variation_prices_regular_price', $variation->get_regular_price('edit'), $variation, $product);
                     $sale_price = apply_filters('woocommerce_variation_prices_sale_price', $variation->get_sale_price('edit'), $variation, $product);
                     // Skip empty prices
                     if ('' === $price) {
                         continue;
                     }
                     // If sale price does not equal price, the product is not yet on sale
                     if ($sale_price === $regular_price || $sale_price !== $price) {
                         $sale_price = $regular_price;
                     }
                     // If we are getting prices for display, we need to account for taxes
                     if ($include_taxes) {
                         if ('incl' === get_option('woocommerce_tax_display_shop')) {
                             $price = '' === $price ? '' : wc_get_price_including_tax($variation, array('qty' => 1, 'price' => $price));
                             $regular_price = '' === $regular_price ? '' : wc_get_price_including_tax($variation, array('qty' => 1, 'price' => $regular_price));
                             $sale_price = '' === $sale_price ? '' : wc_get_price_including_tax($variation, array('qty' => 1, 'price' => $sale_price));
                         } else {
                             $price = '' === $price ? '' : wc_get_price_excluding_tax($variation, array('qty' => 1, 'price' => $price));
                             $regular_price = '' === $regular_price ? '' : wc_get_price_excluding_tax($variation, array('qty' => 1, 'price' => $regular_price));
                             $sale_price = '' === $sale_price ? '' : wc_get_price_excluding_tax($variation, array('qty' => 1, 'price' => $sale_price));
                         }
                     }
                     $prices[$variation_id] = wc_format_decimal($price, wc_get_price_decimals());
                     $regular_prices[$variation_id] = wc_format_decimal($regular_price, wc_get_price_decimals());
                     $sale_prices[$variation_id] = wc_format_decimal($sale_price . '.00', wc_get_price_decimals());
                 }
             }
             asort($prices);
             asort($regular_prices);
             asort($sale_prices);
             $transient_cached_prices_array[$price_hash] = array('price' => $prices, 'regular_price' => $regular_prices, 'sale_price' => $sale_prices);
             set_transient($transient_name, json_encode($transient_cached_prices_array), DAY_IN_SECONDS * 30);
         }
         /**
          * Give plugins one last chance to filter the variation prices array which has been generated and store locally to the class.
          * This value may differ from the transient cache. It is filtered once before storing locally.
          */
         $this->prices_array[$price_hash] = apply_filters('woocommerce_variation_prices', $transient_cached_prices_array[$price_hash], $product, $include_taxes);
         if ($include_taxes) {
             $product->set_variation_prices_including_taxes($this->prices_array[$price_hash]);
         } else {
             $product->set_variation_prices($this->prices_array[$price_hash]);
         }
     }
 }
예제 #12
0
/**
 * Function which handles the start and end of scheduled sales via cron.
 *
 * @access public
 */
function wc_scheduled_sales()
{
    global $wpdb;
    // Sales which are due to start
    $product_ids = $wpdb->get_col($wpdb->prepare("\n\t\tSELECT postmeta.post_id FROM {$wpdb->postmeta} as postmeta\n\t\tLEFT JOIN {$wpdb->postmeta} as postmeta_2 ON postmeta.post_id = postmeta_2.post_id\n\t\tLEFT JOIN {$wpdb->postmeta} as postmeta_3 ON postmeta.post_id = postmeta_3.post_id\n\t\tWHERE postmeta.meta_key = '_sale_price_dates_from'\n\t\tAND postmeta_2.meta_key = '_price'\n\t\tAND postmeta_3.meta_key = '_sale_price'\n\t\tAND postmeta.meta_value > 0\n\t\tAND postmeta.meta_value < %s\n\t\tAND postmeta_2.meta_value != postmeta_3.meta_value\n\t", current_time('timestamp')));
    if ($product_ids) {
        foreach ($product_ids as $product_id) {
            $sale_price = get_post_meta($product_id, '_sale_price', true);
            if ($sale_price) {
                update_post_meta($product_id, '_price', $sale_price);
            } else {
                // No sale price!
                update_post_meta($product_id, '_sale_price_dates_from', '');
                update_post_meta($product_id, '_sale_price_dates_to', '');
            }
            $parent = wp_get_post_parent_id($product_id);
            // Sync parent
            if ($parent) {
                // We can force variable product prices to sync up by removing their min price meta
                delete_post_meta($parent, '_min_price_variation_id');
                // Grouped products need syncing via a function
                $this_product = wc_get_product($product_id);
                if ($this_product->is_type('simple')) {
                    $this_product->grouped_product_sync();
                }
            }
        }
        delete_transient('wc_products_onsale');
    }
    // Sales which are due to end
    $product_ids = $wpdb->get_col($wpdb->prepare("\n\t\tSELECT postmeta.post_id FROM {$wpdb->postmeta} as postmeta\n\t\tLEFT JOIN {$wpdb->postmeta} as postmeta_2 ON postmeta.post_id = postmeta_2.post_id\n\t\tLEFT JOIN {$wpdb->postmeta} as postmeta_3 ON postmeta.post_id = postmeta_3.post_id\n\t\tWHERE postmeta.meta_key = '_sale_price_dates_to'\n\t\tAND postmeta_2.meta_key = '_price'\n\t\tAND postmeta_3.meta_key = '_regular_price'\n\t\tAND postmeta.meta_value > 0\n\t\tAND postmeta.meta_value < %s\n\t\tAND postmeta_2.meta_value != postmeta_3.meta_value\n\t", current_time('timestamp')));
    if ($product_ids) {
        foreach ($product_ids as $product_id) {
            $regular_price = get_post_meta($product_id, '_regular_price', true);
            update_post_meta($product_id, '_price', $regular_price);
            update_post_meta($product_id, '_sale_price', '');
            update_post_meta($product_id, '_sale_price_dates_from', '');
            update_post_meta($product_id, '_sale_price_dates_to', '');
            $parent = wp_get_post_parent_id($product_id);
            // Sync parent
            if ($parent) {
                // Grouped products need syncing via a function
                $this_product = wc_get_product($product_id);
                if ($this_product->is_type('simple')) {
                    $this_product->grouped_product_sync();
                }
            }
        }
        WC_Cache_Helper::get_transient_version('product', true);
        delete_transient('wc_products_onsale');
    }
}
 /**
  * Get an array of all sale and regular prices from all variations. This is used for example when displaying the price range at variable product level or seeing if the variable product is on sale.
  *
  * Can be filtered by plugins which modify costs, but otherwise will include the raw meta costs unlike get_price() which runs costs through the woocommerce_get_price filter.
  * This is to ensure modified prices are not cached, unless intended.
  *
  * @param  bool $display Are prices for display? If so, taxes will be calculated.
  * @return array() Array of RAW prices, regular prices, and sale prices with keys set to variation ID.
  */
 public function get_variation_prices($display = false)
 {
     global $wp_filter;
     /**
      * Transient name for storing prices for this product (note: Max transient length is 45)
      * @since 2.5.0 a single transient is used per product for all prices, rather than many transients per product.
      */
     $transient_name = 'wc_var_prices_' . $this->id;
     /**
      * Create unique cache key based on the tax location (affects displayed/cached prices), product version and active price filters.
      * DEVELOPERS should filter this hash if offering conditonal pricing to keep it unique.
      * @var string
      */
     if ($display) {
         $price_hash = array(get_option('woocommerce_tax_display_shop', 'excl'), WC_Tax::get_rates());
     } else {
         $price_hash = array(false);
     }
     $filter_names = array('woocommerce_variation_prices_price', 'woocommerce_variation_prices_regular_price', 'woocommerce_variation_prices_sale_price');
     foreach ($filter_names as $filter_name) {
         if (!empty($wp_filter[$filter_name])) {
             $price_hash[$filter_name] = array();
             foreach ($wp_filter[$filter_name] as $priority => $callbacks) {
                 $price_hash[$filter_name][] = array_values(wp_list_pluck($callbacks, 'function'));
             }
         }
     }
     $price_hash = md5(json_encode(apply_filters('woocommerce_get_variation_prices_hash', $price_hash, $this, $display)));
     // If the value has already been generated, we don't need to grab the values again.
     if (empty($this->prices_array[$price_hash])) {
         // Get value of transient
         $prices_array = array_filter((array) json_decode(strval(get_transient($transient_name)), true));
         // If the product version has changed, reset cache
         if (empty($prices_array['version']) || $prices_array['version'] !== WC_Cache_Helper::get_transient_version('product')) {
             $this->prices_array = array('version' => WC_Cache_Helper::get_transient_version('product'));
         }
         // If the prices are not stored for this hash, generate them
         if (empty($prices_array[$price_hash])) {
             $prices = array();
             $regular_prices = array();
             $sale_prices = array();
             $variation_ids = $this->get_children(true);
             foreach ($variation_ids as $variation_id) {
                 if ($variation = $this->get_child($variation_id)) {
                     $price = apply_filters('woocommerce_variation_prices_price', $variation->price, $variation, $this);
                     $regular_price = apply_filters('woocommerce_variation_prices_regular_price', $variation->regular_price, $variation, $this);
                     $sale_price = apply_filters('woocommerce_variation_prices_sale_price', $variation->sale_price, $variation, $this);
                     // Skip empty prices
                     if ('' === $price) {
                         continue;
                     }
                     // If sale price does not equal price, the product is not yet on sale
                     if ($sale_price === $regular_price || $sale_price !== $price) {
                         $sale_price = $regular_price;
                     }
                     // If we are getting prices for display, we need to account for taxes
                     if ($display) {
                         if ('incl' === get_option('woocommerce_tax_display_shop')) {
                             $price = '' === $price ? '' : $variation->get_price_including_tax(1, $price);
                             $regular_price = '' === $regular_price ? '' : $variation->get_price_including_tax(1, $regular_price);
                             $sale_price = '' === $sale_price ? '' : $variation->get_price_including_tax(1, $sale_price);
                         } else {
                             $price = '' === $price ? '' : $variation->get_price_excluding_tax(1, $price);
                             $regular_price = '' === $regular_price ? '' : $variation->get_price_excluding_tax(1, $regular_price);
                             $sale_price = '' === $sale_price ? '' : $variation->get_price_excluding_tax(1, $sale_price);
                         }
                     }
                     $prices[$variation_id] = wc_format_decimal($price, wc_get_price_decimals());
                     $regular_prices[$variation_id] = wc_format_decimal($regular_price, wc_get_price_decimals());
                     $sale_prices[$variation_id] = wc_format_decimal($sale_price . '.00', wc_get_price_decimals());
                 }
             }
             asort($prices);
             asort($regular_prices);
             asort($sale_prices);
             $prices_array[$price_hash] = array('price' => $prices, 'regular_price' => $regular_prices, 'sale_price' => $sale_prices);
             set_transient($transient_name, json_encode($prices_array), DAY_IN_SECONDS * 30);
         }
         /**
          * Give plugins one last chance to filter the variation prices array which has been generated.
          */
         $this->prices_array[$price_hash] = apply_filters('woocommerce_variation_prices', $prices_array[$price_hash], $this, $display);
     }
     /**
      * Return the values.
      */
     return $this->prices_array[$price_hash];
 }
예제 #14
0
/**
 * Clear all transients cache for order data.
 *
 * @param int $post_id (default: 0)
 */
function wc_delete_shop_order_transients($post_id = 0)
{
    $post_id = absint($post_id);
    $transients_to_clear = array();
    // Clear report transients
    $reports = WC_Admin_Reports::get_reports();
    foreach ($reports as $report_group) {
        foreach ($report_group['reports'] as $report_key => $report) {
            $transients_to_clear[] = 'wc_report_' . $report_key;
        }
    }
    // clear API report transient
    $transients_to_clear[] = 'wc_admin_report';
    // Clear transients where we have names
    foreach ($transients_to_clear as $transient) {
        delete_transient($transient);
    }
    // Increments the transient version to invalidate cache
    WC_Cache_Helper::get_transient_version('orders', true);
    do_action('woocommerce_delete_shop_order_transients', $post_id);
}
예제 #15
0
/**
 * Clear all transients cache for product data.
 *
 * @param int $post_id (default: 0)
 */
function wc_delete_product_transients($post_id = 0)
{
    // Core transients
    $transients_to_clear = array('wc_products_onsale', 'wc_featured_products', 'wc_outofstock_count', 'wc_low_stock_count');
    // Transients that include an ID
    $post_transient_names = array('wc_product_children_', 'wc_product_total_stock_');
    if ($post_id > 0) {
        foreach ($post_transient_names as $transient) {
            $transients_to_clear[] = $transient . $post_id;
        }
    }
    // Delete transients
    foreach ($transients_to_clear as $transient) {
        delete_transient($transient);
    }
    // Increments the transient version to invalidate cache
    WC_Cache_Helper::get_transient_version('product', true);
    do_action('woocommerce_delete_product_transients', $post_id);
}
예제 #16
0
 /**
  * calculate_shipping_for_package function.
  *
  * Calculates each shipping methods cost. Rates are cached based on the package to speed up calculations.
  *
  * @access public
  * @param array $package cart items
  * @return array
  * @todo Return array() instead of false for consistent return type?
  */
 public function calculate_shipping_for_package($package = array())
 {
     if (!$this->enabled) {
         return false;
     }
     if (!$package) {
         return false;
     }
     // Check if we need to recalculate shipping for this package
     $package_hash = 'wc_ship_' . md5(json_encode($package) . WC_Cache_Helper::get_transient_version('shipping'));
     $status_options = get_option('woocommerce_status_options', array());
     if (false === ($stored_rates = get_transient($package_hash)) || !empty($status_options['shipping_debug_mode'])) {
         // Calculate shipping method rates
         $package['rates'] = array();
         foreach ($this->load_shipping_methods($package) as $shipping_method) {
             if ($shipping_method->is_available($package) && (empty($package['ship_via']) || in_array($shipping_method->id, $package['ship_via']))) {
                 // Reset Rates
                 $shipping_method->rates = array();
                 // Calculate Shipping for package
                 $shipping_method->calculate_shipping($package);
                 // Place rates in package array
                 if (!empty($shipping_method->rates) && is_array($shipping_method->rates)) {
                     foreach ($shipping_method->rates as $rate) {
                         $package['rates'][$rate->id] = $rate;
                     }
                 }
             }
         }
         // Filter the calculated rates
         $package['rates'] = apply_filters('woocommerce_package_rates', $package['rates'], $package);
         // Store
         set_transient($package_hash, $package['rates'], 60 * 60);
         // Cached for an hour
     } else {
         $package['rates'] = $stored_rates;
     }
     return $package;
 }
예제 #17
0
/**
 * Checks if a user (by email or ID or both) has bought an item.
 * @param string $customer_email
 * @param int $user_id
 * @param int $product_id
 * @return bool
 */
function wc_customer_bought_product($customer_email, $user_id, $product_id)
{
    global $wpdb;
    $transient_name = 'wc_cbp_' . md5($customer_email . $user_id . WC_Cache_Helper::get_transient_version('orders'));
    if (false === ($result = get_transient($transient_name))) {
        $customer_data = array($user_id);
        if ($user_id) {
            $user = get_user_by('id', $user_id);
            if (isset($user->user_email)) {
                $customer_data[] = $user->user_email;
            }
        }
        if (is_email($customer_email)) {
            $customer_data[] = $customer_email;
        }
        $customer_data = array_map('esc_sql', array_filter(array_unique($customer_data)));
        if (sizeof($customer_data) == 0) {
            return false;
        }
        $result = $wpdb->get_col("\n\t\t\tSELECT im.meta_value FROM {$wpdb->posts} AS p\n\t\t\tINNER JOIN {$wpdb->postmeta} AS pm ON p.ID = pm.post_id\n\t\t\tINNER JOIN {$wpdb->prefix}woocommerce_order_items AS i ON p.ID = i.order_id\n\t\t\tINNER JOIN {$wpdb->prefix}woocommerce_order_itemmeta AS im ON i.order_item_id = im.order_item_id\n\t\t\tWHERE p.post_status IN ( 'wc-completed', 'wc-processing' )\n\t\t\tAND pm.meta_key IN ( '_billing_email', '_customer_user' )\n\t\t\tAND im.meta_key IN ( '_product_id', '_variation_id' )\n\t\t\tAND im.meta_value != 0\n\t\t\tAND pm.meta_value IN ( '" . implode("','", $customer_data) . "' )\n\t\t");
        $result = array_map('absint', $result);
        set_transient($transient_name, $result, DAY_IN_SECONDS * 30);
    }
    return in_array(absint($product_id), $result);
}
예제 #18
0
 /**
  * Add a shipping method to this zone.
  * @param string $type shipping method type
  * @return int new instance_id, 0 on failure
  */
 public function add_shipping_method($type)
 {
     global $wpdb;
     if (null === $this->get_id()) {
         return 0;
     }
     $instance_id = 0;
     $wc_shipping = WC_Shipping::instance();
     $allowed_classes = $wc_shipping->get_shipping_method_class_names();
     $count = $wpdb->get_var($wpdb->prepare("SELECT COUNT(*) FROM {$wpdb->prefix}woocommerce_shipping_zone_methods WHERE zone_id = %d", $this->get_id()));
     if (in_array($type, array_keys($allowed_classes))) {
         $wpdb->insert($wpdb->prefix . 'woocommerce_shipping_zone_methods', array('method_id' => $type, 'zone_id' => $this->get_id(), 'method_order' => $count + 1), array('%s', '%d', '%d'));
         $instance_id = $wpdb->insert_id;
     }
     if ($instance_id) {
         do_action('woocommerce_shipping_zone_method_added', $instance_id, $type, $this->get_id());
     }
     WC_Cache_Helper::get_transient_version('shipping', true);
     return $instance_id;
 }
예제 #19
0
 /**
  * Makes the new booking belonging to an order
  * @param string $status The status for this new booking
  * @param array $order_data Array with all the new order data
  */
 private function new_booking($status, $order_data)
 {
     global $wpdb;
     $order_data = wp_parse_args($order_data, array('user_id' => 0, 'resource_id' => '', 'product_id' => '', 'order_item_id' => '', 'persons' => array(), 'cost' => '', 'start_date' => '', 'end_date' => '', 'all_day' => 0, 'parent_id' => 0));
     // Get parent data
     if ($order_data['parent_id']) {
         if (!$order_data['order_item_id']) {
             $order_data['order_item_id'] = get_post_meta($order_data['parent_id'], '_booking_order_item_id', true);
         }
         if (!$order_data['user_id']) {
             $order_data['user_id'] = get_post_meta($order_data['parent_id'], '_booking_customer_id', true);
         }
     }
     // Get order ID from order item
     if ($order_data['order_item_id']) {
         $order_id = $wpdb->get_var($wpdb->prepare("SELECT order_id FROM {$wpdb->prefix}woocommerce_order_items WHERE order_item_id = %d", $order_data['order_item_id']));
     } else {
         $order_id = 0;
     }
     $booking_data = array('post_type' => 'wc_booking', 'post_title' => sprintf(__('Booking &ndash; %s', 'woocommerce-bookings'), strftime(_x('%b %d, %Y @ %I:%M %p', 'Booking date parsed by strftime', 'woocommerce-bookings'))), 'post_status' => $status, 'ping_status' => 'closed', 'post_parent' => $order_id);
     $this->id = wp_insert_post($booking_data);
     // Setup the required data for the current user
     if (!$order_data['user_id']) {
         if (is_user_logged_in()) {
             $order_data['user_id'] = get_current_user_id();
         } else {
             $order_data['user_id'] = 0;
         }
     }
     // Convert booking start and end to requried format
     if (is_numeric($order_data['start_date'])) {
         // Convert timestamp
         $order_data['start_date'] = date('YmdHis', $order_data['start_date']);
         $order_data['end_date'] = date('YmdHis', $order_data['end_date']);
     } else {
         $order_data['start_date'] = date('YmdHis', strtotime($order_data['start_date']));
         $order_data['end_date'] = date('YmdHis', strtotime($order_data['end_date']));
     }
     $meta_args = array('_booking_order_item_id' => $order_data['order_item_id'], '_booking_product_id' => $order_data['product_id'], '_booking_resource_id' => $order_data['resource_id'], '_booking_persons' => $order_data['persons'], '_booking_cost' => $order_data['cost'], '_booking_start' => $order_data['start_date'], '_booking_end' => $order_data['end_date'], '_booking_all_day' => intval($order_data['all_day']), '_booking_parent_id' => $order_data['parent_id'], '_booking_customer_id' => $order_data['user_id']);
     foreach ($meta_args as $key => $value) {
         update_post_meta($this->id, $key, $value);
     }
     WC_Cache_Helper::get_transient_version('bookings', true);
     do_action('woocommerce_new_booking', $this->id);
 }
예제 #20
0
 /**
  * Get a coupon ID from it's code.
  * @param  string $code
  * @return int
  */
 private function get_coupon_id_from_code($code)
 {
     global $wpdb;
     $coupon_code_query = $wpdb->prepare(apply_filters('woocommerce_coupon_code_query', "SELECT ID FROM {$wpdb->posts} WHERE post_title = %s AND post_type = 'shop_coupon' AND post_status = 'publish'"), $this->code);
     $transient_name = 'wc_cid_by_code_' . md5($coupon_code_query . WC_Cache_Helper::get_transient_version('coupons'));
     if (false === ($result = get_transient($transient_name))) {
         $result = $wpdb->get_var($coupon_code_query);
         set_transient($transient_name, $result, DAY_IN_SECONDS * 30);
     }
     return absint($result);
 }
 /**
  * Get an array of all sale and regular prices from all variations. This is used for example when displaying the price range at variable product level or seeing if the variable product is on sale.
  *
  * Can be filtered by plugins which modify costs, but otherwise will include the raw meta costs unlike get_price() which runs costs through the woocommerce_get_price filter.
  * This is to ensure modified prices are not cached, unless intended.
  *
  * @param  bool $display Are prices for display? If so, taxes will be calculated.
  * @return array() Array of RAW prices, regular prices, and sale prices with keys set to variation ID.
  */
 public function get_variation_prices($display = false)
 {
     global $wp_filter;
     /**
      * Transient name for storing prices for this product.
      * Max transient length is 45, -10 for get_transient_version.
      * @var string
      * @since 2.5.0 a single transient is used per product for all prices, rather than many transients per product.
      */
     $transient_name = 'wc_var_prices' . $this->id . '_' . WC_Cache_Helper::get_transient_version('product');
     /**
      * Create unique cache key based on the tax location (affects displayed/cached prices), product version and active price filters.
      * DEVELOPERS should filter this hash if offering conditonal pricing to keep it unique.
      * @var string
      */
     if ($display) {
         $price_hash = array(true, WC_Tax::get_rates(), get_option('woocommerce_tax_display_shop'));
     } else {
         $price_hash = array(false);
     }
     foreach ($wp_filter as $key => $val) {
         if (in_array($key, array('woocommerce_variation_prices_price', 'woocommerce_variation_prices_regular_price', 'woocommerce_variation_prices_sale_price'))) {
             $price_hash[$key] = $val;
         }
     }
     $price_hash = md5(json_encode(apply_filters('woocommerce_get_variation_prices_hash', $price_hash, $this, $display)));
     // If the value has already been generated, return it now
     if (!empty($this->prices_array[$price_hash])) {
         return $this->prices_array[$price_hash];
     }
     // Get value of transient
     $this->prices_array = array_filter((array) get_transient($transient_name));
     // If the prices are not stored for this hash, generate them
     if (empty($this->prices_array[$price_hash])) {
         $prices = array();
         $regular_prices = array();
         $sale_prices = array();
         $variation_ids = $this->get_children(true);
         foreach ($variation_ids as $variation_id) {
             if ($variation = $this->get_child($variation_id)) {
                 $price = apply_filters('woocommerce_variation_prices_price', $variation->price, $variation, $this);
                 $regular_price = apply_filters('woocommerce_variation_prices_regular_price', $variation->regular_price, $variation, $this);
                 $sale_price = apply_filters('woocommerce_variation_prices_sale_price', $variation->sale_price, $variation, $this);
                 // If sale price does not equal price, the product is not yet on sale
                 if ($sale_price === $regular_price || $sale_price !== $price) {
                     $sale_price = $regular_price;
                 }
                 // If we are getting prices for display, we need to account for taxes
                 if ($display) {
                     if ('incl' === get_option('woocommerce_tax_display_shop')) {
                         $price = '' === $price ? '' : $variation->get_price_including_tax(1, $price);
                         $regular_price = '' === $regular_price ? '' : $variation->get_price_including_tax(1, $regular_price);
                         $sale_price = '' === $sale_price ? '' : $variation->get_price_including_tax(1, $sale_price);
                     } else {
                         $price = '' === $price ? '' : $variation->get_price_excluding_tax(1, $price);
                         $regular_price = '' === $regular_price ? '' : $variation->get_price_excluding_tax(1, $regular_price);
                         $sale_price = '' === $sale_price ? '' : $variation->get_price_excluding_tax(1, $sale_price);
                     }
                 }
                 $prices[$variation_id] = $price;
                 $regular_prices[$variation_id] = $regular_price;
                 $sale_prices[$variation_id] = $sale_price;
             }
         }
         asort($prices);
         asort($regular_prices);
         asort($sale_prices);
         $this->prices_array[$price_hash] = array('price' => $prices, 'regular_price' => $regular_prices, 'sale_price' => $sale_prices);
         set_transient($transient_name, $this->prices_array, DAY_IN_SECONDS * 30);
     }
     /**
      * Give plugins one last chance to filter the variation prices array which is being returned.
      */
     return $this->prices_array[$price_hash] = apply_filters('woocommerce_variation_prices', $this->prices_array[$price_hash], $this, $display);
 }
예제 #22
0
 /**
  * Handles output of tools
  */
 public static function status_tools()
 {
     global $wpdb;
     $tools = self::get_tools();
     if (!empty($_GET['action']) && !empty($_REQUEST['_wpnonce']) && wp_verify_nonce($_REQUEST['_wpnonce'], 'debug_action')) {
         switch ($_GET['action']) {
             case 'clear_transients':
                 wc_delete_product_transients();
                 wc_delete_shop_order_transients();
                 WC_Cache_Helper::get_transient_version('shipping', true);
                 echo '<div class="updated"><p>' . __('Product Transients Cleared', 'woocommerce') . '</p></div>';
                 break;
             case 'clear_expired_transients':
                 /*
                  * Deletes all expired transients. The multi-table delete syntax is used
                  * to delete the transient record from table a, and the corresponding
                  * transient_timeout record from table b.
                  *
                  * Based on code inside core's upgrade_network() function.
                  */
                 $sql = "DELETE a, b FROM {$wpdb->options} a, {$wpdb->options} b\r\n\t\t\t\t\t\tWHERE a.option_name LIKE %s\r\n\t\t\t\t\t\tAND a.option_name NOT LIKE %s\r\n\t\t\t\t\t\tAND b.option_name = CONCAT( '_transient_timeout_', SUBSTRING( a.option_name, 12 ) )\r\n\t\t\t\t\t\tAND b.option_value < %d";
                 $rows = $wpdb->query($wpdb->prepare($sql, $wpdb->esc_like('_transient_') . '%', $wpdb->esc_like('_transient_timeout_') . '%', time()));
                 $sql = "DELETE a, b FROM {$wpdb->options} a, {$wpdb->options} b\r\n\t\t\t\t\t\tWHERE a.option_name LIKE %s\r\n\t\t\t\t\t\tAND a.option_name NOT LIKE %s\r\n\t\t\t\t\t\tAND b.option_name = CONCAT( '_site_transient_timeout_', SUBSTRING( a.option_name, 17 ) )\r\n\t\t\t\t\t\tAND b.option_value < %d";
                 $rows2 = $wpdb->query($wpdb->prepare($sql, $wpdb->esc_like('_site_transient_') . '%', $wpdb->esc_like('_site_transient_timeout_') . '%', time()));
                 echo '<div class="updated"><p>' . sprintf(__('%d Transients Rows Cleared', 'woocommerce'), $rows + $rows2) . '</p></div>';
                 break;
             case 'reset_roles':
                 // Remove then re-add caps and roles
                 WC_Install::remove_roles();
                 WC_Install::create_roles();
                 echo '<div class="updated"><p>' . __('Roles successfully reset', 'woocommerce') . '</p></div>';
                 break;
             case 'recount_terms':
                 $product_cats = get_terms('product_cat', array('hide_empty' => false, 'fields' => 'id=>parent'));
                 _wc_term_recount($product_cats, get_taxonomy('product_cat'), true, false);
                 $product_tags = get_terms('product_tag', array('hide_empty' => false, 'fields' => 'id=>parent'));
                 _wc_term_recount($product_tags, get_taxonomy('product_tag'), true, false);
                 echo '<div class="updated"><p>' . __('Terms successfully recounted', 'woocommerce') . '</p></div>';
                 break;
             case 'clear_sessions':
                 $wpdb->query("\r\n\t\t\t\t\t\tDELETE FROM {$wpdb->options}\r\n\t\t\t\t\t\tWHERE option_name LIKE '_wc_session_%' OR option_name LIKE '_wc_session_expires_%'\r\n\t\t\t\t\t");
                 wp_cache_flush();
                 echo '<div class="updated"><p>' . __('Sessions successfully cleared', 'woocommerce') . '</p></div>';
                 break;
             case 'install_pages':
                 WC_Install::create_pages();
                 echo '<div class="updated"><p>' . __('All missing WooCommerce pages was installed successfully.', 'woocommerce') . '</p></div>';
                 break;
             case 'delete_taxes':
                 $wpdb->query("TRUNCATE " . $wpdb->prefix . "woocommerce_tax_rates");
                 $wpdb->query("TRUNCATE " . $wpdb->prefix . "woocommerce_tax_rate_locations");
                 echo '<div class="updated"><p>' . __('Tax rates successfully deleted', 'woocommerce') . '</p></div>';
                 break;
             case 'reset_tracking':
                 delete_option('woocommerce_allow_tracking');
                 WC_Admin_Notices::add_notice('tracking');
                 echo '<div class="updated"><p>' . __('Usage tracking settings successfully reset.', 'woocommerce') . '</p></div>';
                 break;
             default:
                 $action = esc_attr($_GET['action']);
                 if (isset($tools[$action]['callback'])) {
                     $callback = $tools[$action]['callback'];
                     $return = call_user_func($callback);
                     if ($return === false) {
                         if (is_array($callback)) {
                             echo '<div class="error"><p>' . sprintf(__('There was an error calling %s::%s', 'woocommerce'), get_class($callback[0]), $callback[1]) . '</p></div>';
                         } else {
                             echo '<div class="error"><p>' . sprintf(__('There was an error calling %s', 'woocommerce'), $callback) . '</p></div>';
                         }
                     }
                 }
                 break;
         }
     }
     // Manual translation update messages
     if (isset($_GET['translation_updated'])) {
         WC_Language_Pack_Upgrader::language_update_messages();
     }
     // Display message if settings settings have been saved
     if (isset($_REQUEST['settings-updated'])) {
         echo '<div class="updated"><p>' . __('Your changes have been saved.', 'woocommerce') . '</p></div>';
     }
     include_once 'views/html-admin-page-status-tools.php';
 }
 /**
  * Get an array of all sale and regular prices from all variations.
  * @since WooCommerce 2.4
  * @param array() sale and regular prices for default location
  * @param WC_Product_Variable 
  * @param  bool Are prices for display? If so, taxes will be calculated.
  * @return array()
  */
 public function get_variation_prices_array($prices_array, $product, $display)
 {
     if ($this->customer->group_key) {
         $cache_key = 'var_prices_' . md5(json_encode(array($product->id, $display ? WC_Tax::get_rates() : '', $this->customer->group_key, WC_Cache_Helper::get_transient_version('product'))));
         if (false === ($prices_array = get_transient($cache_key))) {
             $prices = array();
             $regular_prices = array();
             $sale_prices = array();
             $tax_display_mode = get_option('woocommerce_tax_display_shop');
             foreach ($product->get_children(true) as $variation_id) {
                 if ($variation = $product->get_child($variation_id)) {
                     $price = $variation->get_price();
                     $regular_price = $variation->get_regular_price();
                     $sale_price = $variation->get_sale_price();
                     // If sale price does not equal price, the product is not yet on sale
                     if ($price != $sale_price) {
                         $sale_price = $regular_price;
                     }
                     // If we are getting prices for display, we need to account for taxes
                     if ($display) {
                         $price = $tax_display_mode == 'incl' ? $variation->get_price_including_tax(1, $price) : $variation->get_price_excluding_tax(1, $price);
                         $regular_price = $tax_display_mode == 'incl' ? $variation->get_price_including_tax(1, $regular_price) : $variation->get_price_excluding_tax(1, $regular_price);
                         $sale_price = $tax_display_mode == 'incl' ? $variation->get_price_including_tax(1, $sale_price) : $variation->get_price_excluding_tax(1, $sale_price);
                     }
                     $prices[$variation_id] = $price;
                     $regular_prices[$variation_id] = $regular_price;
                     $sale_prices[$variation_id] = $sale_price;
                 }
             }
             asort($prices);
             asort($regular_prices);
             asort($sale_prices);
             $prices_array = array('price' => $prices, 'regular_price' => $regular_prices, 'sale_price' => $sale_prices);
             set_transient($cache_key, $prices_array, DAY_IN_SECONDS * 30);
         }
     }
     return $prices_array;
 }
 /**
  * Set stock level of the product variation.
  *
  * Uses queries rather than update_post_meta so we can do this in one query (to avoid stock issues).
  * We cannot rely on the original loaded value in case another order was made since then.
  *
  * @param int $amount
  * @param string $mode can be set, add, or subtract
  * @return int new stock level
  */
 public function set_stock($amount = null, $mode = 'set')
 {
     global $wpdb;
     if (!is_null($amount) && true === $this->managing_stock()) {
         // Ensure key exists
         add_post_meta($this->variation_id, '_stock', 0, true);
         // Update stock in DB directly
         switch ($mode) {
             case 'add':
                 $wpdb->query($wpdb->prepare("UPDATE {$wpdb->postmeta} SET meta_value = meta_value + %f WHERE post_id = %d AND meta_key='_stock'", $amount, $this->variation_id));
                 break;
             case 'subtract':
                 $wpdb->query($wpdb->prepare("UPDATE {$wpdb->postmeta} SET meta_value = meta_value - %f WHERE post_id = %d AND meta_key='_stock'", $amount, $this->variation_id));
                 break;
             default:
                 $wpdb->query($wpdb->prepare("UPDATE {$wpdb->postmeta} SET meta_value = %f WHERE post_id = %d AND meta_key='_stock'", $amount, $this->variation_id));
                 break;
         }
         // Clear caches
         wp_cache_delete($this->variation_id, 'post_meta');
         // Clear total stock transient
         delete_transient('wc_product_total_stock_' . $this->id . WC_Cache_Helper::get_transient_version('product'));
         // Stock status
         $this->check_stock_status();
         // Sync the parent
         WC_Product_Variable::sync($this->id);
         // Trigger action
         do_action('woocommerce_variation_set_stock', $this);
     } elseif (!is_null($amount)) {
         return $this->parent->set_stock($amount, $mode);
     }
     return $this->get_stock_quantity();
 }
 /**
  * Check if we will be showing products or not (and not subcats only)
  *
  * @access public
  * @subpackage	Loop
  * @return bool
  */
 function woocommerce_products_will_display()
 {
     if (is_shop()) {
         return get_option('woocommerce_shop_page_display') != 'subcategories';
     }
     if (!is_product_taxonomy()) {
         return false;
     }
     if (is_search() || is_filtered() || is_paged()) {
         return true;
     }
     $term = get_queried_object();
     if (is_product_category()) {
         switch (get_woocommerce_term_meta($term->term_id, 'display_type', true)) {
             case 'subcategories':
                 // Nothing - we want to continue to see if there are products/subcats
                 break;
             case 'products':
             case 'both':
                 return true;
                 break;
             default:
                 // Default - no setting
                 if (get_option('woocommerce_category_archive_display') != 'subcategories') {
                     return true;
                 }
                 break;
         }
     }
     // Begin subcategory logic
     global $wpdb;
     $parent_id = empty($term->term_id) ? 0 : $term->term_id;
     $taxonomy = empty($term->taxonomy) ? '' : $term->taxonomy;
     $products_will_display = true;
     if (!$parent_id && !$taxonomy) {
         return true;
     }
     $transient_name = 'wc_products_will_display_' . $parent_id . WC_Cache_Helper::get_transient_version('product_query');
     if (false === ($products_will_display = get_transient($transient_name))) {
         $has_children = $wpdb->get_col($wpdb->prepare("SELECT term_id FROM {$wpdb->term_taxonomy} WHERE parent = %d AND taxonomy = %s", $parent_id, $taxonomy));
         if ($has_children) {
             // Check terms have products inside - parents first. If products are found inside, subcats will be shown instead of products so we can return false.
             if (sizeof(get_objects_in_term($has_children, $taxonomy)) > 0) {
                 $products_will_display = false;
             } else {
                 // If we get here, the parents were empty so we're forced to check children
                 foreach ($has_children as $term) {
                     $children = get_term_children($term, $taxonomy);
                     if (sizeof(get_objects_in_term($children, $taxonomy)) > 0) {
                         $products_will_display = false;
                         break;
                     }
                 }
             }
         } else {
             $products_will_display = true;
         }
     }
     set_transient($transient_name, $products_will_display, YEAR_IN_SECONDS);
     return $products_will_display;
 }
예제 #26
0
 /**
  * Clear transients for a review.
  * @param int $post_id
  */
 public static function clear_transients($post_id)
 {
     $post_id = absint($post_id);
     $transient_version = WC_Cache_Helper::get_transient_version('product');
     delete_transient('wc_average_rating_' . $post_id . $transient_version);
     delete_transient('wc_rating_count_' . $post_id . $transient_version);
     delete_transient('wc_review_count_' . $post_id . $transient_version);
 }
 /**
  * Delete a shipping method from a zone.
  * @param int $instance_id
  * @return True on success, false on failure
  */
 public function delete_shipping_method($instance_id)
 {
     global $wpdb;
     if (null === $this->get_id()) {
         return false;
     }
     $wpdb->delete($wpdb->prefix . 'woocommerce_shipping_zone_methods', array('instance_id' => $instance_id));
     do_action('woocommerce_shipping_zone_method_deleted', $instance_id, $this->get_id());
     WC_Cache_Helper::get_transient_version('shipping', true);
     return true;
 }
 /**
  * Get an array of all sale and regular prices from all variations. This is used for example when displaying the price range at variable product level or seeing if the variable product is on sale.
  *
  * Can be filtered by plugins which modify costs, but otherwise will include the raw meta costs unlike get_price() which runs costs through the woocommerce_get_price filter.
  * This is to ensure modified prices are not cached, unless intended.
  *
  * @param  bool $display Are prices for display? If so, taxes will be calculated.
  * @return array() Array of RAW prices, regular prices, and sale prices with keys set to variation ID.
  */
 public function get_variation_prices($display = false)
 {
     global $wp_filter;
     /**
      * Create unique cache key based on the tax location (affects displayed/cached prices), product version and active price filters.
      * Max transient length is 45, -10 for get_transient_version.
      * @var string
      */
     $hash = array($this->id, $display, $display ? WC_Tax::get_rates() : array());
     foreach ($wp_filter as $key => $val) {
         if (in_array($key, array('woocommerce_variation_prices_price', 'woocommerce_variation_prices_regular_price', 'woocommerce_variation_prices_sale_price'))) {
             $hash[$key] = $val;
         }
     }
     /**
      * DEVELOPERS should filter this hash if offering conditonal pricing to keep it unique.
      */
     $hash = apply_filters('woocommerce_get_variation_prices_hash', $hash, $this, $display);
     $cache_key = 'wc_var_prices' . substr(md5(json_encode($hash)), 0, 22) . WC_Cache_Helper::get_transient_version('product');
     $this->prices_array = get_transient($cache_key);
     if (empty($this->prices_array)) {
         $prices = array();
         $regular_prices = array();
         $sale_prices = array();
         $tax_display_mode = get_option('woocommerce_tax_display_shop');
         $variation_ids = $this->get_children(true);
         foreach ($variation_ids as $variation_id) {
             if ($variation = $this->get_child($variation_id)) {
                 $price = apply_filters('woocommerce_variation_prices_price', $variation->price, $variation, $this);
                 $regular_price = apply_filters('woocommerce_variation_prices_regular_price', $variation->regular_price, $variation, $this);
                 $sale_price = apply_filters('woocommerce_variation_prices_sale_price', $variation->sale_price, $variation, $this);
                 // If sale price does not equal price, the product is not yet on sale
                 if ($sale_price === $regular_price || $sale_price !== $price) {
                     $sale_price = $regular_price;
                 }
                 // If we are getting prices for display, we need to account for taxes
                 if ($display) {
                     if ('incl' === $tax_display_mode) {
                         $price = '' === $price ? '' : $variation->get_price_including_tax(1, $price);
                         $regular_price = '' === $regular_price ? '' : $variation->get_price_including_tax(1, $regular_price);
                         $sale_price = '' === $sale_price ? '' : $variation->get_price_including_tax(1, $sale_price);
                     } else {
                         $price = '' === $price ? '' : $variation->get_price_excluding_tax(1, $price);
                         $regular_price = '' === $regular_price ? '' : $variation->get_price_excluding_tax(1, $regular_price);
                         $sale_price = '' === $sale_price ? '' : $variation->get_price_excluding_tax(1, $sale_price);
                     }
                 }
                 $prices[$variation_id] = $price;
                 $regular_prices[$variation_id] = $regular_price;
                 $sale_prices[$variation_id] = $sale_price;
             }
         }
         asort($prices);
         asort($regular_prices);
         asort($sale_prices);
         $this->prices_array = array('price' => $prices, 'regular_price' => $regular_prices, 'sale_price' => $sale_prices);
         set_transient($cache_key, $this->prices_array, DAY_IN_SECONDS * 30);
     }
     /**
      * Give plugins one last chance to filter the variation prices array.
      */
     return $this->prices_array = apply_filters('woocommerce_variation_prices', $this->prices_array, $this, $display);
 }
 /**
  * Get and return related products.
  *
  * @param int $limit (default: 5)
  * @return array Array of post IDs
  */
 public function get_related($limit = 5)
 {
     global $wpdb;
     $limit = absint($limit);
     // Related products are found from category and tag
     $tags_array = array(0);
     $cats_array = array(0);
     // Get tags
     $terms = apply_filters('woocommerce_get_related_product_tag_terms', wp_get_post_terms($this->id, 'product_tag'), $this->id);
     foreach ($terms as $term) {
         $tags_array[] = $term->term_id;
     }
     // Get categories
     $terms = apply_filters('woocommerce_get_related_product_cat_terms', wp_get_post_terms($this->id, 'product_cat'), $this->id);
     foreach ($terms as $term) {
         $cats_array[] = $term->term_id;
     }
     // Don't bother if none are set
     if (sizeof($cats_array) == 1 && sizeof($tags_array) == 1) {
         return array();
     }
     // Sanitize
     $cats_array = array_map('absint', $cats_array);
     $tags_array = array_map('absint', $tags_array);
     $exclude_ids = array_map('absint', array_merge(array(0, $this->id), $this->get_upsells()));
     // Generate query
     $query = array();
     $query['fields'] = "SELECT DISTINCT ID FROM {$wpdb->posts} p";
     $query['join'] = " INNER JOIN {$wpdb->postmeta} pm ON ( pm.post_id = p.ID AND pm.meta_key='_visibility' )";
     $query['join'] .= " INNER JOIN {$wpdb->term_relationships} tr ON (p.ID = tr.object_id)";
     $query['join'] .= " INNER JOIN {$wpdb->term_taxonomy} tt ON (tr.term_taxonomy_id = tt.term_taxonomy_id)";
     $query['join'] .= " INNER JOIN {$wpdb->terms} t ON (t.term_id = tt.term_id)";
     if (get_option('woocommerce_hide_out_of_stock_items') === 'yes') {
         $query['join'] .= " INNER JOIN {$wpdb->postmeta} pm2 ON ( pm2.post_id = p.ID AND pm2.meta_key='_stock_status' )";
     }
     $query['where'] = " WHERE 1=1";
     $query['where'] .= " AND p.post_status = 'publish'";
     $query['where'] .= " AND p.post_type = 'product'";
     $query['where'] .= " AND p.ID NOT IN ( " . implode(',', $exclude_ids) . " )";
     $query['where'] .= " AND pm.meta_value IN ( 'visible', 'catalog' )";
     if (get_option('woocommerce_hide_out_of_stock_items') === 'yes') {
         $query['where'] .= " AND pm2.meta_value = 'instock'";
     }
     if (apply_filters('woocommerce_product_related_posts_relate_by_category', true, $this->id)) {
         $query['where'] .= " AND ( tt.taxonomy = 'product_cat' AND t.term_id IN ( " . implode(',', $cats_array) . " ) )";
         $andor = 'OR';
     } else {
         $andor = 'AND';
     }
     // when query is OR - need to check against excluded ids again
     if (apply_filters('woocommerce_product_related_posts_relate_by_tag', true, $this->id)) {
         $query['where'] .= " {$andor} ( ( tt.taxonomy = 'product_tag' AND t.term_id IN ( " . implode(',', $tags_array) . " ) )";
         $query['where'] .= " AND p.ID NOT IN ( " . implode(',', $exclude_ids) . " ) )";
     }
     $query = apply_filters('woocommerce_product_related_posts_query', $query, $this->id);
     // How many rows total?
     $max_related_posts_transient_name = 'wc_max_related_' . $this->id . WC_Cache_Helper::get_transient_version('product');
     if (false === ($max_related_posts = get_transient($max_related_posts_transient_name))) {
         $max_related_posts_query = $query;
         $max_related_posts_query['fields'] = "SELECT COUNT(DISTINCT ID) FROM {$wpdb->posts} p";
         $max_related_posts = absint($wpdb->get_var(implode(' ', apply_filters('woocommerce_product_max_related_posts_query', $max_related_posts_query, $this->id))));
         set_transient($max_related_posts_transient_name, $max_related_posts, DAY_IN_SECONDS * 30);
     }
     // Generate limit
     $offset = $max_related_posts < $limit ? 0 : absint(rand(0, $max_related_posts - $limit));
     $query['limits'] = " LIMIT {$offset}, {$limit} ";
     // Get the posts
     $related_posts = $wpdb->get_col(implode(' ', $query));
     return $related_posts;
 }
 /**
  * Handles output of tools
  */
 public static function status_tools()
 {
     global $wpdb;
     $tools = self::get_tools();
     if (!empty($_GET['action']) && !empty($_REQUEST['_wpnonce']) && wp_verify_nonce($_REQUEST['_wpnonce'], 'debug_action')) {
         switch ($_GET['action']) {
             case 'clear_transients':
                 wc_delete_product_transients();
                 wc_delete_shop_order_transients();
                 WC_Cache_Helper::get_transient_version('shipping', true);
                 echo '<div class="updated"><p>' . __('Product Transients Cleared', 'woocommerce') . '</p></div>';
                 break;
             case 'clear_expired_transients':
                 // http://w-shadow.com/blog/2012/04/17/delete-stale-transients/
                 $rows = $wpdb->query("\n\t\t\t\t\t\tDELETE\n\t\t\t\t\t\t\ta, b\n\t\t\t\t\t\tFROM\n\t\t\t\t\t\t\t{$wpdb->options} a, {$wpdb->options} b\n\t\t\t\t\t\tWHERE\n\t\t\t\t\t\t\ta.option_name LIKE '_transient_%' AND\n\t\t\t\t\t\t\ta.option_name NOT LIKE '_transient_timeout_%' AND\n\t\t\t\t\t\t\tb.option_name = CONCAT(\n\t\t\t\t\t\t\t\t'_transient_timeout_',\n\t\t\t\t\t\t\t\tSUBSTRING(\n\t\t\t\t\t\t\t\t\ta.option_name,\n\t\t\t\t\t\t\t\t\tCHAR_LENGTH('_transient_') + 1\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\tAND b.option_value < UNIX_TIMESTAMP()\n\t\t\t\t\t");
                 $rows2 = $wpdb->query("\n\t\t\t\t\t\tDELETE\n\t\t\t\t\t\t\ta, b\n\t\t\t\t\t\tFROM\n\t\t\t\t\t\t\t{$wpdb->options} a, {$wpdb->options} b\n\t\t\t\t\t\tWHERE\n\t\t\t\t\t\t\ta.option_name LIKE '_site_transient_%' AND\n\t\t\t\t\t\t\ta.option_name NOT LIKE '_site_transient_timeout_%' AND\n\t\t\t\t\t\t\tb.option_name = CONCAT(\n\t\t\t\t\t\t\t\t'_site_transient_timeout_',\n\t\t\t\t\t\t\t\tSUBSTRING(\n\t\t\t\t\t\t\t\t\ta.option_name,\n\t\t\t\t\t\t\t\t\tCHAR_LENGTH('_site_transient_') + 1\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\tAND b.option_value < UNIX_TIMESTAMP()\n\t\t\t\t\t");
                 echo '<div class="updated"><p>' . sprintf(__('%d Transients Rows Cleared', 'woocommerce'), $rows + $rows2) . '</p></div>';
                 break;
             case 'reset_roles':
                 // Remove then re-add caps and roles
                 WC_Install::remove_roles();
                 WC_Install::create_roles();
                 echo '<div class="updated"><p>' . __('Roles successfully reset', 'woocommerce') . '</p></div>';
                 break;
             case 'recount_terms':
                 $product_cats = get_terms('product_cat', array('hide_empty' => false, 'fields' => 'id=>parent'));
                 _wc_term_recount($product_cats, get_taxonomy('product_cat'), true, false);
                 $product_tags = get_terms('product_tag', array('hide_empty' => false, 'fields' => 'id=>parent'));
                 _wc_term_recount($product_tags, get_taxonomy('product_tag'), true, false);
                 echo '<div class="updated"><p>' . __('Terms successfully recounted', 'woocommerce') . '</p></div>';
                 break;
             case 'clear_sessions':
                 $wpdb->query("\n\t\t\t\t\t\tDELETE FROM {$wpdb->options}\n\t\t\t\t\t\tWHERE option_name LIKE '_wc_session_%' OR option_name LIKE '_wc_session_expires_%'\n\t\t\t\t\t");
                 wp_cache_flush();
                 echo '<div class="updated"><p>' . __('Sessions successfully cleared', 'woocommerce') . '</p></div>';
                 break;
             case 'install_pages':
                 WC_Install::create_pages();
                 echo '<div class="updated"><p>' . __('All missing WooCommerce pages was installed successfully.', 'woocommerce') . '</p></div>';
                 break;
             case 'delete_taxes':
                 $wpdb->query("TRUNCATE " . $wpdb->prefix . "woocommerce_tax_rates");
                 $wpdb->query("TRUNCATE " . $wpdb->prefix . "woocommerce_tax_rate_locations");
                 echo '<div class="updated"><p>' . __('Tax rates successfully deleted', 'woocommerce') . '</p></div>';
                 break;
             case 'reset_tracking':
                 delete_option('woocommerce_allow_tracking');
                 WC_Admin_Notices::add_notice('tracking');
                 echo '<div class="updated"><p>' . __('Usage tracking settings successfully reset.', 'woocommerce') . '</p></div>';
                 break;
             default:
                 $action = esc_attr($_GET['action']);
                 if (isset($tools[$action]['callback'])) {
                     $callback = $tools[$action]['callback'];
                     $return = call_user_func($callback);
                     if ($return === false) {
                         if (is_array($callback)) {
                             echo '<div class="error"><p>' . sprintf(__('There was an error calling %s::%s', 'woocommerce'), get_class($callback[0]), $callback[1]) . '</p></div>';
                         } else {
                             echo '<div class="error"><p>' . sprintf(__('There was an error calling %s', 'woocommerce'), $callback) . '</p></div>';
                         }
                     }
                 }
                 break;
         }
     }
     // Manual translation update messages
     if (isset($_GET['translation_updated'])) {
         switch ($_GET['translation_updated']) {
             case 2:
                 echo '<div class="error"><p>' . __('Failed to install/update the translation:', 'woocommerce') . ' ' . __('Seems you don\'t have permission to do this!', 'woocommerce') . '</p></div>';
                 break;
             case 3:
                 echo '<div class="error"><p>' . __('Failed to install/update the translation:', 'woocommerce') . ' ' . sprintf(__('An authentication error occurred while updating the translation. Please try again or configure your %sUpgrade Constants%s.', 'woocommerce'), '<a href="http://codex.wordpress.org/Editing_wp-config.php#WordPress_Upgrade_Constants">', '</a>') . '</p></div>';
                 break;
             case 4:
                 echo '<div class="error"><p>' . __('Failed to install/update the translation:', 'woocommerce') . ' ' . __('Sorry but there is no translation available for your language =/', 'woocommerce') . '</p></div>';
                 break;
             default:
                 // Force WordPress find for new updates and hide the WooCommerce translation update
                 set_site_transient('update_plugins', null);
                 echo '<div class="updated"><p>' . __('Translations installed/updated successfully!', 'woocommerce') . '</p></div>';
                 break;
         }
     }
     // Display message if settings settings have been saved
     if (isset($_REQUEST['settings-updated'])) {
         echo '<div class="updated"><p>' . __('Your changes have been saved.', 'woocommerce') . '</p></div>';
     }
     include_once 'views/html-admin-page-status-tools.php';
 }