/** * Returns the price including or excluding tax, based on the 'woocommerce_tax_display_shop' setting. * Should be safe to remove when we drop WC 2.2 compatibility * * @param WC_Product $product the product object * @param string $price to calculate, left blank to just use get_price() * @param integer $qty passed on to get_price_including_tax() or get_price_excluding_tax() * @return string */ public static function get_product_display_price($product, $price = '', $qty = 1) { if (SV_WC_Plugin_Compatibility::is_wc_version_gte_2_3()) { return $product->get_display_price($price, $qty); } else { if ($price === '') { $price = $product->get_price(); } $tax_display_mode = get_option('woocommerce_tax_display_shop'); $display_price = $tax_display_mode == 'incl' ? $product->get_price_including_tax($qty, $price) : $product->get_price_excluding_tax($qty, $price); return $display_price; } }
/** * Get settings array * * @since 1.0.0 * @param string $current_section Optional. Defaults to empty string. * @return array Array of settings */ public function get_settings($current_section = '') { if ('products' == $current_section) { /** * Filter Memberships products Settings * * @since 1.0.0 * @param array $settings Array of the plugin settings */ $settings = apply_filters('wc_memberships_products_settings', array(array('name' => __('Products', WC_Memberships::TEXT_DOMAIN), 'type' => 'title', 'desc' => '', 'id' => 'memberships_products_options'), array('type' => 'checkbox', 'id' => 'wc_memberships_hide_restricted_products', 'name' => __('Hide restricted products', WC_Memberships::TEXT_DOMAIN), 'desc' => __('If enabled, products with viewing restricted will be hidden from the shop catalog. Products will still be accessible directly, unless Content Restriction Mode is "Hide completely".', WC_Memberships::TEXT_DOMAIN), 'default' => 'no'), array('type' => 'sectionend', 'id' => 'memberships_products_options'), array('name' => __('Product Restriction Messages', WC_Memberships::TEXT_DOMAIN), 'type' => 'title', 'desc' => sprintf(__('%s automatically inserts the product(s) needed to gain access. %s inserts the URL to my account page with the login form. HTML is allowed.', WC_Memberships::TEXT_DOMAIN), '<code>{products}</code>', '<code>{login_url}</code>'), 'id' => 'memberships_product_messages'), array('type' => 'textarea', 'id' => 'wc_memberships_product_viewing_restricted_message', 'class' => 'input-text wide-input', 'name' => __('Product Viewing Restricted - Purchase Required', WC_Memberships::TEXT_DOMAIN), 'desc' => __('Displays when purchase is required to view the product.', WC_Memberships::TEXT_DOMAIN), 'default' => __('This product can only be viewed by members. To view or purchase this product, sign up by purchasing {products}.', WC_Memberships::TEXT_DOMAIN), 'desc_tip' => __('Message displayed if viewing is restricted to members but access can be purchased.', WC_Memberships::TEXT_DOMAIN)), array('type' => 'textarea', 'id' => 'wc_memberships_product_viewing_restricted_message_no_products', 'class' => 'input-text wide-input', 'name' => __('Product Viewing Restricted - Membership Required', WC_Memberships::TEXT_DOMAIN), 'desc' => __('Displays if viewing is restricted to a membership that cannot be purchased.', WC_Memberships::TEXT_DOMAIN), 'default' => __('This product can only be viewed by members.', WC_Memberships::TEXT_DOMAIN), 'desc_tip' => __('Message displayed if viewing is restricted to members and no products can grant access.', WC_Memberships::TEXT_DOMAIN)), array('type' => 'textarea', 'id' => 'wc_memberships_product_purchasing_restricted_message', 'class' => 'input-text wide-input', 'name' => __('Product Buying Restricted - Purchase Required', WC_Memberships::TEXT_DOMAIN), 'desc' => __('Displays when purchase is required to buy the product.', WC_Memberships::TEXT_DOMAIN), 'default' => __('This product can only be purchased by members. To purchase this product, sign up by purchasing {products}.', WC_Memberships::TEXT_DOMAIN), 'desc_tip' => __('Message displayed if purchasing is restricted to members but access can be purchased.', WC_Memberships::TEXT_DOMAIN)), array('type' => 'textarea', 'id' => 'wc_memberships_product_purchasing_restricted_message_no_products', 'class' => 'input-text wide-input', 'name' => __('Product Buying Restricted - Membership Required', WC_Memberships::TEXT_DOMAIN), 'desc' => __('Displays if purchasing is restricted to a membership that cannot be purchased.', WC_Memberships::TEXT_DOMAIN), 'default' => __('This product can only be purchased by members.', WC_Memberships::TEXT_DOMAIN), 'desc_tip' => __('Message displayed if purchasing is restricted to members and no products can grant access.', WC_Memberships::TEXT_DOMAIN)), array('type' => 'textarea', 'id' => 'wc_memberships_product_discount_message', 'class' => 'input-text wide-input', 'name' => __('Product Discounted - Purchase Required', WC_Memberships::TEXT_DOMAIN), 'desc' => __('Message displayed to non-members if the product has a member discount.', WC_Memberships::TEXT_DOMAIN), 'default' => __('Want a discount? Become a member by purchasing {products}.', WC_Memberships::TEXT_DOMAIN), 'desc_tip' => __('Displays below add to cart buttons. Leave blank to disable.', WC_Memberships::TEXT_DOMAIN)), array('type' => 'textarea', 'id' => 'wc_memberships_product_discount_message_no_products', 'class' => 'input-text wide-input', 'name' => __('Product Discounted - Membership Required', WC_Memberships::TEXT_DOMAIN), 'desc' => __('Message displayed to non-members if the product has a member discount, but no products can grant access.', WC_Memberships::TEXT_DOMAIN), 'default' => __('Want a discount? Become a member.', WC_Memberships::TEXT_DOMAIN), 'desc_tip' => __('Displays below add to cart buttons. Leave blank to disable.', WC_Memberships::TEXT_DOMAIN)), array('type' => 'sectionend', 'id' => 'memberships_product_messages'))); } else { /** * Filter Memberships general Settings * * @since 1.0.0 * @param array $settings Array of the plugin settings */ $settings = apply_filters('wc_memberships_general_settings', array(array('name' => __('General', WC_Memberships::TEXT_DOMAIN), 'type' => 'title', 'desc' => '', 'id' => 'memberships_options'), array('type' => 'select', 'id' => 'wc_memberships_restriction_mode', 'name' => __('Content Restriction Mode', WC_Memberships::TEXT_DOMAIN), 'options' => array('hide' => __('Hide completely', WC_Memberships::TEXT_DOMAIN), 'hide_content' => __('Hide content only', WC_Memberships::TEXT_DOMAIN), 'redirect' => __('Redirect to page', WC_Memberships::TEXT_DOMAIN)), 'class' => SV_WC_Plugin_Compatibility::is_wc_version_gte_2_3() ? 'wc-enhanced-select' : 'wc-memberships-chosen_select', 'desc_tip' => __('Specifies the way content is restricted: whether to show nothing, excerpts, or send to a landing page.', WC_Memberships::TEXT_DOMAIN), 'desc' => __('"Hide completely" removes all traces of content for non-members and search engines and 404s restricted pages.<br />"Hide content only" will show items in archives, but protect page or post content and comments.', WC_Memberships::TEXT_DOMAIN), 'default' => 'hide_content'), array('title' => __('Redirect Page', WC_Memberships::TEXT_DOMAIN), 'desc' => __('Select the page to redirect non-members to - should contain the [wcm_content_restricted] shortcode.', WC_Memberships::TEXT_DOMAIN), 'id' => 'wc_memberships_redirect_page_id', 'type' => 'single_select_page', 'class' => SV_WC_Plugin_Compatibility::is_wc_version_gte_2_3() ? 'wc-enhanced-select-nostd js-redirect-page' : 'wc-memberships-chosen_select_nostd js-redirect-page', 'css' => 'min-width:300px;', 'desc_tip' => true), array('type' => 'checkbox', 'id' => 'wc_memberships_show_excerpts', 'name' => __('Show Excerpts', WC_Memberships::TEXT_DOMAIN), 'desc' => __('If enabled, an excerpt of the protected content will be displayed to non-members & search engines.', WC_Memberships::TEXT_DOMAIN), 'default' => 'yes'), array('type' => 'select', 'id' => 'wc_memberships_display_member_login_notice', 'name' => __('Show Member Login Notice', WC_Memberships::TEXT_DOMAIN), 'options' => array('never' => __('Never', WC_Memberships::TEXT_DOMAIN), 'cart' => __('On Cart Page', WC_Memberships::TEXT_DOMAIN), 'checkout' => __('On Checkout Page', WC_Memberships::TEXT_DOMAIN), 'both' => __('On both Cart & Checkout Page', WC_Memberships::TEXT_DOMAIN)), 'class' => SV_WC_Plugin_Compatibility::is_wc_version_gte_2_3() ? 'wc-enhanced-select' : 'wc-memberships-chosen_select', 'desc_tip' => __('Select when & where to display login reminder notice for guests if products in cart have member discounts.', WC_Memberships::TEXT_DOMAIN), 'default' => 'both'), array('type' => 'sectionend', 'id' => 'memberships_options'), array('title' => __('Content Restricted Messages', WC_Memberships::TEXT_DOMAIN), 'type' => 'title', 'desc' => sprintf(__('%s automatically inserts the product(s) needed to gain access. %s inserts the URL to my account page with the login form. HTML is allowed.', WC_Memberships::TEXT_DOMAIN), '<code>{products}</code>', '<code>{login_url}</code>'), 'id' => 'memberships_restriction_messages'), array('type' => 'textarea', 'id' => 'wc_memberships_content_restricted_message', 'class' => 'input-text wide-input', 'name' => __('Content Restricted - Purchase Required', WC_Memberships::TEXT_DOMAIN), 'desc' => __('Displays when purchase is required to view the content.', WC_Memberships::TEXT_DOMAIN), 'default' => __('To access this content, you must purchase {products}.', WC_Memberships::TEXT_DOMAIN), 'desc_tip' => __('Message displayed if visitor does not have access to content, but can purchase it.', WC_Memberships::TEXT_DOMAIN)), array('type' => 'textarea', 'id' => 'wc_memberships_content_restricted_message_no_products', 'class' => 'input-text wide-input', 'name' => __('Content Restricted - Membership Required', WC_Memberships::TEXT_DOMAIN), 'desc' => __('Displays if the content is restricted to a membership that cannot be purchased.', WC_Memberships::TEXT_DOMAIN), 'default' => __('This content is only available to members.', WC_Memberships::TEXT_DOMAIN), 'desc_tip' => __('Message displayed if visitor does not have access to content and no products can grant access.', WC_Memberships::TEXT_DOMAIN)), array('type' => 'sectionend', 'id' => 'memberships_restriction_messages'))); } /** * Filter Memberships Settings * * @since 1.0.0 * @param array $settings Array of the plugin settings */ return apply_filters('woocommerce_get_settings_' . $this->id, $settings, $current_section); }
/** * Add original transaction ID for capturing a prior authorization * * @since 3.0 * @param WC_Order $order order object * @return WC_Order object with payment and transaction information attached */ protected function get_order_for_capture($order) { $order = parent::get_order_for_capture($order); $order->auth_net_aim_ref_trans_id = SV_WC_Plugin_Compatibility::get_order_custom_field($order, 'wc_authorize_net_aim_trans_id'); $order->description = sprintf(__('%s - Capture for Order %s', $this->text_domain), esc_html(get_bloginfo('name')), $order->get_order_number()); return $order; }
/** * Constructor * * Set up membership emails * * @since 1.0.0 */ public function __construct() { add_filter('woocommerce_email_classes', array($this, 'memberships_emails')); if (SV_WC_Plugin_Compatibility::is_wc_version_gte_2_3()) { add_action('wc_memberships_new_user_membership_note', array('WC_Emails', 'send_transactional_email'), 10, 10); } else { add_action('wc_memberships_new_user_membership_note', array(WC(), 'send_transactional_email'), 10, 10); } }
/** * Construct and initialize the price calculator settings * * @param mixed $settings optional product or product id to load settings from. Otherwise, default settings object is instantiated */ public function __construct($product = null) { $settings = null; // product id if (is_numeric($product)) { $product = SV_WC_Plugin_Compatibility::wc_get_product($product); } // have a product if ($product) { $this->product = $product; $settings = WC_Price_Calculator_Product::get_product_meta($product, 'wc_price_calculator'); } $this->set_raw_settings($settings); }
/** * Pluggable function to render the checkout page payment fields form * * @since 3.0 * @param WC_Gateway_Authorize_Net_AIM_Credit_Card $gateway gateway object */ function woocommerce_authorize_net_aim_echeck_payment_fields($gateway) { // safely display the description, if there is one if ($gateway->get_description()) { echo '<p>' . wp_kses_post($gateway->get_description()) . '</p>'; } $payment_method_defaults = array('account-number' => '', 'routing-number' => ''); // for the test environment, display a notice and supply a default test payment method if ($gateway->is_environment('test')) { echo '<p>' . __('TEST MODE ENABLED', WC_Authorize_Net_AIM::TEXT_DOMAIN) . '</p>'; $payment_method_defaults = array('account-number' => '8675309', 'routing-number' => '031202084'); } // load the payment fields template file woocommerce_get_template('checkout/authorize-net-aim-echeck-payment-fields.php', array('payment_method_defaults' => $payment_method_defaults, 'sample_check_image_url' => SV_WC_Plugin_Compatibility::force_https_url($gateway->get_plugin()->get_plugin_url()) . '/' . $gateway->get_plugin()->get_framework_image_path() . 'example-check.png', 'states' => SV_WC_Plugin_Compatibility::WC()->countries->get_states('US')), '', $gateway->get_plugin()->get_plugin_path() . '/templates/'); }
/** * Adds support for subscriptions by hooking in some necessary actions * * @since 4.1.0 */ public function add_support() { $this->get_gateway()->add_support(array('subscriptions', 'subscription_suspension', 'subscription_cancellation', 'subscription_reactivation', 'subscription_amount_changes', 'subscription_date_changes', 'multiple_subscriptions', 'subscription_payment_method_change_customer', 'subscription_payment_method_change_admin')); // 2.0.x hooks if (SV_WC_Plugin_Compatibility::is_wc_subscriptions_version_gte_2_0()) { // force tokenization when needed add_filter('wc_payment_gateway_' . $this->get_gateway()->get_id() . '_tokenization_forced', array($this, 'maybe_force_tokenization')); // save token/customer ID to subscription objects add_action('wc_payment_gateway_' . $this->get_gateway()->get_id() . '_add_transaction_data', array($this, 'save_payment_meta'), 10, 2); // process renewal payments add_action('woocommerce_scheduled_subscription_payment_' . $this->get_gateway()->get_id(), array($this, 'process_renewal_payment'), 10, 2); // update the customer/token ID on the subscription when updating a previously failing payment method add_action('woocommerce_subscription_failing_payment_method_updated_' . $this->get_gateway()->get_id(), array($this, 'update_failing_payment_method'), 10, 2); // display the current payment method used for a subscription in the "My Subscriptions" table add_filter('woocommerce_my_subscriptions_payment_method', array($this, 'maybe_render_payment_method'), 10, 3); // don't copy over order-specific meta to the WC_Subscription object during renewal processing add_filter('wcs_renewal_order_meta', array($this, 'do_not_copy_order_meta')); // remove order-specific meta from the Subscription object after the change payment method action add_filter('woocommerce_subscriptions_process_payment_for_change_method_via_pay_shortcode', array($this, 'remove_order_meta_from_change_payment'), 10, 2); // don't copy over order-specific meta to the new WC_Subscription object during upgrade to 2.0.x add_filter('wcs_upgrade_subscription_meta_to_copy', array($this, 'do_not_copy_order_meta_during_upgrade')); // allow concrete gateways to define additional order-specific meta keys to exclude if (is_callable(array($this->get_gateway(), 'subscriptions_get_excluded_order_meta_keys'))) { add_filter('wc_payment_gateway_' . $this->get_gateway()->get_id() . '_subscriptions_order_specific_meta_keys', array($this->get_gateway(), 'subscriptions_get_excluded_order_meta_keys')); } /* My Payment Methods */ add_filter('wc_' . $this->get_gateway()->get_plugin()->get_id() . '_my_payment_methods_table_headers', array($this, 'add_my_payment_methods_table_header'), 10, 2); add_filter('wc_' . $this->get_gateway()->get_plugin()->get_id() . '_my_payment_methods_table_body_row_data', array($this, 'add_my_payment_methods_table_body_row_data'), 10, 3); add_filter('wc_' . $this->get_gateway()->get_plugin()->get_id() . '_my_payment_methods_table_method_actions', array($this, 'disable_my_payment_methods_table_method_delete'), 10, 3); /* Admin Change Payment Method support */ // framework defaults - payment_token and customer_id add_filter('woocommerce_subscription_payment_meta', array($this, 'admin_add_payment_meta'), 9, 2); add_action('woocommerce_subscription_validate_payment_meta_' . $this->get_gateway()->get_id(), array($this, 'admin_validate_payment_meta'), 9); // allow concrete gateways to add/change defaults if (is_callable(array($this->get_gateway(), 'subscriptions_admin_add_payment_meta'))) { add_filter('woocommerce_subscription_payment_meta', array($this->get_gateway(), 'subscriptions_admin_add_payment_meta'), 10, 2); } // allow concrete gateways to perform additional validation if (is_callable(array($this->get_gateway(), 'subscriptions_admin_validate_payment_meta'))) { add_action('woocommerce_subscription_validate_payment_meta_' . $this->get_gateway()->get_id(), array($this->get_gateway(), 'subscriptions_admin_validate_payment_meta'), 10); } } else { // 1.5.x $this->add_support_1_5(); } }
/** * Get the most reviewed products * * @since 1.0.0 * @return array */ public function get_products() { global $wpdb; $reviewed_products = array(); $results = $wpdb->get_results("\n\t\t\tSELECT p.ID, c.review_count, c2.highest_rating, c2.lowest_rating\n\t\t\tFROM {$wpdb->posts} AS p\n\t\t\tLEFT JOIN ( SELECT comment_post_ID, COUNT(comment_ID) AS review_count\n\t\t\t\tFROM {$wpdb->comments}\n\t\t\t\tWHERE comment_type = 'review'\n\t\t\t\tAND comment_approved = '1'\n\t\t\t\tGROUP BY comment_post_ID\n\t\t\t) AS c ON ( c.comment_post_ID = p.ID )\n\t\t\tJOIN ( SELECT comment_post_ID, MAX(meta_value) AS highest_rating, MIN(meta_value) AS lowest_rating\n\t\t\t\tFROM {$wpdb->comments} c\n\t\t\t\tLEFT JOIN {$wpdb->commentmeta} cm\n\t\t\t\tON cm.comment_id = c.comment_ID\n\t\t\t\tWHERE comment_type = 'review'\n\t\t\t\tAND meta_key = 'rating'\n\t\t\t\tAND comment_approved = '1'\n\t\t\t\tGROUP BY comment_post_ID\n\t\t\t) AS c2 ON( c2.comment_post_ID = p.ID )\n\t\t\tWHERE p.post_type = 'product'\n\t\t\tAND c.review_count > 0\n\t\t\tGROUP BY p.ID\n\t\t\tORDER BY c.review_count DESC\n\t\t"); if (!empty($results)) { foreach ($results as $key => $result) { $product = SV_WC_Plugin_Compatibility::wc_get_product($result->ID); $reviewed_products[$key] = $product; $reviewed_products[$key]->review_count = $result->review_count; $reviewed_products[$key]->highest_rating = $result->highest_rating; $reviewed_products[$key]->lowest_rating = $result->lowest_rating; $reviewed_products[$key]->average_rating = $product->get_average_rating(); } } return $reviewed_products; }
/** * Pluggable function to render social login "link your account" buttons * * @since 1.1.0 * @param string $return_url Return url, defaults my account page */ function woocommerce_social_login_link_account_buttons($return_url = null) { if (!is_user_logged_in()) { return; } // If no return_url, use the my account page if (!$return_url) { $return_url = SV_WC_Plugin_Compatibility::wc_get_page_permalink('myaccount'); } // Enqueue styles and scripts wc_social_login()->frontend->load_styles_scripts(); $available_providers = array(); // determine available providers for user foreach (wc_social_login()->get_available_providers() as $provider) { if (!get_user_meta(get_current_user_id(), '_wc_social_login_' . $provider->get_id() . '_profile', true)) { $available_providers[] = $provider; } } // load the template wc_get_template('global/social-login-link-account.php', array('available_providers' => $available_providers, 'return_url' => $return_url), '', wc_social_login()->get_plugin_path() . '/templates/'); }
/** * Output a pricing table * * * product_id/product_sku - id or sku of product. Defaults to current product, if any * * Usage: * [wc_measurement_price_calculator_pricing_table] * * @param array $atts associative array of shortcode parameters */ public static function output($atts) { global $product, $wpdb; extract(shortcode_atts(array('product_id' => '', 'product_sku' => ''), $atts)); // product by sku? if ($product_sku) { $product_id = $wpdb->get_var($wpdb->prepare("SELECT post_id FROM {$wpdb->postmeta} WHERE meta_key='_sku' AND meta_value=%s LIMIT 1", $product_sku)); } // product by id? if ($product_id) { $product = SV_WC_Plugin_Compatibility::wc_get_product($product_id); } // product ? if (!$product) { return; } // pricing rules? $settings = new WC_Price_Calculator_Settings($product); if (!$settings->pricing_rules_enabled() || !$settings->has_pricing_rules()) { return; } // the countdown element with a unique identifier to allow multiple countdowns on the same page, and common class for ease of styling echo self::get_pricing_rules_table($settings->get_pricing_rules($settings->get_pricing_unit()), $settings); }
/** * Redirect back to the My Account page * * @since 4.0.0 */ protected function redirect_to_my_account() { wp_redirect(SV_WC_Plugin_Compatibility::wc_get_page_permalink('myaccount')); exit; }
/** * Add add-on meta to order row label for display purposes in * order edit screen. * * @since 1.0 * @param string $safe_text * @param string $text * @return string Escaped or unescaped text */ public function append_add_on_fee_meta($safe_text, $text) { if (SV_WC_Plugin_Compatibility::is_wc_version_lt_2_2() && !empty($this->formatted_names)) { foreach ($this->formatted_names as $name => $formatted_name) { if ($text == $name) { $safe_text = $formatted_name; unset($this->formatted_names[$name]); } } } return $safe_text; }
/** * Mark the given order as cancelled and set the order note * * @since 2.1.0 * @param WC_Order $order the order * @param string $message a message to display inside the "Payment Cancelled" order note * @param SV_WC_Payment_Gateway_API_Response optional $response the transaction response object */ protected function mark_order_as_cancelled($order, $message, $response = null) { $order_note = sprintf(_x('%s Transaction Cancelled (%s)', 'Cancelled order note', $this->text_domain), $this->get_method_title(), $message); // Mark order as cancelled if not already set if (!SV_WC_Plugin_Compatibility::order_has_status($order, 'cancelled')) { $order->update_status('cancelled', $order_note); } else { $order->add_order_note($order_note); } $this->add_debug_message($message, 'error'); }
/** * Entry method for the Add Payment Method feature flow. Note this is *not* * stubbed in the WC_Payment_Gateway abstract class, but is called if the * gateway declares support for it. * * @since 4.0.0 */ public function add_payment_method() { assert($this->supports_add_payment_method()); $order = $this->get_order_for_add_payment_method(); try { $result = $this->do_add_payment_method_transaction($order); } catch (SV_WC_Plugin_Exception $e) { $result = array('message' => sprintf(esc_html__('Oops, adding your new payment method failed: %s', 'woocommerce-plugin-framework'), $e->getMessage()), 'success' => false); } SV_WC_Helper::wc_add_notice($result['message'], $result['success'] ? 'success' : 'error'); // if successful, redirect to the newly added method if ($result['success']) { // if this is WooCommerce 2.5.5 or older, redirect to the My Account page if (SV_WC_Plugin_Compatibility::is_wc_version_lt_2_6()) { $redirect_url = wc_get_page_permalink('myaccount'); // otherwise, redirect to the Payment Methods page (WC 2.6+) } else { $redirect_url = wc_get_account_endpoint_url('payment-methods'); } // otherwise, back to the Add Payment Method page } else { $redirect_url = wc_get_endpoint_url('add-payment-method'); } wp_safe_redirect($redirect_url); exit; }
/** * Get the order data format for a single column per line item, compatible with the CSV Import Suite plugin * * @since 3.0 * @param array $order_data an array of order data for the given order * @param WC_Order $order the WC_Order object * @return array modified order data */ private function get_legacy_import_one_column_per_line_item($order_data, WC_Order $order) { $count = 1; // add line items foreach ($order->get_items() as $_ => $item) { // sku/qty/price $product = $order->get_product_from_item($item); if (!is_object($product)) { $product = new WC_Product(0); } $sku = $product->get_sku(); // note that product ID must be prefixed with `product_id:` so the importer can properly parse it vs. the SKU $product_id = SV_WC_Plugin_Compatibility::product_get_id($product); $line_item = array($sku ? $sku : "product_id:{$product_id}", $item['qty'], $order->get_line_total($item)); // Add item meta $item_meta = new WC_Order_Item_Meta($item); $formatted_meta = $item_meta->get_formatted(); if (!empty($formatted_meta)) { foreach ($formatted_meta as $meta_key => $meta) { // remove newlines $label = str_replace(array("\r", "\r\n", "\n"), '', $meta['label']); $value = str_replace(array("\r", "\r\n", "\n"), '', $meta['value']); // escape reserved chars (:;|) $label = str_replace(array(': ', ':', ';', '|'), array('\\: ', '\\:', '\\;', '\\|'), $meta['label']); $value = str_replace(array(': ', ':', ';', '|'), array('\\: ', '\\:', '\\;', '\\|'), $meta['value']); $line_item[] = wp_kses_post($label . ': ' . $value); } } $order_data["order_item_{$count}"] = implode('|', $line_item); $count++; } $count = 1; foreach ($order->get_items('shipping') as $_ => $shipping_item) { $order_data["shipping_method_{$count}"] = $shipping_item['method_id']; $order_data["shipping_cost_{$count}"] = wc_format_decimal($shipping_item['cost'], 2); $count++; } // fix order numbers $order_data['order_id'] = $order->id; $order_data['order_number_formatted'] = get_post_meta($order->id, '_order_number_formatted', true); $order_data['order_number'] = get_post_meta($order->id, '_order_number', true); // fix customer user $user = new WP_User($order_data['customer_id']); $order_data['customer_id'] = $user->user_email; return $order_data; }
/** * Include admin scripts */ public function admin_scripts() { wp_enqueue_style('woocommerce_admin_styles', SV_WC_Plugin_Compatibility::WC()->plugin_url() . '/assets/css/admin.css'); wp_register_style('woocommerce-csv_importer', $this->get_plugin_url() . '/assets/css/admin/wc-customer-order-csv-import.css', '', '1.0.0', 'screen'); wp_enqueue_style('woocommerce-csv_importer'); }
/** * Get renew membership URL for frontend * * @since 1.0 * @return string Renew URL */ public function get_renew_membership_url() { $renew_endpoint = SV_WC_Plugin_Compatibility::wc_get_page_permalink('myaccount'); if (false === strpos($renew_endpoint, '?')) { $renew_endpoint = trailingslashit($renew_endpoint); } /** * Filter the renew membership URL * * @since 1.0.0 * @param string $url * @param WC_Memberships_User_Membership $user_membership */ return apply_filters('wc_memberships_get_renew_membership_url', wp_nonce_url(add_query_arg(array('renew_membership' => 'true', 'user_membership_id' => $this->get_id()), $renew_endpoint), 'wc_memberships-renew_membership'), $this); }
/** * Entry method for the Add Payment Method feature flow. Note this is *not* * stubbed in the WC_Payment_Gateway abstract class, but is called if the * gateway declares support for it. * * @since 4.0.0 */ public function add_payment_method() { assert($this->supports_add_payment_method()); $order = $this->get_order_for_add_payment_method(); try { $result = $this->do_add_payment_method_transaction($order); } catch (SV_WC_Plugin_Exception $e) { $result = array('message' => sprintf(__('Oops, adding your new payment method failed: %s', $this->text_domain), $e->getMessage()), 'success' => false); } SV_WC_Helper::wc_add_notice($result['message'], $result['success'] ? 'success' : 'error'); // redirect to my account on success, or back to Add Payment Method screen on failure so user can try again wp_safe_redirect($result['success'] ? SV_WC_Plugin_Compatibility::wc_get_page_permalink('myaccount') : wc_get_endpoint_url('add-payment-method')); exit; }
/** * Saves errors or messages to WooCommerce Log (woocommerce/logs/plugin-id-xxx.txt) * * @since 2.0 * @param string $message error or message to save to log * @param string $log_id optional log id to segment the files by, defaults to plugin id */ public function log($message, $log_id = null) { if (is_null($log_id)) { $log_id = $this->get_id(); } if (!is_object($this->logger)) { $this->logger = SV_WC_Plugin_Compatibility::new_wc_logger(); } $this->logger->add($log_id, $message); }
/** * Get order line items (products) in a neatly-formatted array of objects * with properties: * * + id - item ID * + name - item name, usually product title, processed through htmlentities() * + description - formatted item meta (e.g. Size: Medium, Color: blue), processed through htmlentities() * + quantity - item quantity * + item_total - item total (line total divided by quantity, excluding tax & rounded) * + line_total - line item total (excluding tax & rounded) * + meta - formatted item meta array * + product - item product or null if getting product from item failed * + item - raw item array * * @since 3.0.0 * @param \WC_Order $order * @return array */ public static function get_order_line_items($order) { $line_items = array(); foreach ($order->get_items() as $id => $item) { $line_item = new stdClass(); $product = $order->get_product_from_item($item); $meta = SV_WC_Plugin_Compatibility::is_wc_version_gte_2_4() ? $item : $item['item_meta']; // get meta + format it $item_meta = new WC_Order_Item_Meta($meta); $item_meta = $item_meta->get_formatted(); if (!empty($item_meta)) { $item_desc = array(); foreach ($item_meta as $meta) { $item_desc[] = sprintf('%s: %s', $meta['label'], $meta['value']); } $item_desc = implode(', ', $item_desc); } else { // default description to SKU $item_desc = is_callable(array($product, 'get_sku')) && $product->get_sku() ? sprintf('SKU: %s', $product->get_sku()) : null; } $line_item->id = $id; $line_item->name = htmlentities($item['name'], ENT_QUOTES, 'UTF-8', false); $line_item->description = htmlentities($item_desc, ENT_QUOTES, 'UTF-8', false); $line_item->quantity = $item['qty']; $line_item->item_total = isset($item['recurring_line_total']) ? $item['recurring_line_total'] : $order->get_item_total($item); $line_item->line_total = $order->get_line_total($item); $line_item->meta = $item_meta; $line_item->product = is_object($product) ? $product : null; $line_item->item = $item; $line_items[] = $line_item; } return $line_items; }
/** * Create new orders based on the parsed data */ private function process_orders() { global $wpdb; $this->imported = $this->merged = 0; // peforming a dry run? $dry_run = isset($_POST['dry_run']) && $_POST['dry_run'] ? true : false; $this->log->add('---'); $this->log->add(__('Processing orders.', WC_Customer_CSV_Import_Suite::TEXT_DOMAIN)); foreach ($this->posts as $post) { // orders with custom order order numbers can be checked for existance, otherwise there's not much we can do if (!empty($post['order_number_formatted']) && isset($this->processed_posts[$post['order_number_formatted']])) { $this->skipped++; $this->log->add(sprintf(__('> Order %s already processed. Skipping.', WC_Customer_CSV_Import_Suite::TEXT_DOMAIN), $post['order_number_formatted']), true); continue; } // see class-wc-checkout.php for reference $order_data = array('post_date' => date('Y-m-d H:i:s', $post['date']), 'post_type' => 'shop_order', 'post_title' => 'Order – ' . date('F j, Y @ h:i A', $post['date']), 'post_status' => 'publish', 'ping_status' => 'closed', 'post_excerpt' => $post['order_comments'], 'post_author' => 1, 'post_password' => uniqid('order_')); if (!$dry_run) { // track whether download permissions need to be granted $add_download_permissions = false; $order_id = wp_insert_post($order_data); if (is_wp_error($order_id)) { $this->errored++; $this->log->add(sprintf(__('> Error inserting %s: %s', WC_Customer_CSV_Import_Suite::TEXT_DOMAIN), $post['order_number_formatted'], $order_id->get_error_message()), true); } // empty update to bump up the post_modified date to today's date (otherwise it would match the post_date, which isn't quite right) wp_update_post(array('ID' => $order_id)); // set order status wp_set_object_terms($order_id, $post['status'], 'shop_order_status'); // handle special meta fields update_post_meta($order_id, '_order_key', apply_filters('woocommerce_generate_order_key', uniqid('order_'))); update_post_meta($order_id, '_order_currency', get_woocommerce_currency()); // TODO: fine to use store default? if (!SV_WC_Plugin_Compatibility::is_wc_version_gte_2_1()) { update_post_meta($order_id, '_order_taxes', array()); // pre-2.1 } update_post_meta($order_id, '_prices_include_tax', get_option('woocommerce_prices_include_tax')); // add order postmeta foreach ($post['postmeta'] as $meta) { $meta_processed = false; // we don't set the "download permissions granted" meta, we call the woocommerce function to take care of this for us if (('Download Permissions Granted' == $meta['key'] || '_download_permissions_granted' == $meta['key']) && $meta['value']) { $add_download_permissions = true; $meta_processed = true; } if (!$meta_processed) { update_post_meta($order_id, $meta['key'], $meta['value']); } // set the paying customer flag on the user meta if applicable if ('_customer_user' == $meta['key'] && $meta['value'] && in_array($post['status'], array('processing', 'completed', 'refunded'))) { update_user_meta($meta['value'], "paying_customer", 1); } } // handle order items $order_items = array(); $order_item_meta = null; foreach ($post['order_items'] as $item) { $product = null; $variation_item_meta = array(); // if there's a product_id then we've already determined during parsing that this product exists if ($item['product_id']) { $product = get_product($item['product_id']); // handle variations if (($product->is_type('variable') || $product->is_type('variation') || $product->is_type('subscription_variation')) && method_exists($product, 'get_variation_id')) { foreach ($product->get_variation_attributes() as $key => $value) { $variation_item_meta[] = array('meta_name' => esc_attr(substr($key, 10)), 'meta_value' => $value); // remove the leading 'attribute_' from the name to get 'pa_color' for instance } } } // order item $order_items[] = array('order_item_name' => $product ? $product->get_title() : __('Unknown Product', WC_Customer_CSV_Import_Suite::TEXT_DOMAIN), 'order_item_type' => 'line_item'); // standard order item meta $_order_item_meta = array('_qty' => (int) $item['qty'], '_tax_class' => '', '_product_id' => $item['product_id'], '_variation_id' => $product && method_exists($product, 'get_variation_id') ? $product->get_variation_id() : 0, '_line_subtotal' => number_format((double) $item['total'], 2, '.', ''), '_line_subtotal_tax' => 0, '_line_total' => number_format((double) $item['total'], 2, '.', ''), '_line_tax' => 0); // add any product variation meta foreach ($variation_item_meta as $meta) { $_order_item_meta[$meta['meta_name']] = $meta['meta_value']; } // include any arbitrary order item meta $_order_item_meta = array_merge($_order_item_meta, $item['meta']); $order_item_meta[] = $_order_item_meta; } foreach ($order_items as $key => $order_item) { $order_item_id = woocommerce_add_order_item($order_id, $order_item); if ($order_item_id) { foreach ($order_item_meta[$key] as $meta_key => $meta_value) { if (strpos($meta_value, ':{i')) { $meta_value = unserialize(stripslashes($meta_value)); //'a:1:{i:0;s:19:"2014-05-01 08:00:00";}'; } woocommerce_add_order_item_meta($order_item_id, $meta_key, $meta_value); } } } // create the shipping order items (WC 2.1+) foreach ($post['order_shipping'] as $order_shipping) { $shipping_order_item = array('order_item_name' => $order_shipping['title'], 'order_item_type' => 'shipping'); $shipping_order_item_id = woocommerce_add_order_item($order_id, $shipping_order_item); if ($shipping_order_item_id) { woocommerce_add_order_item_meta($shipping_order_item_id, 'method_id', $order_shipping['method_id']); woocommerce_add_order_item_meta($shipping_order_item_id, 'cost', $order_shipping['cost']); } } // create the tax order items (WC 2.1+) foreach ($post['tax_items'] as $tax_item) { $tax_order_item = array('order_item_name' => $tax_item['title'], 'order_item_type' => 'tax'); $tax_order_item_id = woocommerce_add_order_item($order_id, $tax_order_item); if ($tax_order_item_id) { woocommerce_add_order_item_meta($tax_order_item_id, 'rate_id', $tax_item['rate_id']); woocommerce_add_order_item_meta($tax_order_item_id, 'label', $tax_item['label']); woocommerce_add_order_item_meta($tax_order_item_id, 'compound', $tax_item['compound']); woocommerce_add_order_item_meta($tax_order_item_id, 'tax_amount', $tax_item['tax_amount']); woocommerce_add_order_item_meta($tax_order_item_id, 'shipping_tax_amount', $tax_item['shipping_tax_amount']); } } // Grant downloadalbe product permissions if ($add_download_permissions) { woocommerce_downloadable_product_permissions($order_id); } // add order notes $order = new WC_Order($order_id); foreach ($post['notes'] as $order_note) { $order->add_order_note($order_note); } // record the product sales $order->record_product_sales(); } // ! dry run // was an original order number provided? if (!empty($post['order_number_formatted'])) { if (!$dry_run) { // do our best to provide some custom order number functionality while also allowing 3rd party plugins to provide their own custom order number facilities do_action('woocommerce_set_order_number', $order, $post['order_number'], $post['order_number_formatted']); $order->add_order_note(sprintf(__("Original order #%s", WC_Customer_CSV_Import_Suite::TEXT_DOMAIN), $post['order_number_formatted'])); // get the order so we can display the correct order number $order = new WC_Order($order_id); } $this->processed_posts[$post['order_number_formatted']] = $post['order_number_formatted']; } $this->imported++; $this->log->add(sprintf(__('> Finished importing order %s', WC_Customer_CSV_Import_Suite::TEXT_DOMAIN), $dry_run ? "" : $order->get_order_number())); } $this->log->add(__('Finished processing orders.', WC_Customer_CSV_Import_Suite::TEXT_DOMAIN)); unset($this->posts); }
/** * Render a notice for the user to select their desired export format * * @since 1.3.3 * @see SV_WC_Plugin::add_admin_notices() */ public function add_admin_notices() { // show any dependency notices parent::add_admin_notices(); $settings = get_option('woocommerce_authorize_net_cim_credit_card_settings'); // install notice if (empty($settings) && !$this->get_admin_notice_handler()->is_notice_dismissed('install-notice')) { $this->get_admin_notice_handler()->add_admin_notice(sprintf(__('Thanks for installing the WooCommerce Authorize.Net CIM Gateway! To start accepting payments, %sset your Authorize.Net API credentials%s. Need help? See the %sdocumentation%s.', 'woocommerce-gateway-authorize-net-cim'), '<a href="' . $this->get_settings_url() . '">', '</a>', '<a target="_blank" href="' . $this->get_documentation_url() . '">', '</a>'), 'install-notice', array('notice_class' => 'updated')); } $gateway = $this->get_gateway(self::CREDIT_CARD_GATEWAY_ID); // bail if gateway is not available, as proper credentials are needed first if (!$gateway->is_available()) { return; } // check if CIM feature is enabled on customer's authorize.net account if (!get_option('wc_authorize_net_cim_feature_enabled')) { if ($gateway->is_cim_feature_enabled()) { update_option('wc_authorize_net_cim_feature_enabled', true); } else { if (!$this->get_admin_notice_handler()->is_notice_dismissed('cim-add-on-notice')) { $this->get_admin_notice_handler()->add_admin_notice(sprintf(__('The CIM Add-On is not enabled on your Authorize.Net account. Please %scontact Authorize.Net%s to enable CIM. You will be unable to process transactions until CIM is enabled. ', 'woocommerce-gateway-authorize-net-cim'), '<a href="http://support.authorize.net" target="_blank">', '</a>'), 'cim-add-on-notice'); } } } if ($gateway->is_accept_js_enabled() && isset($_GET['page']) && 'wc-settings' === $_GET['page']) { $message = ''; if (!$gateway->get_client_key()) { $message = sprintf(__("%s: A valid Client Key is required to use Accept.js at checkout.", 'woocommerce-gateway-authorize-net-cim'), '<strong>' . $this->get_plugin_name() . '</strong>'); } elseif (!SV_WC_Plugin_Compatibility::wc_checkout_is_https()) { $message = sprintf(__("%s: SSL is required to use Accept.js at checkout.", 'woocommerce-gateway-authorize-net-cim'), '<strong>' . $this->get_plugin_name() . '</strong>'); } if ($message) { $this->get_admin_notice_handler()->add_admin_notice($message, 'accept-js-status', array('dismissible' => false, 'notice_class' => 'error')); } } }
/** * Get the order data format for a single column for all line items, compatible with the legacy (pre 3.0) CSV Export format * * Note this code was adapted from the old code to maintain compatibility as close as possible, so it should * not be modified unless absolutely necessary * * @since 3.0 * @param array $order_data an array of order data for the given order * @param WC_Order $order the WC_Order object * @return array modified order data */ private function get_legacy_single_column_line_item($order_data, WC_Order $order) { $line_items = array(); foreach ($order->get_items() as $_ => $item) { $product = $order->get_product_from_item($item); if (!is_object($product)) { $product = new WC_Product(0); } $line_item = $item['name']; if ($product->get_sku()) { $line_item .= ' (' . $product->get_sku() . ')'; } $line_item .= ' x' . $item['qty']; $item_meta = new WC_Order_Item_Meta(SV_WC_Plugin_Compatibility::is_wc_version_gte_2_4() ? $item : $item['item_meta']); $variation = $item_meta->display(true, true); if ($variation) { $line_item .= ' - ' . str_replace(array("\r", "\r\n", "\n"), '', $variation); } $line_items[] = str_replace(array('“', '”'), '', $line_item); } $order_data['order_items'] = implode('; ', $line_items); // convert country codes to full name if (isset(WC()->countries->countries[$order->billing_country])) { $order_data['billing_country'] = WC()->countries->countries[$order->billing_country]; } if (isset(WC()->countries->countries[$order->shipping_country])) { $order_data['shipping_country'] = WC()->countries->countries[$order->shipping_country]; } // set order ID to order number $order_data['order_id'] = ltrim($order->get_order_number(), _x('#', 'hash before the order number', WC_Customer_Order_CSV_Export::TEXT_DOMAIN)); return $order_data; }
/** * Setup main plugin class * * @since 3.0 * @see SV_WC_Plugin::__construct() */ public function __construct() { parent::__construct(self::PLUGIN_ID, self::VERSION, self::TEXT_DOMAIN); // load includes after WC is loaded add_action('sv_wc_framework_plugins_loaded', array($this, 'includes'), 11); // Subscriptions support if ($this->is_plugin_active('woocommerce-subscriptions.php')) { if (SV_WC_Plugin_Compatibility::is_wc_subscriptions_version_gte_2_0()) { // don't copy over FreshBooks invoice meta from the original order to the subscription (subscription objects should not have an invoice) add_filter('wcs_subscription_meta', array($this, 'subscriptions_remove_subscription_order_meta'), 10, 3); // don't copy over FreshBooks invoice meta to subscription object during upgrade from 1.5.x to 2.0 add_filter('wcs_upgrade_subscription_meta_to_copy', array($this, 'subscriptions_remove_subscription_order_meta_during_upgrade')); // don't copy over FreshBooks invoice meta from the subscription to the renewal order add_filter('wcs_renewal_order_meta', array($this, 'subscriptions_remove_renewal_order_meta')); } else { // remove the invoice data from new renewal orders for subscription renewals so a new invoice is created for each renewal order add_filter('woocommerce_subscriptions_renewal_order_meta_query', array($this, 'subscriptions_remove_renewal_order_meta_1_5'), 10, 4); } } // maybe disable API logging if ('on' !== get_option('wc_freshbooks_debug_mode')) { remove_action('wc_' . $this->get_id() . '_api_request_performed', array($this, 'log_api_request'), 10); } }
/** * Process subscription renewal * * @since 1.4 * @param float $amount_to_charge subscription amount to charge, could include * multiple renewals if they've previously failed and the admin * has enabled it * @param WC_Order $order original order containing the subscription * @param int $product_id the ID of the subscription product */ public function process_renewal_payment($amount_to_charge, $order, $product_id = null) { require_once 'class-wc-realex-api.php'; $realex_subscription_count = 0; if (is_numeric($order->realex_subscription_count) && $order->realex_subscription_count) { $realex_subscription_count = $order->realex_subscription_count; } // increment the subscription count so we don't get order number clashes $realex_subscription_count++; update_post_meta($order->id, '_realex_subscription_count', $realex_subscription_count); // set custom class member used by the realex gateway $order->payment_total = SV_WC_Helper::number_format($amount_to_charge); // zero-dollar subscription renewal. weird, but apparently it happens -- only applicable to Subs 1.5.x if (!SV_WC_Plugin_Compatibility::is_wc_subscriptions_version_gte_2_0()) { if (0 == $order->payment_total) { // add order note $order->add_order_note(sprintf(__('%s0 Subscription Renewal Approved', 'woocommerce-gateway-realex'), get_woocommerce_currency_symbol())); // update subscription WC_Subscriptions_Manager::process_subscription_payments_on_order($order, $product_id); return; } } // This order is missing a tokenized card, lets see whether there's one available for the customer if (!get_post_meta($order->id, '_realex_cardref', true)) { $credit_cards = get_user_meta($order->get_user_id(), 'woocommerce_realex_cc', true); if (is_array($credit_cards)) { $card_ref = (object) current($credit_cards); $card_ref = $card_ref->ref; update_post_meta($order->id, '_realex_cardref', $card_ref); if (SV_WC_Plugin_Compatibility::is_wc_subscriptions_version_gte_2_0()) { foreach (wcs_get_subscriptions_for_renewal_order($order) as $subscription) { update_post_meta($subscription->id, '_realex_cardref', $card_ref); } } } } // create the realex api client $realex_client = new Realex_API($this->get_endpoint_url(), $this->get_realvault_endpoint_url(), $this->get_shared_secret()); // create the customer/cc tokens, and authorize the initial payment amount, if any $response = $this->authorize($realex_client, $order); if ($response && '00' == $response->result) { // add order note $order->add_order_note(sprintf(__('Credit Card Subscription Renewal Payment Approved (Payment Reference: %s) ', 'woocommerce-gateway-realex'), $response->pasref)); // update subscription if (SV_WC_Plugin_Compatibility::is_wc_subscriptions_version_gte_2_0()) { $order->payment_complete((string) $response->pasref); } else { WC_Subscriptions_Manager::process_subscription_payments_on_order($order, $product_id); } } else { // generate the result message $message = __('Credit Card Subscription Renewal Payment Failed', 'woocommerce-gateway-realex'); /* translators: Placeholders: %1$s - result, %2$s - result message */ if ($response) { $message .= sprintf(__(' (Result: %1$s - "%2$s").', 'woocommerce-gateway-realex'), $response->result, $response->message); } $order->add_order_note($message); // update subscription if (!SV_WC_Plugin_Compatibility::is_wc_subscriptions_version_gte_2_0()) { WC_Subscriptions_Manager::process_subscription_payment_failure_on_order($order, $product_id); } } }
?> </select> </p> </td> <td class="content-restriction-objects objects-column"> <p class="form-field"> <label for="_content_restriction_rules_<?php echo esc_attr($index); ?> _object_ids"><?php esc_html_e('Title', WC_Memberships::TEXT_DOMAIN); ?> :</label> <?php if (SV_WC_Plugin_Compatibility::is_wc_version_gte_2_3()) { ?> <input type="hidden" class="wc-memberships-object-search js-object-ids" style="width: 50%;" id="_content_restriction_rules_<?php echo esc_attr($index); ?> _object_ids" name="_content_restriction_rules[<?php echo esc_attr($index); ?> ][object_ids]" data-placeholder="<?php esc_attr_e('Search… or leave blank to apply to all', WC_Memberships::TEXT_DOMAIN); ?> " data-action="<?php echo esc_attr($rule->get_object_search_action_name()); ?> " data-multiple="true" data-selected="<?php $json_ids = array();
/** * Get the invoice line items for a given order. This includes: * * + Products, mapped as FreshBooks items when the admin has linked them * + Fees, mapped as a `Fee` item * + Shipping, mapped as a `Shipping` item * + Taxes, mapped using the tax code as the item * * Note that taxes cannot be added per-product as WooCommerce doesn't provide * any way to get individual tax information per product and FreshBooks requires * a tax name/percentage to be set on a per-product basis. Further, FreshBooks * only allows 2 taxes per product where realistically most stores will have * more * * @param \WC_FreshBooks_Order $order order instance * @return array line items * @since 3.0 */ private function get_invoice_lines(WC_FreshBooks_Order $order) { $line_items = array(); // add products foreach ($order->get_items() as $item_key => $item) { $product = $order->get_product_from_item($item); // must be a valid product if (is_object($product)) { $product_id = $product->is_type('variation') ? $product->variation_id : $product->id; $item_name = metadata_exists('post', $product_id, '_wc_freshbooks_item_name') ? get_post_meta($product_id, '_wc_freshbooks_item_name', true) : $product->get_sku(); $item_meta = new WC_Order_Item_Meta(SV_WC_Plugin_Compatibility::is_wc_version_gte_2_4() ? $item : $item['item_meta']); // variation data, item meta, etc $meta = $item_meta->display(true, true); // grouped products include a &arr; in the name which must be converted back to an arrow $item_description = html_entity_decode($product->get_title(), ENT_QUOTES, 'UTF-8') . ($meta ? sprintf(' (%s)', $meta) : ''); } else { $item_name = __('Product', WC_FreshBooks::TEXT_DOMAIN); $item_description = $item['name']; } $line_items[] = array('name' => $item_name, 'description' => apply_filters('wc_freshbooks_line_item_description', $item_description, $item, $order, $item_key), 'unit_cost' => $order->get_item_subtotal($item), 'quantity' => $item['qty']); } $coupons = $order->get_items('coupon'); // add coupons foreach ($coupons as $coupon_item) { $coupon = new WC_Coupon($coupon_item['name']); $coupon_post = get_post($coupon->id); $coupon_type = false !== strpos($coupon->type, '_cart') ? __('Cart Discount', WC_FreshBooks::TEXT_DOMAIN) : __('Product Discount', WC_FreshBooks::TEXT_DOMAIN); $line_items[] = array('name' => $coupon_item['name'], 'description' => is_object($coupon_post) && $coupon_post->post_excerpt ? sprintf(__('%s - %s', WC_FreshBooks::TEXT_DOMAIN), $coupon_type, $coupon_post->post_excerpt) : $coupon_type, 'unit_cost' => wc_format_decimal($coupon_item['discount_amount'] * -1, 2), 'quantity' => 1); } // manually created orders can't have coupon items, but may have an order discount set // which must be added as a line item if (0 == count($coupons) && $order->get_total_discount() > 0) { $line_items[] = array('name' => __('Order Discount', WC_FreshBooks::TEXT_DOMAIN), 'description' => __('Order Discount', WC_FreshBooks::TEXT_DOMAIN), 'unit_cost' => wc_format_decimal($order->get_total_discount() * -1, 2), 'quantity' => 1); } // add fees foreach ($order->get_fees() as $fee_key => $fee) { $line_items[] = array('name' => __('Fee', WC_FreshBooks::TEXT_DOMAIN), 'description' => $fee['name'], 'unit_cost' => $order->get_line_total($fee), 'quantity' => 1); } // add shipping foreach ($order->get_shipping_methods() as $shipping_method_key => $shipping_method) { $line_items[] = array('name' => __('Shipping', WC_FreshBooks::TEXT_DOMAIN), 'description' => ucwords(str_replace('_', ' ', $shipping_method['method_id'])), 'unit_cost' => $shipping_method['cost'], 'quantity' => 1); } // add taxes foreach ($order->get_tax_totals() as $tax_code => $tax) { $line_items[] = array('name' => $tax_code, 'description' => $tax->label, 'unit_cost' => number_Format($tax->amount, 2, '.', ''), 'quantity' => 1); } return $line_items; }
/** * Mark the given order as failed and set the order note * * @since 2.0 * @param WC_Order $order the WC order object * @param string $message a message to display inside the 'Amazon Transaction Failed' order note */ protected function mark_order_as_failed(WC_Order $order, $message = '') { $order_note = sprintf(__('Amazon Transaction Failed (%s)', WC_Amazon_FPS::TEXT_DOMAIN), $message); // Mark order as failed if not already set, otherwise, make sure we add the order note so we can detect when someone fails to check out multiple times if (!SV_WC_Plugin_Compatibility::order_has_status($order, 'failed')) { $order->update_status('failed', $order_note); } else { $order->add_order_note($order_note); } // add customer-facing error message SV_WC_Helper::wc_add_notice(__('An error occurred, please try again or try an alternate form of payment.', WC_Amazon_FPS::TEXT_DOMAIN), 'error'); // log the error message $this->log($message); }
/** * Sync variable product prices with the children lowest/highest price per * unit. * * Code based on WC_Product_Variable version 2.0.0 * @see WC_Product_Variable::variable_product_sync() * @see WC_Price_Calculator_Product::variable_product_unsync() * * @since 3.0 * @param WC_Product_Variable $product the variable product * @param WC_Price_Calculator_Settings $settings the calculator settings */ public static function variable_product_sync($product, $settings) { // save the original values so we can restore the product $product->wcmpc_min_variation_price = $product->min_variation_price; $product->wcmpc_min_variation_regular_price = $product->min_variation_regular_price; $product->wcmpc_min_variation_sale_price = $product->min_variation_sale_price; $product->wcmpc_max_variation_price = $product->max_variation_price; $product->wcmpc_max_variation_regular_price = $product->max_variation_regular_price; $product->wcmpc_max_variation_sale_price = $product->max_variation_sale_price; $product->wcmpc_price = $product->price; $product->min_variation_price = $product->min_variation_regular_price = $product->min_variation_sale_price = $product->max_variation_price = $product->max_variation_regular_price = $product->max_variation_sale_price = ''; foreach ($product->get_children() as $variation_product_id) { $variation_product = apply_filters('wc_measurement_price_calculator_variable_product_sync', SV_WC_Plugin_Compatibility::wc_get_product($variation_product_id), $product); $child_price = $variation_product->price; $child_regular_price = $variation_product->regular_price; $child_sale_price = $variation_product->sale_price; // get the product measurement $measurement = self::get_product_measurement($variation_product, $settings); $measurement->set_unit($settings->get_pricing_unit()); if ('' === $child_price && '' === $child_regular_price || !$measurement->get_value()) { continue; } // convert to price per unit if ('' !== $child_price) { $child_price /= $measurement->get_value(); } // Regular prices if ($child_regular_price !== '') { // convert to price per unit $child_regular_price /= $measurement->get_value(); if (!is_numeric($product->min_variation_regular_price) || $child_regular_price < $product->min_variation_regular_price) { $product->min_variation_regular_price = $child_regular_price; } if (!is_numeric($product->max_variation_regular_price) || $child_regular_price > $product->max_variation_regular_price) { $product->max_variation_regular_price = $child_regular_price; } } // Sale prices if ($child_sale_price !== '') { // convert to price per unit $child_sale_price /= $measurement->get_value(); if ($child_price == $child_sale_price) { if (!is_numeric($product->min_variation_sale_price) || $child_sale_price < $product->min_variation_sale_price) { $product->min_variation_sale_price = $child_sale_price; } if (!is_numeric($product->max_variation_sale_price) || $child_sale_price > $product->max_variation_sale_price) { $product->max_variation_sale_price = $child_sale_price; } } } // Actual prices if ($child_price !== '') { if ($child_price > $product->max_variation_price) { $product->max_variation_price = $child_price; } if ($product->min_variation_price === '' || $child_price < $product->min_variation_price) { $product->min_variation_price = $child_price; } } } // as seen in WC_Product_Variable::get_price_html() $product->price = $product->min_variation_price; }
/** * Display the voucher select box in the product variation meta box for * downloadable variable products * * @since 1.2 * @param int $loop loop counter * @param array $variation_data associative array of variation data */ public function product_after_variable_attributes($loop, $variation_data, $variation) { // WooCommerce 2.3 removed meta data from the $variation_data array, let's add it back if (SV_WC_Plugin_Compatibility::is_wc_version_gte_2_3()) { $variation_data = array_merge(get_post_meta($variation->ID), $variation_data); } $options = array('' => ''); // get all the published vouchers foreach (wc_pdf_product_vouchers()->get_voucher_handler()->get_vouchers() as $voucher) { $options[$voucher->ID] = $voucher->post_title; } if (SV_WC_Plugin_Compatibility::is_wc_version_gte_2_3()) { ?> <div class="show_if_variation_downloadable" style="display:none;"> <p class="form-row form-row-first"> <label><?php _e('Voucher:', WC_PDF_Product_Vouchers::TEXT_DOMAIN); ?> <a class="tips" data-tip="<?php _e('Select a voucher rather than providing a file path', WC_PDF_Product_Vouchers::TEXT_DOMAIN); ?> " href="#">[?]</a></label><select class="variable_voucher" name="variable_voucher_id[<?php echo $loop; ?> ]"><?php foreach ($options as $voucher_id => $name) { echo '<option value="' . $voucher_id . '" '; if (isset($variation_data['_voucher_id'][0])) { selected($voucher_id, $variation_data['_voucher_id'][0]); } echo '>' . $name . '</option>'; } ?> </select> </p> </div> <?php } else { ?> <tr class="show_if_variation_downloadable" style="display:none;"> <td> <label><?php _e('Voucher:', WC_PDF_Product_Vouchers::TEXT_DOMAIN); ?> <a class="tips" data-tip="<?php _e('Select a voucher rather than providing a file path', WC_PDF_Product_Vouchers::TEXT_DOMAIN); ?> " href="#">[?]</a></label><select class="variable_voucher" name="variable_voucher_id[<?php echo $loop; ?> ]"><?php foreach ($options as $voucher_id => $name) { echo '<option value="' . $voucher_id . '" '; if (isset($variation_data['_voucher_id'][0])) { selected($voucher_id, $variation_data['_voucher_id'][0]); } echo '>' . $name . '</option>'; } ?> </select> </td> <td> </td> </tr> <?php } }