| @@ -70,9 +70,9 @@ | ||
| 70 | 70 | public static function CheckoutName($order=null) { |
| 71 | 71 | return "Vipps MobilePay Checkout"; // Do not translate |
| 72 | 72 | } |
| 73 | 73 | public static function ExpressCheckoutName($order=null) { |
| 74 | - return __("Vipps Express Checkout", 'woo-vipps'); | |
| 74 | + return __("Vipps MobilePay Express Checkout", 'woo-vipps'); | |
| 75 | 75 | } |
| 76 | 76 | public static function LoginName() { |
| 77 | 77 | return __("Login with Vipps", 'woo-vipps'); |
| 78 | 78 | } |
| @@ -121,12 +121,17 @@ | ||
| 121 | 121 | add_action('init',array($Vipps,'init')); |
| 122 | 122 | add_action( 'woocommerce_loaded', array($Vipps,'woocommerce_loaded')); |
| 123 | 123 | add_filter( 'woocommerce_available_payment_gateways', array($Vipps, 'payment_gateway_filter')); |
| 124 | 124 | add_action( 'woocommerce_blocks_loaded', [$Vipps, 'woocommerce_blocks_loaded']); |
| 125 | - // Express Checkout and Vipps Checkout supports the new pickup_location shipping method, but the admin interface for this may | |
| 125 | + // Express Checkout and Checkout supports the new pickup_location shipping method, but the admin interface for this may | |
| 126 | 126 | // not have loaded if the default checkout solution isn't the Checkout block. We'll load it anyway if the user has any local pickup locations |
| 127 | 127 | // stored in the database since we support this for both Vipps MobilePay checkokut and Express. IOK 2026-02-25 |
| 128 | 128 | add_action('woocommerce_load_shipping_methods', array($Vipps, 'maybe_load_pickup_locations'), 90); |
| 129 | + | |
| 130 | + // Vipps Checkout replaces the default checkout page, and currently uses its own page for this which needs to exist | |
| 131 | + // Will also probably be used to maintain a real utility-page for Vipps actions later for themes where this | |
| 132 | + // is important. | |
| 133 | + add_filter('woocommerce_create_pages', array($Vipps, 'woocommerce_create_pages'), 50, 1); | |
| 129 | 134 | } |
| 130 | 135 | |
| 131 | 136 | // Register woocommerce store api endpoint to use in buy-now minicart block. LP 2026-02-10 |
| 132 | 137 | public function woocommerce_blocks_loaded() { |
| @@ -280,8 +285,48 @@ | ||
| 280 | 285 | } |
| 281 | 286 | |
| 282 | 287 | // Set default button options, migrating any older setup IOK 2026-07-15 |
| 283 | 288 | $this->init_button_options(); |
| 289 | + | |
| 290 | + /* | |
| 291 | + From version 6.2.x we create a real physical page to handle the "special" vipps pages, | |
| 292 | + where we earlier used just a fake page with no real page id, unless especially configured. | |
| 293 | + We therefore need to add code to maintain this special page. | |
| 294 | + | |
| 295 | + woocommerce_loaded is too early for this because of maybe_create_vipps_pages which calls WC_Install::create_pages, | |
| 296 | + and we hook unto this with woocommerce_create_pages. LP 2026-09-03 | |
| 297 | + */ | |
| 298 | + | |
| 299 | + // Delete special page id option when its deleted or trashed, so that we dont have to load | |
| 300 | + // in the post to check status in woocommerce_loaded when we ensure the special page exists. LP 2026-09-03 | |
| 301 | + $delete_special_page_id = function($post_id, $post = null) { | |
| 302 | + if (static::get_special_page_id() === $post_id) { | |
| 303 | + delete_option('woocommerce_vipps_special_page_page_id'); | |
| 304 | + } | |
| 305 | + }; | |
| 306 | + add_action('delete_post', $delete_special_page_id, 10, 2); | |
| 307 | + add_action('wp_trash_post', $delete_special_page_id, 10, 2); | |
| 308 | + | |
| 309 | + $this->ensure_special_page_exists(); | |
| 310 | + | |
| 311 | + | |
| 312 | + // We want this special page to have a certain title and maybe special scripts and so on, | |
| 313 | + // this gets run in template redirect for these pages. | |
| 314 | + add_action('woo_vipps_before_handling_special_page', function ($action) { | |
| 315 | + // Change title dynamically depending on action. LP 2026-09-02 | |
| 316 | + add_filter('the_title', [$this, 'vipps_special_page_endpoint_title'], 10, 2); | |
| 317 | + | |
| 318 | + // If we are handling the 'wait for payment' action, we need to poll the order status before | |
| 319 | + // we start producing content IOK 2026-09-21 | |
| 320 | + if ($action == 'wait_for_payment') { | |
| 321 | + $this->handle_payment_poll_and_redirect(); | |
| 322 | + } | |
| 323 | + | |
| 324 | + }); | |
| 325 | + | |
| 326 | + // Add an admin interface for this page as well IOK 2026-09-11 | |
| 327 | + add_action('woocommerce_settings_pages', array($this, 'woocommerce_settings_pages')); | |
| 328 | + | |
| 284 | 329 | } |
| 285 | 330 | |
| 286 | 331 | public function admin_init () { |
| 287 | 332 | $gw = $this->gateway(); |
| @@ -401,9 +446,77 @@ | ||
| 401 | 446 | } |
| 402 | 447 | } |
| 403 | 448 | } |
| 404 | 449 | |
| 450 | + | |
| 451 | + /** Ensure we have a special page for payment flows | |
| 452 | + * | |
| 453 | + * woocommerce_loaded is too early for this because of maybe_create_vipps_pages which calls WC_Install::create_pages, | |
| 454 | + * and we hook unto this with woocommerce_create_pages. LP 2026-09-03 | |
| 455 | + **/ | |
| 456 | + public function ensure_special_page_exists() { | |
| 457 | + if (static::get_special_page_id()) return; | |
| 458 | + $this->log(__('Missing id for special page, attempting to fix.', 'woo-vipps'), 'info'); | |
| 405 | 459 | |
| 460 | + // If user had in previous version overriden the fake page with a real one: migrate this page to be the special page. LP 2026-09-01 | |
| 461 | + $old_special_page_id = $this->gateway()->get_option('vippsspecialpageid'); | |
| 462 | + if ($old_special_page_id && ($special_page = get_post($old_special_page_id)) && "trash" !== $special_page->post_status) { | |
| 463 | + $this->log(__('Migrated old special page setting.', 'woo-vipps'), 'info'); | |
| 464 | + // there is no wc_set_page_id() so we update the option directly. LP 2026-09-01 | |
| 465 | + update_option('woocommerce_vipps_special_page_page_id', $old_special_page_id); | |
| 466 | + | |
| 467 | + // Ensure this page has the necessary shortcode. LP 2026-09-01 | |
| 468 | + if (!has_shortcode($special_page->post_content, 'vipps_special_page')) { | |
| 469 | + $new_content = $special_page->post_content . "\n\n<!-- wp:shortcode -->[vipps_special_page]<!-- /wp:shortcode -->"; | |
| 470 | + wp_update_post([ | |
| 471 | + 'ID' => $old_special_page_id, | |
| 472 | + 'post_content' => $new_content, | |
| 473 | + ]); | |
| 474 | + } | |
| 475 | + } else { | |
| 476 | + // Create special page if its missing. LP 2026-09-01 | |
| 477 | + $this->maybe_create_vipps_pages(); | |
| 478 | + } | |
| 479 | + } | |
| 480 | + | |
| 481 | + // Admin interface for the special page on woo/advanced/pages | |
| 482 | + public function woocommerce_settings_pages ($settings) { | |
| 483 | + $i = -1; | |
| 484 | + foreach($settings as $entry) { | |
| 485 | + $i++; | |
| 486 | + if ($entry['type'] == 'sectionend' && $entry['id'] == 'advanced_page_options') { | |
| 487 | + break; | |
| 488 | + } | |
| 489 | + } | |
| 490 | + if ($i > 0) { | |
| 491 | + $vippspagesettings = array( | |
| 492 | + array( | |
| 493 | + 'title' => sprintf(__( '%1$s Page', 'woo-vipps' ), Vipps::CompanyName()), | |
| 494 | + 'desc' => sprintf(__('This page is used for various special pages used by %1$s', 'woo-vipps'), Vipps::CompanyName()) . sprintf( __( 'Page contents: [%1$s]', 'woocommerce' ), 'vipps_special_page') , | |
| 495 | + 'id' => 'woocommerce_vipps_special_page_page_id', | |
| 496 | + 'type' => 'single_select_page_with_search', | |
| 497 | + 'default' => '', | |
| 498 | + 'class' => 'wc-page-search', | |
| 499 | + 'css' => 'min-width:300px;', | |
| 500 | + 'args' => array( | |
| 501 | + 'exclude' => | |
| 502 | + array( | |
| 503 | + wc_get_page_id( 'myaccount' ), | |
| 504 | + wc_get_page_id( 'checkout' ), | |
| 505 | + wc_get_page_id( 'cart' ), | |
| 506 | + ), | |
| 507 | + ), | |
| 508 | + 'desc_tip' => true, | |
| 509 | + 'autoload' => false, | |
| 510 | + )); | |
| 511 | + array_splice($settings, $i, 0, $vippspagesettings); | |
| 512 | + } | |
| 513 | + | |
| 514 | + return $settings; | |
| 515 | + } | |
| 516 | + | |
| 517 | + | |
| 518 | + | |
| 406 | 519 | // Runs on init, adds the Vipps badge feature if activated |
| 407 | 520 | public function maybe_add_vipps_badge_feature () { |
| 408 | 521 | $badge_options = get_option('vipps_badge_options'); |
| 409 | 522 | if (!$badge_options || !@$badge_options['badgeon']) return false; |
| @@ -732,8 +845,11 @@ | ||
| 732 | 845 | |
| 733 | 846 | // Get current brand and language |
| 734 | 847 | $current_brand = strtolower($this->get_payment_method_name()); |
| 735 | 848 | $current_language = $this->get_customer_language(); |
| 849 | + if ('se' === $current_language) $current_language = 'sv'; | |
| 850 | + // Looks like button and badge web components now use 'da' instead of 'dk' for danish. LP 2026-08-13 | |
| 851 | + if ('dk' === $current_language) $current_language = 'da'; | |
| 736 | 852 | |
| 737 | 853 | $variants = ['white'=> __('White', 'woo-vipps'), 'grey' => __('Grey','woo-vipps'), |
| 738 | 854 | 'filled'=> __('Filled', 'woo-vipps'), 'light'=>__('Light','woo-vipps'), |
| 739 | 855 | 'purple'=> __('Purple', 'woo-vipps')]; |
| @@ -796,9 +912,9 @@ | ||
| 796 | 912 | |
| 797 | 913 | <h2><?php _e('Shortcodes', 'woo-vipps'); ?> </h2> |
| 798 | 914 | <p><?php echo sprintf(__('If you need to add a %1$s badge on a specific page, footer, header and so on, and you cannot use the Gutenberg Block provided for this, you can either add the %1$s Badge manually (as <a href="%2$s" nofollow rel=nofollow target=_blank>documented here</a>) or you can use the shortcode.', 'woo-vipps'), Vipps::CompanyName(), "https://developer.vippsmobilepay.com/docs/knowledge-base/design-guidelines/on-site-messaging/"); ?></p> |
| 799 | 915 | <br><?php _e("The shortcode looks like this:", 'woo-vipps')?><br> |
| 800 | - <pre>[vipps-mobilepay-badge variant={white|filled|light|grey|purple}<br> language={en|no|fi|dk} ] </pre><br> | |
| 916 | + <pre>[vipps-mobilepay-badge variant={white|filled|light|grey|purple}<br> language={en|no|fi|da|sv} ] </pre><br> | |
| 801 | 917 | <?php _e("Please refer to the documentation for the meaning of the parameters.", 'woo-vipps'); ?></br> |
| 802 | 918 | <?php _e("The brand will be automatically applied.", 'woo-vipps'); ?> |
| 803 | 919 | </p> |
| 804 | 920 | |
| @@ -876,9 +992,12 @@ | ||
| 876 | 992 | public function vipps_mobilepay_badge_shortcode($atts) { |
| 877 | 993 | $args = shortcode_atts( array('id'=>'', 'class'=>'', 'brand' => '', 'variant' => '','language'=>''), $atts ); |
| 878 | 994 | |
| 879 | 995 | $variant = in_array($args['variant'], ['orange', 'light-orange', 'grey','white', 'purple', 'filled', 'light']) ? $args['variant'] : ""; |
| 880 | - $language = in_array($args['language'], ['en','no', 'fi', 'dk']) ? $args['language'] : $this->get_customer_language(); | |
| 996 | + $language = in_array($args['language'], ['en', 'no', 'sv', 'da', 'dk', 'fi']) ? $args['language'] : $this->get_customer_language(); | |
| 997 | + if ('se' === $language) $language = 'sv'; | |
| 998 | + // Looks like button and badge web components now use 'da' instead of 'dk' for danish. LP 2026-08-11 | |
| 999 | + if ('dk' === $language) $language = 'da'; | |
| 881 | 1000 | $id = sanitize_title($args['id']); |
| 882 | 1001 | $class = sanitize_text_field($args['class']); |
| 883 | 1002 | |
| 884 | 1003 | $attributes = []; |
| @@ -894,13 +1013,18 @@ | ||
| 894 | 1013 | return "<vipps-mobilepay-badge $badgeatts></vipps-mobilepay-badge>"; |
| 895 | 1014 | } |
| 896 | 1015 | |
| 897 | 1016 | // legacy vipps_badge shortcode, the new one is vipps_mobilepay_badge_shortcode. LP 19.11.2024 |
| 1017 | + // Diff: this one doesn't support brand (JUST VIPPS). LP 2026-08-11 | |
| 898 | 1018 | public function vipps_badge_shortcode($atts) { |
| 899 | 1019 | $args = shortcode_atts( array('id'=>'', 'class'=>'','variant' => '','language'=>''), $atts ); |
| 900 | 1020 | |
| 901 | 1021 | $variant = in_array($args['variant'], ['orange', 'light-orange', 'grey','white', 'purple']) ? $args['variant'] : ""; |
| 902 | - $language = in_array($args['language'], ['en','no', 'dk', 'fi']) ? $args['language'] : $this->get_customer_language(); | |
| 1022 | + $language = in_array($args['language'], ['en', 'no', 'sv', 'da', 'dk', 'fi']) ? $args['language'] : $this->get_customer_language(); | |
| 1023 | + if ('se' === $language) $language = 'sv'; | |
| 1024 | + // Looks like button and badge web components now use 'da' instead of 'dk' for danish. LP 2026-08-11 | |
| 1025 | + if ('dk' === $language) $language = 'da'; | |
| 1026 | + | |
| 903 | 1027 | $id = sanitize_title($args['id']); |
| 904 | 1028 | $class = sanitize_text_field($args['class']); |
| 905 | 1029 | |
| 906 | 1030 | $attributes = []; |
| @@ -952,8 +1076,10 @@ | ||
| 952 | 1076 | // Support using store language |
| 953 | 1077 | if ('store' === $attrs['language']) $attrs['language'] = $this->get_customer_language(); |
| 954 | 1078 | // Don't support these login verbs. LP 2026-06-04 |
| 955 | 1079 | if (in_array($attrs['verb'], ['login', 'register'])) $attrs['verb'] = 'buy'; |
| 1080 | + // Looks like button and badge web components now use 'da' instead of 'dk' for danish. LP 2026-08-11 | |
| 1081 | + if ('dk' === $attrs['language']) $attrs['language'] = 'da'; | |
| 956 | 1082 | |
| 957 | 1083 | $escaped_attrs = []; |
| 958 | 1084 | foreach($attrs as $k => $v) { |
| 959 | 1085 | $escaped_attrs[$k] = esc_attr($v); |
| @@ -1151,9 +1277,9 @@ | ||
| 1151 | 1277 | |
| 1152 | 1278 | // Update the preview web component's attributes. LP 2026-06-24 |
| 1153 | 1279 | function updatePreview(event) { |
| 1154 | 1280 | const args = getPreviewArgs(); |
| 1155 | - // LP FIXME: when i use get_customer_language() here it gives me my user language, but on frontend it gives the site language, i.e not the same value. So this preview will be wrong language. so use get_locale for now. LP 2026-07-02 | |
| 1281 | + // FIXME: when i use get_customer_language() here it gives me my user language, but on frontend it gives the site language, i.e not the same value. So this preview will be wrong language. so use get_locale for now. LP 2026-07-02 | |
| 1156 | 1282 | // if ('store' === args.language) args.language = '<?php echo $this->get_customer_language(); ?>'; |
| 1157 | 1283 | if ('store' === args.language) args.language = '<?php echo substr(get_locale(), 0, 2); ?>'; |
| 1158 | 1284 | const button = jQuery('#vipps-button-express-preview'); |
| 1159 | 1285 | button.attr(args); |
| @@ -1646,9 +1772,9 @@ | ||
| 1646 | 1772 | [ |
| 1647 | 1773 | 'in_footer' => true, |
| 1648 | 1774 | 'strategy' => 'async', |
| 1649 | 1775 | ], |
| 1650 | - ); | |
| 1776 | + ); | |
| 1651 | 1777 | |
| 1652 | 1778 | // Button web component downloaded from https://cdn.vippsmobilepay.com/js/button/button.js. LP 2026-06-24 |
| 1653 | 1779 | wp_register_script('vipps-button-webcomponent', |
| 1654 | 1780 | plugins_url('js/vipps-button.js', WC_VIPPS_PAYMENT_MAIN_FILE), |
| @@ -1654,10 +1780,9 @@ | ||
| 1654 | 1780 | plugins_url('js/vipps-button.js', WC_VIPPS_PAYMENT_MAIN_FILE), |
| 1655 | 1781 | array(), |
| 1656 | 1782 | filemtime(dirname(WC_VIPPS_PAYMENT_MAIN_FILE) . '/js/vipps-button.js'), |
| 1657 | 1783 | [ |
| 1658 | - 'in_footer' => true, | |
| 1659 | - 'strategy' => 'async', | |
| 1784 | + 'in_footer' => false | |
| 1660 | 1785 | ], |
| 1661 | 1786 | ); |
| 1662 | 1787 | } |
| 1663 | 1788 | |
| @@ -1692,8 +1817,11 @@ | ||
| 1692 | 1817 | // New vipps-mobilepay-badge shortcode. LP 19.11.2024 |
| 1693 | 1818 | add_shortcode('vipps-mobilepay-badge', array($this, 'vipps_mobilepay_badge_shortcode')); |
| 1694 | 1819 | // Legacy vipps-badge shortcode. LP 19.11.2024 |
| 1695 | 1820 | add_shortcode('vipps-badge', array($this, 'vipps_badge_shortcode')); |
| 1821 | + | |
| 1822 | + // special page handling, previously a fake page. LP 2026-08-25 | |
| 1823 | + add_shortcode('vipps_special_page', array($this, 'vipps_special_page_shortcode')); | |
| 1696 | 1824 | } |
| 1697 | 1825 | |
| 1698 | 1826 | |
| 1699 | 1827 | public function log ($what,$type='info') { |
| @@ -1719,8 +1847,10 @@ | ||
| 1719 | 1847 | } |
| 1720 | 1848 | |
| 1721 | 1849 | // Show express button option on checkout form. LP 2026-03-23 |
| 1722 | 1850 | public function checkout_before_customer_details_express () { |
| 1851 | + if (did_action('woo_vipps_checkout_before_customer_details_express')) return; | |
| 1852 | + do_action('woo_vipps_checkout_before_customer_details_express'); | |
| 1723 | 1853 | $gw = $this->gateway(); |
| 1724 | 1854 | if (!$gw->show_express_checkout()) return; |
| 1725 | 1855 | $this->express_checkout_section_html(); |
| 1726 | 1856 | } |
| @@ -2506,77 +2636,69 @@ | ||
| 2506 | 2636 | return null; |
| 2507 | 2637 | } |
| 2508 | 2638 | } |
| 2509 | 2639 | |
| 2640 | + // Special pages, and some callbacks. IOK 2018-05-18 | |
| 2641 | + public function template_redirect() { | |
| 2510 | 2642 | |
| 2511 | - // If this is a special page, return true very early because we are handling this. IOK 2023-02-22 | |
| 2512 | - public function pre_handle_404($current, $query) { | |
| 2513 | - if (!is_admin()) { | |
| 2514 | - $special = $this->is_special_page(); | |
| 2515 | - if ($special) { | |
| 2516 | - // Ensure very early on that Autooptimize does not try to optimize us (if installed) IOK 2023-03-04 | |
| 2517 | - add_filter( 'autoptimize_filter_noptimize', '__return_true'); | |
| 2518 | - return true; | |
| 2519 | - } | |
| 2643 | + // Handle legacy vipps-buy-now urls that auto-start express checkout for certain product - in QR codes etc IOK 2026-09-11 | |
| 2644 | + // We redirect these to the new location. | |
| 2645 | + $path = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH); | |
| 2646 | + if (( ($_GET['VippsSpecialPage'] ?? '') == 'vipps-buy-product') || ($path && preg_match("!/vipps-buy-product/?$!", $path)) ) { | |
| 2647 | + $url = static::get_special_page_url(); | |
| 2648 | + $_GET['action'] = 'buy_product'; | |
| 2649 | + $q = build_query($_GET); | |
| 2650 | + wp_redirect($url . "?" . $q, 302); | |
| 2651 | + exit(); | |
| 2520 | 2652 | } |
| 2521 | - return $current; | |
| 2522 | - } | |
| 2523 | 2653 | |
| 2524 | - // Special pages, and some callbacks. IOK 2018-05-18 | |
| 2525 | - public function template_redirect() { | |
| 2526 | - global $post; | |
| 2527 | - // Handle special callbacks | |
| 2528 | - $special = $this->is_special_page() ; | |
| 2529 | - | |
| 2530 | - if ($special) { | |
| 2654 | + if (static::is_special_page()) { | |
| 2655 | + // Legacy: Stop the canonical redirect here. Unclear if still necessary. IOK 2026-09-11 | |
| 2531 | 2656 | remove_filter('template_redirect', 'redirect_canonical', 10); |
| 2532 | - do_action('woo_vipps_before_handling_special_page', $special); | |
| 2657 | + // dont cache special page. LP 2026-08-25 | |
| 2658 | + $this->nocache(); | |
| 2659 | + // Do the custom pre-load actions for these pages IOK 2026-09-11 | |
| 2660 | + do_action('woo_vipps_before_handling_special_page', ($_GET['action'] ?? "")); | |
| 2661 | + } | |
| 2662 | + } | |
| 2533 | 2663 | |
| 2534 | - // Allow above hook to actually handle special pages. It should probably call $Vipps->fakepage or a redirect; can be used | |
| 2535 | - // to intercept express checkout etc. IOK 2022-03-18 | |
| 2536 | - if (! apply_filters('woo_vipps_special_page_handled', false, $special)) { | |
| 2537 | - $this->$special(); | |
| 2538 | - } | |
| 2539 | - } | |
| 2664 | + // Dynamic special page title depending on endpoint/action, only frontend. LP 2026-09-02 | |
| 2665 | + public function vipps_special_page_endpoint_title($title, $postid = 0) { | |
| 2666 | + global $wp_query; | |
| 2667 | + // Comment from woocommerce's wc_page_endpoint_title where this logic is from: LP 2026-09-02 | |
| 2540 | 2668 | |
| 2541 | - $consentremoval = $this->is_consent_removal(); | |
| 2542 | - if ($consentremoval) { | |
| 2543 | - remove_filter('template_redirect', 'redirect_canonical', 10); | |
| 2544 | - do_action('woo_vipps_before_handling_special_page', 'consentremoval'); | |
| 2545 | - if (! apply_filters('woo_vipps_special_page_handled', false, 'consentremoval')) { | |
| 2546 | - $this->vipps_consent_removal_callback($consentremoval); | |
| 2669 | + // In block themes the whole template (header, footer, content) renders inside the main | |
| 2670 | + // loop, so `the_title` fires for any post title rendered on the page (e.g. a product in a | |
| 2671 | + // server-rendered mini-cart) - not just the page's own heading. Only replace the title of | |
| 2672 | + // the queried page so an earlier title doesn't consume this one-shot filter. | |
| 2673 | + if ( ! is_null( $wp_query ) && ! is_admin() && is_main_query() && in_the_loop() && is_page() && $postid == static::get_special_page_id() ) { | |
| 2674 | + switch ($_GET['action'] ?? '') { | |
| 2675 | + case 'wait_for_payment': | |
| 2676 | + $title = __('Processing order', 'woo-vipps'); | |
| 2677 | + break; | |
| 2678 | + case 'do_express_checkout': | |
| 2679 | + case 'buy_product': | |
| 2680 | + $title = __('Express Checkout', 'woo-vipps'); | |
| 2681 | + break; | |
| 2547 | 2682 | } |
| 2548 | 2683 | } |
| 2684 | + return $title; | |
| 2549 | 2685 | } |
| 2686 | + | |
| 2550 | 2687 | // Template handling for special pages. IOK 2018-11-21 |
| 2688 | + // This is legacy - the special page is now a real page, so it can have a special template using standard WP methods. IOK 2026-09-11 | |
| 2551 | 2689 | public function template_include($template) { |
| 2552 | - $special = $this->is_special_page() ; | |
| 2553 | - if ($special) { | |
| 2690 | + if (static::is_special_page()) { | |
| 2554 | 2691 | // Get any special template override from the options IOK 2020-02-18 |
| 2555 | 2692 | $specific = $this->gateway()->get_option('vippsspecialpagetemplate'); |
| 2556 | 2693 | $found = locate_template($specific,false,false); |
| 2557 | 2694 | if ($found) $template=$found; |
| 2558 | 2695 | |
| 2559 | - return apply_filters('woo_vipps_special_page_template', $template, $special); | |
| 2696 | + return apply_filters('woo_vipps_special_page_template', $template, $_GET['action'] ?? ''); | |
| 2560 | 2697 | } |
| 2561 | 2698 | return $template; |
| 2562 | 2699 | } |
| 2563 | 2700 | |
| 2564 | - | |
| 2565 | - // Can't use wc-api for this, as that does not support DELETE . IOK 2018-05-18 | |
| 2566 | - private function is_consent_removal () { | |
| 2567 | - | |
| 2568 | - if ($_SERVER['REQUEST_METHOD'] != 'DELETE') return false; | |
| 2569 | - if ( !get_option('permalink_structure')) { | |
| 2570 | - if (@$_REQUEST['vipps-consent-removal']) return @$_REQUEST['callback']; | |
| 2571 | - return false; | |
| 2572 | - } | |
| 2573 | - if (preg_match("!/vipps-consent-removal/([^/]*)!", $_SERVER['REQUEST_URI'], $matches)) { | |
| 2574 | - return @$_REQUEST['callback']; | |
| 2575 | - } | |
| 2576 | - return false; | |
| 2577 | - } | |
| 2578 | - | |
| 2579 | 2701 | // On the thank you page, we have a completed order, so we need to restore any saved cart and possibly log in |
| 2580 | 2702 | // the user if using Express Checkout IOK 2020-10-09 |
| 2581 | 2703 | public function woocommerce_before_thankyou ($orderid) { |
| 2582 | 2704 | $order = wc_get_order($orderid); |
| @@ -2581,9 +2703,9 @@ | ||
| 2581 | 2703 | public function woocommerce_before_thankyou ($orderid) { |
| 2582 | 2704 | $order = wc_get_order($orderid); |
| 2583 | 2705 | if ($order) { |
| 2584 | 2706 | // Requires that this is express checkout and that 'create users on express checkout' is chosen. IOK 2020-10-09 |
| 2585 | - // -- or the same thing for Vipps Checkout. Also, the NHG code should not be running, and there is a filter, too. IOK 2023-08-04 | |
| 2707 | + // -- or the same thing for Checkout. Also, the NHG code should not be running, and there is a filter, too. IOK 2023-08-04 | |
| 2586 | 2708 | $this->maybe_log_in_user($order); |
| 2587 | 2709 | $order->delete_meta_data('_vipps_limited_session'); |
| 2588 | 2710 | $order->save(); |
| 2589 | 2711 | |
| @@ -2644,9 +2766,8 @@ | ||
| 2644 | 2766 | |
| 2645 | 2767 | // Support adding pickup locations to any shipping rate using the 'woo_vipps_shipping_method_pickup_points' filter |
| 2646 | 2768 | // IOK 2025-11-19 |
| 2647 | 2769 | add_filter('woo_vipps_modify_express_checkout_rate', array($this, 'express_add_pickup_location_options'), 10, 4); |
| 2648 | - | |
| 2649 | 2770 | } |
| 2650 | 2771 | |
| 2651 | 2772 | public function get_payment_method_name() { |
| 2652 | 2773 | return $this->gateway()->get_option('payment_method_name'); |
| @@ -2666,14 +2787,13 @@ | ||
| 2666 | 2787 | public function after_setup_theme() { |
| 2667 | 2788 | // To facilitate development, allow loading the plugin-supplied translations. Must be called here at the earliest. |
| 2668 | 2789 | $ok = Vipps::load_plugin_textdomain('woo-vipps', false, basename( dirname( dirname( __FILE__ ) ) ) . "/languages"); |
| 2669 | 2790 | |
| 2670 | - // Vipps Checkout replaces the default checkout page, and currently uses its own page for this which needs to exist | |
| 2791 | + // Checkout replaces the default checkout page, and currently uses its own page for this which needs to exist | |
| 2671 | 2792 | // Will also probably be used to maintain a real utility-page for Vipps actions later for themes where this |
| 2672 | 2793 | // is important. |
| 2673 | 2794 | add_filter('woocommerce_create_pages', array($this, 'woocommerce_create_pages'), 50, 1); |
| 2674 | 2795 | |
| 2675 | - | |
| 2676 | 2796 | // Callbacks use the Woo API IOK 2018-05-18 |
| 2677 | 2797 | add_action( 'woocommerce_api_wc_gateway_vipps', array($this,'vipps_callback')); |
| 2678 | 2798 | add_action( 'woocommerce_api_vipps_shipping_details', array($this,'vipps_shipping_details_callback')); |
| 2679 | 2799 | |
| @@ -2684,9 +2804,9 @@ | ||
| 2684 | 2804 | add_action( 'woocommerce_cart_actions', array($this, 'cart_express_checkout_button')); |
| 2685 | 2805 | add_action( 'woocommerce_widget_shopping_cart_buttons', array($this, 'minicart_express_checkout_button'), 30); |
| 2686 | 2806 | |
| 2687 | 2807 | // Previously we added an express html banner to the action 'woocommerce_before_checkout_form.', |
| 2688 | - // replaced by the new express buttons in manner more like Gutenberg. LP 2026-03-23 | |
| 2808 | + // replaced by the new express buttons in manner more like Gutenberg. for grepping: "express legacy checkout". LP 2026-03-23 | |
| 2689 | 2809 | add_action('woocommerce_checkout_before_customer_details', array($this, 'checkout_before_customer_details_express'), 5); |
| 2690 | 2810 | |
| 2691 | 2811 | add_action('woocommerce_after_add_to_cart_button', array($this, 'single_product_buy_now_button')); |
| 2692 | 2812 | add_action('woocommerce_after_shop_loop_item', array($this, 'loop_single_product_buy_now_button'), 20); |
| @@ -2691,12 +2811,10 @@ | ||
| 2691 | 2811 | add_action('woocommerce_after_add_to_cart_button', array($this, 'single_product_buy_now_button')); |
| 2692 | 2812 | add_action('woocommerce_after_shop_loop_item', array($this, 'loop_single_product_buy_now_button'), 20); |
| 2693 | 2813 | |
| 2694 | 2814 | |
| 2695 | - // Special pages and callbacks handled by template_redirect | |
| 2696 | - // We must also notify WP and other plugins that we are handling this 404-like situation. IOK 2023-02-22 | |
| 2815 | + // Special pages and callbacks handled by template_redirect. IOK 2023-02-22 | |
| 2697 | 2816 | add_action('template_redirect', array($this,'template_redirect'),1); |
| 2698 | - add_action('pre_handle_404', array($this, 'pre_handle_404'), 1, 2); | |
| 2699 | 2817 | |
| 2700 | 2818 | // Allow overriding their templates |
| 2701 | 2819 | add_filter('template_include', array($this,'template_include'), 10, 1); |
| 2702 | 2820 | |
| @@ -2982,14 +3100,14 @@ | ||
| 2982 | 3100 | |
| 2983 | 3101 | $raw_post = @file_get_contents( 'php://input' ); |
| 2984 | 3102 | $result = @json_decode($raw_post,true); |
| 2985 | 3103 | |
| 2986 | - // This handler handles both Vipps Checkout and Vipps ECom IOK 2021-09-02 | |
| 3104 | + // This handler handles both Checkout and Vipps ECom IOK 2021-09-02 | |
| 2987 | 3105 | // .. and the epayment webhooks 2023-12-19 |
| 2988 | 3106 | $ischeckout = false; |
| 2989 | 3107 | $iswebhook = false; |
| 2990 | 3108 | $callback = isset($_REQUEST['callback']) ? $_REQUEST['callback'] : ""; |
| 2991 | - // For Vipps Checkout v3 and onwards, we control the callback so the type is just this field | |
| 3109 | + // For Checkout v3 and onwards, we control the callback so the type is just this field | |
| 2992 | 3110 | if ($callback == 'checkout') { |
| 2993 | 3111 | $ischeckout = true; |
| 2994 | 3112 | } |
| 2995 | 3113 | // For the webhooks, we will add 'webhook' to the result, but we also know that 'pspReference' will be present. IOK 2023-12-19 |
| @@ -3403,10 +3521,10 @@ | ||
| 3403 | 3521 | $this->log(sprintf(__("Wrong %1\$s Orderid on shipping details callback", 'woo-vipps'), $this->get_payment_method_name()), 'warning'); |
| 3404 | 3522 | exit(); |
| 3405 | 3523 | } |
| 3406 | 3524 | |
| 3407 | - // If we are doing this for Vipps Checkout after version 3, communicate to any shipping methods with | |
| 3408 | - // special support for Vipps Checkout that this is in fact happening. IOK 2023-01-19 | |
| 3525 | + // If we are doing this for Checkout after version 3, communicate to any shipping methods with | |
| 3526 | + // special support for Checkout that this is in fact happening. IOK 2023-01-19 | |
| 3409 | 3527 | // This needs to be done before "calculate totals". |
| 3410 | 3528 | // Moved from "vipps_shipping_details_callback_handler" because we need it before restoring sessions. IOK 2025-05-06 |
| 3411 | 3529 | $ischeckout = $order->get_meta('_vipps_checkout'); |
| 3412 | 3530 | |
| @@ -3582,9 +3700,9 @@ | ||
| 3582 | 3700 | ), 'debug'); |
| 3583 | 3701 | |
| 3584 | 3702 | } |
| 3585 | 3703 | |
| 3586 | - // Add shipping tax rates to the *order* so we can calculate this correctly when using Vipps Checkouts | |
| 3704 | + // Add shipping tax rates to the *order* so we can calculate this correctly when using Checkouts | |
| 3587 | 3705 | // 'dynamic pricing' 2023-01-26 |
| 3588 | 3706 | // Which may be deprecated, but anyway, for future use IOK 2025-08-14 |
| 3589 | 3707 | $taxrate = 0; |
| 3590 | 3708 | if (is_array($shipping_tax_rates) && !empty($shipping_tax_rates)) { |
| @@ -3710,9 +3828,9 @@ | ||
| 3710 | 3828 | $vippsmethod['shippingMethod'] = $rate->get_label(); |
| 3711 | 3829 | $vippsmethod['shippingMethodId'] = $key; |
| 3712 | 3830 | $vippsmethods[]=$vippsmethod; |
| 3713 | 3831 | |
| 3714 | - // Metadata and settings stored for later use for Vipps Checkout | |
| 3832 | + // Metadata and settings stored for later use for Checkout | |
| 3715 | 3833 | // and express checkout - basically, for each *key* have the corresponding object. IOK 2025-08-15 |
| 3716 | 3834 | // In the end, this data will be serialized and stored in the Order, and used in the gateways method set_order_shipping_details to |
| 3717 | 3835 | // finalize the order. IOK 2025-08-15 |
| 3718 | 3836 | $ratemap[$key]=$rate; |
| @@ -3730,9 +3848,9 @@ | ||
| 3730 | 3848 | // This then is the old Express Checkout format, which we have exposed in filters. IOK 2025-08-14 |
| 3731 | 3849 | $return = array('addressId'=>intval($addressid), 'orderId'=>$vippsorderid, 'shippingDetails'=>$vippsmethods); |
| 3732 | 3850 | $return = apply_filters('woo_vipps_vipps_formatted_shipping_methods', $return); // Mostly for debugging |
| 3733 | 3851 | |
| 3734 | - // IOK 2021-11-16 Vipps Checkout uses a slightly different syntax and format. | |
| 3852 | + // IOK 2021-11-16 Checkout uses a slightly different syntax and format. | |
| 3735 | 3853 | // IOK 2025-08-15 and new Express yet another slightly different format. |
| 3736 | 3854 | // IOK 2025-08-15 pass the ratemap as a reference, so transforms can update them |
| 3737 | 3855 | if ($ischeckout) { |
| 3738 | 3856 | $return = VippsCheckout::instance()->format_shipping_methods($return, $ratemap, $methodmap, $order); |
| @@ -4108,17 +4226,8 @@ | ||
| 4108 | 4226 | header("X-Accel-Expires: 0"); |
| 4109 | 4227 | } |
| 4110 | 4228 | |
| 4111 | 4229 | |
| 4112 | - | |
| 4113 | - // Handle DELETE on a vipps consent removal callback | |
| 4114 | - public function vipps_consent_removal_callback ($callback) { | |
| 4115 | - Vipps::nocache(); | |
| 4116 | - // Currently, no such requests will be posted, and as this code isn't sufficiently tested,we'll just have | |
| 4117 | - // to escape here when the API is changed. IOK 2020-10-14 | |
| 4118 | - $this->log("Consent removal is non-functional pending API changes as of 2020-10-14"); print "1"; exit(); | |
| 4119 | - } | |
| 4120 | - | |
| 4121 | 4230 | public function woocommerce_payment_gateways($methods) { |
| 4122 | 4231 | require_once(dirname(__FILE__) . "/WC_Gateway_Vipps.class.php"); |
| 4123 | 4232 | require_once(dirname(__FILE__) . "/WC_Gateway_VippsCard.class.php"); |
| 4124 | 4233 | // Protect the singleton: Use the object instead of the class name IOK 2025-02-04 |
| @@ -4212,9 +4321,9 @@ | ||
| 4212 | 4321 | // Poll status and correct woo status. LP 2026-05-19 |
| 4213 | 4322 | $order_data = $gw->get_payment_details($order); |
| 4214 | 4323 | |
| 4215 | 4324 | // If we already know the order failed, we don't need to process the order further below. LP 2026-05-19 |
| 4216 | - if ('CANCEL' === $order_data['STATE']) { | |
| 4325 | + if ('CANCEL' === ($order_data['state'] ?? "")) { | |
| 4217 | 4326 | /* translators: company name */ |
| 4218 | 4327 | $order->update_status('cancelled', sprintf(__('Payment cancelled at %1$s.', 'woo-vipps'), Vipps::CompanyName())); |
| 4219 | 4328 | return; |
| 4220 | 4329 | } |
| @@ -4241,20 +4350,40 @@ | ||
| 4241 | 4350 | } |
| 4242 | 4351 | } |
| 4243 | 4352 | |
| 4244 | 4353 | public function activate () { |
| 4245 | - static::maybe_add_cron_event(); | |
| 4246 | - $gw = $this->gateway(); | |
| 4354 | + static::maybe_add_cron_event(); | |
| 4355 | + $gw = $this->gateway(); | |
| 4247 | 4356 | |
| 4248 | - // If store is using the default "Woo" orderprefix, generate a new one, this time using the stores' sitename if possible. IOK 2020-05-19 | |
| 4249 | - if ($gw->get_option('orderprefix') == 'Woo') { | |
| 4250 | - $gw->update_option('orderprefix', $this->generate_order_prefix()); | |
| 4251 | - } | |
| 4252 | - // IOK 2023-12-20 for the epayment api, we need to re-initialize webhooks at this point. | |
| 4253 | - $gw->initialize_webhooks(); | |
| 4254 | - $this->payment_method_name = $gw->get_option('payment_method_name'); | |
| 4255 | - } | |
| 4357 | + // If store is using the default "Woo" orderprefix, generate a new one, this time using the stores' sitename if possible. IOK 2020-05-19 | |
| 4358 | + if ($gw->get_option('orderprefix') == 'Woo') { | |
| 4359 | + $gw->update_option('orderprefix', $this->generate_order_prefix()); | |
| 4360 | + } | |
| 4361 | + // IOK 2023-12-20 for the epayment api, we need to re-initialize webhooks at this point. | |
| 4362 | + $gw->initialize_webhooks(); | |
| 4363 | + $this->payment_method_name = $gw->get_option('payment_method_name'); | |
| 4256 | 4364 | |
| 4365 | + | |
| 4366 | + // Check if the special page is noted and actually does exist | |
| 4367 | + $special = static::get_special_page_id(); | |
| 4368 | + if ($special) { | |
| 4369 | + $special_page = get_post($special); | |
| 4370 | + if ($special_page && 'trash' !== $special_page->post_status) { | |
| 4371 | + // Ensure this page has the necessary shortcode. LP 2026-09-01 | |
| 4372 | + if (!has_shortcode($special_page->post_content, 'vipps_special_page')) { | |
| 4373 | + $new_content = $special_page->post_content . "\n\n<!-- wp:shortcode -->[vipps_special_page]<!-- /wp:shortcode -->"; | |
| 4374 | + wp_update_post([ | |
| 4375 | + 'ID' => $special, | |
| 4376 | + 'post_content' => $new_content, | |
| 4377 | + ]); | |
| 4378 | + } | |
| 4379 | + } else { | |
| 4380 | + delete_option('woocommerce_vipps_special_page_page_id'); | |
| 4381 | + } | |
| 4382 | + } | |
| 4383 | + | |
| 4384 | + } | |
| 4385 | + | |
| 4257 | 4386 | // We have added some hooks to wp-cron; remove these. IOK 2020-04-01 |
| 4258 | 4387 | public static function deactivate() { |
| 4259 | 4388 | $timestamp = wp_next_scheduled('vipps_cron_cleanup_hook'); |
| 4260 | 4389 | wp_unschedule_event($timestamp, 'vipps_cron_cleanup_hook'); |
| @@ -4307,9 +4436,10 @@ | ||
| 4307 | 4436 | // If setting is true, use Vipps as default payment. Called by the woocommrece_cart_updated hook. IOK 2018-06-06 |
| 4308 | 4437 | private function maybe_set_vipps_as_default() { |
| 4309 | 4438 | if (WC()->session->get('chosen_payment_method')) return; // User has already chosen payment method, so we're done. |
| 4310 | 4439 | $gw = $this->gateway(); |
| 4311 | - if ($gw->get_option('vippsdefault')=='yes') { | |
| 4440 | + // Do *not* default to vipps if Kustom Checkout is installed IOK 2026-09-11 | |
| 4441 | + if ($gw->get_option('vippsdefault')=='yes' && !class_exists('KCO')) { | |
| 4312 | 4442 | WC()->session->set('chosen_payment_method', $gw->id); |
| 4313 | 4443 | } |
| 4314 | 4444 | } |
| 4315 | 4445 | |
| @@ -4414,13 +4544,13 @@ | ||
| 4414 | 4544 | if (is_user_logged_in()) return; |
| 4415 | 4545 | if (!$order || ! self::is_vipps_order($order)) return; |
| 4416 | 4546 | |
| 4417 | 4547 | // We *do* want to log in express checkout customers, but not those that |
| 4418 | - // use the Vipps Checkout solution - those can change their emails in the | |
| 4548 | + // use the Checkout solution - those can change their emails in the | |
| 4419 | 4549 | // checkout screen. IOK 2021-09-03 |
| 4420 | 4550 | $do_login = $order->get_meta('_vipps_express_checkout'); |
| 4421 | 4551 | |
| 4422 | - // We will not log in Vipps Checkout users unless the option for that is true | |
| 4552 | + // We will not log in Checkout users unless the option for that is true | |
| 4423 | 4553 | if ($order->get_meta('_vipps_checkout') && 'yes' != $this->gateway()->get_option('checkoutcreateuser')) { |
| 4424 | 4554 | $do_login = false; |
| 4425 | 4555 | } |
| 4426 | 4556 | |
| @@ -4455,9 +4585,9 @@ | ||
| 4455 | 4585 | |
| 4456 | 4586 | // Both Checkout and Express Checkout have the below value set to true |
| 4457 | 4587 | if (!$order->get_meta('_vipps_express_checkout')) return; |
| 4458 | 4588 | |
| 4459 | - // Creating/logging in users are handled separately for Vipps Checkout and Express Checkout, so check the correct setting | |
| 4589 | + // Creating/logging in users are handled separately for Checkout and Express Checkout, so check the correct setting | |
| 4460 | 4590 | // IOK 2023-07-27 |
| 4461 | 4591 | $ischeckout = $order->get_meta('_vipps_checkout'); |
| 4462 | 4592 | if ($ischeckout) { |
| 4463 | 4593 | if ($this->gateway()->get_option('checkoutcreateuser') != 'yes') return null; |
| @@ -4842,9 +4972,9 @@ | ||
| 4842 | 4972 | $ok = wc()->shipping->register_shipping_method( new Automattic\WooCommerce\Blocks\Shipping\PickupLocation() ); |
| 4843 | 4973 | } |
| 4844 | 4974 | } |
| 4845 | 4975 | |
| 4846 | - // Vipps Checkout and Express Checkout allows loading specific kinds of shipping methods with non-standard APIs, such as PickupLocations. IOK 2025-05-08 | |
| 4976 | + // Checkout and Express Checkout allows loading specific kinds of shipping methods with non-standard APIs, such as PickupLocations. IOK 2025-05-08 | |
| 4847 | 4977 | // Must be called *early*. IOK 2025-05-08. Called in callback methods, and if using static shipping, in the 'start session' callback. |
| 4848 | 4978 | public function load_extra_shipping_methods($order, $addressdata, $ischeckout=false) { |
| 4849 | 4979 | // If we need to add more shipping methods *before* the shipping callback starts, it must be done before we load the session. IOK 2025-05-06 |
| 4850 | 4980 | add_action('woocommerce_load_shipping_methods', function () use ($order, $addressdata) { |
| @@ -4915,46 +5045,37 @@ | ||
| 4915 | 5045 | wp_send_json(array('status'=>'error', 'msg'=> __('Unknown payment status','woo-vipps') . ' ' . $payment)); |
| 4916 | 5046 | return false; |
| 4917 | 5047 | } |
| 4918 | 5048 | |
| 4919 | - // The various return URLs for special pages of the Vipps stuff depend on settings and pretty-URLs so we supply them from here | |
| 4920 | - // These are for the "fallback URL" mostly. IOK 2018-05-18 | |
| 4921 | - private function make_vipps_url($what) { | |
| 4922 | - if ( !get_option('permalink_structure')) { | |
| 4923 | - return add_query_arg('VippsSpecialPage', $what, home_url("/", 'https')); | |
| 4924 | - } | |
| 4925 | - return trailingslashit(home_url($what, 'https')); | |
| 5049 | + // The various return URLs for special pages of the Vipps stuff. Previously used a fake page and had to check permalink_structure. LP 2026-08-26 | |
| 5050 | + private function make_special_page_url($action) { | |
| 5051 | + return add_query_arg('action', $action, $this->get_special_page_url()); | |
| 4926 | 5052 | } |
| 5053 | + | |
| 4927 | 5054 | public function payment_return_url() { |
| 4928 | - return apply_filters('woo_vipps_payment_return_url', $this->make_vipps_url('vipps-betaling')); | |
| 5055 | + return apply_filters('woo_vipps_payment_return_url', $this->make_special_page_url('wait_for_payment')); | |
| 4929 | 5056 | } |
| 4930 | 5057 | public function express_checkout_url() { |
| 4931 | - return $this->make_vipps_url('vipps-express-checkout'); | |
| 5058 | + return $this->make_special_page_url('do_express_checkout'); | |
| 4932 | 5059 | } |
| 4933 | 5060 | public function buy_product_url() { |
| 4934 | - return $this->make_vipps_url('vipps-buy-product'); | |
| 5061 | + return $this->make_special_page_url('buy_product'); | |
| 4935 | 5062 | } |
| 4936 | 5063 | |
| 4937 | - // Return the method in the Vipps | |
| 4938 | - public function is_special_page() { | |
| 4939 | - $specials = array('vipps-betaling' => 'vipps_wait_for_payment', 'vipps-express-checkout'=>'vipps_express_checkout', 'vipps-buy-product'=>'vipps_buy_product'); | |
| 4940 | - $method = null; | |
| 4941 | - if ( get_option('permalink_structure')) { | |
| 4942 | - foreach($specials as $special=>$specialmethod) { | |
| 4943 | - // IOK 2018-06-07 Change to add any prefix from home-url for better matching IOK 2018-06-07 | |
| 4944 | - $path = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH); | |
| 4945 | - if ($path && preg_match("!/$special/?$!", $path, $matches)) { | |
| 4946 | - $method = $specialmethod; break; | |
| 4947 | - } | |
| 4948 | - } | |
| 4949 | - } else { | |
| 4950 | - if (isset($_GET['VippsSpecialPage'])) { | |
| 4951 | - $method = @$specials[$_GET['VippsSpecialPage']]; | |
| 4952 | - } | |
| 4953 | - } | |
| 4954 | - return $method; | |
| 5064 | + public static function is_special_page() { | |
| 5065 | + $id = static::get_special_page_id(); | |
| 5066 | + return $id && is_page($id); | |
| 4955 | 5067 | } |
| 4956 | 5068 | |
| 5069 | + public static function get_special_page_id() { | |
| 5070 | + $id = wc_get_page_id('vipps_special_page'); // -1 if not found | |
| 5071 | + return $id > 0 ? $id : null; | |
| 5072 | + } | |
| 5073 | + | |
| 5074 | + public static function get_special_page_url() { | |
| 5075 | + return get_permalink(static::get_special_page_id()); | |
| 5076 | + } | |
| 5077 | + | |
| 4957 | 5078 | // Just create a spinner and a overlay. |
| 4958 | 5079 | public function spinner () { |
| 4959 | 5080 | $flavour = sanitize_title($this->get_payment_method_name()); |
| 4960 | 5081 | ob_start(); |
| @@ -5001,16 +5122,8 @@ | ||
| 5001 | 5122 | } |
| 5002 | 5123 | return null; |
| 5003 | 5124 | } |
| 5004 | 5125 | |
| 5005 | - // DEPRECATED: Legacy function as of new web component express buttons. see get_buy_now_button and get_html_button. LP 2026-06-26 | |
| 5006 | - public function get_buy_now_button_manual($product_id, $variation_id=null, $sku=null, $disabled=false, $classes='', | |
| 5007 | - $_logo_variant=null, $_logo_lang=null, // deprecated params | |
| 5008 | - $context='global', $button_args_override = [], | |
| 5009 | - ) { | |
| 5010 | - return $this->get_buy_now_button($product_id, $variation_id, $sku, $disabled, $classes, $context, $button_args_override); | |
| 5011 | - } | |
| 5012 | - | |
| 5013 | 5126 | // Code that will generate various versions of the 'buy now with Vipps' button IOK 2018-09-27 |
| 5014 | 5127 | // $context is slug describing where its to be used, like 'catalog', 'cart', 'product' etc. and will |
| 5015 | 5128 | // be used unless $button_args_override is nonempty. See init_button_options() and get_html_button() LP 2026-06-26 |
| 5016 | 5129 | public function get_buy_now_button($product_id,$variation_id=null,$sku=null,$disabled=false, $classes='', $context='global', $button_args_override = []) { |
| @@ -5029,9 +5142,8 @@ | ||
| 5029 | 5142 | if ($sku) $data['product_sku'] = $sku; |
| 5030 | 5143 | if ($product_id) $data['product_id'] = $product_id; |
| 5031 | 5144 | if ($variation_id) $data['variation_id'] = $variation_id; |
| 5032 | 5145 | |
| 5033 | - | |
| 5034 | 5146 | $buttoncode = "<a href='javascript:void(0)' $disabled "; |
| 5035 | 5147 | foreach($data as $key=>$value) { |
| 5036 | 5148 | $value = esc_attr($value); |
| 5037 | 5149 | $buttoncode .= " data-$key='$value' "; |
| @@ -5055,8 +5167,11 @@ | ||
| 5055 | 5167 | if ($classes) $classes = " $classes"; |
| 5056 | 5168 | if ($short) $classes = "short $classes"; |
| 5057 | 5169 | |
| 5058 | 5170 | $buttoncode .= " class='single-product button vipps-buy-now $payment_method $disabled$classes' title='$title'>$button</a>"; |
| 5171 | + | |
| 5172 | + | |
| 5173 | + | |
| 5059 | 5174 | return apply_filters('woo_vipps_buy_now_button', $buttoncode, $product_id, $variation_id, $sku, $disabled); |
| 5060 | 5175 | } |
| 5061 | 5176 | |
| 5062 | 5177 | // Display a 'buy now with express checkout' button on the product page IOK 2018-09-27 |
| @@ -5140,43 +5255,90 @@ | ||
| 5140 | 5255 | } |
| 5141 | 5256 | |
| 5142 | 5257 | |
| 5143 | 5258 | |
| 5144 | - // Vipps Checkout replaces the default checkout page, and currently uses its own page for this which needs to exist | |
| 5259 | + // Checkout replaces the default checkout page, and currently uses its own page for this which needs to exist | |
| 5145 | 5260 | // IOK 2026-04-30 remove this when checkout is end-of-life'd |
| 5261 | + // We now also use this for the vipps special page, previously a fakepage. LP 2026-08-18 | |
| 5146 | 5262 | public function woocommerce_create_pages ($data) { |
| 5263 | + // Vipps Checkout page | |
| 5147 | 5264 | $vipps_checkout_activated = get_option('woo_vipps_checkout_activated', false); |
| 5148 | - if (!$vipps_checkout_activated) return $data; | |
| 5265 | + if ($vipps_checkout_activated) { | |
| 5266 | + $data['vipps_checkout'] = array( | |
| 5267 | + 'name' => _x( 'vipps_checkout', 'Page slug', 'woo-vipps' ), | |
| 5268 | + 'title' => _x( 'Vipps MobilePay Checkout', 'Page title', 'woo-vipps' ), | |
| 5269 | + 'content' => '<!-- wp:shortcode -->[' . 'vipps_checkout' . ']<!-- /wp:shortcode -->', | |
| 5270 | + ); | |
| 5271 | + } | |
| 5149 | 5272 | |
| 5150 | - $data['vipps_checkout'] = array( | |
| 5151 | - 'name' => _x( 'vipps_checkout', 'Page slug', 'woo-vipps' ), | |
| 5152 | - 'title' => _x( 'Vipps MobilePay Checkout', 'Page title', 'woo-vipps' ), | |
| 5153 | - 'content' => '<!-- wp:shortcode -->[' . 'vipps_checkout' . ']<!-- /wp:shortcode -->', | |
| 5154 | - ); | |
| 5155 | - | |
| 5273 | + // Vipps special page for certain payment flow actions. Previously a fake page. LP 2026-08-18 | |
| 5274 | + $data['vipps_special_page'] = [ | |
| 5275 | + 'name' => 'vipps-payment', // slug | |
| 5276 | + /* translators: company name */ | |
| 5277 | + 'title' => sprintf(__('%s special page', 'woo-vipps'), static::CompanyName()), // we hide the title frontend in template_redirect. LP 2026-08-27 | |
| 5278 | + 'content' => '<!-- wp:shortcode -->[vipps_special_page]<!-- /wp:shortcode -->', | |
| 5279 | + ]; | |
| 5156 | 5280 | return $data; |
| 5157 | 5281 | } |
| 5158 | 5282 | |
| 5159 | - // Creates any necessary Vipps pages. Will be called e.g. when activating Vipps Checkout or turning it on. | |
| 5283 | + // Creates any necessary Vipps pages. E.g vipps checkout page or vipps special page. LP 2026-09-01 | |
| 5284 | + // If a page slug already exists, then it won't overwrite or duplicate it!. LP 2026-09-02 | |
| 5160 | 5285 | public function maybe_create_vipps_pages () { |
| 5286 | + $make_pages = false; | |
| 5287 | + | |
| 5288 | + // Vipps Checkout page. LP 2026-08-18 | |
| 5161 | 5289 | $checkoutid = wc_get_page_id('vipps_checkout'); |
| 5162 | - $makeit = !$checkoutid || ! get_post_status($checkoutid); | |
| 5163 | - if ($makeit) { | |
| 5290 | + if (!$checkoutid || ! get_post_status($checkoutid)) { | |
| 5164 | 5291 | delete_option('woocommerce_vipps_checkout_page_id'); |
| 5292 | + $make_pages = true; | |
| 5165 | 5293 | } |
| 5166 | 5294 | |
| 5167 | - if ($makeit) { | |
| 5168 | - WC_Install::create_pages(); | |
| 5295 | + // vipps special page, previously a fake page. LP 2026-08-18 | |
| 5296 | + $builtin_special_page_id = static::get_special_page_id(); | |
| 5297 | + if (!$builtin_special_page_id || !get_post_status($builtin_special_page_id)) { | |
| 5298 | + delete_option('woocommerce_vipps_special_page_page_id'); | |
| 5299 | + $make_pages = true; | |
| 5169 | 5300 | } |
| 5301 | + | |
| 5302 | + if ($make_pages) { | |
| 5303 | + WC_Install::create_pages(); | |
| 5304 | + } | |
| 5170 | 5305 | } |
| 5171 | 5306 | |
| 5307 | + public function vipps_special_page_shortcode($atts, $content) { | |
| 5308 | + // No point in expanding this unless we are actually doing the special actions. LP 2026-08-25 | |
| 5309 | + if (is_admin()) return; | |
| 5310 | + if (wp_doing_ajax()) return; | |
| 5311 | + if (defined('REST_REQUEST') && REST_REQUEST) return; | |
| 5312 | + if (did_filter('woo_vipps_special_page_html')) return; // User has somehow added two shortcodes. IOK 2026-09-18 | |
| 5172 | 5313 | |
| 5314 | + $action = $_GET['action'] ?? ''; | |
| 5315 | + $html = ""; | |
| 5316 | + switch ($action) { | |
| 5317 | + case 'wait_for_payment': | |
| 5318 | + $html = $this->vipps_wait_for_payment(); | |
| 5319 | + break; | |
| 5320 | + case 'do_express_checkout': | |
| 5321 | + $html = $this->vipps_express_checkout(); | |
| 5322 | + break; | |
| 5323 | + case 'buy_product': | |
| 5324 | + $html = $this->vipps_buy_product(); | |
| 5325 | + break; | |
| 5326 | + default: | |
| 5327 | + $html = ''; | |
| 5328 | + } | |
| 5329 | + // This is mostly to avoid this shortcode evaluating twice IOK 2026-09-18 | |
| 5330 | + $html = apply_filters('woo_vipps_special_page_html', $html, $action); | |
| 5331 | + | |
| 5332 | + // Remember, this is a shortcode, so the html must be returned, not echoed IOK 2026-09-11 | |
| 5333 | + return $html; | |
| 5334 | + } | |
| 5335 | + | |
| 5336 | + | |
| 5173 | 5337 | // This URL will when accessed add a product to the cart and go directly to the express checkout page. |
| 5174 | 5338 | // The argument passed must be a shareable link created for a given product - so this in effect acts as a landing page for |
| 5175 | 5339 | // the buying thru Vipps Express Checkout of a single product linked to in for instance banners. IOK 2018-09-24 |
| 5176 | 5340 | public function vipps_buy_product() { |
| 5177 | - status_header(200,'OK'); | |
| 5178 | - Vipps::nocache(); | |
| 5179 | 5341 | |
| 5180 | 5342 | add_filter('body_class', function ($classes) { |
| 5181 | 5343 | $classes[] = 'vipps-express-checkout'; |
| 5182 | 5344 | $classes[] = 'woocommerce-checkout'; // Required by Pixel Your Site IOK 2022-11-24 |
| @@ -5212,9 +5374,9 @@ | ||
| 5212 | 5374 | |
| 5213 | 5375 | if (!$productinfo) { |
| 5214 | 5376 | $title = __("Product is no longer available",'woo-vipps'); |
| 5215 | 5377 | $content = __("The link you have followed is for a product that is no longer available at this location. Please return to the store and try again",'woo-vipps'); |
| 5216 | - return $this->fakepage($title,$content); | |
| 5378 | + return $this->special_page_html($title,$content); | |
| 5217 | 5379 | } |
| 5218 | 5380 | |
| 5219 | 5381 | // Pass the productinfo to the express checkout form |
| 5220 | 5382 | $args = array(); |
| @@ -5231,15 +5393,13 @@ | ||
| 5231 | 5393 | } |
| 5232 | 5394 | $args[sanitize_title(wp_unslash($key))] = sanitize_text_field(wp_unslash($value)); |
| 5233 | 5395 | } |
| 5234 | 5396 | |
| 5235 | - $this->print_express_checkout_page(true,'do_single_product_express_checkout',$args); | |
| 5397 | + return $this->express_checkout_page_html(true,'do_single_product_express_checkout',$args); | |
| 5236 | 5398 | } |
| 5237 | 5399 | |
| 5238 | 5400 | // This is a landing page for the express checkout of then normal cart - it is done like this because this could take time on slower hosts. |
| 5239 | 5401 | public function vipps_express_checkout() { |
| 5240 | - status_header(200,'OK'); | |
| 5241 | - Vipps::nocache(); | |
| 5242 | 5402 | // We need a nonce to get here, but we should only get here when we have a cart, so this will not be cached. |
| 5243 | 5403 | // IOK 2018-05-28 |
| 5244 | 5404 | $ok = isset($_REQUEST['sec']) && wp_verify_nonce($_REQUEST['sec'],'express'); |
| 5245 | 5405 | |
| @@ -5266,9 +5426,9 @@ | ||
| 5266 | 5426 | }); |
| 5267 | 5427 | |
| 5268 | 5428 | do_action('woo_vipps_express_checkout_page'); |
| 5269 | 5429 | |
| 5270 | - $this->print_express_checkout_page(true, 'do_express_checkout'); | |
| 5430 | + return $this->express_checkout_page_html(true, 'do_express_checkout'); | |
| 5271 | 5431 | } |
| 5272 | 5432 | |
| 5273 | 5433 | // This method tries to ensure that a customer does not 'lose' the return page and |
| 5274 | 5434 | // starts ordering the same products twice. IOK 2020-01-22 |
| @@ -5363,9 +5523,10 @@ | ||
| 5363 | 5523 | return $orderspec; |
| 5364 | 5524 | } |
| 5365 | 5525 | |
| 5366 | 5526 | // Used as a landing page for launching express checkout - borh for the cart and for single products. IOK 2018-09-28 |
| 5367 | - protected function print_express_checkout_page($execute,$action,$productinfo=null) { | |
| 5527 | + // Returns the html. LP 2026-08-27 | |
| 5528 | + protected function express_checkout_page_html($execute,$action,$productinfo=null) { | |
| 5368 | 5529 | $gw = $this->gateway(); |
| 5369 | 5530 | |
| 5370 | 5531 | $expressCheckoutMessages = array(); |
| 5371 | 5532 | $expressCheckoutMessages['termsAndConditionsError'] = __( 'Please read and accept the terms and conditions to proceed with your order.', 'woocommerce' ); |
| @@ -5448,10 +5609,9 @@ | ||
| 5448 | 5609 | |
| 5449 | 5610 | if ($execute) { |
| 5450 | 5611 | $content .= "<p id=waiting>" . __("Please wait while we are preparing your order", 'woo-vipps') . "</p>"; |
| 5451 | 5612 | $content .= "<div id='vipps-status-message'></div>"; |
| 5452 | - $this->fakepage(__('Order in progress','woo-vipps'), $content); | |
| 5453 | - return; | |
| 5613 | + return $this->special_page_html('', $content); | |
| 5454 | 5614 | } else { |
| 5455 | 5615 | $content .= $askForConfirmationHTML; |
| 5456 | 5616 | $content .= $extraHTML; |
| 5457 | 5617 | $content .= $termsHTML; |
| @@ -5458,21 +5618,16 @@ | ||
| 5458 | 5618 | $content .= apply_filters('woo_vipps_express_checkout_validation_elements', ''); |
| 5459 | 5619 | $title = sprintf(__('Buy now with %1$s!', 'woo-vipps'), $this->get_payment_method_name()); |
| 5460 | 5620 | $content .= "<div class='vipps_buy_now_wrapper noloop'><a href='#' id='do-express-checkout' class='vipps-express-checkout' title='$title'>$buttonhtml</a></div>"; |
| 5461 | 5621 | $content .= "<div id='vipps-status-message'></div>"; |
| 5462 | - $this->fakepage(sprintf(__('%1$s Express Checkout','woo-vipps'), $this->get_payment_method_name()), $content); | |
| 5463 | - return; | |
| 5622 | + return $this->special_page_html('', $content); | |
| 5464 | 5623 | } |
| 5465 | 5624 | } |
| 5466 | 5625 | |
| 5467 | 5626 | |
| 5468 | - | |
| 5469 | - public function vipps_wait_for_payment() { | |
| 5470 | - status_header(200,'OK'); | |
| 5471 | - Vipps::nocache(); | |
| 5472 | - | |
| 5627 | + // Called in template_redirect before we get to the wait-for-payment page IOK 2026-09-21 | |
| 5628 | + private function handle_payment_poll_and_redirect () { | |
| 5473 | 5629 | $orderid = WC()->session->get('_vipps_pending_order'); |
| 5474 | - | |
| 5475 | 5630 | $order = null; |
| 5476 | 5631 | $gw = $this->gateway(); |
| 5477 | 5632 | |
| 5478 | 5633 | // Failsafe for when the session disappears IOK 2018-11-19 |
| @@ -5484,9 +5639,9 @@ | ||
| 5484 | 5639 | // If so, we will read the order id from the GET arguments and check if the auth token is correct, |
| 5485 | 5640 | // simulating the session with that. |
| 5486 | 5641 | // IOK 2019-11-19, changed to using GET 2023-01-23 |
| 5487 | 5642 | if ($no_session && $limited_session) { |
| 5488 | - $orderid = intval(@$_GET['id']); | |
| 5643 | + $orderid = intval($_GET['id'] ?? false); | |
| 5489 | 5644 | } |
| 5490 | 5645 | if ($orderid) { |
| 5491 | 5646 | clean_post_cache($orderid); |
| 5492 | 5647 | $order = wc_get_order($orderid); |
| @@ -5505,11 +5660,8 @@ | ||
| 5505 | 5660 | $session->set('_vipps_pending_order', $orderid); |
| 5506 | 5661 | } |
| 5507 | 5662 | } |
| 5508 | 5663 | |
| 5509 | - | |
| 5510 | - do_action('woo_vipps_wait_for_payment_page',$order); | |
| 5511 | - | |
| 5512 | 5664 | $deleted_order=0; |
| 5513 | 5665 | if ($orderid && !$order) { |
| 5514 | 5666 | // If this happens, we actually did have an order, but it has been deleted, which must mean that it was cancelled. |
| 5515 | 5667 | // Concievably a hook on the 'cancel'-transition or in the callback handlers could clean that up before we get here. IOK 2019-09-26 |
| @@ -5534,9 +5686,9 @@ | ||
| 5534 | 5686 | clean_post_cache($orderid); |
| 5535 | 5687 | $order = wc_get_order($orderid); // Reload order object |
| 5536 | 5688 | } |
| 5537 | 5689 | } else { |
| 5538 | - // No need to do anyting here. IOK 2020-01-26 | |
| 5690 | + // No need to do anyting here. IOK 2020-01-26 | |
| 5539 | 5691 | } |
| 5540 | 5692 | |
| 5541 | 5693 | $payment = 'notchecked'; |
| 5542 | 5694 | if ($do_poll) { |
| @@ -5552,9 +5704,8 @@ | ||
| 5552 | 5704 | exit(); |
| 5553 | 5705 | } |
| 5554 | 5706 | |
| 5555 | 5707 | // We are done, but in failure. Don't poll. |
| 5556 | - $content = ""; | |
| 5557 | 5708 | $failure_redirect = apply_filters('woo_vipps_order_failed_redirect', '', $orderid); |
| 5558 | 5709 | |
| 5559 | 5710 | // Status is failed; still send to return url (as of now /order-recieved), the text there will depend on the status. |
| 5560 | 5711 | // For failed it shows a "Retry payment" button that takes the customer to /pay-for-order where it will be retried. LP 2026-03-17 |
| @@ -5562,8 +5713,9 @@ | ||
| 5562 | 5713 | $failure_redirect = $failure_redirect ?: $gw->get_return_url($order); |
| 5563 | 5714 | wp_redirect($failure_redirect); |
| 5564 | 5715 | exit(); |
| 5565 | 5716 | } |
| 5717 | + | |
| 5566 | 5718 | if ($status == 'cancelled' || $payment == 'cancelled') { |
| 5567 | 5719 | $this->maybe_restore_cart($orderid,'failed'); |
| 5568 | 5720 | if ($failure_redirect){ |
| 5569 | 5721 | wp_redirect($failure_redirect); |
| @@ -5568,27 +5720,45 @@ | ||
| 5568 | 5720 | if ($failure_redirect){ |
| 5569 | 5721 | wp_redirect($failure_redirect); |
| 5570 | 5722 | exit(); |
| 5571 | 5723 | } |
| 5724 | + } else { | |
| 5725 | + // If not, enqueue the status checker IOK 2026-09-21 | |
| 5726 | + wp_enqueue_script('check-vipps',plugins_url('js/check-order-status.js',__FILE__),array('jquery','vipps-gw'),filemtime(dirname(__FILE__) . "/js/check-order-status.js"), 'true'); | |
| 5727 | + } | |
| 5728 | + | |
| 5729 | + // Communicate this to the shortcode IOK 2026-09-21 | |
| 5730 | + add_filter('woo_vipps_wait_for_payment_status', function () use($orderid, $status, $payment) { | |
| 5731 | + return ['orderid'=>$orderid, 'status'=>$status, 'payment'=>$payment]; | |
| 5732 | + }); | |
| 5733 | + | |
| 5734 | + } | |
| 5735 | + | |
| 5736 | + public function vipps_wait_for_payment() { | |
| 5737 | + | |
| 5738 | + // This will have been computed in template_redirect, but the status will be either still pending or failed. IOK 2026-09-21 | |
| 5739 | + $data = apply_filters('woo_vipps_wait_for_payment_status', []); | |
| 5740 | + | |
| 5741 | + $orderid = $data['orderid'] ?? 0; | |
| 5742 | + $status = $data['status'] ?? ""; | |
| 5743 | + $payment = $data['payment'] ?? ""; | |
| 5744 | + | |
| 5745 | + $order = wc_get_order($orderid); | |
| 5746 | + if (!$order) wp_die(__('Unknown order', 'woo-vipps')); | |
| 5747 | + | |
| 5748 | + do_action('woo_vipps_wait_for_payment_page',$order); | |
| 5749 | + $gw = $this->gateway(); | |
| 5750 | + | |
| 5751 | + $content = ""; | |
| 5752 | + if ($status == 'cancelled' || $payment == 'cancelled') { | |
| 5572 | 5753 | $content .= "<div id=failure><p>". __('Order cancelled','woo-vipps') . '</p>'; |
| 5573 | 5754 | $content .= "<p><a href='" . home_url() . "' class='btn button'>" . __('Continue shopping','woo-vipps') . '</a></p>'; |
| 5574 | 5755 | $content .= "</div>"; |
| 5575 | - $this->fakepage(__('Order cancelled','woo-vipps'), $content); | |
| 5576 | - | |
| 5577 | - return; | |
| 5756 | + return $this->special_page_html('', $content); | |
| 5578 | 5757 | } |
| 5579 | 5758 | |
| 5580 | 5759 | // Still pending and order is supposed to exist, so wait for Vipps. This happens all the time, so logging is removed. IOK 2018-09-27 |
| 5581 | - | |
| 5582 | 5760 | // Otherwise, go to a page waiting/polling for the callback. IOK 2018-05-16 |
| 5583 | - wp_enqueue_script('check-vipps',plugins_url('js/check-order-status.js',__FILE__),array('jquery','vipps-gw'),filemtime(dirname(__FILE__) . "/js/check-order-status.js"), 'true'); | |
| 5584 | - | |
| 5585 | - // Check that order exists and belongs to our session. Can use WC()->session->get() I guess - set the orderid or a hash value in the session | |
| 5586 | - // and check that the order matches (and is 'pending') (and exists) | |
| 5587 | - $vippsstamp = $order->get_meta('_vipps_init_timestamp'); | |
| 5588 | - $vippsstatus = $order->get_meta('_vipps_status'); | |
| 5589 | - $message = __($order->get_meta('_vipps_confirm_message'),'woo-vipps'); | |
| 5590 | - | |
| 5591 | 5761 | $signal = $this->callbackSignal($order); |
| 5592 | 5762 | $content = ""; |
| 5593 | 5763 | $content .= "<div id='waiting'><p>" . sprintf(__('Waiting for confirmation of purchase from %1$s','woo-vipps'), $this->get_payment_method_name()); |
| 5594 | 5764 | |
| @@ -5596,15 +5766,16 @@ | ||
| 5596 | 5766 | $signalurl = $this->callbackSignalURL($signal); |
| 5597 | 5767 | |
| 5598 | 5768 | $content .= "</p></div>"; |
| 5599 | 5769 | |
| 5600 | - // We impersonate the woocommerce-checkout form here mainly to work with the Pixel Your Site plugin IOK 2022-11-24 | |
| 5601 | - $classlist = apply_filters("woo_vipps_express_checkout_form_classes", "woocommerce-checkout"); | |
| 5602 | - $content .= "<form id='vippsdata' class='" . esc_attr($classlist) . "'>"; | |
| 5770 | + $failure_redirect = apply_filters('woo_vipps_order_failed_redirect', '', $orderid); | |
| 5771 | + | |
| 5772 | + // Carry the order status to the checking script IOK 2026-09-21 | |
| 5773 | + $content .= "<form id='vippsdata'>"; | |
| 5603 | 5774 | $content .= "<input type='hidden' id='fkey' name='fkey' value='".htmlspecialchars($signalurl)."'>"; |
| 5604 | 5775 | $content .= "<input type='hidden' name='key' value='".htmlspecialchars($order->get_order_key())."'>"; |
| 5605 | 5776 | $content .= "<input type='hidden' name='action' value='check_order_status'>"; |
| 5606 | - $content .= wp_nonce_field('vippsstatus','sec',1,false); | |
| 5777 | + $content .= wp_nonce_field('vippsstatus','sec',1,false); | |
| 5607 | 5778 | $content .= "</form>"; |
| 5608 | 5779 | |
| 5609 | 5780 | |
| 5610 | 5781 | $content .= "<div id='error' style='display:none'><p>".__('Error during order confirmation','woo-vipps'). '</p>'; |
| @@ -5621,93 +5792,21 @@ | ||
| 5621 | 5792 | $content .= "<a id='continueToOrderFailed' style='display:none' href='" . $failure_redirect . "'></a>"; |
| 5622 | 5793 | $content .= "<a id='continueToOrderFailedFallback' style='display:none' href='" . $gw->get_return_url($order) . "'></a>"; |
| 5623 | 5794 | $content .= "</div>"; |
| 5624 | 5795 | |
| 5796 | + return $this->special_page_html('', $content); | |
| 5797 | + } | |
| 5625 | 5798 | |
| 5626 | - $this->fakepage(__('Waiting for your order confirmation','woo-vipps'), $content); | |
| 5799 | + // Returns formatted html for the vipps special page. LP 2026-08-27 | |
| 5800 | + public function special_page_html($header, $content) { | |
| 5801 | + $header_html = $header ? "<h2 class='vipps-special-page-title page-title'>$header</h2>" : ''; | |
| 5802 | + $html = <<<EOF | |
| 5803 | + $header_html | |
| 5804 | + <div class="vipps-special-page-content">$content</div> | |
| 5805 | + EOF; | |
| 5806 | + return apply_filters('woo_vipps_special_page_html', $html, $header, $content); | |
| 5627 | 5807 | } |
| 5628 | 5808 | |
| 5629 | - | |
| 5630 | - | |
| 5631 | - public function fakepage($title,$content) { | |
| 5632 | - global $wp, $wp_query; | |
| 5633 | - // We don't want this here. | |
| 5634 | - remove_filter ('the_content', 'wpautop'); | |
| 5635 | - | |
| 5636 | - $specialid = $this->gateway()->get_option('vippsspecialpageid'); | |
| 5637 | - $wp_post = null; | |
| 5638 | - if ($specialid) { | |
| 5639 | - $wp_post = get_post($specialid); | |
| 5640 | - if ($wp_post) { | |
| 5641 | - $wp_post->post_title = $title; | |
| 5642 | - $wp_post->post_content = $content; | |
| 5643 | - // Normalize a bit | |
| 5644 | - $wp_post->filter = 'raw'; // important | |
| 5645 | - $wp_post->post_status = 'publish'; | |
| 5646 | - $wp_post->comment_status= 'closed'; | |
| 5647 | - $wp_post->ping_status= 'closed'; | |
| 5648 | - } else { | |
| 5649 | - $this->log(sprintf(__("Could not use special page with id %s - it seems not to exist.", 'woo-vipps'), $specialid), 'error'); | |
| 5650 | - } | |
| 5651 | - } | |
| 5652 | - if (!$wp_post || is_wp_error($wp_post)) { | |
| 5653 | - $post = new stdClass(); | |
| 5654 | - $post->ID = -99; | |
| 5655 | - $post->post_author = 1; | |
| 5656 | - $post->post_date = current_time( 'mysql' ); | |
| 5657 | - $post->post_date_gmt = current_time( 'mysql', 1 ); | |
| 5658 | - $post->post_title = $title; | |
| 5659 | - $post->post_content = $content; | |
| 5660 | - $post->post_status = 'publish'; | |
| 5661 | - $post->comment_status = 'closed'; | |
| 5662 | - $post->ping_status = 'closed'; | |
| 5663 | - $post->post_name = 'vippsconfirm-fake-page-name'; | |
| 5664 | - $post->post_type = 'page'; | |
| 5665 | - $post->filter = 'raw'; // important | |
| 5666 | - $wp_post = new WP_Post($post); | |
| 5667 | - wp_cache_add( -99, $wp_post, 'posts' ); | |
| 5668 | - } | |
| 5669 | - | |
| 5670 | - // Update the main query | |
| 5671 | - $wp_query->post = $wp_post; | |
| 5672 | - $wp_query->posts = array( $wp_post ); | |
| 5673 | - $wp_query->queried_object = $wp_post; | |
| 5674 | - $wp_query->queried_object_id = $wp_post->ID; | |
| 5675 | - $wp_query->found_posts = 1; | |
| 5676 | - $wp_query->post_count = 1; | |
| 5677 | - $wp_query->max_num_pages = 1; | |
| 5678 | - $wp_query->is_page = true; | |
| 5679 | - $wp_query->is_singular = true; | |
| 5680 | - $wp_query->is_single = false; | |
| 5681 | - $wp_query->is_attachment = false; | |
| 5682 | - $wp_query->is_archive = false; | |
| 5683 | - $wp_query->is_category = false; | |
| 5684 | - $wp_query->is_tag = false; | |
| 5685 | - $wp_query->is_tax = false; | |
| 5686 | - $wp_query->is_author = false; | |
| 5687 | - $wp_query->is_date = false; | |
| 5688 | - $wp_query->is_year = false; | |
| 5689 | - $wp_query->is_month = false; | |
| 5690 | - $wp_query->is_day = false; | |
| 5691 | - $wp_query->is_time = false; | |
| 5692 | - $wp_query->is_search = false; | |
| 5693 | - $wp_query->is_feed = false; | |
| 5694 | - $wp_query->is_comment_feed = false; | |
| 5695 | - $wp_query->is_trackback = false; | |
| 5696 | - $wp_query->is_home = false; | |
| 5697 | - $wp_query->is_embed = false; | |
| 5698 | - $wp_query->is_404 = false; | |
| 5699 | - $wp_query->is_paged = false; | |
| 5700 | - $wp_query->is_admin = false; | |
| 5701 | - $wp_query->is_preview = false; | |
| 5702 | - $wp_query->is_robots = false; | |
| 5703 | - $wp_query->is_posts_page = false; | |
| 5704 | - $wp_query->is_post_type_archive = false; | |
| 5705 | - // Update globals | |
| 5706 | - $GLOBALS['wp_query'] = $wp_query; | |
| 5707 | - $wp->register_globals(); | |
| 5708 | - return $wp_post; | |
| 5709 | - } | |
| 5710 | 5809 | |
| 5711 | 5810 | // Support the interactivity API with data about our cart IOK 2026-02-23 |
| 5712 | 5811 | public function woo_vipps_store_api_cart_data() { |
| 5713 | 5812 | // Reverting the condition with the directive data-wp-bind--hidden does not work, so we need the flipped bool here (hide instead of show). LP 2026-02-10 |