From 57157db9bf4903750d4c30ceeeec7a66ecb39f4e Mon Sep 17 00:00:00 2001 From: Mike Jolley Date: Fri, 9 Aug 2013 17:11:15 +0100 Subject: [PATCH] Function refactoring. --- includes/abstracts/abstract-wc-product.php | 6 +- includes/admin/class-wc-admin-post-types.php | 4 +- includes/admin/class-wc-admin-settings.php | 2 +- includes/admin/class-wc-admin-status.php | 7 +- .../post-types/class-wc-admin-cpt-product.php | 2 +- .../class-wc-meta-box-product-data.php | 4 +- includes/class-wc-comments.php | 152 + includes/class-wc-download-handler.php | 313 ++ includes/class-wc-form-handler.php | 750 +++++ includes/class-wc-install.php | 78 +- includes/class-wc-product-simple.php | 2 +- includes/class-wc-product-variable.php | 8 +- includes/class-wc-product-variation.php | 6 +- includes/class-wc-query.php | 198 +- includes/class-wc-shortcodes.php | 61 +- .../helpers/class-wc-body-class-helper.php | 36 - .../helpers/class-wc-post-class-helper.php | 55 - .../helpers/class-wc-shortcode-helper.php | 34 - .../helpers/class-wc-transient-helper.php | 65 - .../class-wc-shortcode-change-password.php | 3 +- .../class-wc-shortcode-checkout.php | 3 +- .../class-wc-shortcode-my-account.php | 3 +- .../class-wc-shortcode-order-tracking.php | 3 +- .../class-wc-shortcode-view-order.php | 3 +- includes/wc-cart-functions.php | 134 + includes/wc-conditional-functions.php | 204 ++ includes/wc-core-functions.php | 171 ++ includes/wc-customer-functions.php | 260 ++ includes/wc-deprecated-functions.php | 35 + includes/wc-formatting-functions.php | 454 +++ includes/wc-message-functions.php | 1 - includes/wc-order-functions.php | 327 ++ includes/wc-page-functions.php | 174 ++ includes/wc-product-functions.php | 481 +++ includes/wc-reporting-functions.php | 14 - .../wc-template-functions.php | 293 +- includes/wc-template-hooks.php | 194 ++ includes/wc-term-functions.php | 501 ++++ uninstall.php | 7 +- woocommerce-ajax.php | 2 +- woocommerce-core-functions.php | 2641 ----------------- woocommerce-functions.php | 1762 ----------- woocommerce-hooks.php | 290 -- woocommerce.php | 79 +- 44 files changed, 4789 insertions(+), 5033 deletions(-) create mode 100644 includes/class-wc-comments.php create mode 100644 includes/class-wc-download-handler.php create mode 100644 includes/class-wc-form-handler.php delete mode 100755 includes/helpers/class-wc-body-class-helper.php delete mode 100755 includes/helpers/class-wc-post-class-helper.php delete mode 100755 includes/helpers/class-wc-shortcode-helper.php delete mode 100755 includes/helpers/class-wc-transient-helper.php create mode 100644 includes/wc-cart-functions.php create mode 100644 includes/wc-conditional-functions.php create mode 100644 includes/wc-core-functions.php create mode 100644 includes/wc-customer-functions.php create mode 100644 includes/wc-formatting-functions.php create mode 100644 includes/wc-order-functions.php create mode 100644 includes/wc-page-functions.php create mode 100644 includes/wc-product-functions.php delete mode 100644 includes/wc-reporting-functions.php rename woocommerce-template.php => includes/wc-template-functions.php (82%) create mode 100644 includes/wc-template-hooks.php create mode 100644 includes/wc-term-functions.php delete mode 100644 woocommerce-core-functions.php delete mode 100644 woocommerce-functions.php delete mode 100644 woocommerce-hooks.php diff --git a/includes/abstracts/abstract-wc-product.php b/includes/abstracts/abstract-wc-product.php index bc5620ae1e8..1eb609ac965 100644 --- a/includes/abstracts/abstract-wc-product.php +++ b/includes/abstracts/abstract-wc-product.php @@ -170,7 +170,7 @@ class WC_Product { elseif ( $this->backorders_allowed() || $this->get_total_stock() > 0 ) $this->set_stock_status( 'instock' ); - $woocommerce->get_helper( 'transient' )->clear_product_transients( $this->id ); // Clear transient + wc_delete_product_transients( $this->id ); // Clear transient return $this->get_stock_quantity(); } @@ -196,7 +196,7 @@ class WC_Product { if ( ! $this->backorders_allowed() && $this->get_total_stock() <= 0 ) $this->set_stock_status( 'outofstock' ); - $woocommerce->get_helper( 'transient' )->clear_product_transients( $this->id ); // Clear transient + wc_delete_product_transients( $this->id ); // Clear transient return $this->get_stock_quantity(); } @@ -222,7 +222,7 @@ class WC_Product { if ( $this->backorders_allowed() || $this->get_total_stock() > 0 ) $this->set_stock_status( 'instock' ); - $woocommerce->get_helper( 'transient' )->clear_product_transients( $this->id ); // Clear transient + wc_delete_product_transients( $this->id ); // Clear transient return $this->get_stock_quantity(); } diff --git a/includes/admin/class-wc-admin-post-types.php b/includes/admin/class-wc-admin-post-types.php index e727979a61a..1c5b0759cbe 100644 --- a/includes/admin/class-wc-admin-post-types.php +++ b/includes/admin/class-wc-admin-post-types.php @@ -149,12 +149,12 @@ class WC_Admin_Post_Types { wp_update_post( $child_post ); } - WC()->get_helper( 'transient' )->clear_product_transients(); + wc_delete_product_transients(); break; case 'product_variation' : - WC()->get_helper( 'transient' )->clear_product_transients(); + wc_delete_product_transients(); break; } diff --git a/includes/admin/class-wc-admin-settings.php b/includes/admin/class-wc-admin-settings.php index 751c38d4746..3d05a9118fd 100644 --- a/includes/admin/class-wc-admin-settings.php +++ b/includes/admin/class-wc-admin-settings.php @@ -58,7 +58,7 @@ class WC_Admin_Settings { do_action( 'woocommerce_update_options' ); // Clear any unwanted data - WC()->get_helper( 'transient' )->clear_product_transients(); + wc_delete_product_transients(); delete_transient( 'woocommerce_cache_excluded_uris' ); self::add_message( __( 'Your settings have been saved.', 'woocommerce' ) ); diff --git a/includes/admin/class-wc-admin-status.php b/includes/admin/class-wc-admin-status.php index 63df30eaef8..fea64843ba9 100644 --- a/includes/admin/class-wc-admin-status.php +++ b/includes/admin/class-wc-admin-status.php @@ -47,7 +47,7 @@ class WC_Admin_Status { switch ( $_GET['action'] ) { case "clear_transients" : - $woocommerce->get_helper( 'transient' )->clear_product_transients(); + wc_delete_product_transients(); echo '

' . __( 'Product Transients Cleared', 'woocommerce' ) . '

'; break; @@ -95,8 +95,9 @@ class WC_Admin_Status { break; case "reset_roles" : // Remove then re-add caps and roles - woocommerce_remove_roles(); - woocommerce_init_roles(); + $installer = include( WC()->plugin_path() . '/includes/class-wc-install.php' ); + $installer->remove_roles(); + $installer->create_roles(); echo '

' . __( 'Roles successfully reset', 'woocommerce' ) . '

'; break; diff --git a/includes/admin/post-types/class-wc-admin-cpt-product.php b/includes/admin/post-types/class-wc-admin-cpt-product.php index 0664ff3e49a..4850f251880 100644 --- a/includes/admin/post-types/class-wc-admin-cpt-product.php +++ b/includes/admin/post-types/class-wc-admin-cpt-product.php @@ -666,7 +666,7 @@ class WC_Admin_CPT_Product extends WC_Admin_CPT { $this->bulk_edit_save( $post_id, $product ); // Clear transient - $woocommerce->get_helper( 'transient' )->clear_product_transients( $post_id ); + wc_delete_product_transients( $post_id ); } /** diff --git a/includes/admin/post-types/meta-boxes/class-wc-meta-box-product-data.php b/includes/admin/post-types/meta-boxes/class-wc-meta-box-product-data.php index 01a63bc4ba6..83a9218b218 100644 --- a/includes/admin/post-types/meta-boxes/class-wc-meta-box-product-data.php +++ b/includes/admin/post-types/meta-boxes/class-wc-meta-box-product-data.php @@ -1131,7 +1131,7 @@ class WC_Meta_Box_Product_Data { } // Clear cache/transients - WC()->get_helper( 'transient' )->clear_product_transients( $clear_id ); + wc_delete_product_transients( $clear_id ); } } } @@ -1265,7 +1265,7 @@ class WC_Meta_Box_Product_Data { do_action( 'woocommerce_process_product_meta_' . $product_type, $post_id ); // Clear cache/transients - WC()->get_helper( 'transient' )->clear_product_transients( $post_id ); + wc_delete_product_transients( $post_id ); } /** diff --git a/includes/class-wc-comments.php b/includes/class-wc-comments.php new file mode 100644 index 00000000000..31d20f9f588 --- /dev/null +++ b/includes/class-wc-comments.php @@ -0,0 +1,152 @@ +comment_post_ID ) should keep them safe since only admin and + * shop managers can view orders anyway. + * + * The frontend view order pages get around this filter by using remove_filter('comments_clauses', 'woocommerce_exclude_order_comments'); + * + * @param array $clauses + * @return array + */ + public function exclude_order_comments( $clauses ) { + global $wpdb, $typenow, $pagenow; + + if ( is_admin() && $typenow == 'shop_order' && current_user_can( 'manage_woocommerce' ) ) + return $clauses; // Don't hide when viewing orders in admin + + if ( ! $clauses['join'] ) + $clauses['join'] = ''; + + if ( ! strstr( $clauses['join'], "JOIN $wpdb->posts" ) ) + $clauses['join'] .= " LEFT JOIN $wpdb->posts ON comment_post_ID = $wpdb->posts.ID "; + + if ( $clauses['where'] ) + $clauses['where'] .= ' AND '; + + $clauses['where'] .= " $wpdb->posts.post_type NOT IN ('shop_order') "; + + return $clauses; + } + + /** + * Exclude order comments from queries and RSS + * + * @param string $join + * @return string + */ + public function exclude_order_comments_from_feed_join( $join ) { + global $wpdb; + + if ( ! $join ) + $join = " LEFT JOIN $wpdb->posts ON $wpdb->comments.comment_post_ID = $wpdb->posts.ID "; + + return $join; + } + + /** + * Exclude order comments from queries and RSS + * + * @param string $where + * @return string + */ + public function exclude_order_comments_from_feed_where( $where ) { + global $wpdb; + + if ( $where ) + $where .= ' AND '; + + $where .= " $wpdb->posts.post_type NOT IN ('shop_order') "; + + return $where; + } + + /** + * Validate the comment ratings. + * + * @param array $comment_data + * @return array + */ + public function check_comment_rating( $comment_data ) { + global $woocommerce; + + // If posting a comment (not trackback etc) and not logged in + if ( isset( $_POST['rating'] ) && ! wp_verify_nonce( $_POST['_wpnonce'], 'woocommerce-comment_rating' ) ) + wp_die( __( 'You have taken too long. Please go back and refresh the page.', 'woocommerce' ) ); + + elseif ( isset( $_POST['rating'] ) && empty( $_POST['rating'] ) && $comment_data['comment_type'] == '' && get_option('woocommerce_review_rating_required') == 'yes' ) { + wp_die( __( 'Please rate the product.', 'woocommerce' ) ); + exit; + } + return $comment_data; + } + + /** + * Rating field for comments. + * + * @param mixed $comment_id + */ + public function add_comment_rating( $comment_id ) { + if ( isset( $_POST['rating'] ) ) { + + if ( ! $_POST['rating'] || $_POST['rating'] > 5 || $_POST['rating'] < 0 ) + return; + + add_comment_meta( $comment_id, 'rating', (int) esc_attr( $_POST['rating'] ), true ); + + woocommerce_clear_comment_rating_transients( $comment_id ); + } + } + + /** + * Clear transients for a review. + * + * @param mixed $comment_id + */ + public function clear_transients( $comment_id ) { + $comment = get_comment( $comment_id ); + + if ( ! empty( $comment->comment_post_ID ) ) { + delete_transient( 'wc_average_rating_' . absint( $comment->comment_post_ID ) ); + delete_transient( 'wc_rating_count_' . absint( $comment->comment_post_ID ) ); + } + } +} + +new WC_Comments(); \ No newline at end of file diff --git a/includes/class-wc-download-handler.php b/includes/class-wc-download-handler.php new file mode 100644 index 00000000000..3a27741032a --- /dev/null +++ b/includes/class-wc-download-handler.php @@ -0,0 +1,313 @@ +' . __( 'Go to homepage →', 'woocommerce' ) . '' ); + + $query = " + SELECT order_id,downloads_remaining,user_id,download_count,access_expires,download_id + FROM " . $wpdb->prefix . "woocommerce_downloadable_product_permissions + WHERE user_email = %s + AND order_key = %s + AND product_id = %s"; + + $args = array( + $email, + $order_key, + $product_id + ); + + if ( $download_id ) { + // backwards compatibility for existing download URLs + $query .= " AND download_id = %s"; + $args[] = $download_id; + } + + $download_result = $wpdb->get_row( $wpdb->prepare( $query, $args ) ); + + if ( ! $download_result ) + wp_die( __( 'Invalid download.', 'woocommerce' ) . ' ' . __( 'Go to homepage →', 'woocommerce' ) . '' ); + + $download_id = $download_result->download_id; + $order_id = $download_result->order_id; + $downloads_remaining = $download_result->downloads_remaining; + $download_count = $download_result->download_count; + $user_id = $download_result->user_id; + $access_expires = $download_result->access_expires; + + if ( $user_id && get_option( 'woocommerce_downloads_require_login' ) == 'yes' ) { + + if ( ! is_user_logged_in() ) + wp_die( __( 'You must be logged in to download files.', 'woocommerce' ) . ' ' . __( 'Login →', 'woocommerce' ) . '', __( 'Log in to Download Files', 'woocommerce' ) ); + + elseif ( $user_id != get_current_user_id() ) + wp_die( __( 'This is not your download link.', 'woocommerce' ) ); + + } + + if ( ! get_post( $product_id ) ) + wp_die( __( 'Product no longer exists.', 'woocommerce' ) . ' ' . __( 'Go to homepage →', 'woocommerce' ) . '' ); + + if ( $order_id ) { + $order = new WC_Order( $order_id ); + + if ( ! $order->is_download_permitted() || $order->post_status != 'publish' ) + wp_die( __( 'Invalid order.', 'woocommerce' ) . ' ' . __( 'Go to homepage →', 'woocommerce' ) . '' ); + } + + if ( $downloads_remaining == '0' ) + wp_die( __( 'Sorry, you have reached your download limit for this file', 'woocommerce' ) . ' ' . __( 'Go to homepage →', 'woocommerce' ) . '' ); + + if ( $access_expires > 0 && strtotime( $access_expires) < current_time( 'timestamp' ) ) + wp_die( __( 'Sorry, this download has expired', 'woocommerce' ) . ' ' . __( 'Go to homepage →', 'woocommerce' ) . '' ); + + if ( $downloads_remaining > 0 ) { + $wpdb->update( $wpdb->prefix . "woocommerce_downloadable_product_permissions", array( + 'downloads_remaining' => $downloads_remaining - 1, + ), array( + 'user_email' => $email, + 'order_key' => $order_key, + 'product_id' => $product_id, + 'download_id' => $download_id + ), array( '%d' ), array( '%s', '%s', '%d', '%s' ) ); + } + + // Count the download + $wpdb->update( $wpdb->prefix . "woocommerce_downloadable_product_permissions", array( + 'download_count' => $download_count + 1, + ), array( + 'user_email' => $email, + 'order_key' => $order_key, + 'product_id' => $product_id, + 'download_id' => $download_id + ), array( '%d' ), array( '%s', '%s', '%d', '%s' ) ); + + // Trigger action + do_action( 'woocommerce_download_product', $email, $order_key, $product_id, $user_id, $download_id, $order_id ); + + // Get the download URL and try to replace the url with a path + $file_path = $_product->get_file_download_path( $download_id ); + + // Download it! + $this->download( $file_path ); + } + } + + /** + * Download a file - hook into init function. + * + * @access public + * @return void + */ + function download( $file_path ) { + + $file_download_method = apply_filters( 'woocommerce_file_download_method', get_option( 'woocommerce_file_download_method' ), $product_id ); + + if ( ! $file_path ) + wp_die( __( 'No file defined', 'woocommerce' ) . ' ' . __( 'Go to homepage →', 'woocommerce' ) . '' ); + + // Redirect to the file... + if ( $file_download_method == "redirect" ) { + header( 'Location: ' . $file_path ); + exit; + } + + // ...or serve it + if ( ! is_multisite() ) { + + /* + * Download file may be either http or https. + * site_url() depends on whether the page containing the download (ie; My Account) is served via SSL because WC + * modifies site_url() via a filter to force_ssl. + * So blindly doing a str_replace is incorrect because it will fail when schemes are mismatched. This code + * handles the various permutations. + */ + $scheme = parse_url( $file_path, PHP_URL_SCHEME ); + + if ( $scheme ) { + $site_url = set_url_scheme( site_url( '' ), $scheme ); + } else { + $site_url = is_ssl() ? str_replace( 'https:', 'http:', site_url() ) : site_url(); + } + + $file_path = str_replace( trailingslashit( $site_url ), ABSPATH, $file_path ); + + } else { + + $network_url = is_ssl() ? str_replace( 'https:', 'http:', network_admin_url() ) : network_admin_url(); + $upload_dir = wp_upload_dir(); + + // Try to replace network url + $file_path = str_replace( trailingslashit( $network_url ), ABSPATH, $file_path ); + + // Now try to replace upload URL + $file_path = str_replace( $upload_dir['baseurl'], $upload_dir['basedir'], $file_path ); + } + + // See if its local or remote + if ( strstr( $file_path, 'http:' ) || strstr( $file_path, 'https:' ) || strstr( $file_path, 'ftp:' ) ) { + $remote_file = true; + } else { + $remote_file = false; + + // Remove Query String + if ( strstr( $file_path, '?' ) ) + $file_path = current( explode( '?', $file_path ) ); + + $file_path = realpath( $file_path ); + } + + $file_extension = strtolower( substr( strrchr( $file_path, "." ), 1 ) ); + $ctype = "application/force-download"; + + foreach ( get_allowed_mime_types() as $mime => $type ) { + $mimes = explode( '|', $mime ); + if ( in_array( $file_extension, $mimes ) ) { + $ctype = $type; + break; + } + } + + // Start setting headers + if ( ! ini_get('safe_mode') ) + @set_time_limit(0); + + if ( function_exists( 'get_magic_quotes_runtime' ) && get_magic_quotes_runtime() ) + @set_magic_quotes_runtime(0); + + if( function_exists( 'apache_setenv' ) ) + @apache_setenv( 'no-gzip', 1 ); + + @session_write_close(); + @ini_set( 'zlib.output_compression', 'Off' ); + @ob_end_clean(); + + if ( ob_get_level() ) + @ob_end_clean(); // Zip corruption fix + + if ( $is_IE && is_ssl() ) { + // IE bug prevents download via SSL when Cache Control and Pragma no-cache headers set. + header( 'Expires: Wed, 11 Jan 1984 05:00:00 GMT' ); + header( 'Cache-Control: private' ); + } else { + nocache_headers(); + } + + $file_name = basename( $file_path ); + + if ( strstr( $file_name, '?' ) ) + $file_name = current( explode( '?', $file_name ) ); + + header( "Robots: none" ); + header( "Content-Type: " . $ctype ); + header( "Content-Description: File Transfer" ); + header( "Content-Disposition: attachment; filename=\"" . $file_name . "\";" ); + header( "Content-Transfer-Encoding: binary" ); + + if ( $size = @filesize( $file_path ) ) + header( "Content-Length: " . $size ); + + if ( $file_download_method == 'xsendfile' ) { + + // Path fix - kudos to Jason Judge + if ( getcwd() ) + $file_path = trim( preg_replace( '`^' . getcwd() . '`' , '', $file_path ), '/' ); + + header( "Content-Disposition: attachment; filename=\"" . $file_name . "\";" ); + + if ( function_exists( 'apache_get_modules' ) && in_array( 'mod_xsendfile', apache_get_modules() ) ) { + + header("X-Sendfile: $file_path"); + exit; + + } elseif ( stristr( getenv( 'SERVER_SOFTWARE' ), 'lighttpd' ) ) { + + header( "X-Lighttpd-Sendfile: $file_path" ); + exit; + + } elseif ( stristr( getenv( 'SERVER_SOFTWARE' ), 'nginx' ) || stristr( getenv( 'SERVER_SOFTWARE' ), 'cherokee' ) ) { + + header( "X-Accel-Redirect: /$file_path" ); + exit; + + } + } + + if ( $remote_file ) + $this->readfile_chunked( $file_path ) or header( 'Location: ' . $file_path ); + else + $this->readfile_chunked( $file_path ) or wp_die( __( 'File not found', 'woocommerce' ) . ' ' . __( 'Go to homepage →', 'woocommerce' ) . '' ); + + exit; + } + + /** + * readfile_chunked + * + * Reads file in chunks so big downloads are possible without changing PHP.INI - http://codeigniter.com/wiki/Download_helper_for_large_files/ + * + * @param string file + * @param boolean return bytes of file + */ + public static function readfile_chunked( $file, $retbytes = true ) { + + $chunksize = 1 * ( 1024 * 1024 ); + $buffer = ''; + $cnt = 0; + + $handle = @fopen( $file, 'r' ); + if ( $handle === FALSE ) + return FALSE; + + while ( ! feof( $handle ) ) { + $buffer = fread( $handle, $chunksize ); + echo $buffer; + ob_flush(); + flush(); + + if ( $retbytes ) + $cnt += strlen( $buffer ); + } + + $status = fclose( $handle ); + + if ( $retbytes && $status ) + return $cnt; + + return $status; + } +} + +new WC_Download_Handler(); \ No newline at end of file diff --git a/includes/class-wc-form-handler.php b/includes/class-wc-form-handler.php new file mode 100644 index 00000000000..b7d1c207fff --- /dev/null +++ b/includes/class-wc-form-handler.php @@ -0,0 +1,750 @@ +validation(); + + $user_id = get_current_user_id(); + + if ( $user_id <= 0 ) return; + + $load_address = ( $wp->query_vars['edit-address'] == 'billing' || $wp->query_vars['edit-address'] == 'shipping' ) ? $wp->query_vars['edit-address'] : 'billing'; + + $address = $woocommerce->countries->get_address_fields( esc_attr( $_POST[ $load_address . '_country' ] ), $load_address . '_' ); + + foreach ($address as $key => $field) : + + if (!isset($field['type'])) $field['type'] = 'text'; + + // Get Value + switch ($field['type']) : + case "checkbox" : + $_POST[$key] = isset($_POST[$key]) ? 1 : 0; + break; + default : + $_POST[$key] = isset($_POST[$key]) ? woocommerce_clean($_POST[$key]) : ''; + break; + endswitch; + + // Hook to allow modification of value + $_POST[$key] = apply_filters('woocommerce_process_myaccount_field_' . $key, $_POST[$key]); + + // Validation: Required fields + if ( isset($field['required']) && $field['required'] && empty($_POST[$key]) ) wc_add_error( $field['label'] . ' ' . __( 'is a required field.', 'woocommerce' ) ); + + // Postcode + if ($key=='billing_postcode' || $key=='shipping_postcode') : + if ( ! $validation->is_postcode( $_POST[$key], $_POST[ $load_address . '_country' ] ) ) : + wc_add_error( __( 'Please enter a valid postcode/ZIP.', 'woocommerce' ) ); + else : + $_POST[$key] = $validation->format_postcode( $_POST[$key], $_POST[ $load_address . '_country' ] ); + endif; + endif; + + endforeach; + + if ( wc_error_count() == 0 ) { + + foreach ($address as $key => $field) : + update_user_meta( $user_id, $key, $_POST[$key] ); + endforeach; + + wc_add_message( __( 'Address changed successfully.', 'woocommerce' ) ); + + do_action( 'woocommerce_customer_save_address', $user_id ); + + wp_safe_redirect( get_permalink( woocommerce_get_page_id('myaccount') ) ); + exit; + } + } + + /** + * Save the password/account details and redirect back to the my account page. + */ + public function save_account_details() { + global $woocommerce; + + if ( 'POST' !== strtoupper( $_SERVER[ 'REQUEST_METHOD' ] ) ) + return; + + if ( empty( $_POST[ 'action' ] ) || ( 'save_account_details' !== $_POST[ 'action' ] ) ) + return; + + wp_verify_nonce( $_POST['_wpnonce'], 'woocommerce-save_account_details' ); + + $update = true; + $errors = new WP_Error(); + $user = new stdClass(); + + $user->ID = (int) get_current_user_id(); + $current_user = get_user_by( 'id', $user->ID ); + + if ( $user->ID <= 0 ) + return; + + $account_first_name = ! empty( $_POST[ 'account_first_name' ] ) ? woocommerce_clean( $_POST[ 'account_first_name' ] ) : ''; + $account_last_name = ! empty( $_POST[ 'account_last_name' ] ) ? woocommerce_clean( $_POST[ 'account_last_name' ] ) : ''; + $account_email = ! empty( $_POST[ 'account_email' ] ) ? woocommerce_clean( $_POST[ 'account_email' ] ) : ''; + $pass1 = ! empty( $_POST[ 'password_1' ] ) ? woocommerce_clean( $_POST[ 'password_1' ] ) : ''; + $pass2 = ! empty( $_POST[ 'password_2' ] ) ? woocommerce_clean( $_POST[ 'password_2' ] ) : ''; + + $user->first_name = $account_first_name; + $user->last_name = $account_last_name; + $user->user_email = $account_email; + $user->display_name = $user->first_name; + + if ( $pass1 ) + $user->user_pass = $pass1; + + if ( empty( $account_first_name ) || empty( $account_last_name ) ) + wc_add_error( __( 'Please enter your name.', 'woocommerce' ) ); + + if ( empty( $account_email ) || ! is_email( $account_email ) ) + wc_add_error( __( 'Please provide a valid email address.', 'woocommerce' ) ); + + elseif ( email_exists( $account_email ) && $account_email !== $current_user->user_email ) + wc_add_error( __( 'This email address is already registered.', 'woocommerce' ) ); + + if ( ! empty( $pass1 ) && empty( $pass2 ) ) + wc_add_error( __( 'Please re-enter your password.', 'woocommerce' ) ); + + elseif ( ! empty( $pass1 ) && $pass1 !== $pass2 ) + wc_add_error( __( 'Passwords do not match.', 'woocommerce' ) ); + + // Allow plugins to return their own errors. + do_action_ref_array( 'user_profile_update_errors', array ( &$errors, $update, &$user ) ); + + if ( $errors->get_error_messages() ) + foreach( $errors->get_error_messages() as $error ) + wc_add_error( $error ); + + if ( wc_error_count() == 0 ) { + + wp_update_user( $user ) ; + + wc_add_message( __( 'Account details changed successfully.', 'woocommerce' ) ); + + do_action( 'woocommerce_save_account_details', $user->ID ); + + wp_safe_redirect( get_permalink( woocommerce_get_page_id( 'myaccount' ) ) ); + exit; + } + } + + /** + * Process the checkout form. + */ + public function checkout_action() { + if ( isset( $_POST['woocommerce_checkout_place_order'] ) || isset( $_POST['woocommerce_checkout_update_totals'] ) ) { + + if ( sizeof( WC()->cart->get_cart() ) == 0 ) { + wp_redirect( get_permalink( woocommerce_get_page_id( 'cart' ) ) ); + exit; + } + + if ( ! defined( 'WOOCOMMERCE_CHECKOUT' ) ) + define( 'WOOCOMMERCE_CHECKOUT', true ); + + $woocommerce_checkout = WC()->checkout(); + $woocommerce_checkout->process_checkout(); + } + } + + /** + * Process the pay form. + */ + public function pay_action() { + global $wp; + + if ( isset( $_POST['woocommerce_pay'] ) && wp_verify_nonce( $_POST['_wpnonce'], 'woocommerce-pay' ) ) { + + ob_start(); + + // Pay for existing order + $order_key = urldecode( $_GET['key'] ); + $order_id = absint( $wp->query_vars['order-pay'] ); + $order = new WC_Order( $order_id ); + + if ( $order->id == $order_id && $order->order_key == $order_key && in_array( $order->status, array( 'pending', 'failed' ) ) ) { + + // Set customer location to order location + if ( $order->billing_country ) + WC()->customer->set_country( $order->billing_country ); + if ( $order->billing_state ) + WC()->customer->set_state( $order->billing_state ); + if ( $order->billing_postcode ) + WC()->customer->set_postcode( $order->billing_postcode ); + if ( $order->billing_city ) + WC()->customer->set_city( $order->billing_city ); + + // Update payment method + if ( $order->order_total > 0 ) { + $payment_method = woocommerce_clean( $_POST['payment_method'] ); + + $available_gateways = WC()->payment_gateways->get_available_payment_gateways(); + + // Update meta + update_post_meta( $order_id, '_payment_method', $payment_method ); + + if ( isset( $available_gateways[ $payment_method ] ) ) + $payment_method_title = $available_gateways[ $payment_method ]->get_title(); + + update_post_meta( $order_id, '_payment_method_title', $payment_method_title); + + // Validate + $available_gateways[ $payment_method ]->validate_fields(); + + // Process + if ( wc_error_count() == 0 ) { + + $result = $available_gateways[ $payment_method ]->process_payment( $order_id ); + + // Redirect to success/confirmation/payment page + if ( $result['result'] == 'success' ) { + wp_redirect( $result['redirect'] ); + exit; + } + + } + + } else { + // No payment was required for order + $order->payment_complete(); + wp_safe_redirect( $order->get_checkout_order_received_url() ); + exit; + } + + } + + } + } + + /** + * Remove from cart/update. + */ + public function update_cart_action() { + // Remove from cart + if ( ! empty( $_GET['remove_item'] ) && wp_verify_nonce( $_GET['_wpnonce'], 'woocommerce-cart' ) ) { + + WC()->cart->set_quantity( $_GET['remove_item'], 0 ); + + wc_add_message( __( 'Cart updated.', 'woocommerce' ) ); + + $referer = ( wp_get_referer() ) ? wp_get_referer() : WC()->cart->get_cart_url(); + wp_safe_redirect( $referer ); + exit; + + // Update Cart + } elseif ( ( ! empty( $_POST['update_cart'] ) || ! empty( $_POST['proceed'] ) ) && wp_verify_nonce( $_POST['_wpnonce'], 'woocommerce-cart' ) ) { + + $cart_totals = isset( $_POST['cart'] ) ? $_POST['cart'] : ''; + + if ( sizeof( WC()->cart->get_cart() ) > 0 ) { + foreach ( WC()->cart->get_cart() as $cart_item_key => $values ) { + + $_product = $values['data']; + + // Skip product if no updated quantity was posted + if ( ! isset( $cart_totals[$cart_item_key]['qty'] ) ) + continue; + + // Sanitize + $quantity = apply_filters( 'woocommerce_stock_amount_cart_item', apply_filters( 'woocommerce_stock_amount', preg_replace( "/[^0-9\.]/", "", $cart_totals[ $cart_item_key ]['qty'] ) ), $cart_item_key ); + + if ( "" === $quantity ) + continue; + + // Update cart validation + $passed_validation = apply_filters( 'woocommerce_update_cart_validation', true, $cart_item_key, $values, $quantity ); + + // is_sold_individually + if ( $_product->is_sold_individually() && $quantity > 1 ) { + wc_add_error( sprintf( __( 'You can only have 1 %s in your cart.', 'woocommerce' ), $_product->get_title() ) ); + $passed_validation = false; + } + + if ( $passed_validation ) + WC()->cart->set_quantity( $cart_item_key, $quantity ); + + } + } + + if ( ! empty( $_POST['proceed'] ) ) { + wp_safe_redirect( WC()->cart->get_checkout_url() ); + exit; + } else { + wc_add_message( __( 'Cart updated.', 'woocommerce' ) ); + + $referer = ( wp_get_referer() ) ? wp_get_referer() : WC()->cart->get_cart_url(); + $referer = remove_query_arg( 'remove_discounts', $referer ); + wp_safe_redirect( $referer ); + exit; + } + } + } + + /** + * Place a previous order again. + */ + public function order_again() { + global $woocommerce; + + // Nothing to do + if ( ! isset( $_GET['order_again'] ) || ! is_user_logged_in() || ! $woocommerce->verify_nonce( 'order_again', '_GET' ) || ! wp_verify_nonce( $_GET['_wpnonce'], 'woocommerce-order_again' ) ) + return; + + // Clear current cart + $woocommerce->cart->empty_cart(); + + // Load the previous order - Stop if the order does not exist + $order = new WC_Order( absint( $_GET['order_again'] ) ); + + if ( empty( $order->id ) ) + return; + + if ( $order->status != 'completed' ) + return; + + // Make sure the previous order belongs to the current customer + if ( $order->user_id != get_current_user_id() ) + return; + + // Copy products from the order to the cart + foreach ( $order->get_items() as $item ) { + // Load all product info including variation data + $product_id = (int) apply_filters( 'woocommerce_add_to_cart_product_id', $item['product_id'] ); + $quantity = (int) $item['qty']; + $variation_id = (int) $item['variation_id']; + $variations = array(); + $cart_item_data = apply_filters( 'woocommerce_order_again_cart_item_data', array(), $item, $order ); + + foreach ( $item['item_meta'] as $meta_name => $meta_value ) { + if ( taxonomy_is_product_attribute( $meta_name ) ) + $variations[ $meta_name ] = $meta_value[0]; + } + + // Add to cart validation + if ( ! apply_filters( 'woocommerce_add_to_cart_validation', true, $product_id, $quantity, $variation_id, $variations, $cart_item_data ) ) continue; + + $woocommerce->cart->add_to_cart( $product_id, $quantity, $variation_id, $variations, $cart_item_data ); + } + + do_action( 'woocommerce_ordered_again', $order->id ); + + // Redirect to cart + wc_add_message( __( 'The cart has been filled with the items from your previous order.', 'woocommerce' ) ); + wp_safe_redirect( $woocommerce->cart->get_cart_url() ); + exit; + } + + /** + * Cancel a pending order. + */ + public function cancel_order() { + + global $woocommerce; + + if ( isset($_GET['cancel_order']) && isset($_GET['order']) && isset($_GET['order_id']) ) : + + $order_key = urldecode( $_GET['order'] ); + $order_id = (int) $_GET['order_id']; + + $order = new WC_Order( $order_id ); + + if ( $order->id == $order_id && $order->order_key == $order_key && in_array( $order->status, array( 'pending', 'failed' ) ) && wp_verify_nonce( $_GET['_wpnonce'], 'woocommerce-cancel_order' ) ) : + + // Cancel the order + restore stock + $order->cancel_order( __('Order cancelled by customer.', 'woocommerce' ) ); + + // Message + wc_add_message( __( 'Your order was cancelled.', 'woocommerce' ) ); + + do_action( 'woocommerce_cancelled_order', $order->id ); + + elseif ( $order->status != 'pending' ) : + + wc_add_error( __( 'Your order is no longer pending and could not be cancelled. Please contact us if you need assistance.', 'woocommerce' ) ); + + else : + + wc_add_error( __( 'Invalid order.', 'woocommerce' ) ); + + endif; + + wp_safe_redirect($woocommerce->cart->get_cart_url()); + exit; + + endif; + } + + /** + * Add to cart action + * + * Checks for a valid request, does validation (via hooks) and then redirects if valid. + * + * @param bool $url (default: false) + */ + public function add_to_cart_action( $url = false ) { + if ( empty( $_REQUEST['add-to-cart'] ) || ! is_numeric( $_REQUEST['add-to-cart'] ) ) + return; + + $product_id = apply_filters( 'woocommerce_add_to_cart_product_id', absint( $_REQUEST['add-to-cart'] ) ); + $was_added_to_cart = false; + $added_to_cart = array(); + $adding_to_cart = get_product( $product_id ); + $add_to_cart_handler = apply_filters( 'woocommerce_add_to_cart_handler', $adding_to_cart->product_type, $adding_to_cart ); + + // Variable product handling + if ( 'variable' === $add_to_cart_handler ) { + + $variation_id = empty( $_REQUEST['variation_id'] ) ? '' : absint( $_REQUEST['variation_id'] ); + $quantity = empty( $_REQUEST['quantity'] ) ? 1 : apply_filters( 'woocommerce_stock_amount', $_REQUEST['quantity'] ); + $all_variations_set = true; + $variations = array(); + + // Only allow integer variation ID - if its not set, redirect to the product page + if ( empty( $variation_id ) ) { + wc_add_error( __( 'Please choose product options…', 'woocommerce' ) ); + return; + } + + $attributes = $adding_to_cart->get_attributes(); + $variation = get_product( $variation_id ); + + // Verify all attributes + foreach ( $attributes as $attribute ) { + if ( ! $attribute['is_variation'] ) + continue; + + $taxonomy = 'attribute_' . sanitize_title( $attribute['name'] ); + + if ( ! empty( $_REQUEST[ $taxonomy ] ) ) { + + // Get value from post data + // Don't use woocommerce_clean as it destroys sanitized characters + $value = sanitize_title( trim( stripslashes( $_REQUEST[ $taxonomy ] ) ) ); + + // Get valid value from variation + $valid_value = $variation->variation_data[ $taxonomy ]; + + // Allow if valid + if ( $valid_value == '' || $valid_value == $value ) { + if ( $attribute['is_taxonomy'] ) + $variations[ esc_html( $attribute['name'] ) ] = $value; + else { + // For custom attributes, get the name from the slug + $options = array_map( 'trim', explode( '|', $attribute['value'] ) ); + foreach ( $options as $option ) { + if ( sanitize_title( $option ) == $value ) { + $value = $option; + break; + } + } + $variations[ esc_html( $attribute['name'] ) ] = $value; + } + continue; + } + + } + + $all_variations_set = false; + } + + if ( $all_variations_set ) { + // Add to cart validation + $passed_validation = apply_filters( 'woocommerce_add_to_cart_validation', true, $product_id, $quantity, $variation_id, $variations ); + + if ( $passed_validation ) { + if ( WC()->cart->add_to_cart( $product_id, $quantity, $variation_id, $variations ) ) { + woocommerce_add_to_cart_message( $product_id ); + $was_added_to_cart = true; + $added_to_cart[] = $product_id; + } + } + } else { + wc_add_error( __( 'Please choose product options…', 'woocommerce' ) ); + return; + } + + // Grouped Products + } elseif ( 'grouped' === $add_to_cart_handler ) { + + if ( ! empty( $_REQUEST['quantity'] ) && is_array( $_REQUEST['quantity'] ) ) { + + $quantity_set = false; + + foreach ( $_REQUEST['quantity'] as $item => $quantity ) { + if ( $quantity <= 0 ) + continue; + + $quantity_set = true; + + // Add to cart validation + $passed_validation = apply_filters( 'woocommerce_add_to_cart_validation', true, $item, $quantity ); + + if ( $passed_validation ) { + if ( WC()->cart->add_to_cart( $item, $quantity ) ) { + $was_added_to_cart = true; + $added_to_cart[] = $item; + } + } + } + + if ( $was_added_to_cart ) { + woocommerce_add_to_cart_message( $added_to_cart ); + } + + if ( ! $was_added_to_cart && ! $quantity_set ) { + wc_add_error( __( 'Please choose the quantity of items you wish to add to your cart…', 'woocommerce' ) ); + return; + } + + } elseif ( $product_id ) { + + /* Link on product archives */ + wc_add_error( __( 'Please choose a product to add to your cart…', 'woocommerce' ) ); + return; + + } + + // Simple Products + } else { + + $quantity = empty( $_REQUEST['quantity'] ) ? 1 : apply_filters( 'woocommerce_stock_amount', $_REQUEST['quantity'] ); + + // Add to cart validation + $passed_validation = apply_filters( 'woocommerce_add_to_cart_validation', true, $product_id, $quantity ); + + if ( $passed_validation ) { + // Add the product to the cart + if ( WC()->cart->add_to_cart( $product_id, $quantity ) ) { + woocommerce_add_to_cart_message( $product_id ); + $was_added_to_cart = true; + $added_to_cart[] = $product_id; + } + } + + } + + // If we added the product to the cart we can now optionally do a redirect. + if ( $was_added_to_cart && wc_error_count() == 0 ) { + + $url = apply_filters( 'add_to_cart_redirect', $url ); + + // If has custom URL redirect there + if ( $url ) { + wp_safe_redirect( $url ); + exit; + } + + // Redirect to cart option + elseif ( get_option('woocommerce_cart_redirect_after_add') == 'yes' ) { + wp_safe_redirect( WC()->cart->get_cart_url() ); + exit; + } + + } + + } + + /** + * Process the login form. + */ + public function process_login() { + if ( ! empty( $_POST['login'] ) ) { + + wp_verify_nonce( $_POST['_wpnonce'], 'woocommerce-login' ); + + try { + $creds = array(); + + if ( empty( $_POST['username'] ) ) + throw new Exception( '' . __( 'Error', 'woocommerce' ) . ': ' . __( 'Username is required.', 'woocommerce' ) ); + if ( empty( $_POST['password'] ) ) + throw new Exception( '' . __( 'Error', 'woocommerce' ) . ': ' . __( 'Password is required.', 'woocommerce' ) ); + + if ( is_email( $_POST['username'] ) ) { + $user = get_user_by( 'email', $_POST['username'] ); + + if ( isset( $user->user_login ) ) + $creds['user_login'] = $user->user_login; + else + throw new Exception( '' . __( 'Error', 'woocommerce' ) . ': ' . __( 'A user could not be found with this email address.', 'woocommerce' ) ); + } else { + $creds['user_login'] = $_POST['username']; + } + + $creds['user_password'] = $_POST['password']; + $creds['remember'] = true; + $secure_cookie = is_ssl() ? true : false; + $user = wp_signon( $creds, $secure_cookie ); + + if ( is_wp_error( $user ) ) { + throw new Exception( $user->get_error_message() ); + } else { + + if ( ! empty( $_POST['redirect'] ) ) { + $redirect = esc_url( $_POST['redirect'] ); + } elseif ( wp_get_referer() ) { + $redirect = esc_url( wp_get_referer() ); + } else { + $redirect = esc_url( get_permalink( woocommerce_get_page_id( 'myaccount' ) ) ); + } + + // Feedback + wc_add_message( sprintf( __( 'You are now logged in as %s', 'woocommerce' ), $user->display_name ) ); + + wp_redirect( apply_filters( 'woocommerce_login_redirect', $redirect, $user ) ); + exit; + } + } catch (Exception $e) { + + wc_add_error( apply_filters('login_errors', $e->getMessage() ) ); + + } + } + } + + /** + * Handle reset password form + */ + public function process_reset_password() { + if ( ! isset( $_POST['wc_reset_password'] ) ) + return; + + // process lost password form + if ( isset( $_POST['user_login'] ) ) { + + wp_verify_nonce( $_POST['_wpnonce'], 'woocommerce-lost_password' ); + + WC_Shortcode_My_Account::retrieve_password(); + } + + // process reset password form + if( isset( $_POST['password_1'] ) && isset( $_POST['password_2'] ) && isset( $_POST['reset_key'] ) && isset( $_POST['reset_login'] ) ) { + + // verify reset key again + $user = WC_Shortcode_My_Account::check_password_reset_key( $_POST['reset_key'], $_POST['reset_login'] ); + + if ( is_object( $user ) ) { + + // save these values into the form again in case of errors + $args['key'] = woocommerce_clean( $_POST['reset_key'] ); + $args['login'] = woocommerce_clean( $_POST['reset_login'] ); + + wp_verify_nonce( $_POST['_wpnonce'], 'woocommerce-reset_password' ); + + if( empty( $_POST['password_1'] ) || empty( $_POST['password_2'] ) ) { + wc_add_error( __( 'Please enter your password.', 'woocommerce' ) ); + $args['form'] = 'reset_password'; + } + + if( $_POST[ 'password_1' ] !== $_POST[ 'password_2' ] ) { + wc_add_error( __( 'Passwords do not match.', 'woocommerce' ) ); + $args['form'] = 'reset_password'; + } + + if( 0 == wc_error_count() && ( $_POST['password_1'] == $_POST['password_2'] ) ) { + + WC_Shortcode_My_Account::reset_password( $user, woocommerce_clean( $_POST['password_1'] ) ); + + do_action( 'woocommerce_customer_reset_password', $user ); + + wc_add_message( __( 'Your password has been reset.', 'woocommerce' ) . ' ' . __( 'Log in', 'woocommerce' ) . '' ); + + wp_redirect( remove_query_arg( array( 'key', 'login' ) ) ); + exit; + } + } + + } + } + + /** + * Process the registration form. + */ + public function process_registration() { + if ( ! empty( $_POST['register'] ) ) { + + WC()->verify_nonce( 'register' ); + + $username = ! empty( $_POST['username'] ) ? woocommerce_clean( $_POST['username'] ) : ''; + $email = ! empty( $_POST['email'] ) ? woocommerce_clean( $_POST['email'] ) : ''; + $password = ! empty( $_POST['password'] ) ? woocommerce_clean( $_POST['password'] ) : ''; + + // Anti-spam trap + if ( ! empty( $_POST['email_2'] ) ) { + wc_add_error( '' . __( 'ERROR', 'woocommerce' ) . ': ' . __( 'Anti-spam field was filled in.', 'woocommerce' ) ); + return; + } + + $new_customer = woocommerce_create_new_customer( $email, $username, $password ); + + if ( is_wp_error( $new_customer ) ) { + wc_add_error( $new_customer->get_error_message() ); + return; + } + + woocommerce_set_customer_auth_cookie( $new_customer ); + + // Redirect + if ( wp_get_referer() ) { + $redirect = esc_url( wp_get_referer() ); + } else { + $redirect = esc_url( get_permalink( woocommerce_get_page_id( 'myaccount' ) ) ); + } + + wp_redirect( apply_filters( 'woocommerce_registration_redirect', $redirect ) ); + exit; + } + } +} + +new WC_Form_Handler(); \ No newline at end of file diff --git a/includes/class-wc-install.php b/includes/class-wc-install.php index 05b976f61f1..09327a3bb7f 100644 --- a/includes/class-wc-install.php +++ b/includes/class-wc-install.php @@ -104,7 +104,7 @@ class WC_Install { $this->create_css_from_less(); // Clear transient cache - WC()->get_helper( 'transient' )->clear_product_transients(); + wc_delete_product_transients(); // Queue upgrades $current_version = get_option( 'woocommerce_version', null ); @@ -473,7 +473,7 @@ class WC_Install { 'import' => true ) ); - $capabilities = woocommerce_get_core_capabilities(); + $capabilities = $this->get_core_capabilities(); foreach( $capabilities as $cap_group ) { foreach( $cap_group as $cap ) { @@ -484,6 +484,80 @@ class WC_Install { } } + /** + * Get capabilities for WooCommerce - these are assigned to admin/shop manager during installation or reset + * + * @access public + * @return void + */ + public function get_core_capabilities() { + $capabilities = array(); + + $capabilities['core'] = array( + "manage_woocommerce", + "view_woocommerce_reports" + ); + + $capability_types = array( 'product', 'shop_order', 'shop_coupon' ); + + foreach( $capability_types as $capability_type ) { + + $capabilities[ $capability_type ] = array( + // Post type + "edit_{$capability_type}", + "read_{$capability_type}", + "delete_{$capability_type}", + "edit_{$capability_type}s", + "edit_others_{$capability_type}s", + "publish_{$capability_type}s", + "read_private_{$capability_type}s", + "delete_{$capability_type}s", + "delete_private_{$capability_type}s", + "delete_published_{$capability_type}s", + "delete_others_{$capability_type}s", + "edit_private_{$capability_type}s", + "edit_published_{$capability_type}s", + + // Terms + "manage_{$capability_type}_terms", + "edit_{$capability_type}_terms", + "delete_{$capability_type}_terms", + "assign_{$capability_type}_terms" + ); + } + + return $capabilities; + } + + /** + * woocommerce_remove_roles function. + * + * @access public + * @return void + */ + public function remove_roles() { + global $wp_roles; + + if ( class_exists('WP_Roles') ) + if ( ! isset( $wp_roles ) ) + $wp_roles = new WP_Roles(); + + if ( is_object( $wp_roles ) ) { + + $capabilities = $this->get_core_capabilities(); + + foreach( $capabilities as $cap_group ) { + foreach( $cap_group as $cap ) { + $wp_roles->remove_cap( 'shop_manager', $cap ); + $wp_roles->remove_cap( 'administrator', $cap ); + } + } + + remove_role( 'customer' ); + remove_role( 'shop_manager' ); + } + } + /** * Create files/directories */ diff --git a/includes/class-wc-product-simple.php b/includes/class-wc-product-simple.php index 2203984660b..258ee6995ac 100644 --- a/includes/class-wc-product-simple.php +++ b/includes/class-wc-product-simple.php @@ -70,6 +70,6 @@ class WC_Product_Simple extends WC_Product { } } - $woocommerce->get_helper( 'transient' )->clear_product_transients( $this->id ); + wc_delete_product_transients( $this->id ); } } \ No newline at end of file diff --git a/includes/class-wc-product-variable.php b/includes/class-wc-product-variable.php index dbc3f9e316e..088b3913393 100644 --- a/includes/class-wc-product-variable.php +++ b/includes/class-wc-product-variable.php @@ -87,7 +87,7 @@ class WC_Product_Variable extends WC_Product { elseif ( $this->backorders_allowed() || $this->get_total_stock() > 0 ) $this->set_stock_status( 'instock' ); - $woocommerce->get_helper( 'transient' )->clear_product_transients( $this->id ); // Clear transient + wc_delete_product_transients( $this->id ); // Clear transient return apply_filters( 'woocommerce_stock_amount', $this->stock ); } @@ -112,7 +112,7 @@ class WC_Product_Variable extends WC_Product { if ( ! $this->backorders_allowed() && $this->get_total_stock() <= 0 ) $this->set_stock_status( 'outofstock' ); - $woocommerce->get_helper( 'transient' )->clear_product_transients( $this->id ); // Clear transient + wc_delete_product_transients( $this->id ); // Clear transient return apply_filters( 'woocommerce_stock_amount', $this->stock ); } @@ -138,7 +138,7 @@ class WC_Product_Variable extends WC_Product { if ( $this->backorders_allowed() || $this->get_total_stock() > 0 ) $this->set_stock_status( 'instock' ); - $woocommerce->get_helper( 'transient' )->clear_product_transients( $this->id ); // Clear transient + wc_delete_product_transients( $this->id ); // Clear transient return apply_filters( 'woocommerce_stock_amount', $this->stock ); endif; @@ -547,7 +547,7 @@ class WC_Product_Variable extends WC_Product { do_action( 'woocommerce_variable_product_sync', $product_id ); - WC()->get_helper( 'transient' )->clear_product_transients( $product_id ); + wc_delete_product_transients( $product_id ); } } } \ No newline at end of file diff --git a/includes/class-wc-product-variation.php b/includes/class-wc-product-variation.php index dc85859e94a..de2d6ef979a 100644 --- a/includes/class-wc-product-variation.php +++ b/includes/class-wc-product-variation.php @@ -296,7 +296,7 @@ class WC_Product_Variation extends WC_Product { $this->stock = intval( $amount ); $this->total_stock = intval( $amount ); update_post_meta( $this->variation_id, '_stock', $this->stock ); - $woocommerce->get_helper( 'transient' )->clear_product_transients( $this->id ); // Clear transient + wc_delete_product_transients( $this->id ); // Clear transient // Check parents out of stock attribute if ( ! $this->is_in_stock() ) { @@ -335,7 +335,7 @@ class WC_Product_Variation extends WC_Product { $this->stock = $this->stock - $by; $this->total_stock = $this->total_stock - $by; update_post_meta( $this->variation_id, '_stock', $this->stock ); - $woocommerce->get_helper( 'transient' )->clear_product_transients( $this->id ); // Clear transient + wc_delete_product_transients( $this->id ); // Clear transient // Check parents out of stock attribute if ( ! $this->is_in_stock() ) { @@ -372,7 +372,7 @@ class WC_Product_Variation extends WC_Product { $this->stock = $this->stock + $by; $this->total_stock = $this->total_stock + $by; update_post_meta( $this->variation_id, '_stock', $this->stock ); - $woocommerce->get_helper( 'transient' )->clear_product_transients( $this->id ); // Clear transient + wc_delete_product_transients( $this->id ); // Clear transient // Parents out of stock attribute if ( $this->is_in_stock() ) diff --git a/includes/class-wc-query.php b/includes/class-wc-query.php index ff16aa90ca5..01aace931ff 100644 --- a/includes/class-wc-query.php +++ b/includes/class-wc-query.php @@ -57,6 +57,8 @@ class WC_Query { */ public function __construct() { add_action( 'init', array( $this, 'add_endpoints' ) ); + add_action( 'init', array( $this, 'layered_nav_init' ) ); + add_action( 'init', array( $this, 'price_filter_init' ) ); if ( ! is_admin() ) { add_action( 'init', array( $this, 'get_errors' ) ); @@ -116,8 +118,6 @@ class WC_Query { * @return void */ public function pre_get_posts( $q ) { - global $woocommerce; - // We only want to affect the main query if ( ! $q->is_main_query() ) return; @@ -242,8 +242,6 @@ class WC_Query { * @return void */ public function the_posts( $posts, $query = false ) { - global $woocommerce; - // Abort if there's no query if ( ! $query ) return $posts; @@ -421,8 +419,6 @@ class WC_Query { * @return array */ public function get_catalog_ordering_args( $orderby = '', $order = '' ) { - global $woocommerce; - // Get ordering from query string unless defined if ( ! $orderby ) { $orderby_value = isset( $_GET['orderby'] ) ? woocommerce_clean( $_GET['orderby'] ) : apply_filters( 'woocommerce_default_catalog_orderby', get_option( 'woocommerce_default_catalog_orderby' ) ); @@ -571,6 +567,196 @@ class WC_Query { } return $meta_query; } + + /** + * Layered Nav Init + */ + public function layered_nav_init( ) { + + if ( is_active_widget( false, false, 'woocommerce_layered_nav', true ) && ! is_admin() ) { + + global $_chosen_attributes; + + $_chosen_attributes = array(); + + $attribute_taxonomies = WC()->get_helper( 'attribute' )->get_attribute_taxonomies(); + if ( $attribute_taxonomies ) { + foreach ( $attribute_taxonomies as $tax ) { + + $attribute = sanitize_title( $tax->attribute_name ); + $taxonomy = WC()->get_helper( 'attribute' )->attribute_taxonomy_name( $attribute ); + $name = 'filter_' . $attribute; + $query_type_name = 'query_type_' . $attribute; + + if ( ! empty( $_GET[ $name ] ) && taxonomy_exists( $taxonomy ) ) { + + $_chosen_attributes[ $taxonomy ]['terms'] = explode( ',', $_GET[ $name ] ); + + if ( empty( $_GET[ $query_type_name ] ) || ! in_array( strtolower( $_GET[ $query_type_name ] ), array( 'and', 'or' ) ) ) + $_chosen_attributes[ $taxonomy ]['query_type'] = apply_filters( 'woocommerce_layered_nav_default_query_type', 'and' ); + else + $_chosen_attributes[ $taxonomy ]['query_type'] = strtolower( $_GET[ $query_type_name ] ); + + } + } + } + + add_filter('loop_shop_post_in', array( $this, 'layered_nav_query' ) ); + } + } + + /** + * Layered Nav post filter + * + * @param array $filtered_posts + * @return array + */ + public function layered_nav_query( $filtered_posts ) { + global $_chosen_attributes, $wp_query; + + if ( sizeof( $_chosen_attributes ) > 0 ) { + + $matched_products = array(); + $filtered_attribute = false; + + foreach ( $_chosen_attributes as $attribute => $data ) { + + $matched_products_from_attribute = array(); + $filtered = false; + + if ( sizeof( $data['terms'] ) > 0 ) { + foreach ( $data['terms'] as $value ) { + + $posts = get_posts( + array( + 'post_type' => 'product', + 'numberposts' => -1, + 'post_status' => 'publish', + 'fields' => 'ids', + 'no_found_rows' => true, + 'tax_query' => array( + array( + 'taxonomy' => $attribute, + 'terms' => $value, + 'field' => 'id' + ) + ) + ) + ); + + // AND or OR + if ( $data['query_type'] == 'or' ) { + + if ( ! is_wp_error( $posts ) && ( sizeof( $matched_products_from_attribute ) > 0 || $filtered ) ) + $matched_products_from_attribute = array_merge($posts, $matched_products_from_attribute); + elseif ( ! is_wp_error( $posts ) ) + $matched_products_from_attribute = $posts; + + } else { + + if ( ! is_wp_error( $posts ) && ( sizeof( $matched_products_from_attribute ) > 0 || $filtered ) ) + $matched_products_from_attribute = array_intersect($posts, $matched_products_from_attribute); + elseif ( ! is_wp_error( $posts ) ) + $matched_products_from_attribute = $posts; + } + + $filtered = true; + + } + } + + if ( sizeof( $matched_products ) > 0 || $filtered_attribute ) + $matched_products = array_intersect( $matched_products_from_attribute, $matched_products ); + else + $matched_products = $matched_products_from_attribute; + + $filtered_attribute = true; + + } + + if ( $filtered ) { + + WC()->query->layered_nav_post__in = $matched_products; + WC()->query->layered_nav_post__in[] = 0; + + if ( sizeof( $filtered_posts ) == 0 ) { + $filtered_posts = $matched_products; + $filtered_posts[] = 0; + } else { + $filtered_posts = array_intersect( $filtered_posts, $matched_products ); + $filtered_posts[] = 0; + } + + } + } + return (array) $filtered_posts; + } + + /** + * Price filter Init + */ + public function price_filter_init() { + if ( is_active_widget( false, false, 'woocommerce_price_filter', true ) && ! is_admin() ) { + + $suffix = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min'; + + wp_register_script( 'wc-price-slider', WC()->plugin_url() . '/assets/js/frontend/price-slider' . $suffix . '.js', array( 'jquery-ui-slider' ), '1.6', true ); + + wp_localize_script( 'wc-price-slider', 'woocommerce_price_slider_params', array( + 'currency_symbol' => get_woocommerce_currency_symbol(), + 'currency_pos' => get_option( 'woocommerce_currency_pos' ), + 'min_price' => isset( $_GET['min_price'] ) ? esc_attr( $_GET['min_price'] ) : '', + 'max_price' => isset( $_GET['max_price'] ) ? esc_attr( $_GET['max_price'] ) : '' + ) ); + + add_filter( 'loop_shop_post_in', array( $this, 'price_filter' ) ); + } + } + + /** + * Price Filter post filter + * + * @param array $filtered_posts + * @return array + */ + public function price_filter($filtered_posts) { + global $wpdb; + + if ( isset( $_GET['max_price'] ) && isset( $_GET['min_price'] ) ) { + + $matched_products = array(); + $min = floatval( $_GET['min_price'] ); + $max = floatval( $_GET['max_price'] ); + + $matched_products_query = $wpdb->get_results( $wpdb->prepare(" + SELECT DISTINCT ID, post_parent, post_type FROM $wpdb->posts + INNER JOIN $wpdb->postmeta ON ID = post_id + WHERE post_type IN ( 'product', 'product_variation' ) AND post_status = 'publish' AND meta_key = %s AND meta_value BETWEEN %d AND %d + ", '_price', $min, $max ), OBJECT_K ); + + if ( $matched_products_query ) { + foreach ( $matched_products_query as $product ) { + if ( $product->post_type == 'product' ) + $matched_products[] = $product->ID; + if ( $product->post_parent > 0 && ! in_array( $product->post_parent, $matched_products ) ) + $matched_products[] = $product->post_parent; + } + } + + // Filter the id's + if ( sizeof( $filtered_posts ) == 0) { + $filtered_posts = $matched_products; + $filtered_posts[] = 0; + } else { + $filtered_posts = array_intersect( $filtered_posts, $matched_products ); + $filtered_posts[] = 0; + } + + } + + return (array) $filtered_posts; + } + } endif; diff --git a/includes/class-wc-shortcodes.php b/includes/class-wc-shortcodes.php index 5a21d324b88..1a70f56960c 100644 --- a/includes/class-wc-shortcodes.php +++ b/includes/class-wc-shortcodes.php @@ -36,6 +36,34 @@ class WC_Shortcodes { add_shortcode( 'woocommerce_my_account', array( $this, 'my_account' ) ); } + /** + * Shortcode Wrapper + * + * @param mixed $function + * @param array $atts (default: array()) + * @return string + */ + public static function shortcode_wrapper( + $function, + $atts = array(), + $wrapper = array( + 'class' => 'woocommerce', + 'before' => null, + 'after' => null + ) + ){ + ob_start(); + + $before = empty( $wrapper['before'] ) ? '
' : $wrapper['before']; + $after = empty( $wrapper['after'] ) ? '
' : $wrapper['after']; + + echo $before; + call_user_func( $function, $atts ); + echo $after; + + return ob_get_clean(); + } + /** * Cart page shortcode. * @@ -44,8 +72,7 @@ class WC_Shortcodes { * @return string */ public function cart( $atts ) { - global $woocommerce; - return $woocommerce->get_helper( 'shortcode' )->shortcode_wrapper( array( 'WC_Shortcode_Cart', 'output' ), $atts ); + return $this->shortcode_wrapper( array( 'WC_Shortcode_Cart', 'output' ), $atts ); } /** @@ -56,8 +83,7 @@ class WC_Shortcodes { * @return string */ public function checkout( $atts ) { - global $woocommerce; - return $woocommerce->get_helper( 'shortcode' )->shortcode_wrapper( array( 'WC_Shortcode_Checkout', 'output' ), $atts ); + return $this->shortcode_wrapper( array( 'WC_Shortcode_Checkout', 'output' ), $atts ); } /** @@ -68,8 +94,7 @@ class WC_Shortcodes { * @return string */ public function order_tracking( $atts ) { - global $woocommerce; - return $woocommerce->get_helper( 'shortcode' )->shortcode_wrapper( array( 'WC_Shortcode_Order_Tracking', 'output' ), $atts ); + return $this->shortcode_wrapper( array( 'WC_Shortcode_Order_Tracking', 'output' ), $atts ); } /** @@ -80,8 +105,7 @@ class WC_Shortcodes { * @return string */ public function my_account( $atts ) { - global $woocommerce; - return $woocommerce->get_helper( 'shortcode' )->shortcode_wrapper( array( 'WC_Shortcode_My_Account', 'output' ), $atts ); + return $this->shortcode_wrapper( array( 'WC_Shortcode_My_Account', 'output' ), $atts ); } /** @@ -92,7 +116,7 @@ class WC_Shortcodes { * @return string */ public function product_category( $atts ){ - global $woocommerce, $woocommerce_loop; + global $woocommerce_loop; if ( empty( $atts ) ) return; @@ -108,7 +132,7 @@ class WC_Shortcodes { if ( ! $category ) return; // Default ordering args - $ordering_args = $woocommerce->query->get_catalog_ordering_args( $orderby, $order ); + $ordering_args = WC()->query->get_catalog_ordering_args( $orderby, $order ); $args = array( 'post_type' => 'product', @@ -238,7 +262,6 @@ class WC_Shortcodes { return '
' . ob_get_clean() . '
'; } - /** * Recent Products shortcode * @@ -248,7 +271,7 @@ class WC_Shortcodes { */ public function recent_products( $atts ) { - global $woocommerce_loop, $woocommerce; + global $woocommerce_loop; extract(shortcode_atts(array( 'per_page' => '12', @@ -257,7 +280,7 @@ class WC_Shortcodes { 'order' => 'desc' ), $atts)); - $meta_query = $woocommerce->query->get_meta_query(); + $meta_query = WC()->query->get_meta_query(); $args = array( 'post_type' => 'product', @@ -430,7 +453,6 @@ class WC_Shortcodes { return '
' . ob_get_clean() . '
'; } - /** * Display a single product price + cart button * @@ -439,7 +461,7 @@ class WC_Shortcodes { * @return string */ public function product_add_to_cart( $atts ) { - global $wpdb, $woocommerce; + global $wpdb; if ( empty( $atts ) ) return; @@ -456,7 +478,7 @@ class WC_Shortcodes { if ( 'product' == $product_data->post_type ) { - $product = $woocommerce->setup_product_data( $product_data ); + $product = WC()->setup_product_data( $product_data ); ob_start(); ?> @@ -511,7 +533,6 @@ class WC_Shortcodes { } } - /** * Get the add to cart URL for a product * @@ -548,7 +569,7 @@ class WC_Shortcodes { * @return string */ public function sale_products( $atts ){ - global $woocommerce_loop, $woocommerce; + global $woocommerce_loop; extract( shortcode_atts( array( 'per_page' => '12', @@ -561,8 +582,8 @@ class WC_Shortcodes { $product_ids_on_sale = woocommerce_get_product_ids_on_sale(); $meta_query = array(); - $meta_query[] = $woocommerce->query->visibility_meta_query(); - $meta_query[] = $woocommerce->query->stock_status_meta_query(); + $meta_query[] = WC()->query->visibility_meta_query(); + $meta_query[] = WC()->query->stock_status_meta_query(); $meta_query = array_filter( $meta_query ); $args = array( diff --git a/includes/helpers/class-wc-body-class-helper.php b/includes/helpers/class-wc-body-class-helper.php deleted file mode 100755 index 1f3ee3017df..00000000000 --- a/includes/helpers/class-wc-body-class-helper.php +++ /dev/null @@ -1,36 +0,0 @@ -_body_classes[] = sanitize_html_class( strtolower($class) ); - } - - /** - * Output classes on the body tag. - * - * @access public - * @param mixed $classes - * @return array - */ - public function output_body_class( $classes ) { - if ( sizeof( $this->_body_classes ) > 0 ) $classes = array_merge( $classes, $this->_body_classes ); - - if ( is_singular('product') ) { - $key = array_search( 'singular', $classes ); - if ( $key !== false ) unset( $classes[$key] ); - } - - return $classes; - } -} - -return new WC_Body_Class_Helper(); \ No newline at end of file diff --git a/includes/helpers/class-wc-post-class-helper.php b/includes/helpers/class-wc-post-class-helper.php deleted file mode 100755 index 7d1a305e1be..00000000000 --- a/includes/helpers/class-wc-post-class-helper.php +++ /dev/null @@ -1,55 +0,0 @@ -is_on_sale() ) { - $classes[] = 'sale'; - } - if ( $product->is_featured() ) { - $classes[] = 'featured'; - } - if ( $product->is_downloadable() ) { - $classes[] = 'downloadable'; - } - if ( $product->is_virtual() ) { - $classes[] = 'virtual'; - } - if ( $product->is_sold_individually() ) { - $classes[] = 'sold-individually'; - } - if ( $product->is_taxable() ) { - $classes[] = 'taxable'; - } - if ( $product->is_shipping_taxable() ) { - $classes[] = 'shipping-taxable'; - } - if ( $product->is_purchasable() ) { - $classes[] = 'purchasable'; - } - if ( isset( $product->product_type ) ) { - $classes[] = "product-type-".$product->product_type; - } - $classes[] = $product->stock_status; - } - - return $classes; - } -} - -return new WC_Post_Class_Helper(); \ No newline at end of file diff --git a/includes/helpers/class-wc-shortcode-helper.php b/includes/helpers/class-wc-shortcode-helper.php deleted file mode 100755 index 01753180881..00000000000 --- a/includes/helpers/class-wc-shortcode-helper.php +++ /dev/null @@ -1,34 +0,0 @@ - 'woocommerce', - 'before' => null, - 'after' => null - ) - ){ - ob_start(); - - $before = empty( $wrapper['before'] ) ? '
' : $wrapper['before']; - $after = empty( $wrapper['after'] ) ? '
' : $wrapper['after']; - - echo $before; - call_user_func( $function, $atts ); - echo $after; - - return ob_get_clean(); - } -} - -return new WC_Shortcode_Helper(); \ No newline at end of file diff --git a/includes/helpers/class-wc-transient-helper.php b/includes/helpers/class-wc-transient-helper.php deleted file mode 100755 index 6837096d388..00000000000 --- a/includes/helpers/class-wc-transient-helper.php +++ /dev/null @@ -1,65 +0,0 @@ -show_errors(); - - // Clear core transients - $transients_to_clear = array( - 'wc_products_onsale', - 'wc_hidden_product_ids', - 'wc_hidden_product_ids_search', - 'wc_attribute_taxonomies', - 'wc_term_counts' - ); - - foreach( $transients_to_clear as $transient ) { - delete_transient( $transient ); - } - - // Clear transients for which we don't have the name - $wpdb->query( "DELETE FROM `$wpdb->options` WHERE `option_name` LIKE ('_transient_wc_uf_pid_%') OR `option_name` LIKE ('_transient_timeout_wc_uf_pid_%')" ); - $wpdb->query( "DELETE FROM `$wpdb->options` WHERE `option_name` LIKE ('_transient_wc_ln_count_%') OR `option_name` LIKE ('_transient_timeout_wc_ln_count_%')" ); - $wpdb->query( "DELETE FROM `$wpdb->options` WHERE `option_name` LIKE ('_transient_wc_ship_%') OR `option_name` LIKE ('_transient_timeout_wc_ship_%')" ); - - // Clear product specific transients - $post_transients_to_clear = array( - 'wc_product_children_ids_', - 'wc_product_total_stock_', - 'wc_average_rating_', - 'wc_rating_count_', - 'woocommerce_product_type_', // No longer used - 'wc_product_type_', // No longer used - ); - - if ( $post_id > 0 ) { - - foreach( $post_transients_to_clear as $transient ) { - delete_transient( $transient . $post_id ); - $wpdb->query( $wpdb->prepare( "DELETE FROM `$wpdb->options` WHERE `option_name` = %s OR `option_name` = %s", '_transient_' . $transient . $post_id, '_transient_timeout_' . $transient . $post_id ) ); - } - - clean_post_cache( $post_id ); - - } else { - - foreach( $post_transients_to_clear as $transient ) { - $wpdb->query( $wpdb->prepare( "DELETE FROM `$wpdb->options` WHERE `option_name` LIKE %s OR `option_name` LIKE %s", '_transient_' . $transient . '%', '_transient_timeout_' . $transient . '%' ) ); - } - - } - } -} - -return new WC_Transient_Helper(); \ No newline at end of file diff --git a/includes/shortcodes/class-wc-shortcode-change-password.php b/includes/shortcodes/class-wc-shortcode-change-password.php index 2aef8a7c391..a939f2c8564 100644 --- a/includes/shortcodes/class-wc-shortcode-change-password.php +++ b/includes/shortcodes/class-wc-shortcode-change-password.php @@ -17,8 +17,7 @@ class WC_Shortcode_Change_Password { * @return string */ public static function get( $atts ) { - global $woocommerce; - return $woocommerce->get_helper( 'shortcode' )->shortcode_wrapper( array( __CLASS__, 'output' ), $atts ); + return WC_Shortcodes::shortcode_wrapper( array( __CLASS__, 'output' ), $atts ); } /** diff --git a/includes/shortcodes/class-wc-shortcode-checkout.php b/includes/shortcodes/class-wc-shortcode-checkout.php index 5e936bad634..382f9a6063c 100644 --- a/includes/shortcodes/class-wc-shortcode-checkout.php +++ b/includes/shortcodes/class-wc-shortcode-checkout.php @@ -20,8 +20,7 @@ class WC_Shortcode_Checkout { * @return string */ public static function get( $atts ) { - global $woocommerce; - return $woocommerce->get_helper( 'shortcode' )->shortcode_wrapper( array( __CLASS__, 'output' ), $atts ); + return WC_Shortcodes::shortcode_wrapper( array( __CLASS__, 'output' ), $atts ); } /** diff --git a/includes/shortcodes/class-wc-shortcode-my-account.php b/includes/shortcodes/class-wc-shortcode-my-account.php index c709943298b..99a1956beab 100644 --- a/includes/shortcodes/class-wc-shortcode-my-account.php +++ b/includes/shortcodes/class-wc-shortcode-my-account.php @@ -19,8 +19,7 @@ class WC_Shortcode_My_Account { * @return string */ public static function get( $atts ) { - global $woocommerce; - return $woocommerce->get_helper( 'shortcode' )->shortcode_wrapper( array( __CLASS__, 'output' ), $atts ); + return WC_Shortcodes::shortcode_wrapper( array( __CLASS__, 'output' ), $atts ); } /** diff --git a/includes/shortcodes/class-wc-shortcode-order-tracking.php b/includes/shortcodes/class-wc-shortcode-order-tracking.php index 49add394f5f..bbe860bbc0c 100644 --- a/includes/shortcodes/class-wc-shortcode-order-tracking.php +++ b/includes/shortcodes/class-wc-shortcode-order-tracking.php @@ -20,8 +20,7 @@ class WC_Shortcode_Order_Tracking { * @return string */ public static function get( $atts ) { - global $woocommerce; - return $woocommerce->get_helper( 'shortcode' )->shortcode_wrapper( array( __CLASS__, 'output' ), $atts ); + return WC_Shortcodes::shortcode_wrapper( array( __CLASS__, 'output' ), $atts ); } /** diff --git a/includes/shortcodes/class-wc-shortcode-view-order.php b/includes/shortcodes/class-wc-shortcode-view-order.php index 78abf333da2..938726286d0 100644 --- a/includes/shortcodes/class-wc-shortcode-view-order.php +++ b/includes/shortcodes/class-wc-shortcode-view-order.php @@ -18,8 +18,7 @@ class WC_Shortcode_View_Order { * @return string */ public static function get( $atts ) { - global $woocommerce; - return $woocommerce->get_helper( 'shortcode' )->shortcode_wrapper( array( __CLASS__, 'output' ), $atts ); + return WC_Shortcodes::shortcode_wrapper( array( __CLASS__, 'output' ), $atts ); } /** diff --git a/includes/wc-cart-functions.php b/includes/wc-cart-functions.php new file mode 100644 index 00000000000..d593ca582a0 --- /dev/null +++ b/includes/wc-cart-functions.php @@ -0,0 +1,134 @@ +cart ) || $woocommerce->cart == '' ) + $woocommerce->cart = new WC_Cart(); + + $woocommerce->cart->empty_cart( false ); +} +add_action( 'wp_logout', 'woocommerce_empty_cart' ); + + +/** + * Load the cart upon login + * @param mixed $user_login + * @param mixed $user + */ +function woocommerce_load_persistent_cart( $user_login, $user = 0 ) { + global $woocommerce; + + if ( ! $user ) + return; + + $saved_cart = get_user_meta( $user->ID, '_woocommerce_persistent_cart', true ); + + if ( $saved_cart ) + if ( empty( $woocommerce->session->cart ) || ! is_array( $woocommerce->session->cart ) || sizeof( $woocommerce->session->cart ) == 0 ) + $woocommerce->session->cart = $saved_cart['cart']; +} +add_action( 'wp_login', 'woocommerce_load_persistent_cart', 1, 2 ); + + +/** + * Add to cart messages. + * + * @access public + * @return void + */ +function woocommerce_add_to_cart_message( $product_id ) { + global $woocommerce; + + if ( is_array( $product_id ) ) { + + $titles = array(); + + foreach ( $product_id as $id ) { + $titles[] = get_the_title( $id ); + } + + $added_text = sprintf( __( 'Added "%s" to your cart.', 'woocommerce' ), join( __( '" and "', 'woocommerce' ), array_filter( array_merge( array( join( '", "', array_slice( $titles, 0, -1 ) ) ), array_slice( $titles, -1 ) ) ) ) ); + + } else { + $added_text = sprintf( __( '"%s" was successfully added to your cart.', 'woocommerce' ), get_the_title( $product_id ) ); + } + + // Output success messages + if ( get_option( 'woocommerce_cart_redirect_after_add' ) == 'yes' ) : + + $return_to = apply_filters( 'woocommerce_continue_shopping_redirect', wp_get_referer() ? wp_get_referer() : home_url() ); + + $message = sprintf('%s %s', $return_to, __( 'Continue Shopping →', 'woocommerce' ), $added_text ); + + else : + + $message = sprintf('%s %s', get_permalink( woocommerce_get_page_id( 'cart' ) ), __( 'View Cart →', 'woocommerce' ), $added_text ); + + endif; + + wc_add_message( apply_filters('woocommerce_add_to_cart_message', $message) ); +} + +/** + * Clear cart after payment. + * + * @access public + * @return void + */ +function woocommerce_clear_cart_after_payment() { + global $woocommerce, $wp; + + if ( ! empty( $wp->query_vars['order-received'] ) ) { + + $order_id = absint( $wp->query_vars['order-received'] ); + + if ( isset( $_GET['key'] ) ) + $order_key = $_GET['key']; + else + $order_key = ''; + + if ( $order_id > 0 ) { + $order = new WC_Order( $order_id ); + + if ( $order->order_key == $order_key ) { + $woocommerce->cart->empty_cart(); + } + } + + } + + if ( $woocommerce->session->order_awaiting_payment > 0 ) { + + $order = new WC_Order( $woocommerce->session->order_awaiting_payment ); + + if ( $order->id > 0 ) { + // If the order has failed, and the customer is logged in, they can try again from their account page + if ( $order->status == 'failed' && is_user_logged_in() ) + $woocommerce->cart->empty_cart(); + + // If the order has not failed, or is not pending, the order must have gone through + if ( $order->status != 'failed' && $order->status != 'pending' ) + $woocommerce->cart->empty_cart(); + } + } +} +add_action( 'get_header', 'woocommerce_clear_cart_after_payment' ); + diff --git a/includes/wc-conditional-functions.php b/includes/wc-conditional-functions.php new file mode 100644 index 00000000000..9dfb156830b --- /dev/null +++ b/includes/wc-conditional-functions.php @@ -0,0 +1,204 @@ +query_vars['order-pay'] ) ? true : false; + } +} + +if ( ! function_exists( 'is_account_page' ) ) { + + /** + * is_account_page - Returns true when viewing an account page. + * + * @access public + * @return bool + */ + function is_account_page() { + return is_page( woocommerce_get_page_id( 'myaccount' ) ) || apply_filters( 'woocommerce_is_account_page', false ) ? true : false; + } +} + +if ( ! function_exists( 'is_order_received_page' ) ) { + + /** + * is_order_received_page - Returns true when viewing the order received page. + * + * @access public + * @return bool + */ + function is_order_received_page() { + return ( is_page( woocommerce_get_page_id( 'checkout' ) ) && isset( $wp->query_vars['order-received'] ) ) ? true : false; + } +} + +if ( ! function_exists( 'is_ajax' ) ) { + + /** + * is_ajax - Returns true when the page is loaded via ajax. + * + * @access public + * @return bool + */ + function is_ajax() { + if ( defined('DOING_AJAX') ) + return true; + + return ( isset( $_SERVER['HTTP_X_REQUESTED_WITH'] ) && strtolower( $_SERVER['HTTP_X_REQUESTED_WITH'] ) == 'xmlhttprequest' ) ? true : false; + } +} + +if ( ! function_exists( 'is_filtered' ) ) { + + /** + * is_filtered - Returns true when filtering products using layered nav or price sliders. + * + * @access public + * @return bool + */ + function is_filtered() { + global $_chosen_attributes; + + return ( sizeof( $_chosen_attributes ) > 0 || ( isset( $_GET['max_price'] ) && isset( $_GET['min_price'] ) ) ) ? true : false; + } +} + +if ( ! function_exists( 'taxonomy_is_product_attribute' ) ) { + + /** + * taxonomy_is_product_attribute - Returns true when the passed taxonomy name is a product attribute. + * + * @uses $wc_product_attributes global which stores taxonomy names upon registration + * @access public + * @return bool + */ + function taxonomy_is_product_attribute( $name ) { + global $wc_product_attributes; + + return taxonomy_exists( $name ) && array_key_exists( $name, (array) $wc_product_attributes ); + } +} \ No newline at end of file diff --git a/includes/wc-core-functions.php b/includes/wc-core-functions.php new file mode 100644 index 00000000000..711824e98ba --- /dev/null +++ b/includes/wc-core-functions.php @@ -0,0 +1,171 @@ + __( 'Australian Dollars', 'woocommerce' ), + 'BRL' => __( 'Brazilian Real', 'woocommerce' ), + 'CAD' => __( 'Canadian Dollars', 'woocommerce' ), + 'CNY' => __( 'Chinese Yuan', 'woocommerce' ), + 'CZK' => __( 'Czech Koruna', 'woocommerce' ), + 'DKK' => __( 'Danish Krone', 'woocommerce' ), + 'EUR' => __( 'Euros', 'woocommerce' ), + 'HKD' => __( 'Hong Kong Dollar', 'woocommerce' ), + 'HUF' => __( 'Hungarian Forint', 'woocommerce' ), + 'IDR' => __( 'Indonesia Rupiah', 'woocommerce' ), + 'INR' => __( 'Indian Rupee', 'woocommerce' ), + 'ILS' => __( 'Israeli Shekel', 'woocommerce' ), + 'JPY' => __( 'Japanese Yen', 'woocommerce' ), + 'KRW' => __( 'South Korean Won', 'woocommerce' ), + 'MYR' => __( 'Malaysian Ringgits', 'woocommerce' ), + 'MXN' => __( 'Mexican Peso', 'woocommerce' ), + 'NOK' => __( 'Norwegian Krone', 'woocommerce' ), + 'NZD' => __( 'New Zealand Dollar', 'woocommerce' ), + 'PHP' => __( 'Philippine Pesos', 'woocommerce' ), + 'PLN' => __( 'Polish Zloty', 'woocommerce' ), + 'GBP' => __( 'Pounds Sterling', 'woocommerce' ), + 'RON' => __( 'Romanian Leu', 'woocommerce' ), + 'RUB' => __( 'Russian Ruble', 'woocommerce' ), + 'SGD' => __( 'Singapore Dollar', 'woocommerce' ), + 'ZAR' => __( 'South African rand', 'woocommerce' ), + 'SEK' => __( 'Swedish Krona', 'woocommerce' ), + 'CHF' => __( 'Swiss Franc', 'woocommerce' ), + 'TWD' => __( 'Taiwan New Dollars', 'woocommerce' ), + 'THB' => __( 'Thai Baht', 'woocommerce' ), + 'TRY' => __( 'Turkish Lira', 'woocommerce' ), + 'USD' => __( 'US Dollars', 'woocommerce' ), + ) + ) + ); +} + +/** + * Get Currency symbol. + * @param string $currency (default: '') + * @return string + */ +function get_woocommerce_currency_symbol( $currency = '' ) { + if ( ! $currency ) + $currency = get_woocommerce_currency(); + + switch ( $currency ) { + case 'BRL' : + $currency_symbol = 'R$'; + break; + case 'AUD' : + case 'CAD' : + case 'MXN' : + case 'NZD' : + case 'HKD' : + case 'SGD' : + case 'USD' : + $currency_symbol = '$'; + break; + case 'EUR' : + $currency_symbol = '€'; + break; + case 'CNY' : + case 'RMB' : + case 'JPY' : + $currency_symbol = '¥'; + break; + case 'RUB' : + $currency_symbol = 'руб.'; + break; + case 'KRW' : $currency_symbol = '₩'; break; + case 'TRY' : $currency_symbol = 'TL'; break; + case 'NOK' : $currency_symbol = 'kr'; break; + case 'ZAR' : $currency_symbol = 'R'; break; + case 'CZK' : $currency_symbol = 'Kč'; break; + case 'MYR' : $currency_symbol = 'RM'; break; + case 'DKK' : $currency_symbol = 'kr'; break; + case 'HUF' : $currency_symbol = 'Ft'; break; + case 'IDR' : $currency_symbol = 'Rp'; break; + case 'INR' : $currency_symbol = 'Rs.'; break; + case 'ILS' : $currency_symbol = '₪'; break; + case 'PHP' : $currency_symbol = '₱'; break; + case 'PLN' : $currency_symbol = 'zł'; break; + case 'SEK' : $currency_symbol = 'kr'; break; + case 'CHF' : $currency_symbol = 'CHF'; break; + case 'TWD' : $currency_symbol = 'NT$'; break; + case 'THB' : $currency_symbol = '฿'; break; + case 'GBP' : $currency_symbol = '£'; break; + case 'RON' : $currency_symbol = 'lei'; break; + default : $currency_symbol = ''; break; + } + + return apply_filters( 'woocommerce_currency_symbol', $currency_symbol, $currency ); +} + +/** + * Send HTML emails from WooCommerce + * + * @param mixed $to + * @param mixed $subject + * @param mixed $message + * @param string $headers (default: "Content-Type: text/html\r\n") + * @param string $attachments (default: "") + */ +function woocommerce_mail( $to, $subject, $message, $headers = "Content-Type: text/html\r\n", $attachments = "" ) { + global $woocommerce; + + $mailer = $woocommerce->mailer(); + + $mailer->send( $to, $subject, $message, $headers, $attachments ); +} \ No newline at end of file diff --git a/includes/wc-customer-functions.php b/includes/wc-customer-functions.php new file mode 100644 index 00000000000..fc39f75926c --- /dev/null +++ b/includes/wc-customer-functions.php @@ -0,0 +1,260 @@ +get_error_code() ) + return $validation_errors; + + $new_customer_data = apply_filters( 'woocommerce_new_customer_data', array( + 'user_login' => $username, + 'user_pass' => $password, + 'user_email' => $email, + 'role' => 'customer' + ) ); + + $customer_id = wp_insert_user( $new_customer_data ); + + if ( is_wp_error( $customer_id ) ) + return new WP_Error( "registration-error", '' . __( 'ERROR', 'woocommerce' ) . ': ' . __( 'Couldn’t register you… please contact us if you continue to have problems.', 'woocommerce' ) ); + + do_action( 'woocommerce_created_customer', $customer_id, $new_customer_data, $password_generated ); + + return $customer_id; +} + +/** + * Login a customer (set auth cookie and set global user object) + * + * @param int $customer_id + * @return void + */ +function woocommerce_set_customer_auth_cookie( $customer_id ) { + global $current_user; + + $current_user = get_user_by( 'id', $customer_id ); + + wp_set_auth_cookie( $customer_id, true, is_ssl() ); +} + +/** + * Get past orders (by email) and update them + * + * @param int $customer_id + * @return void + */ +function woocommerce_update_new_customer_past_orders( $customer_id ) { + + $customer = get_user_by( 'id', absint( $customer_id ) ); + + $customer_orders = get_posts( array( + 'numberposts' => -1, + 'post_type' => 'shop_order', + 'post_status' => 'publish', + 'fields' => 'ids', + 'meta_query' => array( + array( + 'key' => '_customer_user', + 'value' => array( 0, '' ), + 'compare' => 'IN' + ), + array( + 'key' => '_billing_email', + 'value' => $customer->user_email, + ) + ), + ) ); + + $linked = 0; + $complete = 0; + + if ( $customer_orders ) + foreach ( $customer_orders as $order_id ) { + update_post_meta( $order_id, '_customer_user', $customer->ID ); + + $order_status = wp_get_post_terms( $order_id, 'shop_order_status' ); + + if ( $order_status ) { + $order_status = current( $order_status ); + $order_status = sanitize_title( $order_status->slug ); + } + + if ( $order_status == 'completed' ) + $complete ++; + + $linked ++; + } + + if ( $complete ) { + update_user_meta( $customer_id, 'paying_customer', 1 ); + update_user_meta( $customer_id, '_order_count', '' ); + update_user_meta( $customer_id, '_money_spent', '' ); + } + + return $linked; +} + +/** + * Order Status completed - This is a paying customer + * + * @access public + * @param int $order_id + * @return void + */ +function woocommerce_paying_customer( $order_id ) { + + $order = new WC_Order( $order_id ); + + if ( $order->user_id > 0 ) { + update_user_meta( $order->user_id, 'paying_customer', 1 ); + + $old_spent = absint( get_user_meta( $order->user_id, '_money_spent', true ) ); + update_user_meta( $order->user_id, '_money_spent', $old_spent + $order->order_total ); + + $old_count = absint( get_user_meta( $order->user_id, '_order_count', true ) ); + update_user_meta( $order->user_id, '_order_count', $old_count + 1 ); + } +} +add_action( 'woocommerce_order_status_completed', 'woocommerce_paying_customer' ); + + +/** + * woocommerce_customer_bought_product + * + * Checks if a user (by email) has bought an item + * + * @access public + * @param string $customer_email + * @param int $user_id + * @param int $product_id + * @return bool + */ +function woocommerce_customer_bought_product( $customer_email, $user_id, $product_id ) { + global $wpdb; + + $emails = array(); + + if ( $user_id ) { + $user = get_user_by( 'id', $user_id ); + $emails[] = $user->user_email; + } + + if ( is_email( $customer_email ) ) + $emails[] = $customer_email; + + if ( sizeof( $emails ) == 0 ) + return false; + + $completed = get_term_by( 'slug', 'completed', 'shop_order_status' ); + + return $wpdb->get_var( + $wpdb->prepare( " + SELECT COUNT( DISTINCT order_items.order_item_id ) + FROM {$wpdb->prefix}woocommerce_order_items as order_items + LEFT JOIN {$wpdb->prefix}woocommerce_order_itemmeta AS itemmeta ON order_items.order_item_id = itemmeta.order_item_id + LEFT JOIN {$wpdb->postmeta} AS postmeta ON order_items.order_id = postmeta.post_id + LEFT JOIN {$wpdb->term_relationships} AS rel ON order_items.order_id = rel.object_ID + WHERE + rel.term_taxonomy_id = %d AND + itemmeta.meta_value = %s AND + itemmeta.meta_key IN ( '_variation_id', '_product_id' ) AND + postmeta.meta_key IN ( '_billing_email', '_customer_user' ) AND + ( + postmeta.meta_value IN ( '" . implode( "','", array_unique( $emails ) ) . "' ) OR + ( + postmeta.meta_value = %d AND + postmeta.meta_value > 0 + ) + ) + ", $completed->term_taxonomy_id, $product_id, $user_id + ) + ); +} \ No newline at end of file diff --git a/includes/wc-deprecated-functions.php b/includes/wc-deprecated-functions.php index ef8ee3835a5..13af7335bdf 100644 --- a/includes/wc-deprecated-functions.php +++ b/includes/wc-deprecated-functions.php @@ -32,6 +32,41 @@ function woocommerce_create_page( $slug, $option = '', $page_title = '', $page_c _deprecated_function( 'woocommerce_create_page', '2.1', 'wc_create_page' ); return wc_create_page( $slug, $option, $page_title, $page_content, $post_parent ); } +function woocommerce_readfile_chunked( $file, $retbytes = true ) { + _deprecated_function( 'woocommerce_readfile_chunked', '2.1', 'WC_Download_Handler::readfile_chunked()' ); + return WC_Download_Handler::readfile_chunked( $file, $retbytes ); +} + +/** + * Get product name with extra details such as SKU price and attributes. Used within admin. + * + * @access public + * @param mixed $product + * @deprecated 2.1 + * @return void + */ +function woocommerce_get_formatted_product_name( $product ) { + _deprecated_function( __FUNCTION__, '2.1', 'WC_Product::get_formatted_name()' ); + return $product->get_formatted_name(); +} + +/** + * Handle IPN requests for the legacy paypal gateway by calling gateways manually if needed. + * + * @access public + * @return void + */ +function woocommerce_legacy_paypal_ipn() { + if ( ! empty( $_GET['paypalListener'] ) && $_GET['paypalListener'] == 'paypal_standard_IPN' ) { + global $woocommerce; + + $woocommerce->payment_gateways(); + + do_action( 'woocommerce_api_wc_gateway_paypal' ); + } +} +add_action( 'init', 'woocommerce_legacy_paypal_ipn' ); + /** * Handle renamed filters diff --git a/includes/wc-formatting-functions.php b/includes/wc-formatting-functions.php new file mode 100644 index 00000000000..74ed16e973c --- /dev/null +++ b/includes/wc-formatting-functions.php @@ -0,0 +1,454 @@ + $v ) { + if ( ! array_key_exists( $k, $a2 ) ) + continue; + if ( is_array( $v ) && is_array( $a2[ $k ] ) ) { + $a1[ $k ] = woocommerce_array_overlay( $v, $a2[ $k ] ); + } else { + $a1[ $k ] = $a2[ $k ]; + } + } + return $a1; +} + +/** + * Get the price format depending on the currency position + * + * @return string + */ +function get_woocommerce_price_format() { + $currency_pos = get_option( 'woocommerce_currency_pos' ); + + switch ( $currency_pos ) { + case 'left' : + $format = '%1$s%2$s'; + break; + case 'right' : + $format = '%2$s%1$s'; + break; + case 'left_space' : + $format = '%1$s %2$s'; + break; + case 'right_space' : + $format = '%2$s %1$s'; + break; + } + + return apply_filters( 'woocommerce_price_format', $format, $currency_pos ); +} + +/** + * Format the price with a currency symbol. + * + * @access public + * @param float $price + * @param array $args (default: array()) + * @return string + */ +function woocommerce_price( $price, $args = array() ) { + global $woocommerce; + + extract( shortcode_atts( array( + 'ex_tax_label' => '0' + ), $args ) ); + + $return = ''; + $num_decimals = (int) get_option( 'woocommerce_price_num_decimals' ); + $currency_pos = get_option( 'woocommerce_currency_pos' ); + $currency_symbol = get_woocommerce_currency_symbol(); + $decimal_sep = wp_specialchars_decode( stripslashes( get_option( 'woocommerce_price_decimal_sep' ) ), ENT_QUOTES ); + $thousands_sep = wp_specialchars_decode( stripslashes( get_option( 'woocommerce_price_thousand_sep' ) ), ENT_QUOTES ); + + $price = apply_filters( 'raw_woocommerce_price', (double) $price ); + $price = number_format( $price, $num_decimals, $decimal_sep, $thousands_sep ); + + if ( get_option( 'woocommerce_price_trim_zeros' ) == 'yes' && $num_decimals > 0 ) + $price = woocommerce_trim_zeros( $price ); + + $return = '' . sprintf( get_woocommerce_price_format(), $currency_symbol, $price ) . ''; + + if ( $ex_tax_label && get_option( 'woocommerce_calc_taxes' ) == 'yes' ) + $return .= ' ' . $woocommerce->countries->ex_tax_or_vat() . ''; + + return $return; +} + +/** + * let_to_num function. + * + * This function transforms the php.ini notation for numbers (like '2M') to an integer. + * + * @access public + * @param $size + * @return int + */ +function woocommerce_let_to_num( $size ) { + $l = substr( $size, -1 ); + $ret = substr( $size, 0, -1 ); + switch( strtoupper( $l ) ) { + case 'P': + $ret *= 1024; + case 'T': + $ret *= 1024; + case 'G': + $ret *= 1024; + case 'M': + $ret *= 1024; + case 'K': + $ret *= 1024; + } + return $ret; +} + +/** + * WooCommerce Date Format - Allows to change date format for everything WooCommerce + * + * @access public + * @return string + */ +function woocommerce_date_format() { + return apply_filters( 'woocommerce_date_format', get_option( 'date_format' ) ); +} + +/** + * WooCommerce Time Format - Allows to change time format for everything WooCommerce + * + * @access public + * @return string + */ +function woocommerce_time_format() { + return apply_filters( 'woocommerce_time_format', get_option( 'time_format' ) ); +} + +if ( ! function_exists( 'woocommerce_rgb_from_hex' ) ) { + + /** + * Hex darker/lighter/contrast functions for colours + * + * @access public + * @param mixed $color + * @return string + */ + function woocommerce_rgb_from_hex( $color ) { + $color = str_replace( '#', '', $color ); + // Convert shorthand colors to full format, e.g. "FFF" -> "FFFFFF" + $color = preg_replace( '~^(.)(.)(.)$~', '$1$1$2$2$3$3', $color ); + + $rgb['R'] = hexdec( $color{0}.$color{1} ); + $rgb['G'] = hexdec( $color{2}.$color{3} ); + $rgb['B'] = hexdec( $color{4}.$color{5} ); + return $rgb; + } +} + +if ( ! function_exists( 'woocommerce_hex_darker' ) ) { + + /** + * Hex darker/lighter/contrast functions for colours + * + * @access public + * @param mixed $color + * @param int $factor (default: 30) + * @return string + */ + function woocommerce_hex_darker( $color, $factor = 30 ) { + $base = woocommerce_rgb_from_hex( $color ); + $color = '#'; + + foreach ($base as $k => $v) : + $amount = $v / 100; + $amount = round($amount * $factor); + $new_decimal = $v - $amount; + + $new_hex_component = dechex($new_decimal); + if(strlen($new_hex_component) < 2) : + $new_hex_component = "0".$new_hex_component; + endif; + $color .= $new_hex_component; + endforeach; + + return $color; + } +} + +if ( ! function_exists( 'woocommerce_hex_lighter' ) ) { + + /** + * Hex darker/lighter/contrast functions for colours + * + * @access public + * @param mixed $color + * @param int $factor (default: 30) + * @return string + */ + function woocommerce_hex_lighter( $color, $factor = 30 ) { + $base = woocommerce_rgb_from_hex( $color ); + $color = '#'; + + foreach ($base as $k => $v) : + $amount = 255 - $v; + $amount = $amount / 100; + $amount = round($amount * $factor); + $new_decimal = $v + $amount; + + $new_hex_component = dechex($new_decimal); + if(strlen($new_hex_component) < 2) : + $new_hex_component = "0".$new_hex_component; + endif; + $color .= $new_hex_component; + endforeach; + + return $color; + } +} + +if ( ! function_exists( 'woocommerce_light_or_dark' ) ) { + + /** + * Detect if we should use a light or dark colour on a background colour + * + * @access public + * @param mixed $color + * @param string $dark (default: '#000000') + * @param string $light (default: '#FFFFFF') + * @return string + */ + function woocommerce_light_or_dark( $color, $dark = '#000000', $light = '#FFFFFF' ) { + //return ( hexdec( $color ) > 0xffffff / 2 ) ? $dark : $light; + $hex = str_replace( '#', '', $color ); + + $c_r = hexdec( substr( $hex, 0, 2 ) ); + $c_g = hexdec( substr( $hex, 2, 2 ) ); + $c_b = hexdec( substr( $hex, 4, 2 ) ); + $brightness = ( ( $c_r * 299 ) + ( $c_g * 587 ) + ( $c_b * 114 ) ) / 1000; + + return $brightness > 155 ? $dark : $light; + } +} + +if ( ! function_exists( 'woocommerce_format_hex' ) ) { + + /** + * Format string as hex + * + * @access public + * @param string $hex + * @return string + */ + function woocommerce_format_hex( $hex ) { + + $hex = trim( str_replace( '#', '', $hex ) ); + + if ( strlen( $hex ) == 3 ) { + $hex = $hex[0] . $hex[0] . $hex[1] . $hex[1] . $hex[2] . $hex[2]; + } + + if ( $hex ) return '#' . $hex; + } +} \ No newline at end of file diff --git a/includes/wc-message-functions.php b/includes/wc-message-functions.php index fad7de6541a..8c95d405f76 100644 --- a/includes/wc-message-functions.php +++ b/includes/wc-message-functions.php @@ -84,6 +84,5 @@ function wc_print_messages() { wc_clear_errors(); wc_clear_messages(); } - add_action( 'woocommerce_before_shop_loop', 'wc_print_messages', 10 ); add_action( 'woocommerce_before_single_product', 'wc_print_messages', 10 ); \ No newline at end of file diff --git a/includes/wc-order-functions.php b/includes/wc-order-functions.php new file mode 100644 index 00000000000..9a5e8fff078 --- /dev/null +++ b/includes/wc-order-functions.php @@ -0,0 +1,327 @@ +get_var( "SELECT post_id FROM {$wpdb->prefix}postmeta WHERE meta_key = '_order_key' AND meta_value = '{$order_key}'" ); + + return $order_id; +} + +/** + * Grant downloadable product access to the file identified by $download_id + * + * @access public + * @param string $download_id file identifier + * @param int $product_id product identifier + * @param WC_Order $order the order + * @return int insert id | bool false on failure + */ +function woocommerce_downloadable_file_permission( $download_id, $product_id, $order ) { + global $wpdb; + + if ( $order->status == 'processing' && get_option( 'woocommerce_downloads_grant_access_after_payment' ) == 'no' ) + return; + + $user_email = sanitize_email( $order->billing_email ); + $limit = trim( get_post_meta( $product_id, '_download_limit', true ) ); + $expiry = trim( get_post_meta( $product_id, '_download_expiry', true ) ); + + $limit = empty( $limit ) ? '' : absint( $limit ); + + // Default value is NULL in the table schema + $expiry = empty( $expiry ) ? null : absint( $expiry ); + + if ( $expiry ) + $expiry = date_i18n( "Y-m-d", strtotime( 'NOW + ' . $expiry . ' DAY' ) ); + + $data = array( + 'download_id' => $download_id, + 'product_id' => $product_id, + 'user_id' => absint( $order->user_id ), + 'user_email' => $user_email, + 'order_id' => $order->id, + 'order_key' => $order->order_key, + 'downloads_remaining' => $limit, + 'access_granted' => current_time( 'mysql' ), + 'download_count' => 0 + ); + + $format = array( + '%s', + '%s', + '%s', + '%s', + '%s', + '%s', + '%s', + '%s', + '%d' + ); + + if ( ! is_null( $expiry ) ) { + $data['access_expires'] = $expiry; + $format[] = '%s'; + } + + // Downloadable product - give access to the customer + $result = $wpdb->insert( $wpdb->prefix . 'woocommerce_downloadable_product_permissions', + apply_filters( 'woocommerce_downloadable_file_permission_data', $data ), + apply_filters( 'woocommerce_downloadable_file_permission_format', $format ) + ); + + return $result ? $wpdb->insert_id : false; +} +add_action('woocommerce_order_status_completed', 'woocommerce_downloadable_product_permissions'); +add_action( 'woocommerce_order_status_processing', 'woocommerce_downloadable_product_permissions' ); + + +/** + * Order Status completed - GIVE DOWNLOADABLE PRODUCT ACCESS TO CUSTOMER + * + * @access public + * @param int $order_id + * @return void + */ +function woocommerce_downloadable_product_permissions( $order_id ) { + + if ( get_post_meta( $order_id, __( 'Download Permissions Granted', 'woocommerce' ), true ) == 1 ) + return; // Only do this once + + $order = new WC_Order( $order_id ); + + if (sizeof($order->get_items())>0) foreach ($order->get_items() as $item) : + + if ($item['product_id']>0) : + $_product = $order->get_product_from_item( $item ); + + if ( $_product && $_product->exists() && $_product->is_downloadable() ) : + + $product_id = ($item['variation_id']>0) ? $item['variation_id'] : $item['product_id']; + + $file_download_paths = apply_filters( 'woocommerce_file_download_paths', get_post_meta( $product_id, '_file_paths', true ), $product_id, $order_id, $item ); + if ( ! empty( $file_download_paths ) ) { + foreach ( $file_download_paths as $download_id => $file_path ) { + woocommerce_downloadable_file_permission( $download_id, $product_id, $order ); + } + } + + endif; + + endif; + + endforeach; + + update_post_meta( $order_id, __( 'Download Permissions Granted', 'woocommerce' ), 1); +} + +/** + * Add a item to an order (for example a line item). + * + * @access public + * @param int $order_id + * @param array $data + * @return mixed + */ +function woocommerce_add_order_item( $order_id, $item ) { + global $wpdb; + + $order_id = absint( $order_id ); + + if ( ! $order_id ) + return false; + + $defaults = array( + 'order_item_name' => '', + 'order_item_type' => 'line_item', + ); + + $item = wp_parse_args( $item, $defaults ); + + $wpdb->insert( + $wpdb->prefix . "woocommerce_order_items", + array( + 'order_item_name' => $item['order_item_name'], + 'order_item_type' => $item['order_item_type'], + 'order_id' => $order_id + ), + array( + '%s', '%s', '%d' + ) + ); + + $item_id = absint( $wpdb->insert_id ); + + do_action( 'woocommerce_new_order_item', $item_id, $item, $order_id ); + + return $item_id; +} + +/** + * woocommerce_delete_order_item function. + * + * @access public + * @param int $item_id + * @return bool + */ +function woocommerce_delete_order_item( $item_id ) { + global $wpdb; + + $item_id = absint( $item_id ); + + if ( ! $item_id ) + return false; + + do_action( 'woocommerce_before_delete_order_item', $item_id ); + + $wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->prefix}woocommerce_order_items WHERE order_item_id = %d", $item_id ) ); + $wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->prefix}woocommerce_order_itemmeta WHERE order_item_id = %d", $item_id ) ); + + do_action( 'woocommerce_delete_order_item', $item_id ); + + return true; +} + +/** + * WooCommerce Order Item Meta API - Update term meta + * + * @access public + * @param mixed $item_id + * @param mixed $meta_key + * @param mixed $meta_value + * @param string $prev_value (default: '') + * @return bool + */ +function woocommerce_update_order_item_meta( $item_id, $meta_key, $meta_value, $prev_value = '' ) { + return update_metadata( 'order_item', $item_id, $meta_key, $meta_value, $prev_value ); +} + +/** + * WooCommerce Order Item Meta API - Add term meta + * + * @access public + * @param mixed $item_id + * @param mixed $meta_key + * @param mixed $meta_value + * @param bool $unique (default: false) + * @return bool + */ +function woocommerce_add_order_item_meta( $item_id, $meta_key, $meta_value, $unique = false ){ + return add_metadata( 'order_item', $item_id, $meta_key, $meta_value, $unique ); +} + +/** + * WooCommerce Order Item Meta API - Delete term meta + * + * @access public + * @param mixed $item_id + * @param mixed $meta_key + * @param string $meta_value (default: '') + * @param bool $delete_all (default: false) + * @return bool + */ +function woocommerce_delete_order_item_meta( $item_id, $meta_key, $meta_value = '', $delete_all = false ) { + return delete_metadata( 'order_item', $item_id, $meta_key, $meta_value, $delete_all ); +} + +/** + * WooCommerce Order Item Meta API - Get term meta + * + * @access public + * @param mixed $item_id + * @param mixed $key + * @param bool $single (default: true) + * @return mixed + */ +function woocommerce_get_order_item_meta( $item_id, $key, $single = true ) { + return get_metadata( 'order_item', $item_id, $key, $single ); +} + +/** + * woocommerce_cancel_unpaid_orders function. + * + * @access public + * @return void + */ +function woocommerce_cancel_unpaid_orders() { + global $wpdb; + + $held_duration = get_option( 'woocommerce_hold_stock_minutes' ); + + if ( $held_duration < 1 || get_option( 'woocommerce_manage_stock' ) != 'yes' ) + return; + + $date = date( "Y-m-d H:i:s", strtotime( '-' . absint( $held_duration ) . ' MINUTES', current_time( 'timestamp' ) ) ); + + $unpaid_orders = $wpdb->get_col( $wpdb->prepare( " + SELECT posts.ID + FROM {$wpdb->posts} AS posts + LEFT JOIN {$wpdb->term_relationships} AS rel ON posts.ID=rel.object_ID + LEFT JOIN {$wpdb->term_taxonomy} AS tax USING( term_taxonomy_id ) + LEFT JOIN {$wpdb->terms} AS term USING( term_id ) + + WHERE posts.post_type = 'shop_order' + AND posts.post_status = 'publish' + AND tax.taxonomy = 'shop_order_status' + AND term.slug = 'pending' + AND posts.post_modified < %s + ", $date ) ); + + if ( $unpaid_orders ) { + foreach ( $unpaid_orders as $unpaid_order ) { + $order = new WC_Order( $unpaid_order ); + + if ( apply_filters( 'woocommerce_cancel_unpaid_order', true, $order ) ) + $order->update_status( 'cancelled', __( 'Unpaid order cancelled - time limit reached.', 'woocommerce' ) ); + } + } + + wp_clear_scheduled_hook( 'woocommerce_cancel_unpaid_orders' ); + wp_schedule_single_event( time() + ( absint( $held_duration ) * 60 ), 'woocommerce_cancel_unpaid_orders' ); +} +add_action( 'woocommerce_cancel_unpaid_orders', 'woocommerce_cancel_unpaid_orders' ); + + +/** + * Return the count of processing orders. + * + * @access public + * @return int + */ +function woocommerce_processing_order_count() { + if ( false === ( $order_count = get_transient( 'woocommerce_processing_order_count' ) ) ) { + $order_statuses = get_terms( 'shop_order_status' ); + $order_count = false; + foreach ( $order_statuses as $status ) { + if( $status->slug === 'processing' ) { + $order_count += $status->count; + break; + } + } + $order_count = apply_filters( 'woocommerce_admin_menu_count', intval( $order_count ) ); + set_transient( 'woocommerce_processing_order_count', $order_count ); + } + + return $order_count; +} + diff --git a/includes/wc-page-functions.php b/includes/wc-page-functions.php new file mode 100644 index 00000000000..06d84a2558d --- /dev/null +++ b/includes/wc-page-functions.php @@ -0,0 +1,174 @@ +' . __FUNCTION__, '2.1', 'The "pay" and "thanks" pages are no-longer used - an endpoint is added to the checkout instead. To get a valid link use the WC_Order::get_checkout_payment_url() or WC_Order::get_checkout_order_received_url() methods instead.' ); + + $page = 'checkout'; + } + if ( $page == 'change_password' || $page == 'edit_address' || $page == 'lost_password' ) { + _deprecated_argument( __CLASS__ . '->' . __FUNCTION__, '2.1', 'The "change_password", "edit_address" and "lost_password" pages are no-longer used - an endpoint is added to the my-account instead. To get a valid link use the woocommerce_customer_edit_account_url() function instead.' ); + + $page = 'myaccount'; + } + + $page = apply_filters( 'woocommerce_get_' . $page . '_page_id', get_option('woocommerce_' . $page . '_page_id' ) ); + + return $page ? $page : -1; +} + +/** + * Get endpoint URL + * + * Gets the URL for an endpoint, which varies depending on permalink settings. + * + * @param string $page + * @return string + */ +function woocommerce_get_endpoint_url( $endpoint, $value = '', $permalink = '' ) { + if ( ! $permalink ) + $permalink = get_permalink(); + + if ( get_option( 'permalink_structure' ) ) + $url = trailingslashit( $permalink ) . $endpoint . '/' . $value; + else + $url = add_query_arg( $endpoint, $value, $permalink ); + + return apply_filters( 'woocommerce_get_endpoint_url', $url ); +} + +/** + * woocommerce_lostpassword_url function. + * + * @access public + * @param mixed $url + * @return void + */ +function woocommerce_lostpassword_url( $url ) { + return woocommerce_get_endpoint_url( 'lost-password', '', get_permalink( woocommerce_get_page_id( 'myaccount' ) ) ); +} +add_filter( 'lostpassword_url', 'woocommerce_lostpassword_url' ); + + +/** + * Get the link to the edit account details page + * + * @return string + */ +function woocommerce_customer_edit_account_url() { + $edit_account_url = woocommerce_get_endpoint_url( 'edit-account', '', get_permalink( woocommerce_get_page_id( 'myaccount' ) ) ); + + return apply_filters( 'woocommerce_customer_edit_account_url', $edit_account_url ); +} + +/** + * woocommerce_nav_menu_items function. + * + * @param array $items + * @param mixed $args + * @return array + */ +function woocommerce_nav_menu_items( $items, $args ) { + if ( ! is_user_logged_in() ) { + + $hide_pages = array(); + $hide_pages[] = (int) woocommerce_get_page_id( 'logout' ); + $hide_pages = apply_filters( 'woocommerce_logged_out_hidden_page_ids', $hide_pages ); + + foreach ( $items as $key => $item ) { + if ( ! empty( $item->object_id ) && ! empty( $item->object ) && in_array( $item->object_id, $hide_pages ) && $item->object == 'page' ) { + unset( $items[ $key ] ); + } + } + } + return $items; +} +add_filter( 'wp_nav_menu_objects', 'woocommerce_nav_menu_items', 10, 2 ); + + +/** + * Fix active class in nav for shop page. + * + * @param array $menu_items + * @param array $args + * @return array + */ +function woocommerce_nav_menu_item_classes( $menu_items, $args ) { + + if ( ! is_woocommerce() ) return $menu_items; + + $shop_page = (int) woocommerce_get_page_id('shop'); + $page_for_posts = (int) get_option( 'page_for_posts' ); + + foreach ( (array) $menu_items as $key => $menu_item ) { + + $classes = (array) $menu_item->classes; + + // Unset active class for blog page + if ( $page_for_posts == $menu_item->object_id ) { + $menu_items[$key]->current = false; + unset( $classes[ array_search('current_page_parent', $classes) ] ); + unset( $classes[ array_search('current-menu-item', $classes) ] ); + + // Set active state if this is the shop page link + } elseif ( is_shop() && $shop_page == $menu_item->object_id ) { + $menu_items[$key]->current = true; + $classes[] = 'current-menu-item'; + $classes[] = 'current_page_item'; + + // Set parent state if this is a product page + } elseif ( is_singular( 'product' ) && $shop_page == $menu_item->object_id ) { + $classes[] = 'current_page_parent'; + } + + $menu_items[$key]->classes = array_unique( $classes ); + + } + + return $menu_items; +} +add_filter( 'wp_nav_menu_objects', 'woocommerce_nav_menu_item_classes', 2, 20 ); + + +/** + * Fix active class in wp_list_pages for shop page. + * + * https://github.com/woothemes/woocommerce/issues/177 + * + * @author Jessor, Peter Sterling + * @param string $pages + * @return string + */ +function woocommerce_list_pages( $pages ){ + global $post; + + if (is_woocommerce()) { + $pages = str_replace( 'current_page_parent', '', $pages); // remove current_page_parent class from any item + $shop_page = 'page-item-' . woocommerce_get_page_id('shop'); // find shop_page_id through woocommerce options + + if (is_shop()) : + $pages = str_replace($shop_page, $shop_page . ' current_page_item', $pages); // add current_page_item class to shop page + else : + $pages = str_replace($shop_page, $shop_page . ' current_page_parent', $pages); // add current_page_parent class to shop page + endif; + } + return $pages; +} +add_filter( 'wp_list_pages', 'woocommerce_list_pages' ); diff --git a/includes/wc-product-functions.php b/includes/wc-product-functions.php new file mode 100644 index 00000000000..89e4ab7c399 --- /dev/null +++ b/includes/wc-product-functions.php @@ -0,0 +1,481 @@ +product_factory->get_product( $the_product, $args ); +} + +/** + * Clear all transients cache for product data. + * + * @param int $post_id (default: 0) + */ +function wc_delete_product_transients( $post_id = 0 ) { + global $wpdb; + + $post_id = absint( $post_id ); + + // Clear core transients + $transients_to_clear = array( + 'wc_products_onsale', + 'wc_hidden_product_ids', + 'wc_hidden_product_ids_search', + 'wc_attribute_taxonomies', + 'wc_term_counts' + ); + + foreach( $transients_to_clear as $transient ) { + delete_transient( $transient ); + } + + // Clear transients for which we don't have the name + $wpdb->query( "DELETE FROM `$wpdb->options` WHERE `option_name` LIKE ('_transient_wc_uf_pid_%') OR `option_name` LIKE ('_transient_timeout_wc_uf_pid_%')" ); + $wpdb->query( "DELETE FROM `$wpdb->options` WHERE `option_name` LIKE ('_transient_wc_ln_count_%') OR `option_name` LIKE ('_transient_timeout_wc_ln_count_%')" ); + $wpdb->query( "DELETE FROM `$wpdb->options` WHERE `option_name` LIKE ('_transient_wc_ship_%') OR `option_name` LIKE ('_transient_timeout_wc_ship_%')" ); + + // Clear product specific transients + $post_transients_to_clear = array( + 'wc_product_children_ids_', + 'wc_product_total_stock_', + 'wc_average_rating_', + 'wc_rating_count_', + 'woocommerce_product_type_', // No longer used + 'wc_product_type_', // No longer used + ); + + if ( $post_id > 0 ) { + + foreach( $post_transients_to_clear as $transient ) { + delete_transient( $transient . $post_id ); + $wpdb->query( $wpdb->prepare( "DELETE FROM `$wpdb->options` WHERE `option_name` = %s OR `option_name` = %s", '_transient_' . $transient . $post_id, '_transient_timeout_' . $transient . $post_id ) ); + } + + clean_post_cache( $post_id ); + + } else { + + foreach( $post_transients_to_clear as $transient ) { + $wpdb->query( $wpdb->prepare( "DELETE FROM `$wpdb->options` WHERE `option_name` LIKE %s OR `option_name` LIKE %s", '_transient_' . $transient . '%', '_transient_timeout_' . $transient . '%' ) ); + } + + } +} + +/** + * Function that returns an array containing the IDs of the products that are on sale. + * + * @since 2.0 + * @access public + * @return array + */ +function woocommerce_get_product_ids_on_sale() { + // Load from cache + $product_ids_on_sale = get_transient( 'wc_products_onsale' ); + + // Valid cache found + if ( false !== $product_ids_on_sale ) + return $product_ids_on_sale; + + $on_sale = get_posts( array( + 'post_type' => array( 'product', 'product_variation' ), + 'posts_per_page' => -1, + 'post_status' => 'publish', + 'meta_query' => array( + array( + 'key' => '_sale_price', + 'value' => 0, + 'compare' => '>=', + 'type' => 'DECIMAL', + ), + array( + 'key' => '_sale_price', + 'value' => '', + 'compare' => '!=', + 'type' => '', + ) + ), + 'fields' => 'id=>parent', + ) ); + + $product_ids = array_keys( $on_sale ); + $parent_ids = array_values( $on_sale ); + + // Check for scheduled sales which have not started + foreach ( $product_ids as $key => $id ) { + if ( get_post_meta( $id, '_sale_price_dates_from', true ) > current_time( 'timestamp' ) ) { + unset( $product_ids[ $key ] ); + } + } + + $product_ids_on_sale = array_unique( array_merge( $product_ids, $parent_ids ) ); + + set_transient( 'wc_products_onsale', $product_ids_on_sale ); + + return $product_ids_on_sale; +} + +/** + * woocommerce_get_product_terms function. + * + * Gets product terms in the order they are defined in the backend. + * + * @access public + * @param mixed $object_id + * @param mixed $taxonomy + * @param mixed $fields ids, names, slugs, all + * @return array + */ +function woocommerce_get_product_terms( $object_id, $taxonomy, $fields = 'all' ) { + + if ( ! taxonomy_exists( $taxonomy ) ) + return array(); + + $terms = array(); + $object_terms = get_the_terms( $object_id, $taxonomy ); + + if ( ! is_array( $object_terms ) ) + return array(); + + $all_terms = array_flip( get_terms( $taxonomy, array( 'menu_order' => 'ASC', 'fields' => 'ids' ) ) ); + + switch ( $fields ) { + case 'names' : + foreach ( $object_terms as $term ) + $terms[ $all_terms[ $term->term_id ] ] = $term->name; + break; + case 'ids' : + foreach ( $object_terms as $term ) + $terms[ $all_terms[ $term->term_id ] ] = $term->term_id; + break; + case 'slugs' : + foreach ( $object_terms as $term ) + $terms[ $all_terms[ $term->term_id ] ] = $term->slug; + break; + case 'all' : + foreach ( $object_terms as $term ) + $terms[ $all_terms[ $term->term_id ] ] = $term; + break; + } + + ksort( $terms ); + + return $terms; +} + +/** + * Filter to allow product_cat in the permalinks for products. + * + * @access public + * @param string $permalink The existing permalink URL. + * @param object $post + * @return string + */ +function woocommerce_product_post_type_link( $permalink, $post ) { + // Abort if post is not a product + if ( $post->post_type !== 'product' ) + return $permalink; + + // Abort early if the placeholder rewrite tag isn't in the generated URL + if ( false === strpos( $permalink, '%' ) ) + return $permalink; + + // Get the custom taxonomy terms in use by this post + $terms = get_the_terms( $post->ID, 'product_cat' ); + + if ( empty( $terms ) ) { + // If no terms are assigned to this post, use a string instead (can't leave the placeholder there) + $product_cat = _x( 'uncategorized', 'slug', 'woocommerce' ); + } else { + // Replace the placeholder rewrite tag with the first term's slug + $first_term = array_shift( $terms ); + $product_cat = $first_term->slug; + } + + $find = array( + '%year%', + '%monthnum%', + '%day%', + '%hour%', + '%minute%', + '%second%', + '%post_id%', + '%category%', + '%product_cat%' + ); + + $replace = array( + date_i18n( 'Y', strtotime( $post->post_date ) ), + date_i18n( 'm', strtotime( $post->post_date ) ), + date_i18n( 'd', strtotime( $post->post_date ) ), + date_i18n( 'H', strtotime( $post->post_date ) ), + date_i18n( 'i', strtotime( $post->post_date ) ), + date_i18n( 's', strtotime( $post->post_date ) ), + $post->ID, + $product_cat, + $product_cat + ); + + $replace = array_map( 'sanitize_title', $replace ); + + $permalink = str_replace( $find, $replace, $permalink ); + + return $permalink; +} +add_filter( 'post_type_link', 'woocommerce_product_post_type_link', 10, 2 ); + + +/** + * Get the placeholder image URL for products etc + * + * @access public + * @return string + */ +function woocommerce_placeholder_img_src() { + global $woocommerce; + + return apply_filters( 'woocommerce_placeholder_img_src', $woocommerce->plugin_url() . '/assets/images/placeholder.png' ); +} + +/** + * Get the placeholder image + * + * @access public + * @return string + */ +function woocommerce_placeholder_img( $size = 'shop_thumbnail' ) { + global $woocommerce; + + $dimensions = $woocommerce->get_image_size( $size ); + + return apply_filters('woocommerce_placeholder_img', 'Placeholder' ); +} + +/** + * Variation Formatting + * + * Gets a formatted version of variation data or item meta + * + * @access public + * @param string $variation (default: '') + * @param bool $flat (default: false) + * @return string + */ +function woocommerce_get_formatted_variation( $variation = '', $flat = false ) { + global $woocommerce; + + if ( is_array( $variation ) ) { + + if ( ! $flat ) + $return = '
'; + else + $return = ''; + + $variation_list = array(); + + foreach ( $variation as $name => $value ) { + + if ( ! $value ) + continue; + + // If this is a term slug, get the term's nice name + if ( taxonomy_exists( esc_attr( str_replace( 'attribute_', '', $name ) ) ) ) { + $term = get_term_by( 'slug', $value, esc_attr( str_replace( 'attribute_', '', $name ) ) ); + if ( ! is_wp_error( $term ) && $term->name ) + $value = $term->name; + } + + if ( $flat ) + $variation_list[] = $woocommerce->get_helper( 'attribute' )->attribute_label(str_replace('attribute_', '', $name)).': '.$value; + else + $variation_list[] = '
'.$woocommerce->get_helper( 'attribute' )->attribute_label(str_replace('attribute_', '', $name)).':
'.$value.'
'; + } + + if ( $flat ) + $return .= implode( ', ', $variation_list ); + else + $return .= implode( '', $variation_list ); + + if ( ! $flat ) + $return .= '
'; + + return $return; + } +} + +/** + * Function which handles the start and end of scheduled sales via cron. + * + * @access public + * @return void + */ +function woocommerce_scheduled_sales() { + global $woocommerce, $wpdb; + + // Sales which are due to start + $product_ids = $wpdb->get_col( $wpdb->prepare( " + SELECT postmeta.post_id FROM {$wpdb->postmeta} as postmeta + LEFT JOIN {$wpdb->postmeta} as postmeta_2 ON postmeta.post_id = postmeta_2.post_id + LEFT JOIN {$wpdb->postmeta} as postmeta_3 ON postmeta.post_id = postmeta_3.post_id + WHERE postmeta.meta_key = '_sale_price_dates_from' + AND postmeta_2.meta_key = '_price' + AND postmeta_3.meta_key = '_sale_price' + AND postmeta.meta_value > 0 + AND postmeta.meta_value < %s + AND postmeta_2.meta_value != postmeta_3.meta_value + ", 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', '' ); + } + + wc_delete_product_transients( $product_id ); + + $parent = wp_get_post_parent_id( $product_id ); + + // Sync parent + if ( $parent ) { + // We can force varaible product price to sync up by removing their min price meta + delete_post_meta( $parent, '_min_variation_price' ); + + // Grouped products need syncing via a function + $this_product = get_product( $product_id ); + if ( $this_product->is_type( 'simple' ) ) + $this_product->grouped_product_sync(); + + wc_delete_product_transients( $parent ); + } + } + } + + // Sales which are due to end + $product_ids = $wpdb->get_col( $wpdb->prepare( " + SELECT postmeta.post_id FROM {$wpdb->postmeta} as postmeta + LEFT JOIN {$wpdb->postmeta} as postmeta_2 ON postmeta.post_id = postmeta_2.post_id + LEFT JOIN {$wpdb->postmeta} as postmeta_3 ON postmeta.post_id = postmeta_3.post_id + WHERE postmeta.meta_key = '_sale_price_dates_to' + AND postmeta_2.meta_key = '_price' + AND postmeta_3.meta_key = '_regular_price' + AND postmeta.meta_value > 0 + AND postmeta.meta_value < %s + AND postmeta_2.meta_value != postmeta_3.meta_value + ", 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', '' ); + + wc_delete_product_transients( $product_id ); + + $parent = wp_get_post_parent_id( $product_id ); + + // Sync parent + if ( $parent ) { + // We can force variable product price to sync up by removing their min price meta + delete_post_meta( $parent, '_min_variation_price' ); + + // Grouped products need syncing via a function + $this_product = get_product( $product_id ); + if ( $this_product->is_type( 'simple' ) ) + $this_product->grouped_product_sync(); + + wc_delete_product_transients( $parent ); + } + } + } +} +add_action( 'woocommerce_scheduled_sales', 'woocommerce_scheduled_sales' ); + +/** + * woocommerce_get_attachment_image_attributes function. + * + * @access public + * @param mixed $attr + * @return void + */ +function woocommerce_get_attachment_image_attributes( $attr ) { + if ( strstr( $attr['src'], 'woocommerce_uploads/' ) ) + $attr['src'] = woocommerce_placeholder_img_src(); + + return $attr; +} +add_filter( 'wp_get_attachment_image_attributes', 'woocommerce_get_attachment_image_attributes' ); + + +/** + * woocommerce_prepare_attachment_for_js function. + * + * @access public + * @param mixed $response + * @return void + */ +function woocommerce_prepare_attachment_for_js( $response ) { + + if ( isset( $response['url'] ) && strstr( $response['url'], 'woocommerce_uploads/' ) ) { + $response['full']['url'] = woocommerce_placeholder_img_src(); + if ( isset( $response['sizes'] ) ) { + foreach( $response['sizes'] as $size => $value ) { + $response['sizes'][ $size ]['url'] = woocommerce_placeholder_img_src(); + } + } + } + + return $response; +} +add_filter( 'wp_prepare_attachment_for_js', 'woocommerce_prepare_attachment_for_js' ); + +/** + * Track product views + */ +function woocommerce_track_product_view() { + if ( ! is_singular( 'product' ) ) + return; + + global $post, $product; + + if ( empty( $_COOKIE['woocommerce_recently_viewed'] ) ) + $viewed_products = array(); + else + $viewed_products = (array) explode( '|', $_COOKIE['woocommerce_recently_viewed'] ); + + if ( ! in_array( $post->ID, $viewed_products ) ) + $viewed_products[] = $post->ID; + + if ( sizeof( $viewed_products ) > 15 ) + array_shift( $viewed_products ); + + // Store for session only + setcookie( "woocommerce_recently_viewed", implode( '|', $viewed_products ), 0, COOKIEPATH, COOKIE_DOMAIN, false, true ); +} + +add_action( 'template_redirect', 'woocommerce_track_product_view', 20 ); diff --git a/includes/wc-reporting-functions.php b/includes/wc-reporting-functions.php deleted file mode 100644 index 1ff7832356d..00000000000 --- a/includes/wc-reporting-functions.php +++ /dev/null @@ -1,14 +0,0 @@ -template_url}{$slug}-{$name}.php" ) ); + + // Get default slug-name.php + if ( !$template && $name && file_exists( $woocommerce->plugin_path() . "/templates/{$slug}-{$name}.php" ) ) + $template = $woocommerce->plugin_path() . "/templates/{$slug}-{$name}.php"; + + // If template file doesn't exist, look in yourtheme/slug.php and yourtheme/woocommerce/slug.php + if ( !$template ) + $template = locate_template( array ( "{$slug}.php", "{$woocommerce->template_url}{$slug}.php" ) ); + + if ( $template ) + load_template( $template, false ); +} + +/** + * Get other templates (e.g. product attributes) passing attributes and including the file. + * + * @access public + * @param mixed $template_name + * @param array $args (default: array()) + * @param string $template_path (default: '') + * @param string $default_path (default: '') + * @return void + */ +function woocommerce_get_template( $template_name, $args = array(), $template_path = '', $default_path = '' ) { + global $woocommerce; + + if ( $args && is_array($args) ) + extract( $args ); + + $located = woocommerce_locate_template( $template_name, $template_path, $default_path ); + + do_action( 'woocommerce_before_template_part', $template_name, $template_path, $located, $args ); + + include( $located ); + + do_action( 'woocommerce_after_template_part', $template_name, $template_path, $located, $args ); +} + +/** + * Locate a template and return the path for inclusion. + * + * This is the load order: + * + * yourtheme / $template_path / $template_name + * yourtheme / $template_name + * $default_path / $template_name + * + * @access public + * @param mixed $template_name + * @param string $template_path (default: '') + * @param string $default_path (default: '') + * @return string + */ +function woocommerce_locate_template( $template_name, $template_path = '', $default_path = '' ) { + global $woocommerce; + + if ( ! $template_path ) $template_path = $woocommerce->template_url; + if ( ! $default_path ) $default_path = $woocommerce->plugin_path() . '/templates/'; + + // Look within passed path within the theme - this is priority + $template = locate_template( + array( + trailingslashit( $template_path ) . $template_name, + $template_name + ) + ); + + // Get default template + if ( ! $template ) + $template = $default_path . $template_name; + + // Return what we found + return apply_filters('woocommerce_locate_template', $template, $template_name, $template_path); +} + +/** + * Handle redirects before content is output - hooked into template_redirect so is_page works. + * + * @access public + * @return void + */ +function woocommerce_template_redirect() { + global $woocommerce, $wp_query, $wp; + + // When default permalinks are enabled, redirect shop page to post type archive url + if ( ! empty( $_GET['page_id'] ) && get_option( 'permalink_structure' ) == "" && $_GET['page_id'] == woocommerce_get_page_id( 'shop' ) ) { + wp_safe_redirect( get_post_type_archive_link('product') ); + exit; + } + + // When on the checkout with an empty cart, redirect to cart page + elseif ( is_page( woocommerce_get_page_id( 'checkout' ) ) && sizeof( $woocommerce->cart->get_cart() ) == 0 && empty( $wp->query_vars['order-pay'] ) && ! isset( $wp->query_vars['order-received'] ) ) { + wp_redirect( get_permalink( woocommerce_get_page_id( 'cart' ) ) ); + exit; + } + + // Logout + elseif ( is_page( woocommerce_get_page_id( 'logout' ) ) ) { + wp_redirect( str_replace( '&', '&', wp_logout_url( get_permalink( woocommerce_get_page_id( 'myaccount' ) ) ) ) ); + exit; + } + + // Redirect to the product page if we have a single product + elseif ( is_search() && is_post_type_archive( 'product' ) && apply_filters( 'woocommerce_redirect_single_search_result', true ) && $wp_query->post_count == 1 ) { + $product = get_product( $wp_query->post ); + + if ( $product->is_visible() ) { + wp_safe_redirect( get_permalink( $product->id ), 302 ); + exit; + } + } + + // Force SSL + elseif ( get_option('woocommerce_force_ssl_checkout') == 'yes' && ! is_ssl() ) { + + if ( is_checkout() || is_account_page() || apply_filters( 'woocommerce_force_ssl_checkout', false ) ) { + if ( 0 === strpos( $_SERVER['REQUEST_URI'], 'http' ) ) { + wp_safe_redirect( preg_replace( '|^http://|', 'https://', $_SERVER['REQUEST_URI'] ) ); + exit; + } else { + wp_safe_redirect( 'https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] ); + exit; + } + } + + } + + // Break out of SSL if we leave the checkout/my accounts + elseif ( get_option('woocommerce_force_ssl_checkout') == 'yes' && get_option('woocommerce_unforce_ssl_checkout') == 'yes' && is_ssl() && $_SERVER['REQUEST_URI'] && ! is_checkout() && ! is_ajax() && ! is_account_page() && apply_filters( 'woocommerce_unforce_ssl_checkout', true ) ) { + + if ( 0 === strpos( $_SERVER['REQUEST_URI'], 'http' ) ) { + wp_safe_redirect( preg_replace( '|^https://|', 'http://', $_SERVER['REQUEST_URI'] ) ); + exit; + } else { + wp_safe_redirect( 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] ); + exit; + } + + } + + // Buffer the checkout page + elseif ( is_checkout() ) { + ob_start(); + } +} + +/** + * Add body classes for WC pages + * + * @param array $classes + * @return array + */ +function wc_body_class( $classes ) { + $classes = (array) $classes; + + if ( is_woocommerce() ) { + $classes[] = 'woocommerce'; + $classes[] = 'woocommerce-page'; + } + + elseif ( is_checkout() ) { + $classes[] = 'woocommerce-checkout'; + $classes[] = 'woocommerce-page'; + } + + elseif ( is_cart() ) { + $classes[] = 'woocommerce-cart'; + $classes[] = 'woocommerce-page'; + } + + elseif ( is_account_page() ) { + $classes[] = 'woocommerce-account'; + $classes[] = 'woocommerce-page'; + } + + return array_unique( $classes ); +} + /** Template pages ********************************************************/ if ( ! function_exists( 'woocommerce_content' ) ) { @@ -76,6 +269,58 @@ if ( ! function_exists( 'woocommerce_content' ) ) { /** Global ****************************************************************/ +if ( ! function_exists( 'wc_product_post_class' ) ) { + + /** + * Adds extra post classes for products + * + * @since 2.1.0 + * @param array $classes + * @param string|array $class + * @param int $post_id + * @return array + */ + function wc_product_post_class( $classes, $class = '', $post_id = '' ) { + if ( ! $post_id || get_post_type( $post_id ) !== 'product' ) + return $classes; + + $product = get_product( $post_id ); + + if ( $product ) { + if ( $product->is_on_sale() ) { + $classes[] = 'sale'; + } + if ( $product->is_featured() ) { + $classes[] = 'featured'; + } + if ( $product->is_downloadable() ) { + $classes[] = 'downloadable'; + } + if ( $product->is_virtual() ) { + $classes[] = 'virtual'; + } + if ( $product->is_sold_individually() ) { + $classes[] = 'sold-individually'; + } + if ( $product->is_taxable() ) { + $classes[] = 'taxable'; + } + if ( $product->is_shipping_taxable() ) { + $classes[] = 'shipping-taxable'; + } + if ( $product->is_purchasable() ) { + $classes[] = 'purchasable'; + } + if ( isset( $product->product_type ) ) { + $classes[] = "product-type-" . $product->product_type; + } + $classes[] = $product->stock_status; + } + + return $classes; + } +} + if ( ! function_exists( 'woocommerce_output_content_wrapper' ) ) { /** @@ -306,6 +551,7 @@ if ( ! function_exists( 'woocommerce_show_product_loop_sale_flash' ) ) { woocommerce_get_template( 'loop/sale-flash.php' ); } } + if ( ! function_exists( 'woocommerce_reset_loop' ) ) { /** @@ -322,9 +568,6 @@ if ( ! function_exists( 'woocommerce_reset_loop' ) ) { } } -add_filter( 'loop_end', 'woocommerce_reset_loop' ); - - if ( ! function_exists( 'woocommerce_get_product_thumbnail' ) ) { /** @@ -1491,3 +1734,39 @@ if ( ! function_exists( 'get_product_search_form' ) ) { return apply_filters( 'get_product_search_form', $form ); } } + +if ( ! function_exists( 'woocommerce_products_rss_feed' ) ) { + + /** + * Products RSS Feed. + * + * @access public + * @return void + */ + function woocommerce_products_rss_feed() { + // Product RSS + if ( is_post_type_archive( 'product' ) || is_singular( 'product' ) ) { + + $feed = get_post_type_archive_feed_link( 'product' ); + + echo ''; + + } elseif ( is_tax( 'product_cat' ) ) { + + $term = get_term_by('slug', esc_attr( get_query_var('product_cat') ), 'product_cat'); + + $feed = add_query_arg('product_cat', $term->slug, get_post_type_archive_feed_link( 'product' )); + + echo ''; + + } elseif ( is_tax( 'product_tag' ) ) { + + $term = get_term_by('slug', esc_attr( get_query_var('product_tag') ), 'product_tag'); + + $feed = add_query_arg('product_tag', $term->slug, get_post_type_archive_feed_link( 'product' )); + + echo ''; + + } + } +} diff --git a/includes/wc-template-hooks.php b/includes/wc-template-hooks.php new file mode 100644 index 00000000000..72dcd047b73 --- /dev/null +++ b/includes/wc-template-hooks.php @@ -0,0 +1,194 @@ +query['product_cat'] ) ) ? $wp_query->query['product_cat'] : ''; + $r['menu_order'] = false; + + if ( $orderby == 'order' ) + $r['menu_order'] = 'asc'; + elseif ( $orderby ) + $r['orderby'] = $orderby; + + $terms = get_terms( 'product_cat', $r ); + + if ( ! $terms ) + return; + + $output = ""; + + echo $output; +} + +/** + * Walk the Product Categories. + * + * @access public + * @return void + */ +function woocommerce_walk_category_dropdown_tree() { + global $woocommerce; + + if ( ! class_exists( 'WC_Product_Cat_Dropdown_Walker' ) ) + include_once( $woocommerce->plugin_path() . '/includes/walkers/class-product-cat-dropdown-walker.php' ); + + $args = func_get_args(); + + // the user's options are the third parameter + if ( empty( $args[2]['walker']) || !is_a($args[2]['walker'], 'Walker' ) ) + $walker = new WC_Product_Cat_Dropdown_Walker; + else + $walker = $args[2]['walker']; + + return call_user_func_array(array( &$walker, 'walk' ), $args ); +} + +/** + * WooCommerce Term/Order item Meta API - set table name + * + * @access public + * @return void + */ +function woocommerce_taxonomy_metadata_wpdbfix() { + global $wpdb; + $termmeta_name = 'woocommerce_termmeta'; + $itemmeta_name = 'woocommerce_order_itemmeta'; + + $wpdb->woocommerce_termmeta = $wpdb->prefix . $termmeta_name; + $wpdb->order_itemmeta = $wpdb->prefix . $itemmeta_name; + + $wpdb->tables[] = 'woocommerce_termmeta'; + $wpdb->tables[] = 'order_itemmeta'; +} +add_action( 'init', 'woocommerce_taxonomy_metadata_wpdbfix', 0 ); +add_action( 'switch_blog', 'woocommerce_taxonomy_metadata_wpdbfix', 0 ); + +/** + * WooCommerce Term Meta API - Update term meta + * + * @access public + * @param mixed $term_id + * @param mixed $meta_key + * @param mixed $meta_value + * @param string $prev_value (default: '') + * @return bool + */ +function update_woocommerce_term_meta( $term_id, $meta_key, $meta_value, $prev_value = '' ) { + return update_metadata( 'woocommerce_term', $term_id, $meta_key, $meta_value, $prev_value ); +} + +/** + * WooCommerce Term Meta API - Add term meta + * + * @access public + * @param mixed $term_id + * @param mixed $meta_key + * @param mixed $meta_value + * @param bool $unique (default: false) + * @return bool + */ +function add_woocommerce_term_meta( $term_id, $meta_key, $meta_value, $unique = false ){ + return add_metadata( 'woocommerce_term', $term_id, $meta_key, $meta_value, $unique ); +} + +/** + * WooCommerce Term Meta API - Delete term meta + * + * @access public + * @param mixed $term_id + * @param mixed $meta_key + * @param string $meta_value (default: '') + * @param bool $delete_all (default: false) + * @return bool + */ +function delete_woocommerce_term_meta( $term_id, $meta_key, $meta_value = '', $delete_all = false ) { + return delete_metadata( 'woocommerce_term', $term_id, $meta_key, $meta_value, $delete_all ); +} + +/** + * WooCommerce Term Meta API - Get term meta + * + * @access public + * @param mixed $term_id + * @param mixed $key + * @param bool $single (default: true) + * @return mixed + */ +function get_woocommerce_term_meta( $term_id, $key, $single = true ) { + return get_metadata( 'woocommerce_term', $term_id, $key, $single ); +} + +/** + * Move a term before the a given element of its hierarchy level + * + * @access public + * @param int $the_term + * @param int $next_id the id of the next sibling element in save hierarchy level + * @param string $taxonomy + * @param int $index (default: 0) + * @param mixed $terms (default: null) + * @return int + */ +function woocommerce_order_terms( $the_term, $next_id, $taxonomy, $index = 0, $terms = null ) { + + if( ! $terms ) $terms = get_terms($taxonomy, 'menu_order=ASC&hide_empty=0&parent=0' ); + if( empty( $terms ) ) return $index; + + $id = $the_term->term_id; + + $term_in_level = false; // flag: is our term to order in this level of terms + + foreach ($terms as $term) { + + if( $term->term_id == $id ) { // our term to order, we skip + $term_in_level = true; + continue; // our term to order, we skip + } + // the nextid of our term to order, lets move our term here + if(null !== $next_id && $term->term_id == $next_id) { + $index++; + $index = woocommerce_set_term_order($id, $index, $taxonomy, true); + } + + // set order + $index++; + $index = woocommerce_set_term_order($term->term_id, $index, $taxonomy); + + // if that term has children we walk through them + $children = get_terms($taxonomy, "parent={$term->term_id}&menu_order=ASC&hide_empty=0"); + if( !empty($children) ) { + $index = woocommerce_order_terms( $the_term, $next_id, $taxonomy, $index, $children ); + } + } + + // no nextid meaning our term is in last position + if( $term_in_level && null === $next_id ) + $index = woocommerce_set_term_order($id, $index+1, $taxonomy, true); + + return $index; +} + +/** + * Set the sort order of a term + * + * @access public + * @param int $term_id + * @param int $index + * @param string $taxonomy + * @param bool $recursive (default: false) + * @return int + */ +function woocommerce_set_term_order( $term_id, $index, $taxonomy, $recursive = false ) { + + $term_id = (int) $term_id; + $index = (int) $index; + + // Meta name + if ( taxonomy_is_product_attribute( $taxonomy ) ) + $meta_name = 'order_' . esc_attr( $taxonomy ); + else + $meta_name = 'order'; + + update_woocommerce_term_meta( $term_id, $meta_name, $index ); + + if( ! $recursive ) return $index; + + $children = get_terms($taxonomy, "parent=$term_id&menu_order=ASC&hide_empty=0"); + + foreach ( $children as $term ) { + $index ++; + $index = woocommerce_set_term_order($term->term_id, $index, $taxonomy, true); + } + + clean_term_cache( $term_id, $taxonomy ); + + return $index; +} + +/** + * Add term ordering to get_terms + * + * It enables the support a 'menu_order' parameter to get_terms for the product_cat taxonomy. + * By default it is 'ASC'. It accepts 'DESC' too + * + * To disable it, set it ot false (or 0) + * + * @access public + * @param array $clauses + * @param array $taxonomies + * @param array $args + * @return array + */ +function woocommerce_terms_clauses( $clauses, $taxonomies, $args ) { + global $wpdb, $woocommerce; + + // No sorting when menu_order is false + if ( isset($args['menu_order']) && $args['menu_order'] == false ) return $clauses; + + // No sorting when orderby is non default + if ( isset($args['orderby']) && $args['orderby'] != 'name' ) return $clauses; + + // No sorting in admin when sorting by a column + if ( is_admin() && isset($_GET['orderby']) ) return $clauses; + + // wordpress should give us the taxonomies asked when calling the get_terms function. Only apply to categories and pa_ attributes + $found = false; + foreach ( (array) $taxonomies as $taxonomy ) { + if ( taxonomy_is_product_attribute( $taxonomy ) || in_array( $taxonomy, apply_filters( 'woocommerce_sortable_taxonomies', array( 'product_cat' ) ) ) ) { + $found = true; + break; + } + } + if (!$found) return $clauses; + + // Meta name + if ( ! empty( $taxonomies[0] ) && taxonomy_is_product_attribute( $taxonomies[0] ) ) { + $meta_name = 'order_' . esc_attr( $taxonomies[0] ); + } else { + $meta_name = 'order'; + } + + // query fields + if ( strpos('COUNT(*)', $clauses['fields']) === false ) $clauses['fields'] .= ', tm.* '; + + //query join + $clauses['join'] .= " LEFT JOIN {$wpdb->woocommerce_termmeta} AS tm ON (t.term_id = tm.woocommerce_term_id AND tm.meta_key = '". $meta_name ."') "; + + // default to ASC + if ( ! isset($args['menu_order']) || ! in_array( strtoupper($args['menu_order']), array('ASC', 'DESC')) ) $args['menu_order'] = 'ASC'; + + $order = "ORDER BY tm.meta_value+0 " . $args['menu_order']; + + if ( $clauses['orderby'] ): + $clauses['orderby'] = str_replace('ORDER BY', $order . ',', $clauses['orderby'] ); + else: + $clauses['orderby'] = $order; + endif; + + return $clauses; +} +add_filter( 'terms_clauses', 'woocommerce_terms_clauses', 10, 3 ); + + +/** + * 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 = " + AND ( + meta_stock.meta_key = '_stock_status' + AND + meta_stock.meta_value = 'instock' + )"; + } else { + $stock_query = $stock_join = ''; + } + + // Main query + $count_query = $wpdb->prepare( " + SELECT COUNT( DISTINCT posts.ID ) FROM {$wpdb->posts} as posts + + LEFT JOIN {$wpdb->postmeta} AS meta_visibility ON posts.ID = meta_visibility.post_id + LEFT JOIN {$wpdb->term_relationships} AS rel ON posts.ID = rel.object_ID + LEFT JOIN {$wpdb->term_taxonomy} AS tax USING( term_taxonomy_id ) + LEFT JOIN {$wpdb->terms} AS term USING( term_id ) + $stock_join + + WHERE posts.post_status = 'publish' + AND posts.post_type = 'product' + AND ( + meta_visibility.meta_key = '_visibility' + AND + meta_visibility.meta_value IN ( 'visible', 'catalog' ) + ) + AND tax.taxonomy = %s + $stock_query + ", $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 ) ); + } + + } +} + +/** + * woocommerce_recount_after_stock_change function. + * + * @access public + * @return void + */ +function woocommerce_recount_after_stock_change( $product_id ) { + + $product_terms = get_the_terms( $product_id, 'product_cat' ); + + if ( $product_terms ) { + foreach ( $product_terms as $term ) + $product_cats[ $term->term_id ] = $term->parent; + + _woocommerce_term_recount( $product_cats, get_taxonomy( 'product_cat' ), false, false ); + + } + + $product_terms = get_the_terms( $product_id, 'product_tag' ); + + if ( $product_terms ) { + foreach ( $product_terms as $term ) + $product_tags[ $term->term_id ] = $term->parent; + + _woocommerce_term_recount( $product_tags, get_taxonomy( 'product_tag' ), false, false ); + + } +} +add_action( 'woocommerce_product_set_stock_status', 'woocommerce_recount_after_stock_change' ); + + +/** + * Overrides the original term count for product categories and tags with the product count + * that takes catalog visibility into account. + * + * @param array $terms + * @param mixed $taxonomies + * @param mixed $args + * @return array + */ +function woocommerce_change_term_counts( $terms, $taxonomies, $args ) { + if ( is_admin() || is_ajax() ) + return $terms; + + if ( ! in_array( $taxonomies[0], apply_filters( 'woocommerce_change_term_counts', array( 'product_cat', 'product_tag' ) ) ) ) + return $terms; + + $term_counts = $o_term_counts = get_transient( 'wc_term_counts' ); + + foreach ( $terms as &$term ) { + // If the original term count is zero, there's no way the product count could be higher. + if ( empty( $term->count ) ) continue; + + $term_counts[ $term->term_id ] = isset( $term_counts[ $term->term_id ] ) ? $term_counts[ $term->term_id ] : get_woocommerce_term_meta( $term->term_id, 'product_count_' . $taxonomies[0] , true ); + + if ( $term_counts[ $term->term_id ] != '' ) + $term->count = $term_counts[ $term->term_id ]; + } + + // Update transient + if ( $term_counts != $o_term_counts ) + set_transient( 'wc_term_counts', $term_counts ); + + return $terms; +} +add_filter( 'get_terms', 'woocommerce_change_term_counts', 10, 3 ); diff --git a/uninstall.php b/uninstall.php index c65ff576566..3d91604b9e6 100644 --- a/uninstall.php +++ b/uninstall.php @@ -14,11 +14,8 @@ if( !defined('WP_UNINSTALL_PLUGIN') ) exit(); global $wpdb, $wp_roles; // Roles + caps -if ( ! function_exists( 'woocommerce_remove_roles' ) ) - include_once( 'woocommerce-core-functions.php' ); - -if ( function_exists( 'woocommerce_remove_roles' ) ) - woocommerce_remove_roles(); +$installer = include( 'includes/class-wc-install.php' ); +$installer->remove_roles(); // Pages wp_delete_post( get_option('woocommerce_shop_page_id'), true ); diff --git a/woocommerce-ajax.php b/woocommerce-ajax.php index 20ed65d9a92..672dcdd1cb0 100644 --- a/woocommerce-ajax.php +++ b/woocommerce-ajax.php @@ -741,7 +741,7 @@ function woocommerce_link_all_variations() { break; } - $woocommerce->get_helper( 'transient' )->clear_product_transients( $post_id ); + wc_delete_product_transients( $post_id ); echo $added; diff --git a/woocommerce-core-functions.php b/woocommerce-core-functions.php deleted file mode 100644 index 60d6c7e6dfb..00000000000 --- a/woocommerce-core-functions.php +++ /dev/null @@ -1,2641 +0,0 @@ -product_factory->get_product( $the_product, $args ); -} - -/** - * Get past orders (by email) and update them - * - * @param int $customer_id - * @return void - */ -function woocommerce_update_new_customer_past_orders( $customer_id ) { - - $customer = get_user_by( 'id', absint( $customer_id ) ); - - $customer_orders = get_posts( array( - 'numberposts' => -1, - 'post_type' => 'shop_order', - 'post_status' => 'publish', - 'fields' => 'ids', - 'meta_query' => array( - array( - 'key' => '_customer_user', - 'value' => array( 0, '' ), - 'compare' => 'IN' - ), - array( - 'key' => '_billing_email', - 'value' => $customer->user_email, - ) - ), - ) ); - - $linked = 0; - $complete = 0; - - if ( $customer_orders ) - foreach ( $customer_orders as $order_id ) { - update_post_meta( $order_id, '_customer_user', $customer->ID ); - - $order_status = wp_get_post_terms( $order_id, 'shop_order_status' ); - - if ( $order_status ) { - $order_status = current( $order_status ); - $order_status = sanitize_title( $order_status->slug ); - } - - if ( $order_status == 'completed' ) - $complete ++; - - $linked ++; - } - - if ( $complete ) { - update_user_meta( $customer_id, 'paying_customer', 1 ); - update_user_meta( $customer_id, '_order_count', '' ); - update_user_meta( $customer_id, '_money_spent', '' ); - } - - return $linked; -} - -/** - * Function that returns an array containing the IDs of the products that are on sale. - * - * @since 2.0 - * @access public - * @return array - */ -function woocommerce_get_product_ids_on_sale() { - // Load from cache - $product_ids_on_sale = get_transient( 'wc_products_onsale' ); - - // Valid cache found - if ( false !== $product_ids_on_sale ) - return $product_ids_on_sale; - - $on_sale = get_posts( array( - 'post_type' => array( 'product', 'product_variation' ), - 'posts_per_page' => -1, - 'post_status' => 'publish', - 'meta_query' => array( - array( - 'key' => '_sale_price', - 'value' => 0, - 'compare' => '>=', - 'type' => 'DECIMAL', - ), - array( - 'key' => '_sale_price', - 'value' => '', - 'compare' => '!=', - 'type' => '', - ) - ), - 'fields' => 'id=>parent', - ) ); - - $product_ids = array_keys( $on_sale ); - $parent_ids = array_values( $on_sale ); - - // Check for scheduled sales which have not started - foreach ( $product_ids as $key => $id ) { - if ( get_post_meta( $id, '_sale_price_dates_from', true ) > current_time( 'timestamp' ) ) { - unset( $product_ids[ $key ] ); - } - } - - $product_ids_on_sale = array_unique( array_merge( $product_ids, $parent_ids ) ); - - set_transient( 'wc_products_onsale', $product_ids_on_sale ); - - return $product_ids_on_sale; -} - -/** - * Sanitize taxonomy names. Slug format (no spaces, lowercase). - * - * Doesn't use sanitize_title as this destroys utf chars. - * - * @access public - * @param mixed $taxonomy - * @return void - */ -function woocommerce_sanitize_taxonomy_name( $taxonomy ) { - $taxonomy = strtolower( stripslashes( strip_tags( $taxonomy ) ) ); - $taxonomy = preg_replace( '/&.+?;/', '', $taxonomy ); // Kill entities - $taxonomy = str_replace( array( '.', '\'', '"' ), '', $taxonomy ); // Kill quotes and full stops. - $taxonomy = str_replace( array( ' ', '_' ), '-', $taxonomy ); // Replace spaces and underscores. - - return $taxonomy; -} - -/** - * woocommerce_get_attachment_image_attributes function. - * - * @access public - * @param mixed $attr - * @return void - */ -function woocommerce_get_attachment_image_attributes( $attr ) { - if ( strstr( $attr['src'], 'woocommerce_uploads/' ) ) - $attr['src'] = woocommerce_placeholder_img_src(); - - return $attr; -} - -add_filter( 'wp_get_attachment_image_attributes', 'woocommerce_get_attachment_image_attributes' ); - - -/** - * woocommerce_prepare_attachment_for_js function. - * - * @access public - * @param mixed $response - * @return void - */ -function woocommerce_prepare_attachment_for_js( $response ) { - - if ( isset( $response['url'] ) && strstr( $response['url'], 'woocommerce_uploads/' ) ) { - $response['full']['url'] = woocommerce_placeholder_img_src(); - if ( isset( $response['sizes'] ) ) { - foreach( $response['sizes'] as $size => $value ) { - $response['sizes'][ $size ]['url'] = woocommerce_placeholder_img_src(); - } - } - } - - return $response; -} - -add_filter( 'wp_prepare_attachment_for_js', 'woocommerce_prepare_attachment_for_js' ); - -/** - * woocommerce_get_dimension function. - * - * Normalise dimensions, unify to cm then convert to wanted unit value - * - * Usage: woocommerce_get_dimension(55, 'in'); - * - * @access public - * @param mixed $dim - * @param mixed $to_unit 'in', 'm', 'cm', 'm' - * @return float - */ -function woocommerce_get_dimension( $dim, $to_unit ) { - - $from_unit = strtolower( get_option( 'woocommerce_dimension_unit' ) ); - $to_unit = strtolower( $to_unit ); - - // Unify all units to cm first - if ( $from_unit !== $to_unit ) { - - switch ( $from_unit ) { - case 'in': - $dim *= 2.54; - break; - case 'm': - $dim *= 100; - break; - case 'mm': - $dim *= 0.1; - break; - case 'yd': - $dim *= 0.010936133; - break; - } - - // Output desired unit - switch ( $to_unit ) { - case 'in': - $dim *= 0.3937; - break; - case 'm': - $dim *= 0.01; - break; - case 'mm': - $dim *= 10; - break; - case 'yd': - $dim *= 91.44; - break; - } - } - return ( $dim < 0 ) ? 0 : $dim; -} - - -/** - * woocommerce_get_weight function. - * - * Normalise weights, unify to cm then convert to wanted unit value - * - * Usage: woocommerce_get_weight(55, 'kg'); - * - * @access public - * @param mixed $weight - * @param mixed $to_unit 'g', 'kg', 'lbs' - * @return float - */ -function woocommerce_get_weight( $weight, $to_unit ) { - - $from_unit = strtolower( get_option('woocommerce_weight_unit') ); - $to_unit = strtolower( $to_unit ); - - //Unify all units to kg first - if ( $from_unit !== $to_unit ) { - - switch ( $from_unit ) { - case 'g': - $weight *= 0.001; - break; - case 'lbs': - $weight *= 0.4536; - break; - case 'oz': - $weight *= 0.0283; - break; - } - - // Output desired unit - switch ( $to_unit ) { - case 'g': - $weight *= 1000; - break; - case 'lbs': - $weight *= 2.2046; - break; - case 'oz': - $weight *= 35.274; - break; - } - } - return ( $weight < 0 ) ? 0 : $weight; -} - - -/** - * Get product name with extra details such as SKU price and attributes. Used within admin. - * - * @access public - * @param mixed $product - * @deprecated 2.1 - * @return void - */ -function woocommerce_get_formatted_product_name( $product ) { - - _deprecated_function( __FUNCTION__, '2.1', 'WC_Product::get_formatted_name()' ); - - return $product->get_formatted_name(); -} - - -/** - * Get the placeholder image URL for products etc - * - * @access public - * @return string - */ -function woocommerce_placeholder_img_src() { - global $woocommerce; - - return apply_filters('woocommerce_placeholder_img_src', $woocommerce->plugin_url() . '/assets/images/placeholder.png' ); -} - - -/** - * Get the placeholder image - * - * @access public - * @return string - */ -function woocommerce_placeholder_img( $size = 'shop_thumbnail' ) { - global $woocommerce; - - $dimensions = $woocommerce->get_image_size( $size ); - - return apply_filters('woocommerce_placeholder_img', 'Placeholder' ); -} - - -/** - * woocommerce_lostpassword_url function. - * - * @access public - * @param mixed $url - * @return void - */ -function woocommerce_lostpassword_url( $url ) { - return woocommerce_get_endpoint_url( 'lost-password', '', get_permalink( woocommerce_get_page_id( 'myaccount' ) ) ); -} - -add_filter( 'lostpassword_url', 'woocommerce_lostpassword_url' ); - - -/** - * Send HTML emails from WooCommerce - * - * @access public - * @param mixed $to - * @param mixed $subject - * @param mixed $message - * @param string $headers (default: "Content-Type: text/html\r\n") - * @param string $attachments (default: "") - * @return void - */ -function woocommerce_mail( $to, $subject, $message, $headers = "Content-Type: text/html\r\n", $attachments = "" ) { - global $woocommerce; - - $mailer = $woocommerce->mailer(); - - $mailer->send( $to, $subject, $message, $headers, $attachments ); -} - -if ( ! function_exists( 'woocommerce_get_page_id' ) ) { - - /** - * WooCommerce page IDs - * - * retrieve page ids - used for myaccount, edit_address, shop, cart, checkout, pay, view_order, terms - * - * returns -1 if no page is found - * - * @access public - * @param string $page - * @return int - */ - function woocommerce_get_page_id( $page ) { - - if ( $page == 'pay' || $page == 'thanks' ) { - _deprecated_argument( __CLASS__ . '->' . __FUNCTION__, '2.1', 'The "pay" and "thanks" pages are no-longer used - an endpoint is added to the checkout instead. To get a valid link use the WC_Order::get_checkout_payment_url() or WC_Order::get_checkout_order_received_url() methods instead.' ); - - $page = 'checkout'; - } - if ( $page == 'change_password' || $page == 'edit_address' || $page == 'lost_password' ) { - _deprecated_argument( __CLASS__ . '->' . __FUNCTION__, '2.1', 'The "change_password", "edit_address" and "lost_password" pages are no-longer used - an endpoint is added to the my-account instead. To get a valid link use the woocommerce_customer_edit_account_url() function instead.' ); - - $page = 'myaccount'; - } - - $page = apply_filters( 'woocommerce_get_' . $page . '_page_id', get_option('woocommerce_' . $page . '_page_id' ) ); - - return $page ? $page : -1; - } -} - -if ( ! function_exists( 'woocommerce_get_endpoint_url' ) ) { - - /** - * Get endpoint URL - * - * Gets the URL for an endpoint, which varies depending on permalink settings. - * - * @param string $page - * @return string - */ - function woocommerce_get_endpoint_url( $endpoint, $value = '', $permalink = '' ) { - if ( ! $permalink ) - $permalink = get_permalink(); - - if ( get_option( 'permalink_structure' ) ) - $url = trailingslashit( $permalink ) . $endpoint . '/' . $value; - else - $url = add_query_arg( $endpoint, $value, $permalink ); - - return apply_filters( 'woocommerce_get_endpoint_url', $url ); - } -} - -if ( ! function_exists( 'woocommerce_empty_cart' ) ) { - - /** - * WooCommerce clear cart - * - * Clears the cart session when called - * - * @access public - * @return void - */ - function woocommerce_empty_cart() { - global $woocommerce; - - if ( ! isset( $woocommerce->cart ) || $woocommerce->cart == '' ) - $woocommerce->cart = new WC_Cart(); - - $woocommerce->cart->empty_cart( false ); - } -} - -if ( ! function_exists( 'woocommerce_disable_admin_bar' ) ) { - - /** - * Prevent any user who cannot 'edit_posts' (subscribers, customers etc) from seeing the admin bar - * - * Note: get_option( 'woocommerce_lock_down_admin', true ) is a deprecated option here for backwards compat. Defaults to true. - * - * @access public - * @param bool $show_admin_bar - * @return bool - */ - function woocommerce_disable_admin_bar( $show_admin_bar ) { - if ( apply_filters( 'woocommerce_disable_admin_bar', get_option( 'woocommerce_lock_down_admin', "yes" ) == "yes" ) && ! ( current_user_can('edit_posts') || current_user_can('manage_woocommerce') ) ) { - $show_admin_bar = false; - } - - return $show_admin_bar; - } -} - -add_filter( 'show_admin_bar', 'woocommerce_disable_admin_bar', 10, 1 ); - - -/** - * Load the cart upon login - * - * @access public - * @param mixed $user_login - * @param mixed $user - * @return void - */ -function woocommerce_load_persistent_cart( $user_login, $user = 0 ) { - global $woocommerce; - - if ( ! $user ) - return; - - $saved_cart = get_user_meta( $user->ID, '_woocommerce_persistent_cart', true ); - - if ( $saved_cart ) - if ( empty( $woocommerce->session->cart ) || ! is_array( $woocommerce->session->cart ) || sizeof( $woocommerce->session->cart ) == 0 ) - $woocommerce->session->cart = $saved_cart['cart']; -} - -/** - * is_woocommerce - Returns true if on a page which uses WooCommerce templates (cart and checkout are standard pages with shortcodes and thus are not included) - * - * @access public - * @return bool - */ -function is_woocommerce() { - return ( is_shop() || is_product_taxonomy() || is_product() ) ? true : false; -} - -if ( ! function_exists( 'is_shop' ) ) { - - /** - * is_shop - Returns true when viewing the product type archive (shop). - * - * @access public - * @return bool - */ - function is_shop() { - return ( is_post_type_archive( 'product' ) || is_page( woocommerce_get_page_id( 'shop' ) ) ) ? true : false; - } -} - -if ( ! function_exists( 'is_product_taxonomy' ) ) { - - /** - * is_product_taxonomy - Returns true when viewing a product taxonomy archive. - * - * @access public - * @return bool - */ - function is_product_taxonomy() { - return is_tax( get_object_taxonomies( 'product' ) ); - } -} - -if ( ! function_exists( 'is_product_category' ) ) { - - /** - * is_product_category - Returns true when viewing a product category. - * - * @access public - * @param string $term (default: '') The term slug your checking for. Leave blank to return true on any. - * @return bool - */ - function is_product_category( $term = '' ) { - return is_tax( 'product_cat', $term ); - } -} - -if ( ! function_exists( 'is_product_tag' ) ) { - - /** - * is_product_tag - Returns true when viewing a product tag. - * - * @access public - * @param string $term (default: '') The term slug your checking for. Leave blank to return true on any. - * @return bool - */ - function is_product_tag( $term = '' ) { - return is_tax( 'product_tag', $term ); - } -} - -if ( ! function_exists( 'is_product' ) ) { - - /** - * is_product - Returns true when viewing a single product. - * - * @access public - * @return bool - */ - function is_product() { - return is_singular( array( 'product' ) ); - } -} - -if ( ! function_exists( 'is_cart' ) ) { - - /** - * is_cart - Returns true when viewing the cart page. - * - * @access public - * @return bool - */ - function is_cart() { - return is_page( woocommerce_get_page_id( 'cart' ) ); - } -} - -if ( ! function_exists( 'is_checkout' ) ) { - - /** - * is_checkout - Returns true when viewing the checkout page. - * - * @access public - * @return bool - */ - function is_checkout() { - return is_page( woocommerce_get_page_id( 'checkout' ) ) ? true : false; - } -} - -if ( ! function_exists( 'is_checkout_pay_page' ) ) { - - /** - * is_checkout_pay - Returns true when viewing the checkout's pay page. - * - * @access public - * @return bool - */ - function is_checkout_pay_page() { - global $wp; - - return is_checkout() && ! empty( $wp->query_vars['order-pay'] ) ? true : false; - } -} - -if ( ! function_exists( 'is_account_page' ) ) { - - /** - * is_account_page - Returns true when viewing an account page. - * - * @access public - * @return bool - */ - function is_account_page() { - return is_page( woocommerce_get_page_id( 'myaccount' ) ) || apply_filters( 'woocommerce_is_account_page', false ) ? true : false; - } -} - -if ( ! function_exists( 'is_order_received_page' ) ) { - - /** - * is_order_received_page - Returns true when viewing the order received page. - * - * @access public - * @return bool - */ - function is_order_received_page() { - return ( is_page( woocommerce_get_page_id( 'checkout' ) ) && isset( $wp->query_vars['order-received'] ) ) ? true : false; - } -} - -if ( ! function_exists( 'is_ajax' ) ) { - - /** - * is_ajax - Returns true when the page is loaded via ajax. - * - * @access public - * @return bool - */ - function is_ajax() { - if ( defined('DOING_AJAX') ) - return true; - - return ( isset( $_SERVER['HTTP_X_REQUESTED_WITH'] ) && strtolower( $_SERVER['HTTP_X_REQUESTED_WITH'] ) == 'xmlhttprequest' ) ? true : false; - } -} - -if ( ! function_exists( 'is_filtered' ) ) { - - /** - * is_filtered - Returns true when filtering products using layered nav or price sliders. - * - * @access public - * @return bool - */ - function is_filtered() { - global $_chosen_attributes; - - return ( sizeof( $_chosen_attributes ) > 0 || ( isset( $_GET['max_price'] ) && isset( $_GET['min_price'] ) ) ) ? true : false; - } -} - -if ( ! function_exists( 'taxonomy_is_product_attribute' ) ) { - - /** - * taxonomy_is_product_attribute - Returns true when the passed taxonomy name is a product attribute. - * - * @uses $wc_product_attributes global which stores taxonomy names upon registration - * @access public - * @return bool - */ - function taxonomy_is_product_attribute( $name ) { - global $wc_product_attributes; - - return taxonomy_exists( $name ) && array_key_exists( $name, (array) $wc_product_attributes ); - } -} - -/** - * Get template part (for templates like the shop-loop). - * - * @access public - * @param mixed $slug - * @param string $name (default: '') - * @return void - */ -function woocommerce_get_template_part( $slug, $name = '' ) { - global $woocommerce; - $template = ''; - - // Look in yourtheme/slug-name.php and yourtheme/woocommerce/slug-name.php - if ( $name ) - $template = locate_template( array ( "{$slug}-{$name}.php", "{$woocommerce->template_url}{$slug}-{$name}.php" ) ); - - // Get default slug-name.php - if ( !$template && $name && file_exists( $woocommerce->plugin_path() . "/templates/{$slug}-{$name}.php" ) ) - $template = $woocommerce->plugin_path() . "/templates/{$slug}-{$name}.php"; - - // If template file doesn't exist, look in yourtheme/slug.php and yourtheme/woocommerce/slug.php - if ( !$template ) - $template = locate_template( array ( "{$slug}.php", "{$woocommerce->template_url}{$slug}.php" ) ); - - if ( $template ) - load_template( $template, false ); -} - - -/** - * Get other templates (e.g. product attributes) passing attributes and including the file. - * - * @access public - * @param mixed $template_name - * @param array $args (default: array()) - * @param string $template_path (default: '') - * @param string $default_path (default: '') - * @return void - */ -function woocommerce_get_template( $template_name, $args = array(), $template_path = '', $default_path = '' ) { - global $woocommerce; - - if ( $args && is_array($args) ) - extract( $args ); - - $located = woocommerce_locate_template( $template_name, $template_path, $default_path ); - - do_action( 'woocommerce_before_template_part', $template_name, $template_path, $located, $args ); - - include( $located ); - - do_action( 'woocommerce_after_template_part', $template_name, $template_path, $located, $args ); -} - - -/** - * Locate a template and return the path for inclusion. - * - * This is the load order: - * - * yourtheme / $template_path / $template_name - * yourtheme / $template_name - * $default_path / $template_name - * - * @access public - * @param mixed $template_name - * @param string $template_path (default: '') - * @param string $default_path (default: '') - * @return string - */ -function woocommerce_locate_template( $template_name, $template_path = '', $default_path = '' ) { - global $woocommerce; - - if ( ! $template_path ) $template_path = $woocommerce->template_url; - if ( ! $default_path ) $default_path = $woocommerce->plugin_path() . '/templates/'; - - // Look within passed path within the theme - this is priority - $template = locate_template( - array( - trailingslashit( $template_path ) . $template_name, - $template_name - ) - ); - - // Get default template - if ( ! $template ) - $template = $default_path . $template_name; - - // Return what we found - return apply_filters('woocommerce_locate_template', $template, $template_name, $template_path); -} - - -/** - * Get Base Currency Code. - * - * @access public - * @return string - */ -function get_woocommerce_currency() { - return apply_filters( 'woocommerce_currency', get_option('woocommerce_currency') ); -} - - -/** - * Get full list of currency codes. - * - * @access public - * @return void - */ -function get_woocommerce_currencies() { - return array_unique( - apply_filters( 'woocommerce_currencies', - array( - 'AUD' => __( 'Australian Dollars', 'woocommerce' ), - 'BRL' => __( 'Brazilian Real', 'woocommerce' ), - 'CAD' => __( 'Canadian Dollars', 'woocommerce' ), - 'CNY' => __( 'Chinese Yuan', 'woocommerce' ), - 'CZK' => __( 'Czech Koruna', 'woocommerce' ), - 'DKK' => __( 'Danish Krone', 'woocommerce' ), - 'EUR' => __( 'Euros', 'woocommerce' ), - 'HKD' => __( 'Hong Kong Dollar', 'woocommerce' ), - 'HUF' => __( 'Hungarian Forint', 'woocommerce' ), - 'IDR' => __( 'Indonesia Rupiah', 'woocommerce' ), - 'INR' => __( 'Indian Rupee', 'woocommerce' ), - 'ILS' => __( 'Israeli Shekel', 'woocommerce' ), - 'JPY' => __( 'Japanese Yen', 'woocommerce' ), - 'KRW' => __( 'South Korean Won', 'woocommerce' ), - 'MYR' => __( 'Malaysian Ringgits', 'woocommerce' ), - 'MXN' => __( 'Mexican Peso', 'woocommerce' ), - 'NOK' => __( 'Norwegian Krone', 'woocommerce' ), - 'NZD' => __( 'New Zealand Dollar', 'woocommerce' ), - 'PHP' => __( 'Philippine Pesos', 'woocommerce' ), - 'PLN' => __( 'Polish Zloty', 'woocommerce' ), - 'GBP' => __( 'Pounds Sterling', 'woocommerce' ), - 'RON' => __( 'Romanian Leu', 'woocommerce' ), - 'RUB' => __( 'Russian Ruble', 'woocommerce' ), - 'SGD' => __( 'Singapore Dollar', 'woocommerce' ), - 'ZAR' => __( 'South African rand', 'woocommerce' ), - 'SEK' => __( 'Swedish Krona', 'woocommerce' ), - 'CHF' => __( 'Swiss Franc', 'woocommerce' ), - 'TWD' => __( 'Taiwan New Dollars', 'woocommerce' ), - 'THB' => __( 'Thai Baht', 'woocommerce' ), - 'TRY' => __( 'Turkish Lira', 'woocommerce' ), - 'USD' => __( 'US Dollars', 'woocommerce' ), - ) - ) - ); -} - -/** - * Get Currency symbol. - * - * @access public - * @param string $currency (default: '') - * @return string - */ -function get_woocommerce_currency_symbol( $currency = '' ) { - if ( ! $currency ) - $currency = get_woocommerce_currency(); - - switch ( $currency ) { - case 'BRL' : - $currency_symbol = 'R$'; - break; - case 'AUD' : - case 'CAD' : - case 'MXN' : - case 'NZD' : - case 'HKD' : - case 'SGD' : - case 'USD' : - $currency_symbol = '$'; - break; - case 'EUR' : - $currency_symbol = '€'; - break; - case 'CNY' : - case 'RMB' : - case 'JPY' : - $currency_symbol = '¥'; - break; - case 'RUB' : - $currency_symbol = 'руб.'; - break; - case 'KRW' : $currency_symbol = '₩'; break; - case 'TRY' : $currency_symbol = 'TL'; break; - case 'NOK' : $currency_symbol = 'kr'; break; - case 'ZAR' : $currency_symbol = 'R'; break; - case 'CZK' : $currency_symbol = 'Kč'; break; - case 'MYR' : $currency_symbol = 'RM'; break; - case 'DKK' : $currency_symbol = 'kr'; break; - case 'HUF' : $currency_symbol = 'Ft'; break; - case 'IDR' : $currency_symbol = 'Rp'; break; - case 'INR' : $currency_symbol = 'Rs.'; break; - case 'ILS' : $currency_symbol = '₪'; break; - case 'PHP' : $currency_symbol = '₱'; break; - case 'PLN' : $currency_symbol = 'zł'; break; - case 'SEK' : $currency_symbol = 'kr'; break; - case 'CHF' : $currency_symbol = 'CHF'; break; - case 'TWD' : $currency_symbol = 'NT$'; break; - case 'THB' : $currency_symbol = '฿'; break; - case 'GBP' : $currency_symbol = '£'; break; - case 'RON' : $currency_symbol = 'lei'; break; - default : $currency_symbol = ''; break; - } - - return apply_filters( 'woocommerce_currency_symbol', $currency_symbol, $currency ); -} - - -/** - * Format the price with a currency symbol. - * - * @access public - * @param float $price - * @param array $args (default: array()) - * @return string - */ -function woocommerce_price( $price, $args = array() ) { - global $woocommerce; - - extract( shortcode_atts( array( - 'ex_tax_label' => '0' - ), $args ) ); - - $return = ''; - $num_decimals = (int) get_option( 'woocommerce_price_num_decimals' ); - $currency_pos = get_option( 'woocommerce_currency_pos' ); - $currency_symbol = get_woocommerce_currency_symbol(); - $decimal_sep = wp_specialchars_decode( stripslashes( get_option( 'woocommerce_price_decimal_sep' ) ), ENT_QUOTES ); - $thousands_sep = wp_specialchars_decode( stripslashes( get_option( 'woocommerce_price_thousand_sep' ) ), ENT_QUOTES ); - - $price = apply_filters( 'raw_woocommerce_price', (double) $price ); - $price = number_format( $price, $num_decimals, $decimal_sep, $thousands_sep ); - - if ( get_option( 'woocommerce_price_trim_zeros' ) == 'yes' && $num_decimals > 0 ) - $price = woocommerce_trim_zeros( $price ); - - $return = '' . sprintf( get_woocommerce_price_format(), $currency_symbol, $price ) . ''; - - if ( $ex_tax_label && get_option( 'woocommerce_calc_taxes' ) == 'yes' ) - $return .= ' ' . $woocommerce->countries->ex_tax_or_vat() . ''; - - return $return; -} - -function get_woocommerce_price_format() { - $currency_pos = get_option( 'woocommerce_currency_pos' ); - - switch ( $currency_pos ) { - case 'left' : - $format = '%1$s%2$s'; - break; - case 'right' : - $format = '%2$s%1$s'; - break; - case 'left_space' : - $format = '%1$s %2$s'; - break; - case 'right_space' : - $format = '%2$s %1$s'; - break; - } - - return apply_filters( 'woocommerce_price_format', $format, $currency_pos ); -} - - -/** - * Trim trailing zeros off prices. - * - * @access public - * @param mixed $price - * @return string - */ -function woocommerce_trim_zeros( $price ) { - return preg_replace( '/' . preg_quote( get_option( 'woocommerce_price_decimal_sep' ), '/' ) . '0++$/', '', $price ); -} - - -/** - * Formal decimal numbers - format to 4 dp and remove trailing zeros. - * - * @access public - * @param mixed $number - * @return string - */ -function woocommerce_format_decimal( $number, $dp = '' ) { - if ( $dp == '' ) - $dp = intval( get_option( 'woocommerce_price_num_decimals' ) ); - - $number = number_format( (float) $number, (int) $dp, '.', '' ); - - if ( strstr( $number, '.' ) ) - $number = rtrim( rtrim( $number, '0' ), '.' ); - - return $number; -} - - -/** - * Formal total costs - format to the number of decimal places for the base currency. - * - * @access public - * @param mixed $number - * @return float - */ -function woocommerce_format_total( $number ) { - return number_format( (float) $number, (int) get_option( 'woocommerce_price_num_decimals' ), '.', '' ); -} - - -/** - * Clean variables - * - * @access public - * @param string $var - * @return string - */ -function woocommerce_clean( $var ) { - return sanitize_text_field( $var ); -} - - -/** - * Merge two arrays - * - * @access public - * @param array $a1 - * @param array $a2 - * @return array - */ -function woocommerce_array_overlay( $a1, $a2 ) { - foreach( $a1 as $k => $v ) { - if ( ! array_key_exists( $k, $a2 ) ) - continue; - if ( is_array( $v ) && is_array( $a2[ $k ] ) ) { - $a1[ $k ] = woocommerce_array_overlay( $v, $a2[ $k ] ); - } else { - $a1[ $k ] = $a2[ $k ]; - } - } - return $a1; -} - - -/** - * Get top term - * http://wordpress.stackexchange.com/questions/24794/get-the-the-top-level-parent-of-a-custom-taxonomy-term - * - * @access public - * @param int $term_id - * @param string $taxonomy - * @return int - */ -function woocommerce_get_term_top_most_parent( $term_id, $taxonomy ) { - // start from the current term - $parent = get_term_by( 'id', $term_id, $taxonomy ); - // climb up the hierarchy until we reach a term with parent = '0' - while ( $parent->parent != '0' ) { - $term_id = $parent->parent; - $parent = get_term_by( 'id', $term_id, $taxonomy); - } - return $parent; -} - - -/** - * Variation Formatting - * - * Gets a formatted version of variation data or item meta - * - * @access public - * @param string $variation (default: '') - * @param bool $flat (default: false) - * @return string - */ -function woocommerce_get_formatted_variation( $variation = '', $flat = false ) { - global $woocommerce; - - if ( is_array( $variation ) ) { - - if ( ! $flat ) - $return = '
'; - else - $return = ''; - - $variation_list = array(); - - foreach ( $variation as $name => $value ) { - - if ( ! $value ) - continue; - - // If this is a term slug, get the term's nice name - if ( taxonomy_exists( esc_attr( str_replace( 'attribute_', '', $name ) ) ) ) { - $term = get_term_by( 'slug', $value, esc_attr( str_replace( 'attribute_', '', $name ) ) ); - if ( ! is_wp_error( $term ) && $term->name ) - $value = $term->name; - } - - if ( $flat ) - $variation_list[] = $woocommerce->get_helper( 'attribute' )->attribute_label(str_replace('attribute_', '', $name)).': '.$value; - else - $variation_list[] = '
'.$woocommerce->get_helper( 'attribute' )->attribute_label(str_replace('attribute_', '', $name)).':
'.$value.'
'; - } - - if ( $flat ) - $return .= implode( ', ', $variation_list ); - else - $return .= implode( '', $variation_list ); - - if ( ! $flat ) - $return .= '
'; - - return $return; - - } -} - -if ( ! function_exists( 'woocommerce_rgb_from_hex' ) ) { - - /** - * Hex darker/lighter/contrast functions for colours - * - * @access public - * @param mixed $color - * @return string - */ - function woocommerce_rgb_from_hex( $color ) { - $color = str_replace( '#', '', $color ); - // Convert shorthand colors to full format, e.g. "FFF" -> "FFFFFF" - $color = preg_replace( '~^(.)(.)(.)$~', '$1$1$2$2$3$3', $color ); - - $rgb['R'] = hexdec( $color{0}.$color{1} ); - $rgb['G'] = hexdec( $color{2}.$color{3} ); - $rgb['B'] = hexdec( $color{4}.$color{5} ); - return $rgb; - } -} - -if ( ! function_exists( 'woocommerce_hex_darker' ) ) { - - /** - * Hex darker/lighter/contrast functions for colours - * - * @access public - * @param mixed $color - * @param int $factor (default: 30) - * @return string - */ - function woocommerce_hex_darker( $color, $factor = 30 ) { - $base = woocommerce_rgb_from_hex( $color ); - $color = '#'; - - foreach ($base as $k => $v) : - $amount = $v / 100; - $amount = round($amount * $factor); - $new_decimal = $v - $amount; - - $new_hex_component = dechex($new_decimal); - if(strlen($new_hex_component) < 2) : - $new_hex_component = "0".$new_hex_component; - endif; - $color .= $new_hex_component; - endforeach; - - return $color; - } -} - -if ( ! function_exists( 'woocommerce_hex_lighter' ) ) { - - /** - * Hex darker/lighter/contrast functions for colours - * - * @access public - * @param mixed $color - * @param int $factor (default: 30) - * @return string - */ - function woocommerce_hex_lighter( $color, $factor = 30 ) { - $base = woocommerce_rgb_from_hex( $color ); - $color = '#'; - - foreach ($base as $k => $v) : - $amount = 255 - $v; - $amount = $amount / 100; - $amount = round($amount * $factor); - $new_decimal = $v + $amount; - - $new_hex_component = dechex($new_decimal); - if(strlen($new_hex_component) < 2) : - $new_hex_component = "0".$new_hex_component; - endif; - $color .= $new_hex_component; - endforeach; - - return $color; - } -} - -if ( ! function_exists( 'woocommerce_light_or_dark' ) ) { - - /** - * Detect if we should use a light or dark colour on a background colour - * - * @access public - * @param mixed $color - * @param string $dark (default: '#000000') - * @param string $light (default: '#FFFFFF') - * @return string - */ - function woocommerce_light_or_dark( $color, $dark = '#000000', $light = '#FFFFFF' ) { - //return ( hexdec( $color ) > 0xffffff / 2 ) ? $dark : $light; - $hex = str_replace( '#', '', $color ); - - $c_r = hexdec( substr( $hex, 0, 2 ) ); - $c_g = hexdec( substr( $hex, 2, 2 ) ); - $c_b = hexdec( substr( $hex, 4, 2 ) ); - $brightness = ( ( $c_r * 299 ) + ( $c_g * 587 ) + ( $c_b * 114 ) ) / 1000; - - return $brightness > 155 ? $dark : $light; - } -} - -if ( ! function_exists( 'woocommerce_format_hex' ) ) { - - /** - * Format string as hex - * - * @access public - * @param string $hex - * @return string - */ - function woocommerce_format_hex( $hex ) { - - $hex = trim( str_replace( '#', '', $hex ) ); - - if ( strlen( $hex ) == 3 ) { - $hex = $hex[0] . $hex[0] . $hex[1] . $hex[1] . $hex[2] . $hex[2]; - } - - if ( $hex ) return '#' . $hex; - } -} - - -/** - * Exclude order comments from queries and RSS - * - * This code should exclude shop_order comments from queries. Some queries (like the recent comments widget on the dashboard) are hardcoded - * and are not filtered, however, the code current_user_can( 'read_post', $comment->comment_post_ID ) should keep them safe since only admin and - * shop managers can view orders anyway. - * - * The frontend view order pages get around this filter by using remove_filter('comments_clauses', 'woocommerce_exclude_order_comments'); - * - * @access public - * @param array $clauses - * @return array - */ -function woocommerce_exclude_order_comments( $clauses ) { - global $wpdb, $typenow, $pagenow; - - if ( is_admin() && $typenow == 'shop_order' && current_user_can( 'manage_woocommerce' ) ) - return $clauses; // Don't hide when viewing orders in admin - - if ( ! $clauses['join'] ) - $clauses['join'] = ''; - - if ( ! strstr( $clauses['join'], "JOIN $wpdb->posts" ) ) - $clauses['join'] .= " LEFT JOIN $wpdb->posts ON comment_post_ID = $wpdb->posts.ID "; - - if ( $clauses['where'] ) - $clauses['where'] .= ' AND '; - - $clauses['where'] .= " $wpdb->posts.post_type NOT IN ('shop_order') "; - - return $clauses; -} - -add_filter( 'comments_clauses', 'woocommerce_exclude_order_comments', 10, 1); - -/** - * Exclude order comments from queries and RSS - * - * @access public - * @param string $join - * @return string - */ -function woocommerce_exclude_order_comments_from_feed_join( $join ) { - global $wpdb; - - if ( ! $join ) - $join = " LEFT JOIN $wpdb->posts ON $wpdb->comments.comment_post_ID = $wpdb->posts.ID "; - - return $join; -} - -add_action( 'comment_feed_join', 'woocommerce_exclude_order_comments_from_feed_join' ); - - -/** - * Exclude order comments from queries and RSS - * - * @access public - * @param string $where - * @return string - */ -function woocommerce_exclude_order_comments_from_feed_where( $where ) { - global $wpdb; - - if ( $where ) - $where .= ' AND '; - - $where .= " $wpdb->posts.post_type NOT IN ('shop_order') "; - - return $where; -} - -add_action( 'comment_feed_where', 'woocommerce_exclude_order_comments_from_feed_where' ); - - -/** - * Order Status completed - GIVE DOWNLOADABLE PRODUCT ACCESS TO CUSTOMER - * - * @access public - * @param int $order_id - * @return void - */ -function woocommerce_downloadable_product_permissions( $order_id ) { - - if ( get_post_meta( $order_id, __( 'Download Permissions Granted', 'woocommerce' ), true ) == 1 ) - return; // Only do this once - - $order = new WC_Order( $order_id ); - - if (sizeof($order->get_items())>0) foreach ($order->get_items() as $item) : - - if ($item['product_id']>0) : - $_product = $order->get_product_from_item( $item ); - - if ( $_product && $_product->exists() && $_product->is_downloadable() ) : - - $product_id = ($item['variation_id']>0) ? $item['variation_id'] : $item['product_id']; - - $file_download_paths = apply_filters( 'woocommerce_file_download_paths', get_post_meta( $product_id, '_file_paths', true ), $product_id, $order_id, $item ); - if ( ! empty( $file_download_paths ) ) { - foreach ( $file_download_paths as $download_id => $file_path ) { - woocommerce_downloadable_file_permission( $download_id, $product_id, $order ); - } - } - - endif; - - endif; - - endforeach; - - update_post_meta( $order_id, __( 'Download Permissions Granted', 'woocommerce' ), 1); -} - -add_action('woocommerce_order_status_completed', 'woocommerce_downloadable_product_permissions'); - -/** - * Grant downloadable product access to the file identified by $download_id - * - * @access public - * @param string $download_id file identifier - * @param int $product_id product identifier - * @param WC_Order $order the order - * @return int insert id | bool false on failure - */ -function woocommerce_downloadable_file_permission( $download_id, $product_id, $order ) { - global $wpdb; - - $user_email = sanitize_email( $order->billing_email ); - $limit = trim( get_post_meta( $product_id, '_download_limit', true ) ); - $expiry = trim( get_post_meta( $product_id, '_download_expiry', true ) ); - - $limit = empty( $limit ) ? '' : absint( $limit ); - - // Default value is NULL in the table schema - $expiry = empty( $expiry ) ? null : absint( $expiry ); - - if ( $expiry ) - $expiry = date_i18n( "Y-m-d", strtotime( 'NOW + ' . $expiry . ' DAY' ) ); - - $data = array( - 'download_id' => $download_id, - 'product_id' => $product_id, - 'user_id' => absint( $order->user_id ), - 'user_email' => $user_email, - 'order_id' => $order->id, - 'order_key' => $order->order_key, - 'downloads_remaining' => $limit, - 'access_granted' => current_time( 'mysql' ), - 'download_count' => 0 - ); - - $format = array( - '%s', - '%s', - '%s', - '%s', - '%s', - '%s', - '%s', - '%s', - '%d' - ); - - if ( ! is_null( $expiry ) ) { - $data['access_expires'] = $expiry; - $format[] = '%s'; - } - - // Downloadable product - give access to the customer - $result = $wpdb->insert( $wpdb->prefix . 'woocommerce_downloadable_product_permissions', - apply_filters( 'woocommerce_downloadable_file_permission_data', $data ), - apply_filters( 'woocommerce_downloadable_file_permission_format', $format ) - ); - - return $result ? $wpdb->insert_id : false; -} - -if ( get_option('woocommerce_downloads_grant_access_after_payment') == 'yes' ) - add_action( 'woocommerce_order_status_processing', 'woocommerce_downloadable_product_permissions' ); - -/** - * Gets the filename part of a download URL - * - * @access public - * @param string $file_url - * @return string - */ -function woocommerce_get_filename_from_url( $file_url ) { - $parts = parse_url( $file_url ); - return basename( $parts['path'] ); -} - -/** - * Order Status completed - This is a paying customer - * - * @access public - * @param int $order_id - * @return void - */ -function woocommerce_paying_customer( $order_id ) { - - $order = new WC_Order( $order_id ); - - if ( $order->user_id > 0 ) { - update_user_meta( $order->user_id, 'paying_customer', 1 ); - - $old_spent = absint( get_user_meta( $order->user_id, '_money_spent', true ) ); - update_user_meta( $order->user_id, '_money_spent', $old_spent + $order->order_total ); - - $old_count = absint( get_user_meta( $order->user_id, '_order_count', true ) ); - update_user_meta( $order->user_id, '_order_count', $old_count + 1 ); - } - -} - -add_action( 'woocommerce_order_status_completed', 'woocommerce_paying_customer' ); - - -/** - * Filter to allow product_cat in the permalinks for products. - * - * @access public - * @param string $permalink The existing permalink URL. - * @param object $post - * @return string - */ -function woocommerce_product_post_type_link( $permalink, $post ) { - // Abort if post is not a product - if ( $post->post_type !== 'product' ) - return $permalink; - - // Abort early if the placeholder rewrite tag isn't in the generated URL - if ( false === strpos( $permalink, '%' ) ) - return $permalink; - - // Get the custom taxonomy terms in use by this post - $terms = get_the_terms( $post->ID, 'product_cat' ); - - if ( empty( $terms ) ) { - // If no terms are assigned to this post, use a string instead (can't leave the placeholder there) - $product_cat = _x( 'uncategorized', 'slug', 'woocommerce' ); - } else { - // Replace the placeholder rewrite tag with the first term's slug - $first_term = array_shift( $terms ); - $product_cat = $first_term->slug; - } - - $find = array( - '%year%', - '%monthnum%', - '%day%', - '%hour%', - '%minute%', - '%second%', - '%post_id%', - '%category%', - '%product_cat%' - ); - - $replace = array( - date_i18n( 'Y', strtotime( $post->post_date ) ), - date_i18n( 'm', strtotime( $post->post_date ) ), - date_i18n( 'd', strtotime( $post->post_date ) ), - date_i18n( 'H', strtotime( $post->post_date ) ), - date_i18n( 'i', strtotime( $post->post_date ) ), - date_i18n( 's', strtotime( $post->post_date ) ), - $post->ID, - $product_cat, - $product_cat - ); - - $replace = array_map( 'sanitize_title', $replace ); - - $permalink = str_replace( $find, $replace, $permalink ); - - return $permalink; -} - -add_filter( 'post_type_link', 'woocommerce_product_post_type_link', 10, 2 ); - - - -/** - * Add term ordering to get_terms - * - * It enables the support a 'menu_order' parameter to get_terms for the product_cat taxonomy. - * By default it is 'ASC'. It accepts 'DESC' too - * - * To disable it, set it ot false (or 0) - * - * @access public - * @param array $clauses - * @param array $taxonomies - * @param array $args - * @return array - */ -function woocommerce_terms_clauses( $clauses, $taxonomies, $args ) { - global $wpdb, $woocommerce; - - // No sorting when menu_order is false - if ( isset($args['menu_order']) && $args['menu_order'] == false ) return $clauses; - - // No sorting when orderby is non default - if ( isset($args['orderby']) && $args['orderby'] != 'name' ) return $clauses; - - // No sorting in admin when sorting by a column - if ( is_admin() && isset($_GET['orderby']) ) return $clauses; - - // wordpress should give us the taxonomies asked when calling the get_terms function. Only apply to categories and pa_ attributes - $found = false; - foreach ( (array) $taxonomies as $taxonomy ) { - if ( taxonomy_is_product_attribute( $taxonomy ) || in_array( $taxonomy, apply_filters( 'woocommerce_sortable_taxonomies', array( 'product_cat' ) ) ) ) { - $found = true; - break; - } - } - if (!$found) return $clauses; - - // Meta name - if ( ! empty( $taxonomies[0] ) && taxonomy_is_product_attribute( $taxonomies[0] ) ) { - $meta_name = 'order_' . esc_attr( $taxonomies[0] ); - } else { - $meta_name = 'order'; - } - - // query fields - if ( strpos('COUNT(*)', $clauses['fields']) === false ) $clauses['fields'] .= ', tm.* '; - - //query join - $clauses['join'] .= " LEFT JOIN {$wpdb->woocommerce_termmeta} AS tm ON (t.term_id = tm.woocommerce_term_id AND tm.meta_key = '". $meta_name ."') "; - - // default to ASC - if ( ! isset($args['menu_order']) || ! in_array( strtoupper($args['menu_order']), array('ASC', 'DESC')) ) $args['menu_order'] = 'ASC'; - - $order = "ORDER BY tm.meta_value+0 " . $args['menu_order']; - - if ( $clauses['orderby'] ): - $clauses['orderby'] = str_replace('ORDER BY', $order . ',', $clauses['orderby'] ); - else: - $clauses['orderby'] = $order; - endif; - - return $clauses; -} - -add_filter( 'terms_clauses', 'woocommerce_terms_clauses', 10, 3); - - -/** - * woocommerce_get_product_terms function. - * - * Gets product terms in the order they are defined in the backend. - * - * @access public - * @param mixed $object_id - * @param mixed $taxonomy - * @param mixed $fields ids, names, slugs, all - * @return array - */ -function woocommerce_get_product_terms( $object_id, $taxonomy, $fields = 'all' ) { - - if ( ! taxonomy_exists( $taxonomy ) ) - return array(); - - $terms = array(); - $object_terms = get_the_terms( $object_id, $taxonomy ); - - if ( ! is_array( $object_terms ) ) - return array(); - - $all_terms = array_flip( get_terms( $taxonomy, array( 'menu_order' => 'ASC', 'fields' => 'ids' ) ) ); - - switch ( $fields ) { - case 'names' : - foreach ( $object_terms as $term ) - $terms[ $all_terms[ $term->term_id ] ] = $term->name; - break; - case 'ids' : - foreach ( $object_terms as $term ) - $terms[ $all_terms[ $term->term_id ] ] = $term->term_id; - break; - case 'slugs' : - foreach ( $object_terms as $term ) - $terms[ $all_terms[ $term->term_id ] ] = $term->slug; - break; - case 'all' : - foreach ( $object_terms as $term ) - $terms[ $all_terms[ $term->term_id ] ] = $term; - break; - } - - ksort( $terms ); - - return $terms; -} - - -/** - * WooCommerce Dropdown categories - * - * Stuck with this until a fix for http://core.trac.wordpress.org/ticket/13258 - * We use a custom walker, just like WordPress does - * - * @access public - * @param int $show_counts (default: 1) - * @param int $hierarchical (default: 1) - * @param int $show_uncategorized (default: 1) - * @return string - */ -function woocommerce_product_dropdown_categories( $show_counts = 1, $hierarchical = 1, $show_uncategorized = 1, $orderby = '' ) { - global $wp_query, $woocommerce; - - $r = array(); - $r['pad_counts'] = 1; - $r['hierarchical'] = $hierarchical; - $r['hide_empty'] = 1; - $r['show_count'] = $show_counts; - $r['selected'] = ( isset( $wp_query->query['product_cat'] ) ) ? $wp_query->query['product_cat'] : ''; - $r['menu_order'] = false; - - if ( $orderby == 'order' ) - $r['menu_order'] = 'asc'; - elseif ( $orderby ) - $r['orderby'] = $orderby; - - $terms = get_terms( 'product_cat', $r ); - - if ( ! $terms ) - return; - - $output = ""; - - echo $output; -} - - -/** - * Walk the Product Categories. - * - * @access public - * @return void - */ -function woocommerce_walk_category_dropdown_tree() { - global $woocommerce; - - if ( ! class_exists( 'WC_Product_Cat_Dropdown_Walker' ) ) - include_once( $woocommerce->plugin_path() . '/includes/walkers/class-product-cat-dropdown-walker.php' ); - - $args = func_get_args(); - - // the user's options are the third parameter - if ( empty($args[2]['walker']) || !is_a($args[2]['walker'], 'Walker') ) - $walker = new WC_Product_Cat_Dropdown_Walker; - else - $walker = $args[2]['walker']; - - return call_user_func_array(array( &$walker, 'walk' ), $args ); -} - - -/** - * WooCommerce Term/Order item Meta API - set table name - * - * @access public - * @return void - */ -function woocommerce_taxonomy_metadata_wpdbfix() { - global $wpdb; - $termmeta_name = 'woocommerce_termmeta'; - $itemmeta_name = 'woocommerce_order_itemmeta'; - - $wpdb->woocommerce_termmeta = $wpdb->prefix . $termmeta_name; - $wpdb->order_itemmeta = $wpdb->prefix . $itemmeta_name; - - $wpdb->tables[] = 'woocommerce_termmeta'; - $wpdb->tables[] = 'order_itemmeta'; -} - -add_action( 'init', 'woocommerce_taxonomy_metadata_wpdbfix', 0 ); -add_action( 'switch_blog', 'woocommerce_taxonomy_metadata_wpdbfix', 0 ); - - -/** - * WooCommerce Term Meta API - Update term meta - * - * @access public - * @param mixed $term_id - * @param mixed $meta_key - * @param mixed $meta_value - * @param string $prev_value (default: '') - * @return bool - */ -function update_woocommerce_term_meta( $term_id, $meta_key, $meta_value, $prev_value = '' ) { - return update_metadata( 'woocommerce_term', $term_id, $meta_key, $meta_value, $prev_value ); -} - - -/** - * WooCommerce Term Meta API - Add term meta - * - * @access public - * @param mixed $term_id - * @param mixed $meta_key - * @param mixed $meta_value - * @param bool $unique (default: false) - * @return bool - */ -function add_woocommerce_term_meta( $term_id, $meta_key, $meta_value, $unique = false ){ - return add_metadata( 'woocommerce_term', $term_id, $meta_key, $meta_value, $unique ); -} - - -/** - * WooCommerce Term Meta API - Delete term meta - * - * @access public - * @param mixed $term_id - * @param mixed $meta_key - * @param string $meta_value (default: '') - * @param bool $delete_all (default: false) - * @return bool - */ -function delete_woocommerce_term_meta( $term_id, $meta_key, $meta_value = '', $delete_all = false ) { - return delete_metadata( 'woocommerce_term', $term_id, $meta_key, $meta_value, $delete_all ); -} - - -/** - * WooCommerce Term Meta API - Get term meta - * - * @access public - * @param mixed $term_id - * @param mixed $key - * @param bool $single (default: true) - * @return mixed - */ -function get_woocommerce_term_meta( $term_id, $key, $single = true ) { - return get_metadata( 'woocommerce_term', $term_id, $key, $single ); -} - - -/** - * Move a term before the a given element of its hierarchy level - * - * @access public - * @param int $the_term - * @param int $next_id the id of the next sibling element in save hierarchy level - * @param string $taxonomy - * @param int $index (default: 0) - * @param mixed $terms (default: null) - * @return int - */ -function woocommerce_order_terms( $the_term, $next_id, $taxonomy, $index = 0, $terms = null ) { - - if( ! $terms ) $terms = get_terms($taxonomy, 'menu_order=ASC&hide_empty=0&parent=0' ); - if( empty( $terms ) ) return $index; - - $id = $the_term->term_id; - - $term_in_level = false; // flag: is our term to order in this level of terms - - foreach ($terms as $term) { - - if( $term->term_id == $id ) { // our term to order, we skip - $term_in_level = true; - continue; // our term to order, we skip - } - // the nextid of our term to order, lets move our term here - if(null !== $next_id && $term->term_id == $next_id) { - $index++; - $index = woocommerce_set_term_order($id, $index, $taxonomy, true); - } - - // set order - $index++; - $index = woocommerce_set_term_order($term->term_id, $index, $taxonomy); - - // if that term has children we walk through them - $children = get_terms($taxonomy, "parent={$term->term_id}&menu_order=ASC&hide_empty=0"); - if( !empty($children) ) { - $index = woocommerce_order_terms( $the_term, $next_id, $taxonomy, $index, $children ); - } - } - - // no nextid meaning our term is in last position - if( $term_in_level && null === $next_id ) - $index = woocommerce_set_term_order($id, $index+1, $taxonomy, true); - - return $index; -} - - -/** - * Set the sort order of a term - * - * @access public - * @param int $term_id - * @param int $index - * @param string $taxonomy - * @param bool $recursive (default: false) - * @return int - */ -function woocommerce_set_term_order( $term_id, $index, $taxonomy, $recursive = false ) { - - $term_id = (int) $term_id; - $index = (int) $index; - - // Meta name - if ( taxonomy_is_product_attribute( $taxonomy ) ) - $meta_name = 'order_' . esc_attr( $taxonomy ); - else - $meta_name = 'order'; - - update_woocommerce_term_meta( $term_id, $meta_name, $index ); - - if( ! $recursive ) return $index; - - $children = get_terms($taxonomy, "parent=$term_id&menu_order=ASC&hide_empty=0"); - - foreach ( $children as $term ) { - $index ++; - $index = woocommerce_set_term_order($term->term_id, $index, $taxonomy, true); - } - - clean_term_cache( $term_id, $taxonomy ); - - return $index; -} - - -/** - * let_to_num function. - * - * This function transforms the php.ini notation for numbers (like '2M') to an integer. - * - * @access public - * @param $size - * @return int - */ -function woocommerce_let_to_num( $size ) { - $l = substr( $size, -1 ); - $ret = substr( $size, 0, -1 ); - switch( strtoupper( $l ) ) { - case 'P': - $ret *= 1024; - case 'T': - $ret *= 1024; - case 'G': - $ret *= 1024; - case 'M': - $ret *= 1024; - case 'K': - $ret *= 1024; - } - return $ret; -} - - -/** - * woocommerce_customer_bought_product - * - * Checks if a user (by email) has bought an item - * - * @access public - * @param string $customer_email - * @param int $user_id - * @param int $product_id - * @return bool - */ -function woocommerce_customer_bought_product( $customer_email, $user_id, $product_id ) { - global $wpdb; - - $emails = array(); - - if ( $user_id ) { - $user = get_user_by( 'id', $user_id ); - $emails[] = $user->user_email; - } - - if ( is_email( $customer_email ) ) - $emails[] = $customer_email; - - if ( sizeof( $emails ) == 0 ) - return false; - - $completed = get_term_by( 'slug', 'completed', 'shop_order_status' ); - - return $wpdb->get_var( - $wpdb->prepare( " - SELECT COUNT( DISTINCT order_items.order_item_id ) - FROM {$wpdb->prefix}woocommerce_order_items as order_items - LEFT JOIN {$wpdb->prefix}woocommerce_order_itemmeta AS itemmeta ON order_items.order_item_id = itemmeta.order_item_id - LEFT JOIN {$wpdb->postmeta} AS postmeta ON order_items.order_id = postmeta.post_id - LEFT JOIN {$wpdb->term_relationships} AS rel ON order_items.order_id = rel.object_ID - WHERE - rel.term_taxonomy_id = %d AND - itemmeta.meta_value = %s AND - itemmeta.meta_key IN ( '_variation_id', '_product_id' ) AND - postmeta.meta_key IN ( '_billing_email', '_customer_user' ) AND - ( - postmeta.meta_value IN ( '" . implode( "','", array_unique( $emails ) ) . "' ) OR - ( - postmeta.meta_value = %d AND - postmeta.meta_value > 0 - ) - ) - ", $completed->term_taxonomy_id, $product_id, $user_id - ) - ); -} - - -/** - * Return the count of processing orders. - * - * @access public - * @return int - */ -function woocommerce_processing_order_count() { - if ( false === ( $order_count = get_transient( 'woocommerce_processing_order_count' ) ) ) { - $order_statuses = get_terms( 'shop_order_status' ); - $order_count = false; - foreach ( $order_statuses as $status ) { - if( $status->slug === 'processing' ) { - $order_count += $status->count; - break; - } - } - $order_count = apply_filters( 'woocommerce_admin_menu_count', intval( $order_count ) ); - set_transient( 'woocommerce_processing_order_count', $order_count ); - } - - return $order_count; -} - - -/** - * Get capabilities for WooCommerce - these are assigned to admin/shop manager during installation or reset - * - * @access public - * @return void - */ -function woocommerce_get_core_capabilities() { - $capabilities = array(); - - $capabilities['core'] = array( - "manage_woocommerce", - "view_woocommerce_reports" - ); - - $capability_types = array( 'product', 'shop_order', 'shop_coupon' ); - - foreach( $capability_types as $capability_type ) { - - $capabilities[ $capability_type ] = array( - - // Post type - "edit_{$capability_type}", - "read_{$capability_type}", - "delete_{$capability_type}", - "edit_{$capability_type}s", - "edit_others_{$capability_type}s", - "publish_{$capability_type}s", - "read_private_{$capability_type}s", - "delete_{$capability_type}s", - "delete_private_{$capability_type}s", - "delete_published_{$capability_type}s", - "delete_others_{$capability_type}s", - "edit_private_{$capability_type}s", - "edit_published_{$capability_type}s", - - // Terms - "manage_{$capability_type}_terms", - "edit_{$capability_type}_terms", - "delete_{$capability_type}_terms", - "assign_{$capability_type}_terms" - ); - } - - return $capabilities; -} - - -/** - * woocommerce_init_roles function. - * - * @access public - * @return void - */ -function woocommerce_init_roles() { - global $wp_roles; - - if ( class_exists('WP_Roles') ) - if ( ! isset( $wp_roles ) ) - $wp_roles = new WP_Roles(); - - if ( is_object( $wp_roles ) ) { - - // Customer role - add_role( 'customer', __( 'Customer', 'woocommerce' ), array( - 'read' => true, - 'edit_posts' => false, - 'delete_posts' => false - ) ); - - // Shop manager role - add_role( 'shop_manager', __( 'Shop Manager', 'woocommerce' ), array( - 'level_9' => true, - 'level_8' => true, - 'level_7' => true, - 'level_6' => true, - 'level_5' => true, - 'level_4' => true, - 'level_3' => true, - 'level_2' => true, - 'level_1' => true, - 'level_0' => true, - 'read' => true, - 'read_private_pages' => true, - 'read_private_posts' => true, - 'edit_users' => true, - 'edit_posts' => true, - 'edit_pages' => true, - 'edit_published_posts' => true, - 'edit_published_pages' => true, - 'edit_private_pages' => true, - 'edit_private_posts' => true, - 'edit_others_posts' => true, - 'edit_others_pages' => true, - 'publish_posts' => true, - 'publish_pages' => true, - 'delete_posts' => true, - 'delete_pages' => true, - 'delete_private_pages' => true, - 'delete_private_posts' => true, - 'delete_published_pages' => true, - 'delete_published_posts' => true, - 'delete_others_posts' => true, - 'delete_others_pages' => true, - 'manage_categories' => true, - 'manage_links' => true, - 'moderate_comments' => true, - 'unfiltered_html' => true, - 'upload_files' => true, - 'export' => true, - 'import' => true - ) ); - - $capabilities = woocommerce_get_core_capabilities(); - - foreach( $capabilities as $cap_group ) { - foreach( $cap_group as $cap ) { - $wp_roles->add_cap( 'shop_manager', $cap ); - $wp_roles->add_cap( 'administrator', $cap ); - } - } - } -} - -/** - * woocommerce_remove_roles function. - * - * @access public - * @return void - */ -function woocommerce_remove_roles() { - global $wp_roles; - - if ( class_exists('WP_Roles') ) - if ( ! isset( $wp_roles ) ) - $wp_roles = new WP_Roles(); - - if ( is_object( $wp_roles ) ) { - - $capabilities = woocommerce_get_core_capabilities(); - - foreach( $capabilities as $cap_group ) { - foreach( $cap_group as $cap ) { - $wp_roles->remove_cap( 'shop_manager', $cap ); - $wp_roles->remove_cap( 'administrator', $cap ); - } - } - - remove_role( 'customer' ); - remove_role( 'shop_manager' ); - } -} - - -/** - * Add a item to an order (for example a line item). - * - * @access public - * @param int $order_id - * @param array $data - * @return mixed - */ -function woocommerce_add_order_item( $order_id, $item ) { - global $wpdb; - - $order_id = absint( $order_id ); - - if ( ! $order_id ) - return false; - - $defaults = array( - 'order_item_name' => '', - 'order_item_type' => 'line_item', - ); - - $item = wp_parse_args( $item, $defaults ); - - $wpdb->insert( - $wpdb->prefix . "woocommerce_order_items", - array( - 'order_item_name' => $item['order_item_name'], - 'order_item_type' => $item['order_item_type'], - 'order_id' => $order_id - ), - array( - '%s', '%s', '%d' - ) - ); - - $item_id = absint( $wpdb->insert_id ); - - do_action( 'woocommerce_new_order_item', $item_id, $item, $order_id ); - - return $item_id; -} - -/** - * woocommerce_delete_order_item function. - * - * @access public - * @param int $item_id - * @return bool - */ -function woocommerce_delete_order_item( $item_id ) { - global $wpdb; - - $item_id = absint( $item_id ); - - if ( ! $item_id ) - return false; - - do_action( 'woocommerce_before_delete_order_item', $item_id ); - - $wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->prefix}woocommerce_order_items WHERE order_item_id = %d", $item_id ) ); - $wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->prefix}woocommerce_order_itemmeta WHERE order_item_id = %d", $item_id ) ); - - do_action( 'woocommerce_delete_order_item', $item_id ); - - return true; -} - -/** - * WooCommerce Order Item Meta API - Update term meta - * - * @access public - * @param mixed $item_id - * @param mixed $meta_key - * @param mixed $meta_value - * @param string $prev_value (default: '') - * @return bool - */ -function woocommerce_update_order_item_meta( $item_id, $meta_key, $meta_value, $prev_value = '' ) { - return update_metadata( 'order_item', $item_id, $meta_key, $meta_value, $prev_value ); -} - - -/** - * WooCommerce Order Item Meta API - Add term meta - * - * @access public - * @param mixed $item_id - * @param mixed $meta_key - * @param mixed $meta_value - * @param bool $unique (default: false) - * @return bool - */ -function woocommerce_add_order_item_meta( $item_id, $meta_key, $meta_value, $unique = false ){ - return add_metadata( 'order_item', $item_id, $meta_key, $meta_value, $unique ); -} - - -/** - * WooCommerce Order Item Meta API - Delete term meta - * - * @access public - * @param mixed $item_id - * @param mixed $meta_key - * @param string $meta_value (default: '') - * @param bool $delete_all (default: false) - * @return bool - */ -function woocommerce_delete_order_item_meta( $item_id, $meta_key, $meta_value = '', $delete_all = false ) { - return delete_metadata( 'order_item', $item_id, $meta_key, $meta_value, $delete_all ); -} - - -/** - * WooCommerce Order Item Meta API - Get term meta - * - * @access public - * @param mixed $item_id - * @param mixed $key - * @param bool $single (default: true) - * @return mixed - */ -function woocommerce_get_order_item_meta( $item_id, $key, $single = true ) { - return get_metadata( 'order_item', $item_id, $key, $single ); -} - -/** - * WooCommerce Date Format - Allows to change date format for everything WooCommerce - * - * @access public - * @return string - */ -function woocommerce_date_format() { - return apply_filters( 'woocommerce_date_format', get_option( 'date_format' ) ); -} - -/** - * WooCommerce Time Format - Allows to change time format for everything WooCommerce - * - * @access public - * @return string - */ -function woocommerce_time_format() { - return apply_filters( 'woocommerce_time_format', get_option( 'time_format' ) ); -} - -/** - * 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 = " - AND ( - meta_stock.meta_key = '_stock_status' - AND - meta_stock.meta_value = 'instock' - )"; - } else { - $stock_query = $stock_join = ''; - } - - // Main query - $count_query = $wpdb->prepare( " - SELECT COUNT( DISTINCT posts.ID ) FROM {$wpdb->posts} as posts - - LEFT JOIN {$wpdb->postmeta} AS meta_visibility ON posts.ID = meta_visibility.post_id - LEFT JOIN {$wpdb->term_relationships} AS rel ON posts.ID = rel.object_ID - LEFT JOIN {$wpdb->term_taxonomy} AS tax USING( term_taxonomy_id ) - LEFT JOIN {$wpdb->terms} AS term USING( term_id ) - $stock_join - - WHERE posts.post_status = 'publish' - AND posts.post_type = 'product' - AND ( - meta_visibility.meta_key = '_visibility' - AND - meta_visibility.meta_value IN ( 'visible', 'catalog' ) - ) - AND tax.taxonomy = %s - $stock_query - ", $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 ) ); - } - - } -} - -/** - * woocommerce_recount_after_stock_change function. - * - * @access public - * @return void - */ -function woocommerce_recount_after_stock_change( $product_id ) { - - $product_terms = get_the_terms( $product_id, 'product_cat' ); - - if ( $product_terms ) { - foreach ( $product_terms as $term ) - $product_cats[ $term->term_id ] = $term->parent; - - _woocommerce_term_recount( $product_cats, get_taxonomy( 'product_cat' ), false, false ); - - } - - $product_terms = get_the_terms( $product_id, 'product_tag' ); - - if ( $product_terms ) { - foreach ( $product_terms as $term ) - $product_tags[ $term->term_id ] = $term->parent; - - _woocommerce_term_recount( $product_tags, get_taxonomy( 'product_tag' ), false, false ); - - } - -} - -add_action( 'woocommerce_product_set_stock_status', 'woocommerce_recount_after_stock_change' ); - -/** - * woocommerce_change_term_counts function. - * Overrides the original term count for product categories and tags with the product count - * that takes catalog visibility into account. - * - * @access public - * @param mixed $terms - * @param mixed $taxonomies - * @param mixed $args - * @return void - */ -function woocommerce_change_term_counts( $terms, $taxonomies, $args ) { - - if ( ! in_array( $taxonomies[0], apply_filters( 'woocommerce_change_term_counts', array( 'product_cat', 'product_tag' ) ) ) ) - return $terms; - - $term_counts = $o_term_counts = get_transient( 'wc_term_counts' ); - - foreach ( $terms as &$term ) { - // If the original term count is zero, there's no way the product count could be higher. - if ( empty( $term->count ) ) continue; - - $term_counts[ $term->term_id ] = isset( $term_counts[ $term->term_id ] ) ? $term_counts[ $term->term_id ] : get_woocommerce_term_meta( $term->term_id, 'product_count_' . $taxonomies[0] , true ); - - if ( $term_counts[ $term->term_id ] != '' ) - $term->count = $term_counts[ $term->term_id ]; - } - - // Update transient - if ( $term_counts != $o_term_counts ) - set_transient( 'wc_term_counts', $term_counts ); - - return $terms; -} - -if ( ! is_admin() && ! is_ajax() ) - add_filter( 'get_terms', 'woocommerce_change_term_counts', 10, 3 ); - -/** - * Function which handles the start and end of scheduled sales via cron. - * - * @access public - * @return void - */ -function woocommerce_scheduled_sales() { - global $woocommerce, $wpdb; - - // Sales which are due to start - $product_ids = $wpdb->get_col( $wpdb->prepare( " - SELECT postmeta.post_id FROM {$wpdb->postmeta} as postmeta - LEFT JOIN {$wpdb->postmeta} as postmeta_2 ON postmeta.post_id = postmeta_2.post_id - LEFT JOIN {$wpdb->postmeta} as postmeta_3 ON postmeta.post_id = postmeta_3.post_id - WHERE postmeta.meta_key = '_sale_price_dates_from' - AND postmeta_2.meta_key = '_price' - AND postmeta_3.meta_key = '_sale_price' - AND postmeta.meta_value > 0 - AND postmeta.meta_value < %s - AND postmeta_2.meta_value != postmeta_3.meta_value - ", 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', '' ); - } - - $woocommerce->get_helper( 'transient' )->clear_product_transients( $product_id ); - - $parent = wp_get_post_parent_id( $product_id ); - - // Sync parent - if ( $parent ) { - // We can force varaible product price to sync up by removing their min price meta - delete_post_meta( $parent, '_min_variation_price' ); - - // Grouped products need syncing via a function - $this_product = get_product( $product_id ); - if ( $this_product->is_type( 'simple' ) ) - $this_product->grouped_product_sync(); - - $woocommerce->get_helper( 'transient' )->clear_product_transients( $parent ); - } - } - } - - // Sales which are due to end - $product_ids = $wpdb->get_col( $wpdb->prepare( " - SELECT postmeta.post_id FROM {$wpdb->postmeta} as postmeta - LEFT JOIN {$wpdb->postmeta} as postmeta_2 ON postmeta.post_id = postmeta_2.post_id - LEFT JOIN {$wpdb->postmeta} as postmeta_3 ON postmeta.post_id = postmeta_3.post_id - WHERE postmeta.meta_key = '_sale_price_dates_to' - AND postmeta_2.meta_key = '_price' - AND postmeta_3.meta_key = '_regular_price' - AND postmeta.meta_value > 0 - AND postmeta.meta_value < %s - AND postmeta_2.meta_value != postmeta_3.meta_value - ", 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', '' ); - - $woocommerce->get_helper( 'transient' )->clear_product_transients( $product_id ); - - $parent = wp_get_post_parent_id( $product_id ); - - // Sync parent - if ( $parent ) { - // We can force variable product price to sync up by removing their min price meta - delete_post_meta( $parent, '_min_variation_price' ); - - // Grouped products need syncing via a function - $this_product = get_product( $product_id ); - if ( $this_product->is_type( 'simple' ) ) - $this_product->grouped_product_sync(); - - $woocommerce->get_helper( 'transient' )->clear_product_transients( $parent ); - } - } - } -} - -add_action( 'woocommerce_scheduled_sales', 'woocommerce_scheduled_sales' ); - - -/** - * woocommerce_cancel_unpaid_orders function. - * - * @access public - * @return void - */ -function woocommerce_cancel_unpaid_orders() { - global $wpdb; - - $held_duration = get_option( 'woocommerce_hold_stock_minutes' ); - - if ( $held_duration < 1 || get_option( 'woocommerce_manage_stock' ) != 'yes' ) - return; - - $date = date( "Y-m-d H:i:s", strtotime( '-' . absint( $held_duration ) . ' MINUTES', current_time( 'timestamp' ) ) ); - - $unpaid_orders = $wpdb->get_col( $wpdb->prepare( " - SELECT posts.ID - FROM {$wpdb->posts} AS posts - LEFT JOIN {$wpdb->term_relationships} AS rel ON posts.ID=rel.object_ID - LEFT JOIN {$wpdb->term_taxonomy} AS tax USING( term_taxonomy_id ) - LEFT JOIN {$wpdb->terms} AS term USING( term_id ) - - WHERE posts.post_type = 'shop_order' - AND posts.post_status = 'publish' - AND tax.taxonomy = 'shop_order_status' - AND term.slug = 'pending' - AND posts.post_modified < %s - ", $date ) ); - - if ( $unpaid_orders ) { - foreach ( $unpaid_orders as $unpaid_order ) { - $order = new WC_Order( $unpaid_order ); - - if ( apply_filters( 'woocommerce_cancel_unpaid_order', true, $order ) ) - $order->update_status( 'cancelled', __( 'Unpaid order cancelled - time limit reached.', 'woocommerce' ) ); - } - } - - wp_clear_scheduled_hook( 'woocommerce_cancel_unpaid_orders' ); - wp_schedule_single_event( time() + ( absint( $held_duration ) * 60 ), 'woocommerce_cancel_unpaid_orders' ); -} - -add_action( 'woocommerce_cancel_unpaid_orders', 'woocommerce_cancel_unpaid_orders' ); - -/** - * woocommerce_clear_comment_rating_transients function. - * - * @access public - * @param mixed $comment_id - * @return void - */ -function woocommerce_clear_comment_rating_transients( $comment_id ) { - $comment = get_comment( $comment_id ); - - if ( ! empty( $comment->comment_post_ID ) ) { - delete_transient( 'wc_average_rating_' . absint( $comment->comment_post_ID ) ); - delete_transient( 'wc_rating_count_' . absint( $comment->comment_post_ID ) ); - } -} - -add_action( 'wp_set_comment_status', 'woocommerce_clear_comment_rating_transients' ); -add_action( 'edit_comment', 'woocommerce_clear_comment_rating_transients' ); diff --git a/woocommerce-functions.php b/woocommerce-functions.php deleted file mode 100644 index b4c6957f8c9..00000000000 --- a/woocommerce-functions.php +++ /dev/null @@ -1,1762 +0,0 @@ -payment_gateways(); - - do_action( 'woocommerce_api_wc_gateway_paypal' ); - } -} - -add_action( 'init', 'woocommerce_legacy_paypal_ipn' ); - -/** - * Handle redirects before content is output - hooked into template_redirect so is_page works. - * - * @access public - * @return void - */ -function woocommerce_template_redirect() { - global $woocommerce, $wp_query, $wp; - - // When default permalinks are enabled, redirect shop page to post type archive url - if ( ! empty( $_GET['page_id'] ) && get_option( 'permalink_structure' ) == "" && $_GET['page_id'] == woocommerce_get_page_id( 'shop' ) ) { - wp_safe_redirect( get_post_type_archive_link('product') ); - exit; - } - - // When on the checkout with an empty cart, redirect to cart page - elseif ( is_page( woocommerce_get_page_id( 'checkout' ) ) && sizeof( $woocommerce->cart->get_cart() ) == 0 && empty( $wp->query_vars['order-pay'] ) && ! isset( $wp->query_vars['order-received'] ) ) { - wp_redirect( get_permalink( woocommerce_get_page_id( 'cart' ) ) ); - exit; - } - - // Logout - elseif ( is_page( woocommerce_get_page_id( 'logout' ) ) ) { - wp_redirect( str_replace( '&', '&', wp_logout_url( get_permalink( woocommerce_get_page_id( 'myaccount' ) ) ) ) ); - exit; - } - - // Redirect to the product page if we have a single product - elseif ( is_search() && is_post_type_archive( 'product' ) && apply_filters( 'woocommerce_redirect_single_search_result', true ) && $wp_query->post_count == 1 ) { - $product = get_product( $wp_query->post ); - - if ( $product->is_visible() ) { - wp_safe_redirect( get_permalink( $product->id ), 302 ); - exit; - } - } - - // Force SSL - elseif ( get_option('woocommerce_force_ssl_checkout') == 'yes' && ! is_ssl() ) { - - if ( is_checkout() || is_account_page() || apply_filters( 'woocommerce_force_ssl_checkout', false ) ) { - if ( 0 === strpos( $_SERVER['REQUEST_URI'], 'http' ) ) { - wp_safe_redirect( preg_replace( '|^http://|', 'https://', $_SERVER['REQUEST_URI'] ) ); - exit; - } else { - wp_safe_redirect( 'https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] ); - exit; - } - } - - } - - // Break out of SSL if we leave the checkout/my accounts - elseif ( get_option('woocommerce_force_ssl_checkout') == 'yes' && get_option('woocommerce_unforce_ssl_checkout') == 'yes' && is_ssl() && $_SERVER['REQUEST_URI'] && ! is_checkout() && ! is_ajax() && ! is_account_page() && apply_filters( 'woocommerce_unforce_ssl_checkout', true ) ) { - - if ( 0 === strpos( $_SERVER['REQUEST_URI'], 'http' ) ) { - wp_safe_redirect( preg_replace( '|^https://|', 'http://', $_SERVER['REQUEST_URI'] ) ); - exit; - } else { - wp_safe_redirect( 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] ); - exit; - } - - } - - // Buffer the checkout page - elseif ( is_checkout() ) { - ob_start(); - } - -} - -/** - * woocommerce_nav_menu_items function. - * - * @access public - * @param mixed $items - * @param mixed $args - * @return void - */ -function woocommerce_nav_menu_items( $items, $args ) { - if ( ! is_user_logged_in() ) { - - $hide_pages = array(); - $hide_pages[] = (int) woocommerce_get_page_id( 'logout' ); - $hide_pages = apply_filters( 'woocommerce_logged_out_hidden_page_ids', $hide_pages ); - - foreach ( $items as $key => $item ) { - if ( ! empty( $item->object_id ) && ! empty( $item->object ) && in_array( $item->object_id, $hide_pages ) && $item->object == 'page' ) { - unset( $items[ $key ] ); - } - } - } - return $items; -} - -/** - * Fix active class in nav for shop page. - * - * @access public - * @param array $menu_items - * @param array $args - * @return array - */ -function woocommerce_nav_menu_item_classes( $menu_items, $args ) { - - if ( ! is_woocommerce() ) return $menu_items; - - $shop_page = (int) woocommerce_get_page_id('shop'); - $page_for_posts = (int) get_option( 'page_for_posts' ); - - foreach ( (array) $menu_items as $key => $menu_item ) { - - $classes = (array) $menu_item->classes; - - // Unset active class for blog page - if ( $page_for_posts == $menu_item->object_id ) { - $menu_items[$key]->current = false; - unset( $classes[ array_search('current_page_parent', $classes) ] ); - unset( $classes[ array_search('current-menu-item', $classes) ] ); - - // Set active state if this is the shop page link - } elseif ( is_shop() && $shop_page == $menu_item->object_id ) { - $menu_items[$key]->current = true; - $classes[] = 'current-menu-item'; - $classes[] = 'current_page_item'; - - // Set parent state if this is a product page - } elseif ( is_singular( 'product' ) && $shop_page == $menu_item->object_id ) { - $classes[] = 'current_page_parent'; - } - - $menu_items[$key]->classes = array_unique( $classes ); - - } - - return $menu_items; -} - - -/** - * Fix active class in wp_list_pages for shop page. - * - * https://github.com/woothemes/woocommerce/issues/177 - * - * @author Jessor, Peter Sterling - * @access public - * @param string $pages - * @return string - */ -function woocommerce_list_pages( $pages ){ - global $post; - - if (is_woocommerce()) { - $pages = str_replace( 'current_page_parent', '', $pages); // remove current_page_parent class from any item - $shop_page = 'page-item-' . woocommerce_get_page_id('shop'); // find shop_page_id through woocommerce options - - if (is_shop()) : - $pages = str_replace($shop_page, $shop_page . ' current_page_item', $pages); // add current_page_item class to shop page - else : - $pages = str_replace($shop_page, $shop_page . ' current_page_parent', $pages); // add current_page_parent class to shop page - endif; - } - return $pages; -} - -/** - * Remove from cart/update. - * - * @access public - * @return void - */ -function woocommerce_update_cart_action() { - global $woocommerce; - - // Remove from cart - if ( ! empty( $_GET['remove_item'] ) && wp_verify_nonce( $_GET['_wpnonce'], 'woocommerce-cart' ) ) { - - $woocommerce->cart->set_quantity( $_GET['remove_item'], 0 ); - - wc_add_message( __( 'Cart updated.', 'woocommerce' ) ); - - $referer = ( wp_get_referer() ) ? wp_get_referer() : $woocommerce->cart->get_cart_url(); - wp_safe_redirect( $referer ); - exit; - - // Update Cart - } elseif ( ( ! empty( $_POST['update_cart'] ) || ! empty( $_POST['proceed'] ) ) && wp_verify_nonce( $_POST['_wpnonce'], 'woocommerce-cart' ) ) { - - $cart_totals = isset( $_POST['cart'] ) ? $_POST['cart'] : ''; - - if ( sizeof( $woocommerce->cart->get_cart() ) > 0 ) { - foreach ( $woocommerce->cart->get_cart() as $cart_item_key => $values ) { - - $_product = $values['data']; - - // Skip product if no updated quantity was posted - if ( ! isset( $cart_totals[$cart_item_key]['qty'] ) ) - continue; - - // Sanitize - $quantity = apply_filters( 'woocommerce_stock_amount_cart_item', apply_filters( 'woocommerce_stock_amount', preg_replace( "/[^0-9\.]/", "", $cart_totals[ $cart_item_key ]['qty'] ) ), $cart_item_key ); - - if ( "" === $quantity ) - continue; - - // Update cart validation - $passed_validation = apply_filters( 'woocommerce_update_cart_validation', true, $cart_item_key, $values, $quantity ); - - // is_sold_individually - if ( $_product->is_sold_individually() && $quantity > 1 ) { - wc_add_error( sprintf( __( 'You can only have 1 %s in your cart.', 'woocommerce' ), $_product->get_title() ) ); - $passed_validation = false; - } - - if ( $passed_validation ) - $woocommerce->cart->set_quantity( $cart_item_key, $quantity ); - - } - } - - if ( ! empty( $_POST['proceed'] ) ) { - wp_safe_redirect( $woocommerce->cart->get_checkout_url() ); - exit; - } else { - wc_add_message( __( 'Cart updated.', 'woocommerce' ) ); - - $referer = ( wp_get_referer() ) ? wp_get_referer() : $woocommerce->cart->get_cart_url(); - $referer = remove_query_arg( 'remove_discounts', $referer ); - wp_safe_redirect( $referer ); - exit; - } - - } -} - - -/** - * Add to cart action - * - * Checks for a valid request, does validation (via hooks) and then redirects if valid. - * - * @access public - * @param bool $url (default: false) - * @return void - */ -function woocommerce_add_to_cart_action( $url = false ) { - if ( empty( $_REQUEST['add-to-cart'] ) || ! is_numeric( $_REQUEST['add-to-cart'] ) ) - return; - - global $woocommerce; - - $product_id = apply_filters( 'woocommerce_add_to_cart_product_id', absint( $_REQUEST['add-to-cart'] ) ); - $was_added_to_cart = false; - $added_to_cart = array(); - $adding_to_cart = get_product( $product_id ); - $add_to_cart_handler = apply_filters( 'woocommerce_add_to_cart_handler', $adding_to_cart->product_type, $adding_to_cart ); - - // Variable product handling - if ( 'variable' === $add_to_cart_handler ) { - - $variation_id = empty( $_REQUEST['variation_id'] ) ? '' : absint( $_REQUEST['variation_id'] ); - $quantity = empty( $_REQUEST['quantity'] ) ? 1 : apply_filters( 'woocommerce_stock_amount', $_REQUEST['quantity'] ); - $all_variations_set = true; - $variations = array(); - - // Only allow integer variation ID - if its not set, redirect to the product page - if ( empty( $variation_id ) ) { - wc_add_error( __( 'Please choose product options…', 'woocommerce' ) ); - return; - } - - $attributes = $adding_to_cart->get_attributes(); - $variation = get_product( $variation_id ); - - // Verify all attributes - foreach ( $attributes as $attribute ) { - if ( ! $attribute['is_variation'] ) - continue; - - $taxonomy = 'attribute_' . sanitize_title( $attribute['name'] ); - - if ( ! empty( $_REQUEST[ $taxonomy ] ) ) { - - // Get value from post data - // Don't use woocommerce_clean as it destroys sanitized characters - $value = sanitize_title( trim( stripslashes( $_REQUEST[ $taxonomy ] ) ) ); - - // Get valid value from variation - $valid_value = $variation->variation_data[ $taxonomy ]; - - // Allow if valid - if ( $valid_value == '' || $valid_value == $value ) { - if ( $attribute['is_taxonomy'] ) - $variations[ esc_html( $attribute['name'] ) ] = $value; - else { - // For custom attributes, get the name from the slug - $options = array_map( 'trim', explode( '|', $attribute['value'] ) ); - foreach ( $options as $option ) { - if ( sanitize_title( $option ) == $value ) { - $value = $option; - break; - } - } - $variations[ esc_html( $attribute['name'] ) ] = $value; - } - continue; - } - - } - - $all_variations_set = false; - } - - if ( $all_variations_set ) { - // Add to cart validation - $passed_validation = apply_filters( 'woocommerce_add_to_cart_validation', true, $product_id, $quantity, $variation_id, $variations ); - - if ( $passed_validation ) { - if ( $woocommerce->cart->add_to_cart( $product_id, $quantity, $variation_id, $variations ) ) { - woocommerce_add_to_cart_message( $product_id ); - $was_added_to_cart = true; - $added_to_cart[] = $product_id; - } - } - } else { - wc_add_error( __( 'Please choose product options…', 'woocommerce' ) ); - return; - } - - // Grouped Products - } elseif ( 'grouped' === $add_to_cart_handler ) { - - if ( ! empty( $_REQUEST['quantity'] ) && is_array( $_REQUEST['quantity'] ) ) { - - $quantity_set = false; - - foreach ( $_REQUEST['quantity'] as $item => $quantity ) { - if ( $quantity <= 0 ) - continue; - - $quantity_set = true; - - // Add to cart validation - $passed_validation = apply_filters( 'woocommerce_add_to_cart_validation', true, $item, $quantity ); - - if ( $passed_validation ) { - if ( $woocommerce->cart->add_to_cart( $item, $quantity ) ) { - $was_added_to_cart = true; - $added_to_cart[] = $item; - } - } - } - - if ( $was_added_to_cart ) { - woocommerce_add_to_cart_message( $added_to_cart ); - } - - if ( ! $was_added_to_cart && ! $quantity_set ) { - wc_add_error( __( 'Please choose the quantity of items you wish to add to your cart…', 'woocommerce' ) ); - return; - } - - } elseif ( $product_id ) { - - /* Link on product archives */ - wc_add_error( __( 'Please choose a product to add to your cart…', 'woocommerce' ) ); - return; - - } - - // Simple Products - } else { - - $quantity = empty( $_REQUEST['quantity'] ) ? 1 : apply_filters( 'woocommerce_stock_amount', $_REQUEST['quantity'] ); - - // Add to cart validation - $passed_validation = apply_filters( 'woocommerce_add_to_cart_validation', true, $product_id, $quantity ); - - if ( $passed_validation ) { - // Add the product to the cart - if ( $woocommerce->cart->add_to_cart( $product_id, $quantity ) ) { - woocommerce_add_to_cart_message( $product_id ); - $was_added_to_cart = true; - $added_to_cart[] = $product_id; - } - } - - } - - // If we added the product to the cart we can now optionally do a redirect. - if ( $was_added_to_cart && wc_error_count() == 0 ) { - - $url = apply_filters( 'add_to_cart_redirect', $url ); - - // If has custom URL redirect there - if ( $url ) { - wp_safe_redirect( $url ); - exit; - } - - // Redirect to cart option - elseif ( get_option('woocommerce_cart_redirect_after_add') == 'yes' ) { - wp_safe_redirect( $woocommerce->cart->get_cart_url() ); - exit; - } - - } - -} - - -/** - * Add to cart messages. - * - * @access public - * @return void - */ -function woocommerce_add_to_cart_message( $product_id ) { - global $woocommerce; - - if ( is_array( $product_id ) ) { - - $titles = array(); - - foreach ( $product_id as $id ) { - $titles[] = get_the_title( $id ); - } - - $added_text = sprintf( __( 'Added "%s" to your cart.', 'woocommerce' ), join( __( '" and "', 'woocommerce' ), array_filter( array_merge( array( join( '", "', array_slice( $titles, 0, -1 ) ) ), array_slice( $titles, -1 ) ) ) ) ); - - } else { - $added_text = sprintf( __( '"%s" was successfully added to your cart.', 'woocommerce' ), get_the_title( $product_id ) ); - } - - // Output success messages - if ( get_option( 'woocommerce_cart_redirect_after_add' ) == 'yes' ) : - - $return_to = apply_filters( 'woocommerce_continue_shopping_redirect', wp_get_referer() ? wp_get_referer() : home_url() ); - - $message = sprintf('%s %s', $return_to, __( 'Continue Shopping →', 'woocommerce' ), $added_text ); - - else : - - $message = sprintf('%s %s', get_permalink( woocommerce_get_page_id( 'cart' ) ), __( 'View Cart →', 'woocommerce' ), $added_text ); - - endif; - - wc_add_message( apply_filters('woocommerce_add_to_cart_message', $message) ); -} - - -/** - * Clear cart after payment. - * - * @access public - * @return void - */ -function woocommerce_clear_cart_after_payment() { - global $woocommerce, $wp; - - if ( ! empty( $wp->query_vars['order-received'] ) ) { - - $order_id = absint( $wp->query_vars['order-received'] ); - - if ( isset( $_GET['key'] ) ) - $order_key = $_GET['key']; - else - $order_key = ''; - - if ( $order_id > 0 ) { - $order = new WC_Order( $order_id ); - - if ( $order->order_key == $order_key ) { - $woocommerce->cart->empty_cart(); - } - } - - } - - if ( $woocommerce->session->order_awaiting_payment > 0 ) { - - $order = new WC_Order( $woocommerce->session->order_awaiting_payment ); - - if ( $order->id > 0 ) { - // If the order has failed, and the customer is logged in, they can try again from their account page - if ( $order->status == 'failed' && is_user_logged_in() ) - $woocommerce->cart->empty_cart(); - - // If the order has not failed, or is not pending, the order must have gone through - if ( $order->status != 'failed' && $order->status != 'pending' ) - $woocommerce->cart->empty_cart(); - } - } -} - - -/** - * Process the checkout form. - * - * @access public - * @return void - */ -function woocommerce_checkout_action() { - global $woocommerce; - - if ( isset( $_POST['woocommerce_checkout_place_order'] ) || isset( $_POST['woocommerce_checkout_update_totals'] ) ) { - - if ( sizeof( $woocommerce->cart->get_cart() ) == 0 ) { - wp_redirect( get_permalink( woocommerce_get_page_id( 'cart' ) ) ); - exit; - } - - if ( ! defined( 'WOOCOMMERCE_CHECKOUT' ) ) - define( 'WOOCOMMERCE_CHECKOUT', true ); - - $woocommerce_checkout = $woocommerce->checkout(); - $woocommerce_checkout->process_checkout(); - } -} - - -/** - * Process the pay form. - * - * @access public - * @return void - */ -function woocommerce_pay_action() { - global $woocommerce, $wp; - - if ( isset( $_POST['woocommerce_pay'] ) && wp_verify_nonce( $_POST['_wpnonce'], 'woocommerce-pay' ) ) { - - ob_start(); - - // Pay for existing order - $order_key = urldecode( $_GET['key'] ); - $order_id = absint( $wp->query_vars['order-pay'] ); - $order = new WC_Order( $order_id ); - - if ( $order->id == $order_id && $order->order_key == $order_key && in_array( $order->status, array( 'pending', 'failed' ) ) ) { - - // Set customer location to order location - if ( $order->billing_country ) - $woocommerce->customer->set_country( $order->billing_country ); - if ( $order->billing_state ) - $woocommerce->customer->set_state( $order->billing_state ); - if ( $order->billing_postcode ) - $woocommerce->customer->set_postcode( $order->billing_postcode ); - if ( $order->billing_city ) - $woocommerce->customer->set_city( $order->billing_city ); - - // Update payment method - if ( $order->order_total > 0 ) { - $payment_method = woocommerce_clean( $_POST['payment_method'] ); - - $available_gateways = $woocommerce->payment_gateways->get_available_payment_gateways(); - - // Update meta - update_post_meta( $order_id, '_payment_method', $payment_method ); - - if ( isset( $available_gateways[ $payment_method ] ) ) - $payment_method_title = $available_gateways[ $payment_method ]->get_title(); - - update_post_meta( $order_id, '_payment_method_title', $payment_method_title); - - // Validate - $available_gateways[ $payment_method ]->validate_fields(); - - // Process - if ( wc_error_count() == 0 ) { - - $result = $available_gateways[ $payment_method ]->process_payment( $order_id ); - - // Redirect to success/confirmation/payment page - if ( $result['result'] == 'success' ) { - wp_redirect( $result['redirect'] ); - exit; - } - - } - - } else { - - // No payment was required for order - $order->payment_complete(); - wp_safe_redirect( $order->get_checkout_order_received_url() ); - exit; - - } - - } - - } -} - - -/** - * Process the login form. - * - * @access public - * @return void - */ -function woocommerce_process_login() { - global $woocommerce; - - if ( ! empty( $_POST['login'] ) ) { - - wp_verify_nonce( $_POST['_wpnonce'], 'woocommerce-login' ); - - try { - $creds = array(); - - if ( empty( $_POST['username'] ) ) - throw new Exception( '' . __( 'Error', 'woocommerce' ) . ': ' . __( 'Username is required.', 'woocommerce' ) ); - if ( empty( $_POST['password'] ) ) - throw new Exception( '' . __( 'Error', 'woocommerce' ) . ': ' . __( 'Password is required.', 'woocommerce' ) ); - - if ( is_email( $_POST['username'] ) ) { - $user = get_user_by( 'email', $_POST['username'] ); - - if ( isset( $user->user_login ) ) - $creds['user_login'] = $user->user_login; - else - throw new Exception( '' . __( 'Error', 'woocommerce' ) . ': ' . __( 'A user could not be found with this email address.', 'woocommerce' ) ); - } else { - $creds['user_login'] = $_POST['username']; - } - - $creds['user_password'] = $_POST['password']; - $creds['remember'] = true; - $secure_cookie = is_ssl() ? true : false; - $user = wp_signon( $creds, $secure_cookie ); - - if ( is_wp_error( $user ) ) { - throw new Exception( $user->get_error_message() ); - } else { - - if ( ! empty( $_POST['redirect'] ) ) { - $redirect = esc_url( $_POST['redirect'] ); - } elseif ( wp_get_referer() ) { - $redirect = esc_url( wp_get_referer() ); - } else { - $redirect = esc_url( get_permalink( woocommerce_get_page_id( 'myaccount' ) ) ); - } - - // Feedback - wc_add_message( sprintf( __( 'You are now logged in as %s', 'woocommerce' ), $user->display_name ) ); - - wp_redirect( apply_filters( 'woocommerce_login_redirect', $redirect, $user ) ); - exit; - } - } catch (Exception $e) { - - wc_add_error( apply_filters('login_errors', $e->getMessage() ) ); - - } - } -} - -/** - * Handle reset password form - */ -function woocommerce_process_reset_password() { - if ( ! isset( $_POST['wc_reset_password'] ) ) - return; - - // process lost password form - if ( isset( $_POST['user_login'] ) ) { - - wp_verify_nonce( $_POST['_wpnonce'], 'woocommerce-lost_password' ); - - WC_Shortcode_My_Account::retrieve_password(); - } - - // process reset password form - if( isset( $_POST['password_1'] ) && isset( $_POST['password_2'] ) && isset( $_POST['reset_key'] ) && isset( $_POST['reset_login'] ) ) { - - // verify reset key again - $user = WC_Shortcode_My_Account::check_password_reset_key( $_POST['reset_key'], $_POST['reset_login'] ); - - if ( is_object( $user ) ) { - - // save these values into the form again in case of errors - $args['key'] = woocommerce_clean( $_POST['reset_key'] ); - $args['login'] = woocommerce_clean( $_POST['reset_login'] ); - - wp_verify_nonce( $_POST['_wpnonce'], 'woocommerce-reset_password' ); - - if( empty( $_POST['password_1'] ) || empty( $_POST['password_2'] ) ) { - wc_add_error( __( 'Please enter your password.', 'woocommerce' ) ); - $args['form'] = 'reset_password'; - } - - if( $_POST[ 'password_1' ] !== $_POST[ 'password_2' ] ) { - wc_add_error( __( 'Passwords do not match.', 'woocommerce' ) ); - $args['form'] = 'reset_password'; - } - - if( 0 == wc_error_count() && ( $_POST['password_1'] == $_POST['password_2'] ) ) { - - WC_Shortcode_My_Account::reset_password( $user, woocommerce_clean( $_POST['password_1'] ) ); - - do_action( 'woocommerce_customer_reset_password', $user ); - - wc_add_message( __( 'Your password has been reset.', 'woocommerce' ) . ' ' . __( 'Log in', 'woocommerce' ) . '' ); - - wp_redirect( remove_query_arg( array( 'key', 'login' ) ) ); - exit; - } - } - - } -} - - -/** - * Create a new customer - * - * @param string $email - * @param string $username - * @param string $password - * @return WP_Error on failure, Int (user ID) on success - */ -function woocommerce_create_new_customer( $email, $username = '', $password = '' ) { - - // Check the e-mail address - if ( empty( $email ) || ! is_email( $email ) ) - return new WP_Error( "registration-error", __( "Please provide a valid email address.", "woocommerce" ) ); - - if ( email_exists( $email ) ) - return new WP_Error( "registration-error", __( "An account is already registered with your email address. Please login.", "woocommerce" ) ); - - wp_verify_nonce( $_POST['_wpnonce'], 'woocommerce-register' ); - - // Handle username creation - if ( get_option( 'woocommerce_registration_generate_username' ) == 'no' || ! empty( $username ) ) { - - $username = sanitize_user( $username ); - - if ( empty( $username ) || ! validate_username( $username ) ) - return new WP_Error( "registration-error", __( "Please enter a valid account username.", "woocommerce" ) ); - - if ( username_exists( $username ) ) - return new WP_Error( "registration-error", __( "An account is already registered with that username. Please choose another.", "woocommerce" ) ); - } else { - - $username = sanitize_user( current( explode( '@', $email ) ) ); - - // Ensure username is unique - $append = 1; - $o_username = $username; - - while ( username_exists( $username ) ) { - $username = $o_username . $append; - $append ++; - } - } - - // Handle password creation - if ( get_option( 'woocommerce_registration_generate_password' ) == 'yes' && empty( $password ) ) { - $password = wp_generate_password(); - $password_generated = true; - } elseif ( empty( $password ) ) { - return new WP_Error( "registration-error", __( "Please enter an account password.", "woocommerce" ) ); - } else { - $password_generated = false; - } - - // WP Validation - $validation_errors = new WP_Error(); - - do_action( 'woocommerce_register_post', $username, $email, $validation_errors ); - - $validation_errors = apply_filters( 'woocommerce_registration_errors', $validation_errors, $username, $email ); - - if ( $validation_errors->get_error_code() ) - return $validation_errors; - - $new_customer_data = apply_filters( 'woocommerce_new_customer_data', array( - 'user_login' => $username, - 'user_pass' => $password, - 'user_email' => $email, - 'role' => 'customer' - ) ); - - $customer_id = wp_insert_user( $new_customer_data ); - - if ( is_wp_error( $customer_id ) ) - return new WP_Error( "registration-error", '' . __( 'ERROR', 'woocommerce' ) . ': ' . __( 'Couldn’t register you… please contact us if you continue to have problems.', 'woocommerce' ) ); - - do_action( 'woocommerce_created_customer', $customer_id, $new_customer_data, $password_generated ); - - return $customer_id; -} - -/** - * Login a customer (set auth cookie and set global user object) - * - * @param int $customer_id - * @return void - */ -function woocommerce_set_customer_auth_cookie( $customer_id ) { - global $current_user; - - $current_user = get_user_by( 'id', $customer_id ); - - wp_set_auth_cookie( $customer_id, true, is_ssl() ); -} - -/** - * Process the registration form. - * - * @access public - * @return void - */ -function woocommerce_process_registration() { - global $woocommerce; - - if ( ! empty( $_POST['register'] ) ) { - - $woocommerce->verify_nonce( 'register' ); - - $username = ! empty( $_POST['username'] ) ? woocommerce_clean( $_POST['username'] ) : ''; - $email = ! empty( $_POST['email'] ) ? woocommerce_clean( $_POST['email'] ) : ''; - $password = ! empty( $_POST['password'] ) ? woocommerce_clean( $_POST['password'] ) : ''; - - // Anti-spam trap - if ( ! empty( $_POST['email_2'] ) ) { - wc_add_error( '' . __( 'ERROR', 'woocommerce' ) . ': ' . __( 'Anti-spam field was filled in.', 'woocommerce' ) ); - return; - } - - $new_customer = woocommerce_create_new_customer( $email, $username, $password ); - - if ( is_wp_error( $new_customer ) ) { - wc_add_error( $new_customer->get_error_message() ); - return; - } - - woocommerce_set_customer_auth_cookie( $new_customer ); - - // Redirect - if ( wp_get_referer() ) { - $redirect = esc_url( wp_get_referer() ); - } else { - $redirect = esc_url( get_permalink( woocommerce_get_page_id( 'myaccount' ) ) ); - } - - wp_redirect( apply_filters( 'woocommerce_registration_redirect', $redirect ) ); - exit; - } -} - -/** - * Get the link to the edit account details page - * - * @return string - */ -function woocommerce_customer_edit_account_url() { - $edit_account_url = woocommerce_get_endpoint_url( 'edit-account', '', get_permalink( woocommerce_get_page_id( 'myaccount' ) ) ); - - return apply_filters( 'woocommerce_customer_edit_account_url', $edit_account_url ); -} - -/** - * Place a previous order again. - * - * @access public - * @return void - */ -function woocommerce_order_again() { - global $woocommerce; - - // Nothing to do - if ( ! isset( $_GET['order_again'] ) || ! is_user_logged_in() || ! $woocommerce->verify_nonce( 'order_again', '_GET' ) || ! wp_verify_nonce( $_GET['_wpnonce'], 'woocommerce-order_again' ) ) - return; - - // Clear current cart - $woocommerce->cart->empty_cart(); - - // Load the previous order - Stop if the order does not exist - $order = new WC_Order( absint( $_GET['order_again'] ) ); - - if ( empty( $order->id ) ) - return; - - if ( $order->status != 'completed' ) - return; - - // Make sure the previous order belongs to the current customer - if ( $order->user_id != get_current_user_id() ) - return; - - // Copy products from the order to the cart - foreach ( $order->get_items() as $item ) { - // Load all product info including variation data - $product_id = (int) apply_filters( 'woocommerce_add_to_cart_product_id', $item['product_id'] ); - $quantity = (int) $item['qty']; - $variation_id = (int) $item['variation_id']; - $variations = array(); - $cart_item_data = apply_filters( 'woocommerce_order_again_cart_item_data', array(), $item, $order ); - - foreach ( $item['item_meta'] as $meta_name => $meta_value ) { - if ( taxonomy_is_product_attribute( $meta_name ) ) - $variations[ $meta_name ] = $meta_value[0]; - } - - // Add to cart validation - if ( ! apply_filters( 'woocommerce_add_to_cart_validation', true, $product_id, $quantity, $variation_id, $variations, $cart_item_data ) ) continue; - - $woocommerce->cart->add_to_cart( $product_id, $quantity, $variation_id, $variations, $cart_item_data ); - } - - do_action( 'woocommerce_ordered_again', $order->id ); - - // Redirect to cart - wc_add_message( __( 'The cart has been filled with the items from your previous order.', 'woocommerce' ) ); - wp_safe_redirect( $woocommerce->cart->get_cart_url() ); - exit; -} - - -/** - * Cancel a pending order. - * - * @access public - * @return void - */ -function woocommerce_cancel_order() { - - global $woocommerce; - - if ( isset($_GET['cancel_order']) && isset($_GET['order']) && isset($_GET['order_id']) ) : - - $order_key = urldecode( $_GET['order'] ); - $order_id = (int) $_GET['order_id']; - - $order = new WC_Order( $order_id ); - - if ( $order->id == $order_id && $order->order_key == $order_key && in_array( $order->status, array( 'pending', 'failed' ) ) && wp_verify_nonce( $_GET['_wpnonce'], 'woocommerce-cancel_order' ) ) : - - // Cancel the order + restore stock - $order->cancel_order( __('Order cancelled by customer.', 'woocommerce' ) ); - - // Message - wc_add_message( __( 'Your order was cancelled.', 'woocommerce' ) ); - - do_action( 'woocommerce_cancelled_order', $order->id ); - - elseif ( $order->status != 'pending' ) : - - wc_add_error( __( 'Your order is no longer pending and could not be cancelled. Please contact us if you need assistance.', 'woocommerce' ) ); - - else : - - wc_add_error( __( 'Invalid order.', 'woocommerce' ) ); - - endif; - - wp_safe_redirect($woocommerce->cart->get_cart_url()); - exit; - - endif; -} - - -/** - * Download a file - hook into init function. - * - * @access public - * @return void - */ -function woocommerce_download_product() { - - if ( isset( $_GET['download_file'] ) && isset( $_GET['order'] ) && isset( $_GET['email'] ) ) { - - global $wpdb, $is_IE; - - $product_id = (int) urldecode($_GET['download_file']); - $order_key = urldecode( $_GET['order'] ); - $email = sanitize_email( str_replace( ' ', '+', urldecode( $_GET['email'] ) ) ); - $download_id = isset( $_GET['key'] ) ? preg_replace( '/\s+/', ' ', urldecode( $_GET['key'] ) ) : ''; - $_product = get_product( $product_id ); - $file_download_method = apply_filters( 'woocommerce_file_download_method', get_option( 'woocommerce_file_download_method' ), $product_id ); - - if ( ! is_email( $email) ) - wp_die( __( 'Invalid email address.', 'woocommerce' ) . ' ' . __( 'Go to homepage →', 'woocommerce' ) . '' ); - - $query = " - SELECT order_id,downloads_remaining,user_id,download_count,access_expires,download_id - FROM " . $wpdb->prefix . "woocommerce_downloadable_product_permissions - WHERE user_email = %s - AND order_key = %s - AND product_id = %s"; - $args = array( - $email, - $order_key, - $product_id - ); - - if ( $download_id ) { - // backwards compatibility for existing download URLs - $query .= " AND download_id = %s"; - $args[] = $download_id; - } - - $download_result = $wpdb->get_row( $wpdb->prepare( $query, $args ) ); - - if ( ! $download_result ) - wp_die( __( 'Invalid download.', 'woocommerce' ) . ' ' . __( 'Go to homepage →', 'woocommerce' ) . '' ); - - $download_id = $download_result->download_id; - $order_id = $download_result->order_id; - $downloads_remaining = $download_result->downloads_remaining; - $download_count = $download_result->download_count; - $user_id = $download_result->user_id; - $access_expires = $download_result->access_expires; - - if ( $user_id && get_option( 'woocommerce_downloads_require_login' ) == 'yes' ) { - - if ( ! is_user_logged_in() ) - wp_die( __( 'You must be logged in to download files.', 'woocommerce' ) . ' ' . __( 'Login →', 'woocommerce' ) . '', __( 'Log in to Download Files', 'woocommerce' ) ); - - elseif ( $user_id != get_current_user_id() ) - wp_die( __( 'This is not your download link.', 'woocommerce' ) ); - - } - - if ( ! get_post( $product_id ) ) - wp_die( __( 'Product no longer exists.', 'woocommerce' ) . ' ' . __( 'Go to homepage →', 'woocommerce' ) . '' ); - - if ( $order_id ) { - $order = new WC_Order( $order_id ); - - if ( ! $order->is_download_permitted() || $order->post_status != 'publish' ) - wp_die( __( 'Invalid order.', 'woocommerce' ) . ' ' . __( 'Go to homepage →', 'woocommerce' ) . '' ); - } - - if ( $downloads_remaining == '0' ) - wp_die( __( 'Sorry, you have reached your download limit for this file', 'woocommerce' ) . ' ' . __( 'Go to homepage →', 'woocommerce' ) . '' ); - - if ( $access_expires > 0 && strtotime( $access_expires) < current_time( 'timestamp' ) ) - wp_die( __( 'Sorry, this download has expired', 'woocommerce' ) . ' ' . __( 'Go to homepage →', 'woocommerce' ) . '' ); - - if ( $downloads_remaining > 0 ) { - $wpdb->update( $wpdb->prefix . "woocommerce_downloadable_product_permissions", array( - 'downloads_remaining' => $downloads_remaining - 1, - ), array( - 'user_email' => $email, - 'order_key' => $order_key, - 'product_id' => $product_id, - 'download_id' => $download_id - ), array( '%d' ), array( '%s', '%s', '%d', '%s' ) ); - } - - // Count the download - $wpdb->update( $wpdb->prefix . "woocommerce_downloadable_product_permissions", array( - 'download_count' => $download_count + 1, - ), array( - 'user_email' => $email, - 'order_key' => $order_key, - 'product_id' => $product_id, - 'download_id' => $download_id - ), array( '%d' ), array( '%s', '%s', '%d', '%s' ) ); - - // Trigger action - do_action( 'woocommerce_download_product', $email, $order_key, $product_id, $user_id, $download_id, $order_id ); - - // Get the download URL and try to replace the url with a path - $file_path = $_product->get_file_download_path( $download_id ); - - if ( ! $file_path ) - wp_die( __( 'No file defined', 'woocommerce' ) . ' ' . __( 'Go to homepage →', 'woocommerce' ) . '' ); - - // Redirect to the file... - if ( $file_download_method == "redirect" ) { - header( 'Location: ' . $file_path ); - exit; - } - - // ...or serve it - if ( ! is_multisite() ) { - - /* - * Download file may be either http or https. - * site_url() depends on whether the page containing the download (ie; My Account) is served via SSL because WC - * modifies site_url() via a filter to force_ssl. - * So blindly doing a str_replace is incorrect because it will fail when schemes are mismatched. This code - * handles the various permutations. - */ - $scheme = parse_url( $file_path, PHP_URL_SCHEME ); - - if ( $scheme ) { - $site_url = set_url_scheme( site_url( '' ), $scheme ); - } else { - $site_url = is_ssl() ? str_replace( 'https:', 'http:', site_url() ) : site_url(); - } - - $file_path = str_replace( trailingslashit( $site_url ), ABSPATH, $file_path ); - - } else { - - $network_url = is_ssl() ? str_replace( 'https:', 'http:', network_admin_url() ) : network_admin_url(); - $upload_dir = wp_upload_dir(); - - // Try to replace network url - $file_path = str_replace( trailingslashit( $network_url ), ABSPATH, $file_path ); - - // Now try to replace upload URL - $file_path = str_replace( $upload_dir['baseurl'], $upload_dir['basedir'], $file_path ); - } - - // See if its local or remote - if ( strstr( $file_path, 'http:' ) || strstr( $file_path, 'https:' ) || strstr( $file_path, 'ftp:' ) ) { - $remote_file = true; - } else { - $remote_file = false; - - // Remove Query String - if ( strstr( $file_path, '?' ) ) - $file_path = current( explode( '?', $file_path ) ); - - $file_path = realpath( $file_path ); - } - - $file_extension = strtolower( substr( strrchr( $file_path, "." ), 1 ) ); - $ctype = "application/force-download"; - - foreach ( get_allowed_mime_types() as $mime => $type ) { - $mimes = explode( '|', $mime ); - if ( in_array( $file_extension, $mimes ) ) { - $ctype = $type; - break; - } - } - - // Start setting headers - if ( ! ini_get('safe_mode') ) - @set_time_limit(0); - - if ( function_exists( 'get_magic_quotes_runtime' ) && get_magic_quotes_runtime() ) - @set_magic_quotes_runtime(0); - - if( function_exists( 'apache_setenv' ) ) - @apache_setenv( 'no-gzip', 1 ); - - @session_write_close(); - @ini_set( 'zlib.output_compression', 'Off' ); - @ob_end_clean(); - - if ( ob_get_level() ) - @ob_end_clean(); // Zip corruption fix - - if ( $is_IE && is_ssl() ) { - // IE bug prevents download via SSL when Cache Control and Pragma no-cache headers set. - header( 'Expires: Wed, 11 Jan 1984 05:00:00 GMT' ); - header( 'Cache-Control: private' ); - } else { - nocache_headers(); - } - - $file_name = basename( $file_path ); - - if ( strstr( $file_name, '?' ) ) - $file_name = current( explode( '?', $file_name ) ); - - header( "Robots: none" ); - header( "Content-Type: " . $ctype ); - header( "Content-Description: File Transfer" ); - header( "Content-Disposition: attachment; filename=\"" . $file_name . "\";" ); - header( "Content-Transfer-Encoding: binary" ); - - if ( $size = @filesize( $file_path ) ) - header( "Content-Length: " . $size ); - - if ( $file_download_method == 'xsendfile' ) { - - // Path fix - kudos to Jason Judge - if ( getcwd() ) - $file_path = trim( preg_replace( '`^' . getcwd() . '`' , '', $file_path ), '/' ); - - header( "Content-Disposition: attachment; filename=\"" . $file_name . "\";" ); - - if ( function_exists( 'apache_get_modules' ) && in_array( 'mod_xsendfile', apache_get_modules() ) ) { - - header("X-Sendfile: $file_path"); - exit; - - } elseif ( stristr( getenv( 'SERVER_SOFTWARE' ), 'lighttpd' ) ) { - - header( "X-Lighttpd-Sendfile: $file_path" ); - exit; - - } elseif ( stristr( getenv( 'SERVER_SOFTWARE' ), 'nginx' ) || stristr( getenv( 'SERVER_SOFTWARE' ), 'cherokee' ) ) { - - header( "X-Accel-Redirect: /$file_path" ); - exit; - - } - } - - if ( $remote_file ) - @woocommerce_readfile_chunked( $file_path ) or header( 'Location: ' . $file_path ); - else - @woocommerce_readfile_chunked( $file_path ) or wp_die( __( 'File not found', 'woocommerce' ) . ' ' . __( 'Go to homepage →', 'woocommerce' ) . '' ); - - exit; - } -} - -/** - * readfile_chunked - * - * Reads file in chunks so big downloads are possible without changing PHP.INI - http://codeigniter.com/wiki/Download_helper_for_large_files/ - * - * @access public - * @param string file - * @param boolean return bytes of file - * @return void - */ -function woocommerce_readfile_chunked( $file, $retbytes = true ) { - - $chunksize = 1 * ( 1024 * 1024 ); - $buffer = ''; - $cnt = 0; - - $handle = fopen( $file, 'r' ); - if ( $handle === FALSE ) - return FALSE; - - while ( ! feof( $handle ) ) { - $buffer = fread( $handle, $chunksize ); - echo $buffer; - ob_flush(); - flush(); - - if ( $retbytes ) - $cnt += strlen( $buffer ); - } - - $status = fclose( $handle ); - - if ( $retbytes && $status ) - return $cnt; - - return $status; -} - -/** - * Products RSS Feed. - * - * @access public - * @return void - */ -function woocommerce_products_rss_feed() { - // Product RSS - if ( is_post_type_archive( 'product' ) || is_singular( 'product' ) ) { - - $feed = get_post_type_archive_feed_link( 'product' ); - - echo ''; - - } elseif ( is_tax( 'product_cat' ) ) { - - $term = get_term_by('slug', esc_attr( get_query_var('product_cat') ), 'product_cat'); - - $feed = add_query_arg('product_cat', $term->slug, get_post_type_archive_feed_link( 'product' )); - - echo ''; - - } elseif ( is_tax( 'product_tag' ) ) { - - $term = get_term_by('slug', esc_attr( get_query_var('product_tag') ), 'product_tag'); - - $feed = add_query_arg('product_tag', $term->slug, get_post_type_archive_feed_link( 'product' )); - - echo ''; - - } -} - - -/** - * Rating field for comments. - * - * @access public - * @param mixed $comment_id - * @return void - */ -function woocommerce_add_comment_rating( $comment_id ) { - if ( isset( $_POST['rating'] ) ) { - - if ( ! $_POST['rating'] || $_POST['rating'] > 5 || $_POST['rating'] < 0 ) - return; - - add_comment_meta( $comment_id, 'rating', (int) esc_attr( $_POST['rating'] ), true ); - - woocommerce_clear_comment_rating_transients( $comment_id ); - } -} - - -/** - * Validate the comment ratings. - * - * @access public - * @param array $comment_data - * @return array - */ -function woocommerce_check_comment_rating( $comment_data ) { - global $woocommerce; - - // If posting a comment (not trackback etc) and not logged in - if ( isset( $_POST['rating'] ) && ! wp_verify_nonce( $_POST['_wpnonce'], 'woocommerce-comment_rating' ) ) - wp_die( __( 'You have taken too long. Please go back and refresh the page.', 'woocommerce' ) ); - - elseif ( isset( $_POST['rating'] ) && empty( $_POST['rating'] ) && $comment_data['comment_type'] == '' && get_option('woocommerce_review_rating_required') == 'yes' ) { - wp_die( __( 'Please rate the product.', 'woocommerce' ) ); - exit; - } - return $comment_data; -} - - -/** - * Finds an Order ID based on an order key. - * - * @access public - * @param string $order_key An order key has generated by - * @return int The ID of an order, or 0 if the order could not be found - */ -function woocommerce_get_order_id_by_order_key( $order_key ) { - global $wpdb; - - // Faster than get_posts() - $order_id = $wpdb->get_var( "SELECT post_id FROM {$wpdb->prefix}postmeta WHERE meta_key = '_order_key' AND meta_value = '{$order_key}'" ); - - return $order_id; -} - -/** - * Track product views - * - * @access public - * @package WooCommerce/Widgets - * @return void - */ -function woocommerce_track_product_view() { - if ( ! is_singular( 'product' ) ) - return; - - global $post, $product; - - if ( empty( $_COOKIE['woocommerce_recently_viewed'] ) ) - $viewed_products = array(); - else - $viewed_products = (array) explode( '|', $_COOKIE['woocommerce_recently_viewed'] ); - - if ( ! in_array( $post->ID, $viewed_products ) ) - $viewed_products[] = $post->ID; - - if ( sizeof( $viewed_products ) > 15 ) - array_shift( $viewed_products ); - - // Store for session only - setcookie( "woocommerce_recently_viewed", implode( '|', $viewed_products ), 0, COOKIEPATH, COOKIE_DOMAIN, false, true ); -} - -add_action( 'template_redirect', 'woocommerce_track_product_view', 20 ); - -/** - * Layered Nav Init - * - * @package WooCommerce/Widgets - * @access public - * @return void - */ -function woocommerce_layered_nav_init( ) { - - if ( is_active_widget( false, false, 'woocommerce_layered_nav', true ) && ! is_admin() ) { - - global $_chosen_attributes, $woocommerce; - - $_chosen_attributes = array(); - - $attribute_taxonomies = $woocommerce->get_helper( 'attribute' )->get_attribute_taxonomies(); - if ( $attribute_taxonomies ) { - foreach ( $attribute_taxonomies as $tax ) { - - $attribute = sanitize_title( $tax->attribute_name ); - $taxonomy = $woocommerce->get_helper( 'attribute' )->attribute_taxonomy_name( $attribute ); - $name = 'filter_' . $attribute; - $query_type_name = 'query_type_' . $attribute; - - if ( ! empty( $_GET[ $name ] ) && taxonomy_exists( $taxonomy ) ) { - - $_chosen_attributes[ $taxonomy ]['terms'] = explode( ',', $_GET[ $name ] ); - - if ( empty( $_GET[ $query_type_name ] ) || ! in_array( strtolower( $_GET[ $query_type_name ] ), array( 'and', 'or' ) ) ) - $_chosen_attributes[ $taxonomy ]['query_type'] = apply_filters( 'woocommerce_layered_nav_default_query_type', 'and' ); - else - $_chosen_attributes[ $taxonomy ]['query_type'] = strtolower( $_GET[ $query_type_name ] ); - - } - } - } - - add_filter('loop_shop_post_in', 'woocommerce_layered_nav_query'); - } -} - -add_action( 'init', 'woocommerce_layered_nav_init' ); - - -/** - * Layered Nav post filter - * - * @package WooCommerce/Widgets - * @access public - * @param array $filtered_posts - * @return array - */ -function woocommerce_layered_nav_query( $filtered_posts ) { - global $_chosen_attributes, $woocommerce, $wp_query; - - if ( sizeof( $_chosen_attributes ) > 0 ) { - - $matched_products = array(); - $filtered_attribute = false; - - foreach ( $_chosen_attributes as $attribute => $data ) { - - $matched_products_from_attribute = array(); - $filtered = false; - - if ( sizeof( $data['terms'] ) > 0 ) { - foreach ( $data['terms'] as $value ) { - - $posts = get_posts( - array( - 'post_type' => 'product', - 'numberposts' => -1, - 'post_status' => 'publish', - 'fields' => 'ids', - 'no_found_rows' => true, - 'tax_query' => array( - array( - 'taxonomy' => $attribute, - 'terms' => $value, - 'field' => 'id' - ) - ) - ) - ); - - // AND or OR - if ( $data['query_type'] == 'or' ) { - - if ( ! is_wp_error( $posts ) && ( sizeof( $matched_products_from_attribute ) > 0 || $filtered ) ) - $matched_products_from_attribute = array_merge($posts, $matched_products_from_attribute); - elseif ( ! is_wp_error( $posts ) ) - $matched_products_from_attribute = $posts; - - } else { - - if ( ! is_wp_error( $posts ) && ( sizeof( $matched_products_from_attribute ) > 0 || $filtered ) ) - $matched_products_from_attribute = array_intersect($posts, $matched_products_from_attribute); - elseif ( ! is_wp_error( $posts ) ) - $matched_products_from_attribute = $posts; - } - - $filtered = true; - - } - } - - if ( sizeof( $matched_products ) > 0 || $filtered_attribute ) - $matched_products = array_intersect( $matched_products_from_attribute, $matched_products ); - else - $matched_products = $matched_products_from_attribute; - - $filtered_attribute = true; - - } - - if ( $filtered ) { - - $woocommerce->query->layered_nav_post__in = $matched_products; - $woocommerce->query->layered_nav_post__in[] = 0; - - if ( sizeof( $filtered_posts ) == 0 ) { - $filtered_posts = $matched_products; - $filtered_posts[] = 0; - } else { - $filtered_posts = array_intersect( $filtered_posts, $matched_products ); - $filtered_posts[] = 0; - } - - } - } - - return (array) $filtered_posts; -} - -/** - * Price filter Init - * - * @package WooCommerce/Widgets - * @access public - * @return void - */ -function woocommerce_price_filter_init() { - global $woocommerce; - - if ( is_active_widget( false, false, 'woocommerce_price_filter', true ) && ! is_admin() ) { - - $suffix = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min'; - - wp_register_script( 'wc-price-slider', $woocommerce->plugin_url() . '/assets/js/frontend/price-slider' . $suffix . '.js', array( 'jquery-ui-slider' ), '1.6', true ); - - wp_localize_script( 'wc-price-slider', 'woocommerce_price_slider_params', array( - 'currency_symbol' => get_woocommerce_currency_symbol(), - 'currency_pos' => get_option( 'woocommerce_currency_pos' ), - 'min_price' => isset( $_GET['min_price'] ) ? esc_attr( $_GET['min_price'] ) : '', - 'max_price' => isset( $_GET['max_price'] ) ? esc_attr( $_GET['max_price'] ) : '' - ) ); - - add_filter( 'loop_shop_post_in', 'woocommerce_price_filter' ); - } -} - -add_action( 'init', 'woocommerce_price_filter_init' ); - - -/** - * Price Filter post filter - * - * @package WooCommerce/Widgets - * @access public - * @param array $filtered_posts - * @return array - */ -function woocommerce_price_filter($filtered_posts) { - global $wpdb; - - if ( isset( $_GET['max_price'] ) && isset( $_GET['min_price'] ) ) { - - $matched_products = array(); - $min = floatval( $_GET['min_price'] ); - $max = floatval( $_GET['max_price'] ); - - $matched_products_query = $wpdb->get_results( $wpdb->prepare(" - SELECT DISTINCT ID, post_parent, post_type FROM $wpdb->posts - INNER JOIN $wpdb->postmeta ON ID = post_id - WHERE post_type IN ( 'product', 'product_variation' ) AND post_status = 'publish' AND meta_key = %s AND meta_value BETWEEN %d AND %d - ", '_price', $min, $max ), OBJECT_K ); - - if ( $matched_products_query ) { - foreach ( $matched_products_query as $product ) { - if ( $product->post_type == 'product' ) - $matched_products[] = $product->ID; - if ( $product->post_parent > 0 && ! in_array( $product->post_parent, $matched_products ) ) - $matched_products[] = $product->post_parent; - } - } - - // Filter the id's - if ( sizeof( $filtered_posts ) == 0) { - $filtered_posts = $matched_products; - $filtered_posts[] = 0; - } else { - $filtered_posts = array_intersect( $filtered_posts, $matched_products ); - $filtered_posts[] = 0; - } - - } - - return (array) $filtered_posts; -} - -/** - * Save the password/account details and redirect back to the my account page. - * - * @access public - */ -function woocommerce_save_account_details() { - global $woocommerce; - - if ( 'POST' !== strtoupper( $_SERVER[ 'REQUEST_METHOD' ] ) ) - return; - - if ( empty( $_POST[ 'action' ] ) || ( 'save_account_details' !== $_POST[ 'action' ] ) ) - return; - - wp_verify_nonce( $_POST['_wpnonce'], 'woocommerce-save_account_details' ); - - $update = true; - $errors = new WP_Error(); - $user = new stdClass(); - - $user->ID = (int) get_current_user_id(); - $current_user = get_user_by( 'id', $user->ID ); - - if ( $user->ID <= 0 ) - return; - - $account_first_name = ! empty( $_POST[ 'account_first_name' ] ) ? woocommerce_clean( $_POST[ 'account_first_name' ] ) : ''; - $account_last_name = ! empty( $_POST[ 'account_last_name' ] ) ? woocommerce_clean( $_POST[ 'account_last_name' ] ) : ''; - $account_email = ! empty( $_POST[ 'account_email' ] ) ? woocommerce_clean( $_POST[ 'account_email' ] ) : ''; - $pass1 = ! empty( $_POST[ 'password_1' ] ) ? woocommerce_clean( $_POST[ 'password_1' ] ) : ''; - $pass2 = ! empty( $_POST[ 'password_2' ] ) ? woocommerce_clean( $_POST[ 'password_2' ] ) : ''; - - $user->first_name = $account_first_name; - $user->last_name = $account_last_name; - $user->user_email = $account_email; - $user->display_name = $user->first_name; - - if ( $pass1 ) - $user->user_pass = $pass1; - - if ( empty( $account_first_name ) || empty( $account_last_name ) ) - wc_add_error( __( 'Please enter your name.', 'woocommerce' ) ); - - if ( empty( $account_email ) || ! is_email( $account_email ) ) - wc_add_error( __( 'Please provide a valid email address.', 'woocommerce' ) ); - - elseif ( email_exists( $account_email ) && $account_email !== $current_user->user_email ) - wc_add_error( __( 'This email address is already registered.', 'woocommerce' ) ); - - if ( ! empty( $pass1 ) && empty( $pass2 ) ) - wc_add_error( __( 'Please re-enter your password.', 'woocommerce' ) ); - - elseif ( ! empty( $pass1 ) && $pass1 !== $pass2 ) - wc_add_error( __( 'Passwords do not match.', 'woocommerce' ) ); - - // Allow plugins to return their own errors. - do_action_ref_array( 'user_profile_update_errors', array ( &$errors, $update, &$user ) ); - - if ( $errors->get_error_messages() ) - foreach( $errors->get_error_messages() as $error ) - wc_add_error( $error ); - - if ( wc_error_count() == 0 ) { - - wp_update_user( $user ) ; - - wc_add_message( __( 'Account details changed successfully.', 'woocommerce' ) ); - - do_action( 'woocommerce_save_account_details', $user->ID ); - - wp_safe_redirect( get_permalink( woocommerce_get_page_id( 'myaccount' ) ) ); - exit; - } -} - -add_action( 'template_redirect', 'woocommerce_save_account_details' ); - -/** - * Save and and update a billing or shipping address if the - * form was submitted through the user account page. - * - * @access public - */ -function woocommerce_save_address() { - global $woocommerce, $wp; - - if ( 'POST' !== strtoupper( $_SERVER[ 'REQUEST_METHOD' ] ) ) - return; - - if ( empty( $_POST[ 'action' ] ) || ( 'edit_address' !== $_POST[ 'action' ] ) ) - return; - - wp_verify_nonce( $_POST['_wpnonce'], 'woocommerce-edit_address' ); - - $validation = $woocommerce->validation(); - - $user_id = get_current_user_id(); - - if ( $user_id <= 0 ) return; - - $load_address = ( $wp->query_vars['edit-address'] == 'billing' || $wp->query_vars['edit-address'] == 'shipping' ) ? $wp->query_vars['edit-address'] : 'billing'; - - $address = $woocommerce->countries->get_address_fields( esc_attr( $_POST[ $load_address . '_country' ] ), $load_address . '_' ); - - foreach ($address as $key => $field) : - - if (!isset($field['type'])) $field['type'] = 'text'; - - // Get Value - switch ($field['type']) : - case "checkbox" : - $_POST[$key] = isset($_POST[$key]) ? 1 : 0; - break; - default : - $_POST[$key] = isset($_POST[$key]) ? woocommerce_clean($_POST[$key]) : ''; - break; - endswitch; - - // Hook to allow modification of value - $_POST[$key] = apply_filters('woocommerce_process_myaccount_field_' . $key, $_POST[$key]); - - // Validation: Required fields - if ( isset($field['required']) && $field['required'] && empty($_POST[$key]) ) wc_add_error( $field['label'] . ' ' . __( 'is a required field.', 'woocommerce' ) ); - - // Postcode - if ($key=='billing_postcode' || $key=='shipping_postcode') : - if ( ! $validation->is_postcode( $_POST[$key], $_POST[ $load_address . '_country' ] ) ) : - wc_add_error( __( 'Please enter a valid postcode/ZIP.', 'woocommerce' ) ); - else : - $_POST[$key] = $validation->format_postcode( $_POST[$key], $_POST[ $load_address . '_country' ] ); - endif; - endif; - - endforeach; - - if ( wc_error_count() == 0 ) { - - foreach ($address as $key => $field) : - update_user_meta( $user_id, $key, $_POST[$key] ); - endforeach; - - wc_add_message( __( 'Address changed successfully.', 'woocommerce' ) ); - - do_action( 'woocommerce_customer_save_address', $user_id ); - - wp_safe_redirect( get_permalink( woocommerce_get_page_id('myaccount') ) ); - exit; - } -} - -add_action( 'template_redirect', 'woocommerce_save_address' ); \ No newline at end of file diff --git a/woocommerce-hooks.php b/woocommerce-hooks.php deleted file mode 100644 index e0bc9dfeeff..00000000000 --- a/woocommerce-hooks.php +++ /dev/null @@ -1,290 +0,0 @@ -get_helper( 'template' ), 'comments_template_loader' ) ); add_filter( 'wp_redirect', array( $this, 'redirect' ), 1, 2 ); add_action( 'wp_head', array( $this, 'generator' ) ); - add_action( 'wp_head', array( $this, 'wp_head' ) ); - add_filter( 'body_class', array( $this->get_helper( 'body-class' ), 'output_body_class' ) ); - add_filter( 'post_class', array( $this->get_helper( 'post-class' ), 'post_class' ), 20, 3 ); + add_action( 'wp_footer', array( $this->get_helper( 'inline-javascript' ), 'output_inline_js' ), 25 ); // HTTPS urls with SSL on @@ -623,41 +617,6 @@ final class WooCommerce { } - /** - * Add body classes. - * - * @access public - * @return void - */ - public function wp_head() { - - if ( is_woocommerce() ) { - $this->get_helper( 'body-class' )->add_body_class( 'woocommerce' ); - $this->get_helper( 'body-class' )->add_body_class( 'woocommerce-page' ); - return; - } - - if ( is_checkout() ) { - $this->get_helper( 'body-class' )->add_body_class( 'woocommerce-checkout' ); - $this->get_helper( 'body-class' )->add_body_class( 'woocommerce-page' ); - return; - } - - if ( is_cart() ) { - $this->get_helper( 'body-class' )->add_body_class( 'woocommerce-cart' ); - $this->get_helper( 'body-class' )->add_body_class( 'woocommerce-page' ); - return; - } - - if ( is_account_page() ) { - $this->get_helper( 'body-class' )->add_body_class( 'woocommerce-account' ); - $this->get_helper( 'body-class' )->add_body_class( 'woocommerce-page' ); - return; - } - - } - - /** * Init images. * @@ -875,8 +834,8 @@ final class WooCommerce { // Deprecated 2.1.0 Access via the WC_Transient_Helper helper public function clear_product_transients( $post_id = 0 ) { - _deprecated_function( 'Woocommerce->clear_product_transients', '2.1', 'WC_Transient_Helper->clear_product_transients' ); - $this->get_helper( 'transient' )->clear_product_transients( $post_id ); + _deprecated_function( 'Woocommerce->clear_product_transients', '2.1', 'wc_delete_product_transients' ); + wc_delete_product_transients( $post_id ); } // Deprecated 2.1.0 Access via the WC_Inline_Javascript_Helper helper @@ -911,8 +870,8 @@ final class WooCommerce { // Deprecated 2.1.0 Access via the WC_Shortcode_Helper helper public function shortcode_wrapper( $function, $atts = array(), $wrapper = array( 'class' => 'woocommerce', 'before' => null, 'after' => null ) ) { - _deprecated_function( 'Woocommerce->shortcode_wrapper', '2.1', 'WC_Shortcode_Helper->shortcode_wrapper' ); - return $this->get_helper( 'shortcode' )->shortcode_wrapper( $function, $atts, $wrapper ); + _deprecated_function( 'Woocommerce->shortcode_wrapper', '2.1', 'WC_Shortcodes::shortcode_wrapper' ); + return WC_Shortcodes::shortcode_wrapper( $function, $atts, $wrapper ); } // Deprecated 2.1.0 Access via the WC_Attribute_Helper helper @@ -957,22 +916,14 @@ final class WooCommerce { return wc_get_coupon_type( $type ); } - // Deprecated 2.1.0 Access via the WC_Post_Class_Helper helper - public function post_class( $classes, $class, $post_id ) { - _deprecated_function( 'Woocommerce->post_class', '2.1', 'WC_Post_Class_Helper->post_class' ); - return $this->get_helper( 'post-class' )->post_class( $classes, $class, $post_id ); - } - // Deprecated 2.1.0 Access via the WC_Body_Class_Helper helper public function add_body_class( $class ) { - _deprecated_function( 'Woocommerce->add_body_class', '2.1', 'WC_Body_Class_Helper->add_body_class' ); - $this->get_helper( 'body-class' )->add_body_class( $class ); + _deprecated_function( 'Woocommerce->add_body_class', '2.1' ); } // Deprecated 2.1.0 Access via the WC_Body_Class_Helper helper public function output_body_class( $classes ) { - _deprecated_function( 'Woocommerce->output_body_class', '2.1', 'WC_Body_Class_Helper->output_body_class' ); - return $this->get_helper( 'body-class' )->output_body_class( $classes ); + _deprecated_function( 'Woocommerce->output_body_class', '2.1' ); } // Deprecated 2.1.0 Access via the WC_Template_Helper helper