/**
 * Function for recounting product terms, ignoring hidden products.
 *
 * @param  array $terms
 * @param  string $taxonomy
 * @param  bool $callback
 * @param  bool $terms_are_term_taxonomy_ids
 */
function _wc_term_recount($terms, $taxonomy, $callback = true, $terms_are_term_taxonomy_ids = true)
{
    global $wpdb;
    // Standard callback
    if ($callback) {
        _update_post_term_count($terms, $taxonomy);
    }
    // Stock query
    if (get_option('woocommerce_hide_out_of_stock_items') == 'yes') {
        $stock_join = "LEFT JOIN {$wpdb->postmeta} AS meta_stock ON posts.ID = meta_stock.post_id";
        $stock_query = "\n\t\tAND meta_stock.meta_key = '_stock_status'\n\t\tAND meta_stock.meta_value = 'instock'\n\t\t";
    } else {
        $stock_query = $stock_join = '';
    }
    // Main query
    $count_query = "\n\t\tSELECT COUNT( DISTINCT posts.ID ) FROM {$wpdb->posts} as posts\n\t\tLEFT JOIN {$wpdb->postmeta} AS meta_visibility ON posts.ID = meta_visibility.post_id\n\t\tLEFT JOIN {$wpdb->term_relationships} AS rel ON posts.ID=rel.object_ID\n\t\tLEFT JOIN {$wpdb->term_taxonomy} AS tax USING( term_taxonomy_id )\n\t\tLEFT JOIN {$wpdb->terms} AS term USING( term_id )\n\t\tLEFT JOIN {$wpdb->postmeta} AS postmeta ON posts.ID = postmeta.post_id\n\t\t{$stock_join}\n\t\tWHERE \tpost_status = 'publish'\n\t\tAND \tpost_type \t= 'product'\n\t\tAND \tmeta_visibility.meta_key = '_visibility'\n\t\tAND \tmeta_visibility.meta_value IN ( 'visible', 'catalog' )\n\t\t{$stock_query}\n\t";
    // Pre-process term taxonomy ids
    if (!$terms_are_term_taxonomy_ids) {
        // We passed in an array of TERMS in format id=>parent
        $terms = array_filter((array) array_keys($terms));
    } else {
        // If we have term taxonomy IDs we need to get the term ID
        $term_taxonomy_ids = $terms;
        $terms = array();
        foreach ($term_taxonomy_ids as $term_taxonomy_id) {
            $term = get_term_by('term_taxonomy_id', $term_taxonomy_id, $taxonomy->name);
            $terms[] = $term->term_id;
        }
    }
    // Exit if we have no terms to count
    if (empty($terms)) {
        return;
    }
    // Ancestors need counting
    if (is_taxonomy_hierarchical($taxonomy->name)) {
        foreach ($terms as $term_id) {
            $terms = array_merge($terms, get_ancestors($term_id, $taxonomy->name));
        }
    }
    // Unique terms only
    $terms = array_unique($terms);
    // Count the terms
    foreach ($terms as $term_id) {
        $terms_to_count = array(absint($term_id));
        if (is_taxonomy_hierarchical($taxonomy->name)) {
            // We need to get the $term's hierarchy so we can count its children too
            if (($children = get_term_children($term_id, $taxonomy->name)) && !is_wp_error($children)) {
                $terms_to_count = array_unique(array_map('absint', array_merge($terms_to_count, $children)));
            }
        }
        // Generate term query
        $term_query = 'AND term_id IN ( ' . implode(',', $terms_to_count) . ' )';
        // Get the count
        $count = $wpdb->get_var($count_query . $term_query);
        // Update the count
        update_woocommerce_term_meta($term_id, 'product_count_' . $taxonomy->name, absint($count));
    }
    delete_transient('wc_term_counts');
}
/**
 * Perform term count update immediately.
 *
 * @since 2.5.0
 *
 * @param array  $terms    The term_taxonomy_id of terms to update.
 * @param string $taxonomy The context of the term.
 * @return true Always true when complete.
 */
function wp_update_term_count_now($terms, $taxonomy)
{
    $terms = array_map('intval', $terms);
    $taxonomy = get_taxonomy($taxonomy);
    if (!empty($taxonomy->update_count_callback)) {
        call_user_func($taxonomy->update_count_callback, $terms, $taxonomy);
    } else {
        $object_types = (array) $taxonomy->object_type;
        foreach ($object_types as &$object_type) {
            if (0 === strpos($object_type, 'attachment:')) {
                list($object_type) = explode(':', $object_type);
            }
        }
        if ($object_types == array_filter($object_types, 'post_type_exists')) {
            // Only post types are attached to this taxonomy
            _update_post_term_count($terms, $taxonomy);
        } else {
            // Default count updater
            _update_generic_term_count($terms, $taxonomy);
        }
    }
    clean_term_cache($terms, '', false);
    return true;
}
/**
 * Function for recounting product terms, ignoring hidden products.
 *
 * @access public
 * @param mixed $term
 * @param mixed $taxonomy
 * @return void
 */
function _woocommerce_term_recount($terms, $taxonomy, $callback = true, $terms_are_term_taxonomy_ids = true)
{
    global $wpdb;
    // Standard callback
    if ($callback) {
        _update_post_term_count($terms, $taxonomy);
    }
    // Stock query
    if (get_option('woocommerce_hide_out_of_stock_items') == 'yes') {
        $stock_join = "LEFT JOIN {$wpdb->postmeta} AS meta_stock ON posts.ID = meta_stock.post_id";
        $stock_query = "\n\t\tAND (\n\t\t\tmeta_stock.meta_key = '_stock_status'\n\t\t\tAND\n\t\t\tmeta_stock.meta_value = 'instock'\n\t\t)";
    } else {
        $stock_query = $stock_join = '';
    }
    // Main query
    $count_query = $wpdb->prepare("\n\t\tSELECT COUNT( DISTINCT posts.ID ) FROM {$wpdb->posts} as posts\n\n\t\tLEFT JOIN {$wpdb->postmeta} AS meta_visibility ON posts.ID = meta_visibility.post_id\n\t\tLEFT JOIN {$wpdb->term_relationships} AS rel ON posts.ID = rel.object_ID\n\t\tLEFT JOIN {$wpdb->term_taxonomy} AS tax USING( term_taxonomy_id )\n\t\tLEFT JOIN {$wpdb->terms} AS term USING( term_id )\n\t\t{$stock_join}\n\n\t\tWHERE \tposts.post_status \t= 'publish'\n\t\tAND \tposts.post_type \t= 'product'\n\t\tAND \t(\n\t\t\tmeta_visibility.meta_key = '_visibility'\n\t\t\tAND\n\t\t\tmeta_visibility.meta_value IN ( 'visible', 'catalog' )\n\t\t)\n\t\tAND \ttax.taxonomy\t= %s\n\t\t{$stock_query}\n\t", $taxonomy->name);
    // Store terms + counts here
    $term_counts = array();
    $counted_terms = array();
    $maybe_count_parents = array();
    // Pre-process term taxonomy ids
    if ($terms_are_term_taxonomy_ids) {
        $term_ids = array();
        foreach ((array) $terms as $term) {
            $the_term = $wpdb->get_row("SELECT term_id, parent FROM {$wpdb->term_taxonomy} WHERE term_taxonomy_id = {$term} AND taxonomy = '{$taxonomy->name}'");
            $term_ids[$the_term->term_id] = $the_term->parent;
        }
        $terms = $term_ids;
    }
    // Count those terms!
    foreach ((array) $terms as $term_id => $parent_id) {
        $term_ids = array();
        if (is_taxonomy_hierarchical($taxonomy->name)) {
            // Grab the parents to count later
            $parent = $parent_id;
            while (!empty($parent) && $parent > 0) {
                $maybe_count_parents[] = $parent;
                $parent_term = get_term_by('id', $parent, $taxonomy->name);
                if ($parent_term) {
                    $parent = $parent_term->parent;
                } else {
                    $parent = 0;
                }
            }
            // We need to get the $term's hierarchy so we can count its children too
            $term_ids = get_term_children($term_id, $taxonomy->name);
        }
        $term_ids[] = absint($term_id);
        // Generate term query
        $term_query = 'AND term.term_id IN ( ' . implode(',', $term_ids) . ' )';
        // Get the count
        $count = $wpdb->get_var($count_query . $term_query);
        update_woocommerce_term_meta($term_id, 'product_count_' . $taxonomy->name, absint($count));
        $counted_terms[] = $term_id;
    }
    // Re-count parents
    if (is_taxonomy_hierarchical($taxonomy->name)) {
        $terms = array_diff($maybe_count_parents, $counted_terms);
        foreach ((array) $terms as $term) {
            $term_ids = get_term_children($term, $taxonomy->name);
            $term_ids[] = $term;
            // Generate term query
            $term_query = 'AND term.term_id IN ( ' . implode(',', $term_ids) . ' )';
            // Get the count
            $count = $wpdb->get_var($count_query . $term_query);
            update_woocommerce_term_meta($term, 'product_count_' . $taxonomy->name, absint($count));
        }
    }
}
 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':
                 delete_transient('jigoshop_addons_data');
                 delete_transient('jigoshop_report_coupon_usage');
                 delete_transient('jigoshop_report_customer_list');
                 delete_transient('jigoshop_report_customers');
                 delete_transient('jigoshop_report_low_in_stock');
                 delete_transient('jigoshop_report_most_stocked');
                 delete_transient('jigoshop_report_out_of_stock');
                 delete_transient('jigoshop_report_sales_by_category');
                 delete_transient('jigoshop_report_sales_by_date');
                 delete_transient('jigoshop_report_sales_by_product');
                 delete_transient('jigoshop_widget_cache');
                 $query = new WP_User_Query(array('fields' => 'ids'));
                 $users = $query->get_results();
                 foreach ($users as $user) {
                     delete_transient('jigo_usercart_' . $user);
                 }
                 echo '<div class="updated"><p>' . __('Jigoshop transients cleared', 'jigoshop') . '</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', 'jigoshop'), $rows + $rows2) . '</p></div>';
                 break;
             case 'reset_roles':
                 // Remove then re-add caps and roles
                 /** @var $wp_roles WP_Roles */
                 global $wp_roles;
                 $capabilities = jigoshop_get_core_capabilities();
                 foreach ($capabilities as $cap_group) {
                     foreach ($cap_group as $cap) {
                         $wp_roles->remove_cap('administrator', $cap);
                         $wp_roles->remove_cap('shop_manager', $cap);
                     }
                 }
                 remove_role('customer');
                 remove_role('shop_manager');
                 // Add roles back
                 jigoshop_roles_init();
                 echo '<div class="updated"><p>' . __('Roles successfully reset', 'jigoshop') . '</p></div>';
                 break;
             case 'recount_terms':
                 $product_cats = get_terms('product_cat', array('hide_empty' => false, 'fields' => 'id=>parent'));
                 _update_post_term_count($product_cats, get_taxonomy('product_cat'));
                 $product_tags = get_terms('product_tag', array('hide_empty' => false, 'fields' => 'id=>parent'));
                 _update_post_term_count($product_tags, get_taxonomy('product_tag'));
                 echo '<div class="updated"><p>' . __('Terms successfully recounted', 'jigoshop') . '</p></div>';
                 break;
             case 'delete_taxes':
                 $options = Jigoshop_Base::get_options();
                 $options->set('jigoshop_tax_rates', '');
                 $options->update_options();
                 echo '<div class="updated"><p>' . __('Tax rates successfully deleted', 'jigoshop') . '</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', 'jigoshop'), get_class($callback[0]), $callback[1]) . '</p></div>';
                         } else {
                             echo '<div class="error"><p>' . sprintf(__('There was an error calling %s', 'jigoshop'), $callback) . '</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.', 'jigoshop') . '</p></div>';
     }
     $template = jigoshop_locate_template('admin/status/tools');
     /** @noinspection PhpIncludeInspection */
     include $template;
 }
/**
 * Function for recounting product terms, ignoring hidden products.
 * @param  array $terms
 * @param  string $taxonomy
 * @param  bool $callback
 * @param  bool $terms_are_term_taxonomy_ids
 */
function _wc_term_recount($terms, $taxonomy, $callback = true, $terms_are_term_taxonomy_ids = true)
{
    global $wpdb, $wc_allow_term_recount;
    // Don't recount unless CRUD is calling this.
    if (empty($wc_allow_term_recount)) {
        return;
    }
    // Standard callback
    if ($callback) {
        _update_post_term_count($terms, $taxonomy);
    }
    // Main query
    $count_query = "\n\t\tSELECT COUNT( DISTINCT posts.ID ) FROM {$wpdb->posts} as posts\n\t\tLEFT JOIN {$wpdb->term_relationships} AS rel ON posts.ID=rel.object_ID\n\t\tLEFT JOIN {$wpdb->term_taxonomy} AS tax USING( term_taxonomy_id )\n\t\tWHERE \tpost_status = 'publish'\n\t\tAND \tpost_type \t= 'product'\n\t";
    $product_visibility_term_ids = wc_get_product_visibility_term_ids();
    if ($product_visibility_term_ids['exclude-from-catalog']) {
        $count_query .= " AND term_taxonomy_id !=" . $product_visibility_term_ids['exclude-from-catalog'];
    }
    if ('yes' === get_option('woocommerce_hide_out_of_stock_items') && $product_visibility_term_ids['outofstock']) {
        $count_query .= " AND term_taxonomy_id !=" . $product_visibility_term_ids['outofstock'];
    }
    // Pre-process term taxonomy ids
    if (!$terms_are_term_taxonomy_ids) {
        // We passed in an array of TERMS in format id=>parent
        $terms = array_filter((array) array_keys($terms));
    } else {
        // If we have term taxonomy IDs we need to get the term ID
        $term_taxonomy_ids = $terms;
        $terms = array();
        foreach ($term_taxonomy_ids as $term_taxonomy_id) {
            $term = get_term_by('term_taxonomy_id', $term_taxonomy_id, $taxonomy->name);
            $terms[] = $term->term_id;
        }
    }
    // Exit if we have no terms to count
    if (empty($terms)) {
        return;
    }
    // Ancestors need counting
    if (is_taxonomy_hierarchical($taxonomy->name)) {
        foreach ($terms as $term_id) {
            $terms = array_merge($terms, get_ancestors($term_id, $taxonomy->name));
        }
    }
    // Unique terms only
    $terms = array_unique($terms);
    // Count the terms
    foreach ($terms as $term_id) {
        $terms_to_count = array(absint($term_id));
        if (is_taxonomy_hierarchical($taxonomy->name)) {
            // We need to get the $term's hierarchy so we can count its children too
            if (($children = get_term_children($term_id, $taxonomy->name)) && !is_wp_error($children)) {
                $terms_to_count = array_unique(array_map('absint', array_merge($terms_to_count, $children)));
            }
        }
        // Generate term query
        $term_query = ' AND term_id IN ( ' . implode(',', $terms_to_count) . ' )';
        // Get the count
        $count = $wpdb->get_var($count_query . $term_query);
        // Update the count
        update_woocommerce_term_meta($term_id, 'product_count_' . $taxonomy->name, absint($count));
    }
    delete_transient('wc_term_counts');
}
 /**
  * Term Count Callback that applies custom filter
  * Allows Workflow State counts to include non-published posts
  * @since 1.2.1
  * @param unknown $terms
  * @param unknown $taxonomy
  */
 function term_count_cb($terms, $taxonomy)
 {
     add_filter('query', array(&$this, 'term_count_query_filter'));
     _update_post_term_count($terms, $taxonomy);
     remove_filter('query', array(&$this, 'term_count_query_filter'));
 }