I am using a wordpress/woocommerce theme named "invogue". This theme contain some ajax functions that are called using AJAX, but they are super slow >5 sec each.
Is there any way to edit this function to speed things up ?
the following gets the cart items
#GET CART NAV DATA
public function htheme_get_nav_cart_data(){
#GLOBALS
global $wpdb, $hmenu_helper, $woocommerce;
if ( class_exists( 'WooCommerce' ) ) {
#VARAIBLES
$cart_count = $woocommerce->cart->cart_contents_count;
$cart_link = esc_url(get_permalink(get_option('woocommerce_cart_page_id')));
$cart = $woocommerce->cart->get_cart();
$total_quantity = 0;
#ARRAY OF ITEMS
$cart_items = [];
$cart_count = 1;
#FOREACH CART ITEM
foreach($cart as $item){
$image = wp_get_attachment_image_src ( get_post_thumbnail_id ( $item['product_id'] ), 'full' );
$cart_items[] = array(
'id' => $item['product_id'],
'title' => esc_html($item['data']->post->post_title),
'quantity' => $item['quantity'],
'total' => $item['line_subtotal'],
'link' => get_permalink($item['product_id']),
'price' => wc_get_price_decimals(),
'image' => $image[0],
'price_html' => $this->htheme_return_price_html($item['product_id']),
'qty' => esc_html__('Qty', 'invogue'),
);
$total_quantity += $item['quantity'];
$cart_count++;
}
#ECHO JSON
echo json_encode(array(
'status' => 'active',
'count' => $total_quantity,
'url' => $cart_link,
'cart' => $cart_items,
'symbol' => get_woocommerce_currency_symbol(get_option('woocommerce_currency')),
'total' => $woocommerce->cart->get_cart_total(),
));
exit();
} else {
#NOT ACTIVE
echo json_encode(array(
'status' => 'not'
));
exit();
}
}
the following gets the wishlist items
public function htheme_get_nav_wishlist_data(){
#GLOBALS
global $wpdb, $hmenu_helper, $woocommerce;
if ( class_exists( 'WooCommerce' ) ) {
#GET USER ID
$user_ID = get_current_user_id();
#GET USER WISHLIST
$wishlist = esc_attr( get_the_author_meta( 'user_wishlist', $user_ID ) );
#ARGS
$args = array(
'post_type' => 'product',
'posts_per_page' => -1,
'offset' => 0,
'include' => explode(',', $wishlist)
);
#PRODUCTS
$products = get_posts($args);
#ECHO JSON
echo json_encode($products);
exit();
} else {
#NOT ACTIVE
echo json_encode(array(
'status' => 'not'
));
exit();
}
}
Related
Scenario:
Variable product has attribute color, term is 'yellow'
Variation with yellow term is disabled
Customer filters product by color 'yellow'
Parent product is displayed even if variation which uses the color 'yellow' is not enabled
Note: Query should contain simple and variation product types.
The query is being called by ajax function, I'm not sure how to use filters if its possible.
The query:
add_action('wp_ajax_getProducts', 'getProducts');
add_action('wp_ajax_nopriv_getProducts', 'getProducts');
function getProducts(){
$input = [
'currentTerm' => $_POST['currentTerm'],
'searchTerms' => $_POST['searchTerms'],
'page' => $_POST['page'],
'color' => $_POST['color'],
'sortBy' => $_POST['sortBy'],
'sortDirection' => $_POST['sortDirection'],
'beltWidth' => $_POST['beltWidth'],
];
// args init
$args = array(
'post_type' => 'product',
'posts_per_page' => 12,
'post_status' => 'publish',
'lang' => pll_current_language()
);
$args['meta_query'] = array(
'relation' => 'AND',
array(
'key' => '_stock_status',
'value' => 'instock'
),
);
$args['tax_query'] = array(
'relation' => 'AND',
);
// 0. Search
if( isset() ) {
$sargs = array(
's' => $input['searchquery'],
);
$args = array_merge($sargs, $args);
}
// 1. Terms
if( isset($input['currentTerm']) ) {
$cat_tax = array(
'taxonomy' => 'product_cat',
'field' => 'id',
'terms' => $input['currentTerm'],
);
array_push($args['tax_query'], $cat_tax);
}
// 2. Page
if( isset($input['page']) ) {
$args['paged'] = $input['page'];
}
// 3. color
if( isset($input['color']) && $input['color'] != 'clear') {
$color_tax = array(
'taxonomy' => 'pa_color',
'field' => 'slug',
'terms' => $input['color'],
'operator' => 'IN'
);
array_push($args['tax_query'], $color_tax);
}
// 4. sort
if ( isset($input['sortBy']) ) {
if ( $input['sortBy'] == 'price' ) {
$args['orderby'] = 'meta_value_num';
$args['meta_key'] = '_price';
} elseif ( $input['sortBy'] == 'name' ) {
$args['orderby'] = 'title';
} else {
$args['orderby'] = 'date';
}
}
if ( isset($input['sortDirection'])) {
if ( $_POST['sortDirection'] == 'asc') {
$args['order'] = 'asc';
} else {
$args['order'] = 'desc';
}
}
// query
$wp_query = new WP_Query( $args );
...
echo json_encode($products);
...
}
The query works fine, and I've found the way to clear results, by filtering the results; but it returns uneven number of products per page, which is not very user friendly.
The solution is to do something like code below within the query arguments, not inside the results loop.
if( isset($input['color']) && $input['color'] != 'clear') {
if ($product['terms']) {
foreach($product['terms'] as $item) {
if ((string) $item['slug'] == $input['color']) {
array_push($products, $product);
}
}
}
}
I try to implement the Rawg.io API to my Wordpress Functions.php File but it doesn't work, i tried my code with another API and it is working fine, i think it has something to do with the API link Page='.$current_page.'
as you can see i created an custom post type to add the games to.
i also created custom fields with the right field keys.
My Report.txt file keeps returning current page = 1
function register_game_cpt() {
register_post_type( 'game', array(
'label' => 'Games',
'public' => true,
'capability_type' => 'post',
'supports' => array('title', 'editor', 'thumbnail'),
'taxonomies' => array('recordings', 'category', 'whatever', 'post_tag'),
));
}
add_action( 'init', 'register_game_cpt' );
// if ( ! wp_next_scheduled( 'update_game_list' ) ) {
// wp_schedule_event( time(), 'weekly', 'update_game_list' );
// }
add_action( 'update_game_list', 'get_games_from_api' );
add_action( 'wp_ajax_nopriv_get_games_from_api', 'get_games_from_api' );
add_action( 'wp_ajax_get_games_from_api', 'get_games_from_api' );
function get_games_from_api() {
$file = get_stylesheet_directory() . '/report.txt';
$current_page = ( ! empty( $_POST['current_page'] ) ) ? $_POST['current_page'] : 1;
$games = [];
// Should return an array of objects
$results = wp_remote_retrieve_body(wp_remote_get('https://api.rawg.io/api/games?key=/////////////////////&page='.$current_page.'&page_size=40'));
file_put_contents($file, "Current Page: " . $current_page. "\n\n", FILE_APPEND);
// turn it into a PHP array from JSON string
$results = json_decode( $results );
// Either the API is down or something else spooky happened. Just be done.
if( ! is_array( $results ) || empty( $results ) ){
return false;
}
$games[] = $results;
foreach( $games[0] as $game ){
$game_slug = sanitize_title( $game->name . '-' . $game->id );
$existing_game = get_page_by_path( $game_slug, 'OBJECT', 'game' );
if( $existing_game === null ){
$inserted_game = wp_insert_post( [
'post_name' => $game_slug,
'post_title' => $game_slug,
'post_type' => 'game',
'post_status' => 'publish'
] );
if( is_wp_error( $inserted_game ) || $inserted_game === 0 ) {
die('Could not insert game: ' . $game_slug);
error_log( 'Could not insert game: ' . $game_slug );
continue;
}
// add meta fields
$fillable = [
'field_62684fc72d524' => 'count',
'field_6266cb41982d3' => 'name',
'field_6266cb4c982d4' => 'publishers',
'field_6266cb54982d5' => 'genres',
'field_6266cb64012e9' => 'platforms',
'field_6266cb722ebe8' => 'dates',
'field_626850012d525' => 'results',
];
foreach( $fillable as $key => $name ) {
update_field( $key, $game->$name, $inserted_game );
}
} else {
$existing_game_id = $existing_game->ID;
$exisiting_game_timestamp = get_field('updated_at', $existing_game_id);
if( $game->updated_at >= $exisiting_game_timestamp ){
$fillable = [
'field_62684fc72d524' => 'count',
'field_6266cb41982d3' => 'name',
'field_6266cb4c982d4' => 'publishers',
'field_6266cb54982d5' => 'genres',
'field_6266cb64012e9' => 'platforms',
'field_6266cb722ebe8' => 'dates',
'field_626850012d525' => 'results',
];
foreach( $fillable as $key => $name ){
update_field( $name, $game->$name, $existing_game_id);
}
}
}
}
$current_page = $current_page + 1;
wp_remote_post( admin_url('admin-ajax.php?action=get_games_from_api'), [
'blocking' => false,
'sslverify' => false, // we are sending this to ourselves, so trust it.
'body' => [
'current_page' => $current_page
]
] );
}
Im after some help, I want to be able to replace all my product featured images with the default product category image that I have set.
I have found a plug in that does the reverse however Im not sure what changes will need to be made to reverse it?
Would anyone be able to help?
The original plugin author said the below when I asked
'That should be possible, although I'm not aware of any links off the top of my head. A function called "woocommerce_template_loop_product_thumbnail" is hooked in the "woocommerce_before_shop_loop_item_title" action that you could remove and replace, similar to how my plugin works. The function essentially just calls the "woocommerce_get_product_thumbnail" function found here which looks simple enough to muck about with!'
namespace GazChap;
class WC_Category_Product_Thumbnails {
private $shuffle = true;
private $recurse_category_ids = true;
private $limit = 20; // number of most recent products to fetch when shuffle is true, lower means faster
/**
* WC_Category_Product_Thumbnails constructor.
* Sets a default limit (to -1, i.e. all posts) if none already set and then replaces WC actions with ours
*/
public function __construct() {
add_action( 'plugins_loaded', array( $this, 'replace_wc_actions' ) );
if ( !$this->limit ) $this->limit = -1;
}
/**
* Removes the action that puts the thumbnail before the subcategory title, and replaces it with our version
*/
public function replace_wc_actions() {
remove_action( 'woocommerce_before_subcategory_title', 'woocommerce_subcategory_thumbnail', 10 );
add_action( 'woocommerce_before_subcategory_title', array( $this, 'auto_subcategory_thumbnail' ) );
add_filter( 'woocommerce_get_sections_products', array( $this, 'add_setting_section' ) );
add_filter( 'woocommerce_get_settings_products', array( $this, 'add_settings_to_section' ), 10, 2 );
}
/**
* The function that does all the donkey work.
* #param \WP_Term $category - the category that we're dealing with
*/
public function auto_subcategory_thumbnail( $category ) {
// does this category already have a thumbnail defined? if so, use that instead
if ( get_term_meta( $category->term_id, 'thumbnail_id', true ) ) {
woocommerce_subcategory_thumbnail( $category );
return;
}
// get a list of category IDs inside this category (so we're fetching products from all subcategories, not just the top level one)
if ( $this->recurse_category_ids ) {
$category_ids = $this->get_sub_category_ids( $category );
} else {
$category_ids = array( $category->term_id );
}
$query_args = array(
'posts_per_page' => $this->shuffle ? $this->limit : 1,
'post_status' => 'publish',
'post_type' => 'product',
'meta_query' => array(
array(
'key' => '_thumbnail_id',
'value' => '',
'compare' => '!=',
),
),
'tax_query' => array(
array(
'taxonomy' => 'product_cat',
'field' => 'term_id',
'terms' => $category_ids,
'operator' => 'IN',
),
),
);
$products = get_posts( $query_args );
if ( $products ) {
$image_size = 'shop_thumbnail';
if ( get_option('gazchap-wc-category-product-thumbnails_category-size') ) {
$image_size = get_option('gazchap-wc-category-product-thumbnails_category-size');
}
echo get_the_post_thumbnail( $products[ array_rand( $products ) ]->ID, $image_size );
} else {
// show the default placeholder category image if there's no products inside this one
woocommerce_subcategory_thumbnail( $category );
}
}
/**
* Recursive function to fetch a list of child category IDs for the one passed
*
* #param \WP_Term $start - the category to start from
* #param array $results - this just stores the results as they're being built up
*
* #return array - an array of term IDs for each product_cat inside the original one
*/
private function get_sub_category_ids( $start, $results = array() ) {
if ( !is_array( $results ) ) $results = array();
$results[] = $start->term_id;
$cats = get_terms( array( 'taxonomy' => 'product_cat', 'hide_empty' => false, 'parent' => $start->term_id ) );
if ( is_array( $cats ) ) {
foreach( $cats as $cat ) {
$results = $this->get_sub_category_ids( $cat, $results );
}
}
return $results;
}
function add_setting_section( $sections ) {
$sections['gazchap-wc-category-thumbnails'] = __( 'Auto Category Thumbnails', 'gazchap-wc-category-product-thumbnails' );
return $sections;
}
function add_settings_to_section( $settings, $current_section ) {
/**
* Check the current section is what we want
**/
if ( $current_section == 'gazchap-wc-category-thumbnails' ) {
$new_settings = array();
// Add Title to the Settings
$new_settings[] = array( 'name' => __( 'Auto Category Thumbnails Settings', 'gazchap-wc-category-product-thumbnails' ), 'type' => 'title', 'desc' => __( 'The following options are used to configure GazChap\'s Auto Category Thumbnails', 'text-domain' ), 'id' => 'gazchap-wc-category-thumbnails' );
$temp = $this->_get_all_image_sizes();
$image_sizes = array();
foreach( $temp as $image_size => $image_spec_array ) {
$image_spec = "";
$image_spec .= ($image_spec_array['width'] > 0) ? $image_spec_array['width'] : 'auto';
$image_spec .= ' x ';
$image_spec .= ($image_spec_array['height'] > 0) ? $image_spec_array['height'] : 'auto';
if ( $image_spec_array['crop'] ) {
$image_spec .= ", cropped";
}
$image_sizes[ $image_size ] = $image_size . " (" . $image_spec . ")";
}
// Add first checkbox option
$new_settings[] = array(
'name' => __( 'Thumbnail Size', 'text-domain' ),
'desc_tip' => __( 'Choose the image size to use for the thumbnails', 'gazchap-wc-category-thumbnails' ),
'id' => 'gazchap-wc-category-product-thumbnails_category-size',
'type' => 'select',
'options' => $image_sizes,
'desc' => __( 'Choose the image size to use for the thumbnails', 'gazchap-wc-category-thumbnails' ),
);
$new_settings[] = array( 'type' => 'sectionend', 'id' => 'gazchap-wc-category-thumbnails' );
return $new_settings;
/**
* If not, return the standard settings
**/
} else {
return $settings;
}
}
private function _get_all_image_sizes() {
global $_wp_additional_image_sizes;
$default_image_sizes = get_intermediate_image_sizes();
foreach ( $default_image_sizes as $size ) {
$image_sizes[ $size ][ 'width' ] = intval( get_option( "{$size}_size_w" ) );
$image_sizes[ $size ][ 'height' ] = intval( get_option( "{$size}_size_h" ) );
$image_sizes[ $size ][ 'crop' ] = get_option( "{$size}_crop" ) ? get_option( "{$size}_crop" ) : false;
}
if ( isset( $_wp_additional_image_sizes ) && count( $_wp_additional_image_sizes ) ) {
$image_sizes = array_merge( $image_sizes, $_wp_additional_image_sizes );
}
return $image_sizes;
}
}
new WC_Category_Product_Thumbnails();
If anyone can help it would be most appreciated or be able to provide another way how to achieve this!
Using Woocommerce, I want to force a shipping method when a certain valid coupon is applied at the cart/checkout phase.
Below my code. It extends WC_Shipping_Method, gets the whole woocommerce coupon list, let admin to select one or more, save them and then, when a costumer applies one of those chosen coupons checking out, forces to use only one this shipping method.
if ( in_array( 'woocommerce/woocommerce.php', apply_filters( 'active_plugins', get_option( 'active_plugins' ) ) ) ) {
/* Custom LocalPickup Class */
class WC_Shipping_LocalPickUp_On_Coupon extends WC_Shipping_Method {
public $requires = '';
public function __construct( $instance_id = 0 ) {
$this->id = 'localpickup_on_coupon';
$this->instance_id = absint( $instance_id );
$this->method_title = __( 'Pickup with Coupon', 'Valeo' );
$this->method_description = __( 'Pickup with Coupon', 'Valeo' );
$this->supports = array(
'shipping-zones',
'instance-settings',
'instance-settings-modal',
);
/*Getting Coupon List */
$args = array(
'posts_per_page' => -1,
'orderby' => 'title',
'order' => 'asc',
'post_type' => 'shop_coupon',
'post_status' => 'publish',
);
$coupons = get_posts( $args );
$this->list = [];
foreach($coupons as $item){
$this->list[$item->post_name] = $item->post_title;
}
$this->init();
add_action( 'woocommerce_update_options_shipping_' . $this->id, array( $this, 'process_admin_options' ) );
}
public function init() {
$this->init_form_fields();
$this->init_settings();
$this->title = $this->get_option( 'title' );
$this->requires = $this->get_option( 'requires' );
}
public function init_form_fields() {
$this->instance_form_fields = array(
'title' => array(
'title' => __( 'Title', 'woocommerce' ),
'type' => 'text',
'description' => __( 'This controls the title which the user sees during checkout.', 'woocommerce' ),
'default' => $this->method_title,
'desc_tip' => true,
),
'requires' => array(
'title' => __( 'Il ritiro in sede richiede...', 'Valeo' ),
'type' => 'multiselect',
'class' => 'valeo_multiselect',
'default' => '',
'options' => $this->list
),
);
}
public function is_available( $package ) {
$has_coupon = false;
$coupons = WC()->cart->get_coupons();
if(!empty($coupons)) {
$couponKey = array_keys($coupons)[0];
if ( in_array( $couponKey, $this->requires ) ) {
if ( $coupons ) {
foreach ( $coupons as $code => $coupon ) {
if ( $coupon->is_valid() ) {
$has_coupon = true;
break;
}
}
}
}
}
return apply_filters( 'woocommerce_shipping_' . $this->id . '_is_available', $has_coupon, $package, $this );
}
public function calculate_shipping( $package = array() ) {
$rate = array(
'id' => $this->get_rate_id(),
'label' => $this->title,
'cost' => 0,
'taxes' => 0,
'package' => $package,
);
$this->add_rate($rate);
do_action( 'woocommerce_' . $this->id . '_shipping_add_rate', $this, $rate );
}
}
add_filter( 'woocommerce_shipping_methods', 'register_devso_method' );
function register_devso_method( $methods ) {
$methods[ 'localpickup_on_coupon' ] = 'WC_Shipping_LocalPickUp_On_Coupon';
return $methods;
}
}
Here the filter that checks if customer has inserted the chosen coupon/s and (in a "bad" way) removes all woocommerce package rates but the one I declared in the class.
function filter_woocommerce_package_rates( $array ) {
$check = FALSE;
foreach($array as $index => $value){
if(strpos($index, 'localpickup_on_coupon') !== false) { $check = TRUE; }
}
if($check){
foreach($array as $index => $value){
if(!(strpos($index, 'localpickup_on_coupon') !== false)) { unset($array[$index]); }
}
}
return $array;
};
// add the filter
add_filter( 'woocommerce_package_rates', 'filter_woocommerce_package_rates', 10, 1 );
Is there a better way to do this?
I have this snippet for creating a list of users sorted by the highest post views.
But I'm wondering of how can I create pagination for a custom array like that.
$topuser = array();
$avatar_size = 100;
$args = array(
'role__in' => array( 'contributor', 'author' ),
'hide_empty' => '1'
);
$users = get_users( $args );
foreach ( $users as $user ) {
$query = get_posts(
array(
'author' => $user->ID,
'cat' => '3',
'numberposts' => -1,
'post_type' => 'post',
)
);
$counter = 0;
$post_count = count_user_posts( $user->ID );
if ( ! $post_count ) {
continue;
}
// get each post of a user
foreach ( $query as $post ){
$views = absint( get_post_meta( $post->ID, 'post_views_count', true ) );
$counter += $views;
}
$topuser[] = array(
'id' => $user->ID,
'views' => $counter,
);
wp_reset_query();
}
// function to sort array based on views count
function sortViews( $a, $b ) {
return $b['views'] - $a['views'];
}
usort( $topuser, 'sortViews' ); // sort the array
$output = $topuser;
Thanks in advance!