PluginProbe
Pay with Vipps and MobilePay for WooCommerce / trunk
Pay with Vipps and MobilePay for WooCommerce vtrunk
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 6.0.0 5.4.3 5.4.2 5.4.1 5.4.0 5.3.4 trunk 1.10.0 All 182 releases
woo-vipps / payment / VippsQRCodeController.class.php

VippsQRCodeController.class.php in Pay with Vipps and MobilePay for WooCommerce trunk, at payment/VippsQRCodeController.class.php

665 lines 31.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /*
3 This class is for the Vipps QR-code feature, and is implemented as its own singleton instance because this isolates that 'aspect' of the
4 system. It is instantiated as a member of the main Vipps class.
5
6 This file is part of the plugin Pay with Vipps and MobilePay for WooCommerce
7 Copyright (c) 2022 WP-Hosting AS
8
9 MIT License
10
11 Copyright (c) 2022 WP-Hosting AS
12
13 Permission is hereby granted, free of charge, to any person obtaining a copy
14 of this software and associated documentation files (the "Software"), to deal
15 in the Software without restriction, including without limitation the rights
16 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17 copies of the Software, and to permit persons to whom the Software is
18 furnished to do so, subject to the following conditions:
19
20 The above copyright notice and this permission notice shall be included in all
21 copies or substantial portions of the Software.
22
23 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29 SOFTWARE.
30 */
31
32
33
34 class VippsQRCodeController {
35
36 private static $instance = null;
37 public function __construct() {
38 }
39
40 public static function instance() {
41 if (!static::$instance) static::$instance = new VippsQRCodeController();
42 return static::$instance;
43 }
44
45 public static function register_hooks() {
46 // We can only support the QR api if we are connected to Vipps.
47 if (!get_option('woo-vipps-configured', false)) return;
48 // Some people may want to turn this off
49 if (!apply_filters('woo_vipps_support_qr_codes', true)) return;
50
51 $controller = static::instance();
52 if (is_admin()) {
53 add_action('admin_init',array($controller,'admin_init'));
54 add_action('admin_menu',array($controller,'admin_menu'));
55 }
56 add_action('init',array($controller,'init'));
57 add_action('woocommerce_loaded', array($controller,'woocommerce_loaded'));
58 }
59
60 public function woocommerce_loaded () {
61 }
62 public function admin_init() {
63 add_meta_box( '_vipps_qr_data', __( 'URL', 'woo-vipps' ), array( $this, 'metabox_url' ), 'vipps_qr_code', 'normal', 'default' );
64 add_action('save_post_vipps_qr_code', array($this, 'save_post'), 10, 3);
65 add_action('admin_enqueue_scripts', array($this, 'admin_enqueue_scripts'));
66 add_action('admin_footer', array($this, 'admin_footer'));
67
68 add_filter('views_edit-vipps_qr_code', array($this, 'qr_list_views'));
69
70 add_action('admin_post_vipps_qr_handle_unsynched', array($this, 'handle_unsynched'));
71
72 add_action('in_admin_header', function () {
73 $screen = get_current_screen();
74 if ($screen && $screen->id == 'vipps_qr_code') {
75 global $post;
76 if (!$post) return;
77 $errors = get_post_meta($post->ID, '_vipps_qr_errors', true);
78 if ($errors) {
79 foreach ($errors as $err) {
80 add_action('admin_notices', function () use ($err) {
81 printf( '<div class="notice notice-error"><p>%s</p></div>', esc_html( $err) );
82 });
83 }
84 delete_post_meta($post->ID, '_vipps_qr_errors');
85 }
86
87 $vid = get_post_meta($post->ID, '_vipps_qr_id', true);
88 if ($vid) {
89 // This is kept in a transient, so we should not need to call out
90 $all = $this->get_all_qr_codes_at_vipps();
91 if (!isset($all[$vid])) {
92 delete_post_meta($post->ID, '_vipps_qr_img');
93 add_action('admin_notices', function () use ($err) {
94 printf( '<div class="notice notice-error"><p>%s</p></div>', sprintf(__("Somehow, this QR code has disappeard at %1\$s. Save it to make it work again!", 'woo-vipps'), "Vipps"));
95 });
96 }
97 }
98
99 }
100 });
101 }
102
103 public function admin_enqueue_scripts ($hook) {
104 $screen = get_current_screen();
105 if ($screen && $screen->id == 'edit-vipps_qr_code') {
106 wp_enqueue_script( 'jquery-ui-dialog' );
107 wp_enqueue_style( 'wp-jquery-ui-dialog' );
108 }
109 if ($screen && $screen->id == 'vipps_qr_code') {
110 wp_enqueue_script('wc-enhanced-select');
111 wp_enqueue_style('woocommerce_admin_styles');
112 }
113 }
114
115 // This also does some garbage collection/cleanup by deleting code-objects no longer present at Vipps. It is called on the QR code overview screen.
116 public function get_all_qr_codes_at_vipps () {
117 $stored = get_transient('_woo_vipps_qr_codes');
118 if (is_array($stored)) return $stored;
119 $api = WC_Gateway_Vipps::instance()->api;
120 $all = [];
121 try {
122 $all = $api->get_all_merchant_redirect_qr();
123 } catch (Exception $e) {
124 Vipps::instance()->log(sprintf(__("Error getting list of QR codes from %1\$s: %2\$s", 'woo-vipps'), "Vipps", $e->getMessage()), 'error');
125 delete_transient('_woo_vipps_qr_codes');
126 delete_transient('_woo_vipps_unsynched_qr_codes');
127 return $all;
128 }
129 $table = array();
130 foreach($all as &$entry) {
131 $table[$entry['id']] = $entry;
132 }
133 set_transient('_woo_vipps_qr_codes', $table, DAY_IN_SECONDS);
134 return $table;
135 }
136 // Called only to check if there are unsynchronized codes, which are cached.
137 public function get_all_local_qr_codes () {
138 global $wpdb;
139 $all = $wpdb->get_results("SELECT post_id, meta_key, meta_value from `{$wpdb->postmeta}` WHERE meta_key = '_vipps_qr_id'", ARRAY_A);
140 if (!$all) return [];
141 $table = [];
142 foreach ($all as $entry) {
143 $table[$entry['meta_value']] = $entry['post_id'];
144 }
145 return $table;
146 }
147 public function get_unsynchronized_qr_codes() {
148 $stored = get_transient('_woo_vipps_unsynched_qr_codes');
149 if (is_array($stored)) return $stored;
150 $all = $this->get_all_qr_codes_at_vipps();
151 $local = $this->get_all_local_qr_codes();
152 $table = [];
153 foreach(array_keys($all) as $key) {
154 if (!isset($local[$key])) {
155 $table[$key] = $all[$key];
156 }
157 }
158 set_transient('_woo_vipps_unsynched_qr_codes', $table, DAY_IN_SECONDS);
159 return $table;
160 }
161
162 // POST handler for the import-unsynched feature
163 public function handle_unsynched () {
164 if (!current_user_can('manage_woocommerce')) {
165 wp_die(__('You don\'t have sufficient rights to access this page', 'woo-vipps'));
166 }
167 if (!isset($_POST['vipps_qr_import']) || !wp_verify_nonce($_POST['vipps_qr_import'], 'vipps_qr_import')) {
168 wp_die(__('Invalid request', 'woo-vipps'));
169 }
170 $operation = "";
171 if (isset($_POST['operation-delete']) && $_POST['operation-delete']) {
172 $operation = "delete";
173 } else if (isset($_POST['operation-import']) && $_POST['operation-import']) {
174 $operation = "import";
175 } else {
176 wp_die(__('Unknown operation', 'woo-vipps'));
177 }
178
179 $qrids = isset($_POST['qrids']) ? $_POST['qrids'] : [];
180 if (!is_array($qrids)) $qrids = [];
181 if ($operation == 'delete') {
182 $api = WC_Gateway_Vipps::instance()->api;
183 foreach($qrids as $vid){
184 try {
185 $api->delete_merchant_redirect_qr($vid);
186 } catch (Exception $e) {
187 Vipps::instance()->log(sprintf(__("Error deleting unsynched QR code with id %1\$s: %2\$s", 'woo-vipps'),$vid, $e->getMessage()), 'error');
188 }
189 }
190 } else if ($operation == 'import') {
191 $all = $this->get_all_qr_codes_at_vipps();
192 foreach($qrids as $vid){
193 $entry = $all[$vid];
194 $url = isset($entry['redirectUrl']) ? $entry['redirectUrl'] : home_url("/");
195 if (!$url) {
196 continue;
197 }
198 try {
199 $postargs = array(
200 'post_title' => __("Imported QR Code", 'woo-vipps'),
201 'post_excerpt' => __("Imported QR Code", 'woo-vipps'),
202 'post_status' => 'publish',
203 'post_type' => 'vipps_qr_code',
204 'meta_input' => ['_vipps_qr_id' => $vid, '_vipps_qr_urltype'=>'url', '_vipps_qr_stored' => true]
205 );
206 $ok = wp_insert_post($postargs, 'wp_error', true);
207 if ($ok) {
208 // This will trigger update + image download
209 update_post_meta($ok, '_vipps_qr_url', sanitize_url($url));
210 }
211 if (is_wp_error($ok)) {
212 Vipps::instance()->log(sprintf(__("Error importing unsynched QR code with id %1\$s: %2\$s", 'woo-vipps'),$vid, $e->get_error_message()), 'error');
213 }
214 } catch (Exception $e) {
215 Vipps::instance()->log(sprintf(__("Error importing unsynched QR code with id %1\$s: %2\$s", 'woo-vipps'),$vid, $e->getMessage()), 'error');
216 }
217 }
218
219 }
220 delete_transient('_woo_vipps_qr_codes');
221 delete_transient('_woo_vipps_unsynched_qr_codes');
222 wp_redirect(admin_url("/edit.php?post_type=vipps_qr_code"));
223 }
224
225 public function admin_footer() {
226 $screen = get_current_screen();
227 if ($screen && $screen->id == 'edit-vipps_qr_code') {
228 $all = $this->get_unsynchronized_qr_codes();
229 ?>
230 <!-- The modal / dialog box, hidden somewhere near the footer on the QR screen. -->
231 <div id="vipps_unsynchronized_qr_codes" class="hidden" title="<?php _e('Vipps QR-codes not present on this site', 'woo-vipps'); ?>"
232 <div>
233 <p><?php _e("There are some QR codes present at Vipps that are not part of this Website. This may be because these are part of some <i>other</i> website using this same account, or they may have gotten 'lost' in a database restore - or maybe you are creating an entire new site. If neccessary, you can import these into your current site and manage them from here", 'woo-vipps'); ?></p>
234 <div class="importsection">
235 <form action="<?php echo admin_url('/admin-post.php'); ?>" method="POST" onsubmit="return confirm('<?php _e("Are you sure?", 'woo-vipps'); ?>');">
236 <?php wp_nonce_field("vipps_qr_import", 'vipps_qr_import' ); ?>
237 <input type="hidden" name="action" value="vipps_qr_handle_unsynched">
238 <div class="buttonsection">
239 <button class="button btn primary" name="operation-import" value="vipps_qr_unsynch_import"><?php _e("Import", 'woo-vipps'); ?></button>
240 <button class="button btn secondary" name="operation-delete" value="vipps_qr_unsynch_delete"><?php _e("delete", 'woo-vipps'); ?></button>
241 </div>
242 <table class="table importtable">
243 <thead>
244 <tr><th class='checkboxcell'><th class="idcell"><?php _e("Id", 'woo-vipps'); ?></th><th class='urlcell'><?php _e('URL', 'woo-vipps'); ?></th></tr>
245 </thead>
246 <tbody>
247 <?php foreach ($all as $id=>$entry): ?>
248 <tr>
249 <td class='checkboxcell'><input type="checkbox" name='qrids[]' value="<?php echo esc_attr($id); ?>"></td>
250 <td class='idcell'><?php echo esc_html($id); ?></td>
251 <?php $urlvalue = (isset($entry['redirectUrl'])) ? $entry['redirectUrl'] : home_url("/"); ?>
252 <td class='urlcell'><input type="url" readonly value="<?php echo esc_url($urlvalue); ?>"></td>
253 </tr>
254
255
256 <?php endforeach; ?>
257 </tbody>
258 </table>
259
260 </form>
261 </div>
262
263 </div>
264 <?php
265 }
266 }
267
268 public function qr_list_views ($views) {
269 $all = $this->get_unsynchronized_qr_codes();
270 $count = count(array_keys($all));
271 if ($count>0) {
272 $unsynch = "<a class='open_unsynchronized_qr_codes' href=\"javascript:void(0);\" title='" . __("Show QR codes not synchronized to this site", 'woo-vipps') . "'>";
273 $unsynch .= __("Unsynchronized QR codes", 'woo-vipps');
274 $unsynch .= " <span class='count'>($count)</span>";
275 $unsynch .= "</a>";
276
277 $views['unsynchronized'] = $unsynch;
278 }
279 return $views;
280
281 }
282
283 public function metabox_url () {
284 global $post;
285 $pid = $post->ID;
286 $id = get_post_meta($pid, '_vipps_qr_id', true); // Reference at Vipps
287 $url = get_post_meta($pid, '_vipps_qr_url', true); // The URL to add/modify
288 $qr = get_post_meta($pid, '_vipps_qr_img', true); // The QR image
289 $qrpid = get_post_meta($pid, '_vipps_qr_pid', true); // If linking to a product or page, this would be it
290 $urltype = get_post_meta($pid, '_vipps_qr_urltype', true); // What kind of URL we are working with
291
292 $pngsize = apply_filters('woo_vipps_qr_png_size', 640); // width/height of PNG qr code
293 $imagefilename = sanitize_file_name($post->post_title); // Filename for downloaded svgs and pngs
294
295 if (!$urltype) {
296 // Unknown urltype, either a new QR or some database issue. Try to handle gracefully.
297 if ($qrpid) {
298 if (is_page($qrpid)) {
299 $urltype = 'pageid';
300 } else if (get_post_type($qrpid) == 'product') {
301 $urltype = 'prodid';
302 } else if ($url) { // Unknown product type, we should have the URL still though
303 $urltype = 'url';
304 } else {
305 // This should never happen
306 $qrpid = 0;
307 $urltype = 'url';
308 }
309 } else if ($url) {
310 $urltype = 'url';
311 } else {
312 // Brand new! Assume we want a page.
313 $urltype = 'pageid';
314 }
315 }
316 $pageid = ($urltype == 'pageid') ? $qrpid : 0;
317 $prodid = ($urltype == 'productid') ? $qrpid : 0;
318
319
320 $screen = get_current_screen();
321
322 wp_nonce_field("vipps_qr_metabox_save", 'vipps_qr_metabox_nonce' );
323 ?>
324 <label><?php echo esc_html__( 'QR-id', 'woo-vipps' ); ?>: <?php echo esc_html($id); ?></label><br>
325
326 <div class="url-section">
327 <label><?php echo esc_html__('Select link type', 'woo-vipps'); ?></label>
328 <div class="link-selector">
329 <label for="pageidtab"><?php _e("Page", 'woo-vipps'); ?>
330 <input type=radio class="vipps_urltype" id=pageidtab value="pageid" name="_vipps_qr_urltype" <?php if ($urltype=='pageid') echo " checked "; ?>>
331 </label>
332
333 <label for="productidtab"><?php _e("Product", 'woo-vipps'); ?>
334 <input type=radio class="vipps_urltype" id=productidtab value="productid" name="_vipps_qr_urltype" <?php if ($urltype=='productid') echo " checked "; ?>>
335 </label>
336
337 <label for="urltab"><?php _e("URL", 'woo-vipps'); ?>
338 <input type=radio class="vipps_urltype" id=urltab value="url" name="_vipps_qr_urltype" <?php if ($urltype=='url') echo " checked "; ?>>
339 </label>
340
341 </div>
342 <div class="url-options">
343 <div class="url-option pageid <?php if ($urltype=='pageid') echo " active "; ?>">
344 <label><?php echo esc_html__('Choose page', 'woo-vipps'); ?>:</label>
345 <?php wp_dropdown_pages(['selected'=>$pageid, 'echo'=>1, 'id'=>'page_id', 'name'=>'_vipps_qr_pid', 'class'=>'vipps-page-selector wc-enhanced-select', 'show_option_none'=> __('None chosen', 'woo-vipps')]); ?>
346 </div>
347
348 <div class="url-option productid <?php if ($urltype=='productid') echo " active "; ?>">
349 <label><?php echo esc_html__('Choose product', 'woo-vipps'); ?>:</label>
350 <select class="wc-product-search" style="width:100%" id="product_id" name="_vipps_qr_pid" data-placeholder="<?php esc_attr_e( 'Search for a product&hellip;', 'woocommerce' ); ?>" data-action="woocommerce_json_search_products">
351 <?php if ($prodid):
352 $product = wc_get_product($prodid);
353 if (is_a($product, 'WC_Product')):
354 echo "<option value='" . intval($prodid) . "' selected>" . wp_kses_post( $product->get_formatted_name() ) . "</option>";
355 endif;
356 endif; ?>
357 </select>
358 </div>
359
360
361 <div class="url-option url <?php if ($urltype=='url') echo " active "; ?>">
362 <label><?php echo esc_html__( 'URL', 'woo-vipps' ); ?></label>
363 <input name="_vipps_qr_url" type="url" value="<?php echo esc_attr( sanitize_text_field( $url) ); ?>" style="width:100%;" />
364 </div>
365 </div>
366 </div>
367
368 <div>
369 <label for="excerpt"><?php _e( 'Description' ); ?></label><textarea style="margin-top:0px; width:100%" rows="1" cols="40" name="excerpt" id="excerpt"><?php echo $post->post_excerpt; // textarea_escaped ?></textarea>
370 </div>
371
372 <div class="qrimageholder" style="padding-top:1rem; padding-bottom: 1rem; display:flex; justify-content: space-between">
373 <?php if ($qr): ?>
374 <div class="qrimagedownloadbuttons" style="display:flex;flex-direction:column;">
375 <a class="button downloadsvg" style="margin-top: .7rem"><?php echo esc_html__("Download as SVG", 'woo-vipps'); ?></a>
376 <a class="button downloadpng" style="margin-top: .7rem"><?php echo esc_html__("Download as PNG", 'woo-vipps'); ?></a>
377 </div>
378 <div id='qrimage' class='qrimage' style='width:25%'><?php echo $qr ?></div>
379 <?php endif; ?>
380 </div>
381
382 <script>
383 jQuery('.button.downloadsvg').click(function () {
384 var svgData = jQuery("#qrimage")[0].innerHTML;
385 var svgBlob = new Blob([svgData], {type:"image/svg+xml;charset=utf-8"});
386 var domUrl = window.URL || window.webkitURL || window;
387 var svgUrl = domUrl.createObjectURL(svgBlob);
388 var downloadLink = document.createElement("a");
389 downloadLink.href = svgUrl;
390 downloadLink.target = "_blank";
391 downloadLink.download = <?php echo json_encode($imagefilename . ".svg"); ?>;
392 document.body.appendChild(downloadLink);
393 downloadLink.click();
394 document.body.removeChild(downloadLink);
395 });
396
397 jQuery('.button.downloadpng').click(function () {
398 var svgData = jQuery("#qrimage")[0].innerHTML;
399 var svgBlob = new Blob([svgData], {type:"image/svg+xml;charset=utf-8"});
400 var domUrl = window.URL || window.webkitURL || window;
401 var svgUrl = domUrl.createObjectURL(svgBlob);
402 var canvas = document.createElement("canvas");
403 canvas.width = <?php echo json_encode($pngsize); ?>;
404 canvas.height= <?php echo json_encode($pngsize); ?>;
405 var ctx = canvas.getContext('2d');
406 var img = new Image();
407 img.onload = function () {
408 ctx.drawImage(img, 0, 0);
409 domUrl.revokeObjectURL(svgUrl);
410 var imgURI = canvas.toDataURL('image/png').replace('image/png', 'image/octet-stream');
411
412 var downloadLink = document.createElement("a");
413 downloadLink.href = imgURI;
414 downloadLink.target = "_blank";
415 downloadLink.download = <?php echo json_encode($imagefilename . ".png"); ?>;
416 document.body.appendChild(downloadLink);
417 downloadLink.click();
418 document.body.removeChild(downloadLink);
419
420 };
421
422 img.src = svgUrl;
423 });
424
425
426 </script>
427
428
429 <?php
430 }
431
432
433 // This handles "save post" from the admin backend. IOK 2022-04-13
434 public function save_post ($qid, $post, $update) {
435 if (!isset($_POST['vipps_qr_metabox_nonce']) || !wp_verify_nonce($_POST['vipps_qr_metabox_nonce'], 'vipps_qr_metabox_save')) return;
436 if (!isset($_POST['_vipps_qr_urltype'])) return;
437
438 $urltype = sanitize_title($_POST['_vipps_qr_urltype']);
439 if (!$urltype) return false;
440
441 // Product or page id
442 $pid = intval($_POST['_vipps_qr_pid']);
443 // Literal url
444 $url = sanitize_url($_POST['_vipps_qr_url']);
445
446 $newurl = "";
447 switch ($urltype) {
448 case 'productid':
449 case 'pageid':
450 $newurl = get_permalink($pid);
451 break;
452 case 'url':
453 $newurl = $url;
454 $pid = 0;
455 break;
456 }
457 update_post_meta( $qid, '_vipps_qr_urltype', sanitize_title($urltype));
458 update_post_meta( $qid, '_vipps_qr_pid', intval($pid));
459
460 // MUST BE LAST!
461 if ($newurl){
462 update_post_meta( $qid, '_vipps_qr_url', sanitize_url($newurl));
463 }
464 }
465
466
467 public function admin_menu () {
468 // Vipps QR-codes are handled as a custom post type, we add them to the Vipps admin menu
469 add_submenu_page( 'vipps_admin_menu', __('QR Codes', 'woo-vipps'), __('QR Codes', 'woo-vipps'), 'manage_woocommerce', 'edit.php?post_type=vipps_qr_code', null, 20);
470 }
471
472 public function init () {
473 $this->register_vipps_qr_code();
474 // Ensure we synch with backend when updating
475 add_filter('update_post_metadata', array($this, 'update_post_metadata'), 10, 5);
476
477 // On trash or delete, remove the QR code at vipps
478 add_action('wp_trash_post', array($this, 'delete_qr_code')); // Before status goes to "trash"
479 add_action('before_delete_post',array($this, 'delete_qr_code')); // Before deletion, metadata still available
480
481 // Support resurection - the post id should then be available again
482 add_action('untrashed_post', array($this, 'undelete_qr_code'));
483 }
484
485 // Called when deleting or trashing a post
486 public function delete_qr_code($pid) {
487 $vid = get_post_meta($pid, '_vipps_qr_id', true); // Reference at Vipps
488 if ($vid) {
489 $api = WC_Gateway_Vipps::instance()->api;
490 try {
491 $api->delete_merchant_redirect_qr($vid);
492 } catch (Exception $e) {
493 Vipps::instance()->log(sprintf(__("Error deleting QR code: %1\$s", 'woo-vipps'), $e->getMessage()), 'error');
494 }
495 // Delete data from Vipps, including the ID which should now be free again
496 delete_post_meta($pid, '_vipps_qr_img');
497 delete_post_meta($pid, '_vipps_qr_id');
498 delete_post_meta($pid, '_vipps_qr_stored');
499 }
500 delete_transient('_woo_vipps_qr_codes');
501 delete_transient('_woo_vipps_unsynched_qr_codes');
502 }
503 // Called when undeleting a post. We just need to recreate the QR code, so we do the same as when creating it.
504 public function undelete_qr_code($pid) {
505 $url = get_post_meta($pid, '_vipps_qr_url', true);
506 if ($url) {
507 $this->synch_url($pid, $url, 'NEW');
508 }
509 }
510
511
512 public function update_post_metadata ($nullonsuccess, $pid, $meta_key, $meta_value, $prev_value) {
513
514 if ($meta_key != '_vipps_qr_url') return $nullonsuccess;
515 if (get_post_type($pid) != 'vipps_qr_code') return $nullonsuccess;
516
517 // Prev is only passed when setting multi-values,
518 if (!$prev_value) $prev_value = get_post_meta($pid, '_vipps_qr_url', true);
519
520 return $this->synch_url($pid, $meta_value, $prev_value);
521 }
522
523 // Called when updateing the URL meta-value of the post type: Synch the object with Vipps
524 public function synch_url($pid, $url , $prev) {
525 $vid = get_post_meta($pid, '_vipps_qr_id', true); // Reference at Vipps
526 $gotimage = get_post_meta($pid, '_vipps_qr_img', true); // We only fetch this if necessary
527 $notnew = get_post_meta($pid, '_vipps_qr_stored', true); // Only false if we have never stored this entry.
528 $api = WC_Gateway_Vipps::instance()->api;
529
530 $stored = null;
531 try {
532 $stored = $notnew ? $api-> get_merchant_redirect_qr_entry($vid) : null;
533 } catch (Exception $e) {
534 Vipps::instance()->log(sprintf(__("QR image with id %2\$s that was supposed to be stored at %1\$s, isnt. Recreating it. Error was:. : %3\$s", 'woo-vipps'), "Vipps", $vid, $e->getMessage()), 'debug');
535 }
536
537 // Assume these have or will change. This way these can be updated by saving any QR code.
538 delete_transient('_woo_vipps_qr_codes');
539 delete_transient('_woo_vipps_unsynched_qr_codes');
540
541 try {
542 // Generate a new Vipps ID if we have none.
543 if (!$vid) {
544 $prefix = $api->get_orderprefix();
545 $vid = apply_filters('woo_vipps_qr_id', $prefix . "-qr-" . get_post($pid)->post_name, $pid);
546 }
547
548 // If object does not exist at Vipps, create it
549 if (!$stored) {
550 $ok = $api->create_merchant_redirect_qr ($vid, $url);
551 update_post_meta( $pid, '_vipps_qr_stored', true);
552 update_post_meta( $pid, '_vipps_qr_id', $vid);
553 delete_post_meta($pid, '_vipps_qr_img');
554 } else {
555 if ($url == $prev && $gotimage) {
556 $ok = null;
557 } else {
558 $ok = $api->update_merchant_redirect_qr ($vid, $url) ;
559 }
560 }
561 // This is a time-limited URL which can be used for one hour to download the QR code
562 if ($ok && !$gotimage && isset($ok['url'])) {
563 try {
564 // We don't have to do this via the API, it's fine to use the normal get-content api.
565 $data = $api->get_merchant_redirect_qr($ok['url']);
566 $img = $data['message']; // Could also be png if we allow that, currenlty svg
567 update_post_meta($pid, '_vipps_qr_img', $img);
568 } catch (Exception $e) {
569 Vipps::instance()->log(sprintf(__("Error downloading QR code image: %1\$s", 'woo-vipps'), $e->getMessage()), 'error');
570 if (is_admin() && ! wp_doing_ajax()) {
571 update_post_meta($pid, '_vipps_qr_errors', array(sprintf(__("Couldn't download QR image: try saving post again! Error was: %1\$s", 'woo-vipps'), $e->getMessage())));
572 }
573 return false; // Means *do not* store value.
574 }
575 }
576 } catch (Exception $e) {
577 // IOK here *in particular* catch the 409 thing for previously used ID and retry (If not handled in api).
578 Vipps::instance()->log(sprintf(__("Error creating or updating QR code: %1\$s", 'woo-vipps'), $e->getMessage()), 'error');
579 if (is_admin() && ! wp_doing_ajax()) {
580 $errors = array();
581 $errors[]=sprintf(__("Couldn't create or update QR image: %1\$s", 'woo-vipps'),$e->getMessage());
582 if ($e->responsecode == 409) {
583 delete_post_meta($pid, '_vipps_qr_id');
584 delete_post_meta($pid, '_vipps_qr_stored');
585 delete_post_meta($pid, '_vipps_qr_img');
586 $errors[] = sprintf(__("It seems a QR code with this ID (%1\$s) already exists at Vipps. If you have recently done a database restore, try to instead import the QR code from the Unsynchronized codes, deleting this. If you have several Wordpress instances using the same Vipps account, make sure you use different prefixes (in the WooCommerce Vipps settings). You can try to change the slug of this entry (you may need to enable this in the page settings) and save again if you don't care about the duplicate. ", 'woo-vipps'), sanitize_title($vid));
587 }
588
589 update_post_meta($pid, '_vipps_qr_errors', $errors);
590 }
591 return false; // Means *do not* store value.
592 }
593
594 return null; // null means "ok, store in database".
595 }
596
597 // Register Custom Post Type
598 public function register_vipps_qr_code() {
599
600 $labels = array(
601 'name' => _x( 'Vipps QR Codes', 'Post Type General Name', 'woo-vipps' ),
602 'singular_name' => _x( 'Vipps QR Code', 'Post Type Singular Name', 'woo-vipps' ),
603 'menu_name' => __( 'QR Codes', 'woo-vipps' ),
604 'name_admin_bar' => sprintf(__( '%1$s QR Codes', 'woo-vipps' ), "Vipps"),
605 'archives' => __( 'Item Archives', 'woo-vipps' ),
606 'attributes' => __( 'Item Attributes', 'woo-vipps' ),
607 'parent_item_colon' => __( 'Parent Item:', 'woo-vipps' ),
608 'all_items' => __( 'QR Codes', 'woo-vipps' ),
609 'add_new_item' => __( 'Add New QR Code', 'woo-vipps' ),
610 'add_new' => __( 'Add New', 'woo-vipps' ),
611 'new_item' => __( 'New QR Code', 'woo-vipps' ),
612 'edit_item' => __( 'Edit QR Code', 'woo-vipps' ),
613 'update_item' => __( 'Update QR Code', 'woo-vipps' ),
614 'view_item' => __( 'View QR Code', 'woo-vipps' ),
615 'view_items' => __( 'View QR Codes', 'woo-vipps' ),
616 'search_items' => __( 'Search Item', 'woo-vipps' ),
617 'not_found' => __( 'Not found', 'woo-vipps' ),
618 'not_found_in_trash' => __( 'Not found in Trash', 'woo-vipps' ),
619 'featured_image' => __( 'Featured Image', 'woo-vipps' ),
620 'set_featured_image' => __( 'Set featured image', 'woo-vipps' ),
621 'remove_featured_image' => __( 'Remove featured image', 'woo-vipps' ),
622 'use_featured_image' => __( 'Use as featured image', 'woo-vipps' ),
623 'insert_into_item' => __( 'Insert into item', 'woo-vipps' ),
624 'uploaded_to_this_item' => __( 'Uploaded to this item', 'woo-vipps' ),
625 'items_list' => __( 'Items list', 'woo-vipps' ),
626 'items_list_navigation' => __( 'Items list navigation', 'woo-vipps' ),
627 'filter_items_list' => __( 'Filter items list', 'woo-vipps' ),
628 );
629 $capabilities = array(
630 'edit_post' => 'manage_woocommerce',
631 'read_post' => 'manage_woocommerce',
632 'delete_post' => 'manage_woocommerce',
633 'edit_posts' => 'manage_woocommerce',
634 'edit_others_posts' => 'manage_woocommerce',
635 'publish_posts' => 'manage_woocommerce',
636 'read_private_posts' => 'manage_woocommerce',
637 );
638 $args = array(
639 'label' => sprintf(__( '%1$s QR Code', 'woo-vipps' ), "Vipps"),
640 'description' => sprintf(__( '%1$s QR Codes', 'woo-vipps' ), "Vipps"),
641 'labels' => $labels,
642 'supports' => array( 'title', 'custom-fields' ),
643 'taxonomies' => array( 'post', 'tag' ),
644 'hierarchical' => false,
645 'public' => false,
646 'show_ui' => true,
647 'show_in_menu' => false,
648 'menu_position' => 10,
649 'show_in_admin_bar' => true,
650 'show_in_nav_menus' => false,
651 'can_export' => true,
652 'has_archive' => false,
653 'exclude_from_search' => true,
654 'publicly_queryable' => false,
655 'capabilities' => $capabilities,
656 'show_in_rest' => true,
657 );
658 register_post_type( 'vipps_qr_code', $args );
659
660 }
661
662 }
663
664
665