/**
  * 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;
 }
Esempio n. 19
0
 /**
  * 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);
 }
Esempio n. 20
0
 /**
  * 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 &ndash; ' . 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('&#8220;', '&#8221;'), '', $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;
 }
Esempio n. 24
0
 /**
  * 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&hellip; 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>&nbsp;</td>
			</tr>
		<?php 
        }
    }