PluginProbe
Pay with Vipps and MobilePay for WooCommerce / 6.3.1
Pay with Vipps and MobilePay for WooCommerce v6.3.1
6.3.1 6.2.6 6.3.0 6.2.5 6.2.4 6.2.3 6.2.2 6.2.1 6.2.0 6.1.10 6.1.9 6.1.8 6.1.7 6.1.6 6.1.5 6.1.4 6.1.3 6.1.2 6.1.1 6.1.0 6.0.5 6.0.4 6.0.3 6.0.2 6.0.1 All 190 releases
← All changes | payment/WC_Gateway_Vipps.class.php +36 -62 6.1.9 → 6.3.1 View file →
@@ -227,9 +227,9 @@
227 227 return $enabled;
228 228 }
229 229 $is_vipps_express = (bool) $order->get_meta( '_vipps_express_checkout' );
230 230 $has_billing_email = (bool) $order->get_billing_email();
231 - if ( $is_vipps_express && ! $has_billing_email ) {
231 + if ( $is_vipps_express) {
232 232 return false;
233 233 }
234 234 return $enabled;
235 235 }, 10, 3);
@@ -621,22 +621,8 @@
621 621 }
622 622 public function shipping_details_callback_url($token='',$reference=0) {
623 623 return $this->make_callback_urls('vipps_shipping_details',$token,$reference);
624 624 }
625 - // Callback for the consetn removal callback. Must use template redirect directly, because wc-api doesn't handle DELETE.
626 - // IOK 2018-05-18
627 - public function consent_removal_callback_url () {
628 - $queryargs = [];
629 - $url = home_url("/", 'https');
630 - if ( !get_option('permalink_structure')) {
631 - $queryargs['vipps-consent-removal']=1;
632 - } else {
633 - $url = trailingslashit(home_url('vipps-consent-removal', 'https'));
634 - }
635 - // And we need to add an empty "callback" query arg as the very last arg to receive the actual callback.
636 - // We can't use add_query_arg for that, as an empty argument will remove the equals-sign.
637 - return add_query_arg($queryargs, $url) . "&callback=";
638 - }
639 625
640 626 // Allow user to select the template to be used for the special Vipps MobilePay pages. IOK 2020-02-17
641 627 public function get_theme_page_templates() {
642 628 if (!$this->page_templates) {
@@ -648,22 +634,8 @@
648 634 }
649 635 return $this->page_templates;
650 636 }
651 637
652 - // We can't use get_pages to get a default list of pages for our settings, because it triggers
653 - // actions that can be used by other plugins. Therefore we must use the database directly and cache the results. IOK 2023-08-22
654 - public function get_pagelist () {
655 - if (!$this->page_list) {
656 - global $wpdb;
657 - $page_list = array(''=>__('Use a simulated page (default)', 'woo-vipps'));
658 - foreach($wpdb->get_results("SELECT ID,post_title FROM {$wpdb->prefix}posts WHERE post_type='page' and post_status='publish'") as $page) {
659 - $page_list[$page->ID] = $page->post_title;
660 - }
661 - $this->page_list = $page_list;
662 - }
663 - return $this->page_list;
664 - }
665 -
666 638 // Check to see if the product in question can be bought with express checkout IOK 2018-12-04
667 639 public function product_supports_express_checkout($product) {
668 640 // IOK 2023-12-12 Can only support express checkout for Vipps - not MobilePay (yet!)
669 641 // IOK 2025-09-01 Now supports mobilepay
@@ -1073,9 +1045,8 @@
1073 1045 global $Vipps;
1074 1046
1075 1047 // Used for defaults in the admin interface; however this functions is called a loot more often than that.
1076 1048 $page_templates = $this->get_theme_page_templates();
1077 - $page_list = $this->get_pagelist();
1078 1049
1079 1050 $orderprefix = $Vipps->generate_order_prefix();
1080 1051
1081 1052 // Default handling based on other parameters and earlier values.
@@ -1093,9 +1064,8 @@
1093 1064
1094 1065 // We will only show the Checkout options if the user has activated the feature (thus creating the pages involved etc). IOK 2021-10-01
1095 1066 $vipps_checkout_activated = get_option('woo_vipps_checkout_activated', false);
1096 1067
1097 -
1098 1068 // This is used for new options,to set reasonable defaults based on older settings. We can't use WC_Settings->get_option for this unfortunately.
1099 1069 $current = get_option('woocommerce_vipps_settings');
1100 1070 // New defaults based on old defaults
1101 1071 $default_static_shipping_for_checkout = 'no';
@@ -1620,22 +1590,24 @@
1620 1590 'description' => __('Turn this on to add support for Woos Order Attribution API for Checkout and Express Checkout. Some stores have reported problems when using this API together with Vipps, so be sure to test this if you turn it on.', 'woo-vipps'),
1621 1591 ),
1622 1592
1623 1593 'vippsspecialpagetemplate' => array(
1624 - 'title' => sprintf(__('Override page template used for the special %1$s pages', 'woo-vipps'), Vipps::CompanyName()),
1594 + 'title' => sprintf(__('Legacy: Override page template used for the special %1$s page', 'woo-vipps'), Vipps::CompanyName()),
1625 1595 'label' => sprintf(__('Use specific template for %1$s', 'woo-vipps'), Vipps::CompanyName()),
1626 1596 'type' => 'select',
1627 1597 'options' => $page_templates,
1628 - 'description' => sprintf(__('Use this template from your theme or child-theme to display all the special %1$s pages. You will probably want a full-width template and it should call \'the_content()\' normally.', 'woo-vipps'), Vipps::CompanyName()),
1598 + 'description' => sprintf(__('Use this template from your theme or child-theme for the special %1$s page.<br>Legacy: This is not necessary anymore - you should instead choose a template by editing the page like any other page.','woo-vipps'), Vipps::CompanyName()),
1629 1599 'default' => ''),
1630 1600
1601 + // Deprecated, not shown anymore: TODO: remove this option in future. LP 2026-09-01
1631 1602 'vippsspecialpageid' => array(
1632 1603 'title' => sprintf(__('Use a real page ID for the special %1$s pages - neccessary for some themes', 'woo-vipps'), Vipps::CompanyName()),
1633 1604 'label' => __('Use a real page ID', 'woo-vipps'),
1634 1605 'type' => 'select',
1635 - 'options' => $page_list,
1606 + 'options' => [],
1636 1607 'description' => sprintf(__('Some very few themes do not work with the simulated pages used by this plugin, and needs a real page ID for this. Choose a blank page for this; the content will be replaced, but the template and other metadata will be present. You only need to use this if the plugin seems to break on the special %1$s pages.', 'woo-vipps'), Vipps::CompanyName()),
1637 - 'default'=>''),
1608 + 'default' => ''
1609 + ),
1638 1610
1639 1611 'sendreceipts' => array(
1640 1612 'title' => __("Send receipts and order confirmation info to the customers' app on completed purchases.", 'woo-vipps'),
1641 1613 'label' => sprintf(__("Send receipts to the customers %1\$s app", 'woo-vipps'), Vipps::CompanyName()),
@@ -1651,17 +1623,8 @@
1651 1623 'description' => sprintf(__('If set, this image will be uploaded to %1$s and used to profile your store in the %1$s app for links to the order confirmation etc', 'woo-vipps'), Vipps::CompanyName()),
1652 1624 'default' => 0,
1653 1625 ),
1654 1626
1655 -
1656 - 'use_flock' => array (
1657 - 'title' => __('Use flock() to lock orders for Express Checkout', 'woo-vipps'),
1658 - 'label' => __('Use flock() to lock orders for Express Checkout', 'woo-vipps'),
1659 - 'type' => 'checkbox',
1660 - 'description' => __('Use the flock() system call to ensure orders are only finalized once. You can use this for normal setups, but probably not on Windows with IIS, and possibly not on distributed filesystems like NFS. If you don\t know what it is, probably do not use it. If you get duplicated shipping lines on some express orders, you may try using this', 'woo-vipps'),
1661 - 'default' => 'no',
1662 - ),
1663 -
1664 1627 'delete_settings_on_deactivation' => array (
1665 1628 'title' => __('Delete plugin settings on deactivation', 'woo-vipps'),
1666 1629 'label' => __('Delete plugin settings on deactivation', 'woo-vipps'),
1667 1630 'type' => 'checkbox',
@@ -2384,15 +2347,15 @@
2384 2347 // Default should never happen, but just to ensure we are in our enumeration
2385 2348 return "initiated";
2386 2349 }
2387 2350
2388 - // This does not normally call Vipps, so if you need to refresh status, please use callback_check_order_status first. IOK 2019-01-23
2351 + // This does not normally call Vipps, so if you need to refresh status, please use poll_and_check_order_status first. IOK 2019-01-23
2389 2352 public function check_payment_status($order) {
2390 2353 if (!$order) return 'cancelled';
2391 2354 $status = $this->interpret_vipps_order_status($order->get_meta('_vipps_status'));
2392 2355 // This can happen if the vipps status is set from the back end for instance. IOK 2020-08-14
2393 2356 if ($order->get_status() == 'pending' && $status != 'initiated') {
2394 - $this->callback_check_order_status($order);
2357 + $this->poll_and_check_order_status($order);
2395 2358 $order = wc_get_order($order->get_id()); // refresh to get the new status IOK 2021-01-20
2396 2359 $status = $this->interpret_vipps_order_status($order->get_meta('_vipps_status'));
2397 2360 }
2398 2361 return $status;
@@ -2397,9 +2360,9 @@
2397 2360 }
2398 2361 return $status;
2399 2362 }
2400 2363
2401 - // Called by callback_check_order_status and handle_callback to handle the situation where
2364 + // Called by poll_and_check_order_status and handle_callback to handle the situation where
2402 2365 // the payment method has been set to something else *after* Vipps has gotten the order.
2403 2366 // This happens very rarely for people who use Vipps as an external payment method in Klarna, so
2404 2367 // we only do it for orders that match this. IOK 2023-02-03
2405 2368 public function reset_erroneous_payment_method($order) {
@@ -2426,9 +2389,9 @@
2426 2389 }
2427 2390
2428 2391 // Check status of order at Vipps, in case the callback has been delayed or failed.
2429 2392 // Should only be called if in status 'pending'; it will modify the order when status changes.
2430 - public function callback_check_order_status($order, $allow_retry = true) {
2393 + public function poll_and_check_order_status($order, $allow_retry = true) {
2431 2394 global $Vipps;
2432 2395 $orderid = $order->get_id();
2433 2396
2434 2397 clean_post_cache($order->get_id());
@@ -2461,15 +2424,8 @@
2461 2424 }
2462 2425 // Something changed, so we are now going to sideeffect the order. IOK 2025-10-15
2463 2426 $this->log(sprintf(__("%1\$s poll: Handling order: ", 'woo-vipps'), Vipps::CompanyName()) . " " . $orderid, 'debug');
2464 2427
2465 - // If we are in the process of getting a callback from vipps, don't update anything. Currently, Woo/WP has no locking mechanism,
2466 - // and it isn't feasible to implement one portably. So this reduces somewhat the likelihood of races when this method is called
2467 - // and callbacks happen at the same time.
2468 - if (!$Vipps->lockOrder($order)) {
2469 - return $oldstatus;
2470 - }
2471 -
2472 2428 // Failsafe for rare bug when using Klarna Checkout with Vipps as an external payment method
2473 2429 // IOK 2024-01-09 ensure this is called only when order is complete/authorized
2474 2430 if ($ready) {
2475 2431 $this->reset_erroneous_payment_method($order);
@@ -2501,9 +2457,8 @@
2501 2457
2502 2458 } catch (Exception $e) {
2503 2459 $this->log(sprintf(__("Error getting payment details from %1\$s for order_id:",'woo-vipps'), $this->get_payment_method_name()) . $orderid . "\n" . $e->getMessage(), 'error');
2504 2460 clean_post_cache($order->get_id());
2505 - $Vipps->unlockOrder($order);
2506 2461 return $oldstatus;
2507 2462 }
2508 2463 $order->save();
2509 2464
@@ -2536,9 +2491,8 @@
2536 2491 $this->log(sprintf(__("No address information for order %2\$d, but there still might be an active %1\$s session for it, so do not cancel it.", 'woo-vipps'), Vipps::CheckoutName(), $order->get_id()));
2537 2492 }
2538 2493 }
2539 2494 clean_post_cache($order->get_id());
2540 - $Vipps->unlockOrder($order);
2541 2495 return $oldstatus;
2542 2496 }
2543 2497 }
2544 2498
@@ -2574,9 +2528,8 @@
2574 2528
2575 2529 $order->save();
2576 2530 clean_post_cache($order->get_id());
2577 2531 $newstatus = $order->get_status();
2578 - $Vipps->unlockOrder($order);
2579 2532 return $newstatus;
2580 2533 }
2581 2534
2582 2535 // IOK 2020-01-20 Previously was just a debugging tool, then was used to update postmeta values. Now is used as the main source of info
@@ -3218,9 +3171,14 @@
3218 3171 $is_base64 = $shipping_table ? ( $shipping_table['_is_base64'] ?? false) : false;
3219 3172
3220 3173 if (is_array($shipping_table) && isset($shipping_table[$key])) {
3221 3174 $decoded = $is_base64 ? @base64_decode($shipping_table[$key]) : $shipping_table[$key];
3222 - $shipping_rate = $decoded ? @unserialize($decoded) : null;
3175 +
3176 + // Ensure no shop manager has injected an evil object (that they would have had to add as a plugin) here. IOK 2026-09-18
3177 + $allowed_classes = apply_filters('woo_vipps_express_checkout_allowed_shipping_classes', [WC_Shipping_Rate::class, \stdClass::class]);
3178 + $shipping_rate = $decoded ? @unserialize($decoded, ['allowed_classes' => $allowed_classes]) : null;
3179 + $shipping_rate = is_a($shipping_rate,'WC_Shipping_Rate') ? $shipping_rate : null;
3180 +
3223 3181 if (!$shipping_rate) {
3224 3182 $this->log(sprintf(__("%1\$s: Could not deserialize the chosen shipping method %2\$s for order %3\$d", 'woo-vipps'), Vipps::ExpressCheckoutName(), $method, $order->get_id()), 'error');
3225 3183 $this->log(sprintf(__("Serialized data was %1\$s", 'woo-vipps'), $decoded), 'error');
3226 3184 } else {
@@ -3404,9 +3362,9 @@
3404 3362 $shipping_rate = apply_filters('woo_vipps_express_checkout_shipping_rate',$shipping_rate,$costExTax,$tax,$method,$product);
3405 3363 return $shipping_rate;
3406 3364 }
3407 3365
3408 - // Used by both callback_check_order_status and handle_callback - sets the neccessary order metadata after a successful (or not vipps transaction). IOK 2025-08-13
3366 + // Used by both poll_and_check_order_status and handle_callback - sets the neccessary order metadata after a successful (or not vipps transaction). IOK 2025-08-13
3409 3367 public function order_set_transaction_metadata($order, $transaction) {
3410 3368 // Set Vipps metadata as early as possible
3411 3369 $vippsstamp = strtotime($transaction['timeStamp']);
3412 3370 $vippsamount = $transaction['amount'] ?? '';
@@ -3786,9 +3744,9 @@
3786 3744 }
3787 3745 do_action('woo_vipps_payment_complete_at_shutdown', $order, $this);
3788 3746 } catch (Exception $e) {
3789 3747 // This is/should be non-critical so just log it.
3790 - $this->log(sprintf(__("Could not do all payment-complete actions on %1\$s order %2\$d: %3\$s ", 'woo-vipps'), Vipps::CompanyName(), $orderid, $e->etMessage()), "error");
3748 + $this->log(sprintf(__("Could not do all payment-complete actions on %1\$s order %2\$d: %3\$s ", 'woo-vipps'), Vipps::CompanyName(), $orderid, $e->getMessage()), "error");
3791 3749 }
3792 3750 }
3793 3751
3794 3752 // This is run on payment complete. Per default will it only add a link to the order confirmation page, but
@@ -3895,9 +3853,9 @@
3895 3853
3896 3854 $contents = WC()->cart->get_cart_contents();
3897 3855 $contents = apply_filters('woo_vipps_create_express_checkout_cart_contents',$contents);
3898 3856 try {
3899 - $cart_hash = md5(json_encode(wc_clean($contents)) . WC()->cart->total);
3857 + $cart_hash = WC()->cart->get_cart_hash();
3900 3858 $order = new WC_Order();
3901 3859 $order->set_status('pending');
3902 3860 $order->set_payment_method($this);
3903 3861 if ($ischeckout) {
@@ -3908,8 +3866,9 @@
3908 3866 }
3909 3867 // We use 'checkout' as the created_via key as per requests, but allow merchants to use their own. IOK 2022-09-15
3910 3868 $created_via = apply_filters('woo_vipps_express_checkout_created_via', 'checkout', $order, $ischeckout);
3911 3869 $order->set_created_via($created_via);
3870 + $order->set_cart_hash($cart_hash);
3912 3871
3913 3872 $dummy = sprintf(__('Vipps Express Checkout', 'woo-vipps')); // this is so gettext will find this string.
3914 3873 $dummy = sprintf(__('Vipps Checkout', 'woo-vipps')); // this is so gettext will find this string.
3915 3874
@@ -4134,8 +4093,23 @@
4134 4093 // If enabling this, ensure the page in question exists
4135 4094 if ($this->get_option('vipps_checkout_enabled') == 'yes') {
4136 4095 update_option('woo_vipps_checkout_activated', true, true); // This must be true here, but still, make sure
4137 4096 Vipps::instance()->maybe_create_vipps_pages();
4097 + }
4098 +
4099 + // Ensure special page has the necessary shortcode. LP 2026-09-01
4100 + $special_page = get_post(Vipps::get_special_page_id());
4101 + if ($special_page && !has_shortcode($special_page->post_content, 'vipps_special_page')) {
4102 + $new_content = $special_page->post_content . "\n\n<!-- wp:shortcode -->[vipps_special_page]<!-- /wp:shortcode -->";
4103 + wp_update_post([
4104 + 'ID' => Vipps::get_special_page_id(),
4105 + 'post_content' => $new_content,
4106 + ]);
4107 + } else if (!Vipps::get_special_page_id()) {
4108 + // We shouldn't really get here, the page should be ensured to exist in init. LP 2026-09-03
4109 + /* translators: %s is current method name */
4110 + $this->log(sprintf(__('Missing special page in %s, attempting to fix', 'woo-vipps'), 'process_admin_options'), 'warning');
4111 + Vipps::instance()->ensure_special_page_exists();
4138 4112 }
4139 4113
4140 4114 return $saved;
4141 4115 }