PluginProbe
PostNL for WooCommerce / trunk
PostNL for WooCommerce vtrunk
5.9.12 5.9.11 5.9.10 5.9.9 5.9.8 5.9.7 5.9.6 trunk 2.5.0 2.5.1 2.5.2 2.5.3 2.5.4 2.5.5 3.1.4 3.1.5 3.1.6 3.1.7 4.0.0 4.0.1 4.0.2 4.3.2 4.3.3 4.4.0 4.4.1 All 72 releases
woo-postnl / src / Admin / Api_Key_Banner.php

Api_Key_Banner.php in PostNL for WooCommerce trunk, at src/Admin/Api_Key_Banner.php

251 lines 7.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Class Admin\Api_Key_Banner file.
4 *
5 * Renders the admin banner that asks merchants to enter the new PostNL API
6 * key ahead of the upcoming API migration. The banner is shown on the PostNL
7 * settings screen and on the WooCommerce orders list. Two dismissal modes
8 * are supported: "remind me later" (cleared on the next login) and a
9 * permanent dismiss stored per user.
10 *
11 * @package PostNLWooCommerce\Admin
12 */
13
14 namespace PostNLWooCommerce\Admin;
15
16 use PostNLWooCommerce\Shipping_Method\Settings;
17
18 if ( ! defined( 'ABSPATH' ) ) {
19 exit;
20 }
21
22 /**
23 * Class Api_Key_Banner
24 */
25 class Api_Key_Banner {
26
27 const META_DISMISSED = 'postnl_new_api_key_banner_dismissed';
28 const META_REMIND_LATER = 'postnl_new_api_key_banner_remind_later';
29 const NONCE_ACTION = 'postnl_new_api_key_banner';
30 const AJAX_ACTION = 'postnl_dismiss_new_api_key_banner';
31
32 /**
33 * Memoized result of is_target_screen() for the current request.
34 *
35 * @var bool|null
36 */
37 protected $is_target_screen = null;
38
39 /**
40 * Register hooks.
41 */
42 public function __construct() {
43 add_action( 'admin_notices', array( $this, 'maybe_render' ) );
44 add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_assets' ) );
45 add_action( 'wp_ajax_' . self::AJAX_ACTION, array( $this, 'handle_ajax_dismiss' ) );
46 add_action( 'wp_login', array( $this, 'clear_remind_later_on_login' ), 10, 2 );
47 }
48
49 /**
50 * Is the current screen one where the banner should appear?
51 */
52 protected function is_target_screen() {
53 if ( null !== $this->is_target_screen ) {
54 return $this->is_target_screen;
55 }
56
57 $this->is_target_screen = $this->resolve_target_screen();
58
59 return $this->is_target_screen;
60 }
61
62 /**
63 * Determine whether the current screen is one where the banner appears.
64 */
65 protected function resolve_target_screen() {
66 if ( ! function_exists( 'get_current_screen' ) ) {
67 return false;
68 }
69
70 $screen = get_current_screen();
71 if ( empty( $screen ) ) {
72 return false;
73 }
74
75 if ( 'woocommerce_page_wc-settings' === $screen->id
76 && isset( $_GET['section'] ) // phpcs:ignore WordPress.Security.NonceVerification.Recommended
77 && POSTNL_SETTINGS_ID === sanitize_text_field( wp_unslash( $_GET['section'] ) ) // phpcs:ignore WordPress.Security.NonceVerification.Recommended
78 ) {
79 return true;
80 }
81
82 if ( 'edit-shop_order' === $screen->id ) {
83 return true;
84 }
85
86 if ( 'woocommerce_page_wc-orders' === $screen->id ) {
87 return true;
88 }
89
90 return false;
91 }
92
93 /**
94 * Should the banner be visible right now for this user?
95 */
96 protected function should_show() {
97 if ( ! current_user_can( 'manage_woocommerce' ) ) {
98 return false;
99 }
100
101 if ( ! $this->is_target_screen() ) {
102 return false;
103 }
104
105 $settings = Settings::get_instance();
106 $new_key = $settings->get_api_key_new();
107
108 // If a valid new key has already been entered we have what we need.
109 if ( '' !== $new_key && $settings->is_api_key_new_validated() ) {
110 return false;
111 }
112
113 $user_id = get_current_user_id();
114 if ( get_user_meta( $user_id, self::META_DISMISSED, true ) ) {
115 return false;
116 }
117
118 if ( get_user_meta( $user_id, self::META_REMIND_LATER, true ) ) {
119 return false;
120 }
121
122 return true;
123 }
124
125 /**
126 * Render the banner markup.
127 */
128 public function maybe_render() {
129 if ( ! $this->should_show() ) {
130 return;
131 }
132
133 $nonce = wp_create_nonce( self::NONCE_ACTION );
134 $has_old_key = '' !== trim( (string) Settings::get_instance()->get_original_api_key() );
135
136 // Existing merchants (who already have a key) get the amber "warning"
137 // banner; a fresh install gets the blue "info" one, matching the mockup.
138 $notice_class = $has_old_key ? 'notice-warning' : 'notice-info';
139 ?>
140 <div class="notice <?php echo esc_attr( $notice_class ); ?> postnl-new-api-key-banner" data-nonce="<?php echo esc_attr( $nonce ); ?>">
141 <p><strong><?php esc_html_e( 'PostNL:', 'postnl-for-woocommerce' ); ?></strong> <?php echo wp_kses_post( $this->get_message( $has_old_key ) ); ?></p>
142 <p>
143 <a href="<?php echo esc_url( Settings::SELF_SERVICE_URL ); ?>" target="_blank" rel="noopener noreferrer" class="button button-primary">
144 <?php esc_html_e( 'Get your API key', 'postnl-for-woocommerce' ); ?>
145 </a>
146 <button type="button" class="button button-secondary postnl-new-api-key-remind">
147 <?php esc_html_e( 'Remind me later', 'postnl-for-woocommerce' ); ?>
148 </button>
149 <button type="button" class="button button-secondary postnl-new-api-key-dismiss">
150 <?php esc_html_e( 'Dismiss', 'postnl-for-woocommerce' ); ?>
151 </button>
152 </p>
153 </div>
154 <?php
155 }
156
157 /**
158 * Banner body text (final copy supplied by PostNL). Existing merchants (who
159 * already have a legacy key stored) are told an extra field was added; a fresh
160 * install, which may still hold a pre-migration v2 key, is pointed at the "Get
161 * your API key" button below to request a v4 key. Neither variant carries an
162 * inline link (the button below is the single call to action).
163 *
164 * @param bool $has_old_key Whether a legacy key is already stored.
165 */
166 protected function get_message( $has_old_key ) {
167 if ( $has_old_key ) {
168 return __(
169 'Important: In the latest update of the plug-in, an additional API key field has been added to the account configuration of the PostNL plug-in. This field must be filled in with the new API key that can be obtained via the Self Service module on the PostNL Business Portal. This API key is required to gain access to the new APIs that will be rolled out in a future update of the plug-in. It is very important that this key is entered before the relevant update is performed; otherwise, no connection can be made to the new PostNL APIs, and it will not be possible to create labels or use checkout features such as delivery days and pickup points.',
170 'postnl-for-woocommerce'
171 );
172 }
173
174 return __(
175 'Important: PostNL is migrating to the new Future-proof API v4. Don\'t you have an API key yet, or do you have an API key issued before September 14, 2026? Request a new API key below. Enter your PostNL API key in the account configuration of the PostNL plug-in. This key is required to connect to the PostNL APIs. Without it you cannot create labels or use checkout features such as delivery days and pickup points.',
176 'postnl-for-woocommerce'
177 );
178 }
179
180 /**
181 * Enqueue the dismissal JS on screens where the banner can appear.
182 *
183 * @param string $hook_suffix Current admin page hook.
184 */
185 public function enqueue_assets( $hook_suffix ) {
186 unset( $hook_suffix );
187
188 if ( ! $this->is_target_screen() ) {
189 return;
190 }
191
192 wp_enqueue_script(
193 'postnl-new-api-key-banner',
194 POSTNL_WC_PLUGIN_DIR_URL . '/assets/js/new-api-key-banner.js',
195 array( 'jquery' ),
196 POSTNL_WC_VERSION,
197 true
198 );
199
200 wp_localize_script(
201 'postnl-new-api-key-banner',
202 'postnlNewApiKeyBanner',
203 array(
204 'ajaxUrl' => admin_url( 'admin-ajax.php' ),
205 'action' => self::AJAX_ACTION,
206 )
207 );
208 }
209
210 /**
211 * AJAX handler for both dismiss modes.
212 */
213 public function handle_ajax_dismiss() {
214 if ( ! current_user_can( 'manage_woocommerce' ) ) {
215 wp_send_json_error( array( 'message' => 'forbidden' ), 403 );
216 }
217
218 check_ajax_referer( self::NONCE_ACTION, 'nonce' );
219
220 $mode = isset( $_POST['mode'] ) ? sanitize_key( wp_unslash( $_POST['mode'] ) ) : '';
221 $user_id = get_current_user_id();
222
223 if ( 'remind' === $mode ) {
224 update_user_meta( $user_id, self::META_REMIND_LATER, time() );
225 wp_send_json_success();
226 }
227
228 if ( 'dismiss' === $mode ) {
229 update_user_meta( $user_id, self::META_DISMISSED, 1 );
230 wp_send_json_success();
231 }
232
233 wp_send_json_error( array( 'message' => 'invalid mode' ), 400 );
234 }
235
236 /**
237 * Wipe the "remind me later" flag whenever the user logs in, so the
238 * banner comes back the next session.
239 *
240 * @param string $user_login Username.
241 * @param \WP_User $user Logged-in user.
242 */
243 public function clear_remind_later_on_login( $user_login, $user ) {
244 unset( $user_login );
245
246 if ( $user instanceof \WP_User ) {
247 delete_user_meta( $user->ID, self::META_REMIND_LATER );
248 }
249 }
250 }
251