PluginProbe
Robokassa payment gateway for Woocommerce / trunk
Robokassa payment gateway for Woocommerce vtrunk
1.8.8 1.8.9 trunk
robokassa / payment-widget.php

payment-widget.php in Robokassa payment gateway for Woocommerce trunk, at payment-widget.php

516 lines 14.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 add_action('woocommerce_single_product_summary', 'payment_product_widget', 25);
4 add_action('woocommerce_before_shop_loop_item_title', 'robokassa_product_loop_badge', 11);
5 add_action('wp_enqueue_scripts', 'robokassa_widget_enqueue_assets');
6
7 /**
8 * Выводит компонент Robokassa на странице товара.
9 *
10 * @return void
11 */
12 function payment_product_widget() {
13 global $product;
14
15 robokassa_widget_render_for_product($product);
16 }
17
18 /**
19 * Выводит бейдж Robokassa повер�
20 изображения товара в листинге.
21 *
22 * @return void
23 */
24 function robokassa_product_loop_badge() {
25 global $product;
26
27 if (!$product instanceof WC_Product) {
28 return;
29 }
30
31 if (get_option('robokassa_catalog_badge_enabled', 'false') !== 'true') {
32 return;
33 }
34
35 if (!robokassa_catalog_badge_has_installment_method()) {
36 return;
37 }
38
39 $badge = robokassa_catalog_badge_get_settings();
40 if (!file_exists(__DIR__ . '/assets/images/robokassa-badges/' . $badge['file'])) {
41 return;
42 }
43
44 $src = plugin_dir_url(__FILE__) . 'assets/images/robokassa-badges/' . $badge['file'];
45
46 echo '<div class="robokassa-widget-wrapper robokassa-widget-wrapper--loop robokassa-widget-wrapper--loop-overlay">';
47 echo '<img class="robokassa-catalog-badge robokassa-catalog-badge--' . esc_attr($badge['size']) . '" src="' . esc_url($src) . '" alt="' . esc_attr__('Оплата частями Robokassa', 'robokassa') . '" loading="lazy" decoding="async" width="' . esc_attr($badge['width']) . '" height="' . esc_attr($badge['height']) . '" />';
48 echo '</div>';
49 }
50
51 /**
52 * Выводит компонент Robokassa для переданного товара.
53 *
54 * @param WC_Product|null $product
55 * @param string|null $component
56 * @param string $context
57 *
58 * @return void
59 */
60 function robokassa_widget_render_for_product($product, $component = null, $context = 'single') {
61 if (!$product instanceof WC_Product) {
62 return;
63 }
64
65 $settings = robokassa_widget_get_settings();
66 if (!$settings['enabled']) {
67 return;
68 }
69 if ($component !== null) {
70 $settings['component'] = $component;
71 }
72 if ($context === 'loop' && $settings['component'] === 'badge') {
73 $settings['size'] = 's';
74 }
75
76 $amount = wc_get_price_to_display($product);
77 if ($amount <= 0) {
78 return;
79 }
80
81 $signature = robokassa_widget_get_signature_data($amount);
82 if (!$signature) {
83 return;
84 }
85
86 $checkout_url = robokassa_widget_prepare_checkout_url($product->get_id(), $settings);
87 $attributes = robokassa_widget_prepare_attributes($settings, $signature, $checkout_url);
88
89 robokassa_widget_output_component($settings['component'], $attributes, $product->get_id(), $checkout_url, $settings, $context);
90 }
91
92 /**
93 * Возвращает настройки отображения компонента.
94 *
95 * @return array
96 */
97 function robokassa_widget_get_settings() {
98 $settings = [
99 'enabled' => get_option('robokassa_widget_enabled', 'false') === 'true',
100 'component' => robokassa_widget_get_choice_option('robokassa_widget_component', ['widget', 'badge'], 'widget'),
101 'theme' => robokassa_widget_get_choice_option('robokassa_widget_theme', ['light', 'dark'], 'light'),
102 'size' => robokassa_widget_get_choice_option('robokassa_widget_size', ['s', 'm'], 'm'),
103 'show_logo' => robokassa_widget_get_boolean_option('robokassa_widget_show_logo', 'true'),
104 'type' => robokassa_widget_get_choice_option('robokassa_widget_type', ['', 'bnpl', 'credit'], ''),
105 'border_radius' => sanitize_text_field(get_option('robokassa_widget_border_radius', '')),
106 'has_second_line' => robokassa_widget_get_boolean_option('robokassa_widget_has_second_line', 'false'),
107 'description_position' => robokassa_widget_get_choice_option('robokassa_widget_description_position', ['left', 'right'], 'left'),
108 'color_scheme' => robokassa_widget_get_choice_option('robokassa_widget_color_scheme', ['primary', 'secondary', 'accent', ''], ''),
109 ];
110
111 if (get_option('robokassa_country_code', 'RU') === 'KZ') {
112 $settings['enabled'] = false;
113 }
114
115 return $settings;
116 }
117
118 /**
119 * Возвращает настройки статичного бейджа для каталога.
120 *
121 * @return array
122 */
123 function robokassa_catalog_badge_get_settings() {
124 $size = robokassa_widget_get_choice_option('robokassa_catalog_badge_size', ['xs', 's'], 'xs');
125 $theme_default = robokassa_widget_get_choice_option('robokassa_catalog_badge_variant', ['light', 'dark'], 'light');
126 $theme = robokassa_widget_get_choice_option('robokassa_catalog_badge_theme', ['light', 'dark'], $theme_default);
127 $dimensions = robokassa_catalog_badge_get_dimensions($size);
128
129 return [
130 'size' => $size,
131 'theme' => $theme,
132 'file' => sprintf('%s-catalog-badge-%s.svg', $size, $theme),
133 'width' => $dimensions['width'],
134 'height' => $dimensions['height'],
135 ];
136 }
137
138 /**
139 * Возвращает размеры статичного бейджа для каталога.
140 *
141 * @param string $size
142 *
143 * @return array
144 */
145 function robokassa_catalog_badge_get_dimensions($size) {
146 if ($size === 's') {
147 return [
148 'width' => 88,
149 'height' => 48,
150 ];
151 }
152
153 return [
154 'width' => 74,
155 'height' => 42,
156 ];
157 }
158
159 /**
160 * Проверяет наличие �
161 отя бы одного метода оплаты частями для каталожного бейджа.
162 *
163 * @return bool
164 */
165 function robokassa_catalog_badge_has_installment_method() {
166 static $has_installment_method = null;
167
168 if ($has_installment_method !== null) {
169 return $has_installment_method;
170 }
171
172 $gateway_ids = [
173 'robokassa_podeli',
174 'robokassa_mokka',
175 'robokassa_split',
176 ];
177
178 if (!function_exists('robokassa_get_optional_method_config_by_gateway') || !function_exists('robokassa_is_optional_method_active')) {
179 $has_installment_method = false;
180 return $has_installment_method;
181 }
182
183 foreach ($gateway_ids as $gateway_id) {
184 $config = robokassa_get_optional_method_config_by_gateway($gateway_id);
185 if (!empty($config) && robokassa_is_optional_method_active($config)) {
186 $has_installment_method = true;
187 return $has_installment_method;
188 }
189 }
190
191 $has_installment_method = false;
192 return $has_installment_method;
193 }
194
195 /**
196 * Возвращает значение опции с проверкой допустимы�
197 значений.
198 *
199 * @param string $option_name
200 * @param array $allowed
201 * @param string $default
202 *
203 * @return string
204 */
205 function robokassa_widget_get_choice_option($option_name, array $allowed, $default) {
206 $value = sanitize_text_field(get_option($option_name, $default));
207
208 return in_array($value, $allowed, true) ? $value : $default;
209 }
210
211 /**
212 * Возвращает текстовое представление булевой опции.
213 *
214 * @param string $option_name
215 * @param string $default
216 *
217 * @return string
218 */
219 function robokassa_widget_get_boolean_option($option_name, $default) {
220 $value = get_option($option_name, $default);
221
222 return $value === 'false' ? 'false' : 'true';
223 }
224
225 /**
226 * Возвращает подпись для компонента.
227 *
228 * @param float $amount
229 *
230 * @return array|null
231 */
232 function robokassa_widget_get_signature_data($amount) {
233 $merchant = sanitize_text_field(get_option('robokassa_payment_MerchantLogin'));
234 if ($merchant === '') {
235 return null;
236 }
237
238 $test_mode = get_option('robokassa_payment_test_onoff') === 'true';
239 $pass = $test_mode ? get_option('robokassa_payment_testshoppass1') : get_option('robokassa_payment_shoppass1');
240 $pass = is_string($pass) ? $pass : '';
241 if ($pass === '') {
242 return null;
243 }
244
245 $out_sum = number_format((float)$amount, 2, '.', '');
246 $signature = md5(sprintf('%s:%s::%s', $merchant, $out_sum, $pass));
247
248 return [
249 'merchantLogin' => $merchant,
250 'outSum' => $out_sum,
251 'signature' => $signature,
252 ];
253 }
254
255 /**
256 * Формирует URL оформления заказа для компонента.
257 *
258 * @param int $product_id
259 * @param array $settings
260 *
261 * @return string
262 */
263 function robokassa_widget_prepare_checkout_url($product_id, array $settings) {
264 $base_url = wc_get_checkout_url();
265 $checkout_url = add_query_arg(
266 [
267 'add-to-cart' => $product_id,
268 ],
269 $base_url
270 );
271
272 return esc_url_raw($checkout_url);
273 }
274
275 /**
276 * Подготавливает атрибуты для вывода компонента.
277 *
278 * @param array $settings
279 * @param array $signature
280 * @param string $checkout_url
281 *
282 * @return array
283 */
284 function robokassa_widget_prepare_attributes(array $settings, array $signature, $checkout_url) {
285 $attributes = robokassa_widget_prepare_common_attributes($settings, $signature);
286
287 if ($settings['component'] === 'widget') {
288 return robokassa_widget_apply_widget_attributes($attributes, $settings, $checkout_url);
289 }
290
291 return robokassa_widget_apply_badge_attributes($attributes, $settings);
292 }
293
294 /**
295 * Готовит базовые атрибуты компонента.
296 *
297 * @param array $settings
298 * @param array $signature
299 *
300 * @return array
301 */
302 function robokassa_widget_prepare_common_attributes(array $settings, array $signature) {
303 $attributes = [
304 'outSum' => $signature['outSum'],
305 'merchantLogin' => $signature['merchantLogin'],
306 'signature' => $signature['signature'],
307 'theme' => $settings['theme'],
308 'size' => $settings['size'],
309 'mode' => 'checkout',
310 'oncheckout' => 'robokassaWidgetHandleCheckout',
311 ];
312
313 if ($settings['show_logo'] === 'false') {
314 $attributes['showLogo'] = 'false';
315 }
316
317 if ($settings['type'] !== '') {
318 $attributes['type'] = $settings['type'];
319 }
320
321 return $attributes;
322 }
323
324 /**
325 * Дополняет атрибуты для основного виджета.
326 *
327 * @param array $attributes
328 * @param array $settings
329 * @param string $checkout_url
330 *
331 * @return array
332 */
333 function robokassa_widget_apply_widget_attributes(array $attributes, array $settings, $checkout_url) {
334 if ($settings['border_radius'] !== '') {
335 $attributes['borderRadius'] = $settings['border_radius'];
336 }
337 if ($settings['has_second_line'] === 'true') {
338 $attributes['hasSecondLine'] = 'true';
339 }
340
341 $attributes['descriptionPosition'] = $settings['description_position'];
342 $attributes['checkoutUrl'] = $checkout_url;
343
344 return $attributes;
345 }
346
347 /**
348 * Дополняет атрибуты для бейджа.
349 *
350 * @param array $attributes
351 * @param array $settings
352 *
353 * @return array
354 */
355 function robokassa_widget_apply_badge_attributes(array $attributes, array $settings) {
356 if ($settings['color_scheme'] !== '') {
357 $attributes['colorScheme'] = $settings['color_scheme'];
358 }
359
360 return $attributes;
361 }
362
363 /**
364 * Отображает компонент и подключает обработчики.
365 *
366 * @param string $component
367 * @param array $attributes
368 * @param int $product_id
369 * @param string $checkout_url
370 * @param array $settings
371 * @param string $context
372 *
373 * @return void
374 */
375 function robokassa_widget_output_component($component, array $attributes, $product_id, $checkout_url, array $settings, $context = 'single') {
376 if (empty($attributes)) {
377 return;
378 }
379
380 $tag = $component === 'badge' ? 'robokassa-badge' : 'robokassa-widget';
381 $unique_suffix = function_exists('wp_unique_id') ? wp_unique_id() : uniqid('', false);
382 $element_id = sprintf('%s-%d-%s', $tag, (int)$product_id, $unique_suffix);
383 $context_class = sanitize_html_class($context);
384 $attributes['id'] = $element_id;
385
386 echo '<div class="robokassa-widget-wrapper robokassa-widget-wrapper--' . esc_attr($context_class) . '">';
387 echo robokassa_widget_build_tag($tag, $attributes);
388 echo '</div>';
389
390 if ($component === 'badge') {
391 robokassa_widget_print_badge_script($element_id, $checkout_url);
392 }
393 }
394
395 /**
396 * Собирает HTML тега компонента.
397 *
398 * @param string $tag
399 * @param array $attributes
400 *
401 * @return string
402 */
403 function robokassa_widget_build_tag($tag, array $attributes) {
404 $parts = [];
405
406 foreach ($attributes as $name => $value) {
407 if ($value === '') {
408 continue;
409 }
410
411 $parts[] = sprintf('%s="%s"', esc_attr($name), esc_attr($value));
412 }
413
414 $attributes_string = implode(' ', $parts);
415 $attributes_string = trim($attributes_string);
416 $attributes_string = $attributes_string === '' ? '' : ' ' . $attributes_string;
417
418 $html = sprintf('<%1$s%2$s></%1$s>', esc_attr($tag), $attributes_string);
419
420 return $html;
421 }
422
423 /**
424 * Добавляет обработчик клика для бейджа по умолчанию.
425 *
426 * @param string $element_id
427 * @param string $checkout_url
428 *
429 * @return void
430 */
431 function robokassa_widget_print_badge_script($element_id, $checkout_url) {
432 $url = esc_url_raw($checkout_url);
433 $script = sprintf(
434 "document.addEventListener('DOMContentLoaded',function(){var el=document.getElementById('%s');if(!el){return;}el.addEventListener('click',function(){window.location.href='%s';});});",
435 esc_js($element_id),
436 esc_js($url)
437 );
438
439 echo '<script>' . $script . '</script>';
440 }
441
442 /**
443 * Подключает скрипт виджета, если он нужен.
444 *
445 * @return void
446 */
447 function robokassa_widget_enqueue_assets() {
448 if (!robokassa_widget_should_enqueue_assets()) {
449 return;
450 }
451
452 $settings = robokassa_widget_get_settings();
453 $is_product = function_exists('is_product') && is_product();
454 $catalog_badge_enabled = get_option('robokassa_catalog_badge_enabled', 'false') === 'true';
455
456 if (!$settings['enabled'] && (!$catalog_badge_enabled || $is_product)) {
457 return;
458 }
459
460 $style_path = __DIR__ . '/assets/css/robokassa-widget.css';
461 $style_url = plugin_dir_url(__FILE__) . 'assets/css/robokassa-widget.css';
462 $style_version = file_exists($style_path) ? filemtime($style_path) : null;
463
464 wp_enqueue_style(
465 'robokassa-widget',
466 $style_url,
467 [],
468 $style_version
469 );
470
471 if (!$is_product || !$settings['enabled']) {
472 return;
473 }
474
475 wp_enqueue_script(
476 'robokassa-badge-widget',
477 'https://auth.robokassa.ru/merchant/bundle/robokassa-iframe-badge.js',
478 [],
479 null,
480 true
481 );
482
483 $local_script_path = __DIR__ . '/assets/js/robokassa-widget-init.js';
484 $local_script_url = plugin_dir_url(__FILE__) . 'assets/js/robokassa-widget-init.js';
485 $local_script_version = file_exists($local_script_path) ? filemtime($local_script_path) : null;
486
487 wp_enqueue_script(
488 'robokassa-badge-widget-init',
489 $local_script_url,
490 ['robokassa-badge-widget'],
491 $local_script_version,
492 true
493 );
494 }
495
496 /**
497 * Проверяет, нужна ли загрузка скриптов Robokassa на текущей витрине.
498 *
499 * @return bool
500 */
501 function robokassa_widget_should_enqueue_assets() {
502 if (function_exists('is_product') && is_product()) {
503 return true;
504 }
505
506 if (function_exists('is_shop') && is_shop()) {
507 return true;
508 }
509
510 if (function_exists('is_product_taxonomy') && is_product_taxonomy()) {
511 return true;
512 }
513
514 return false;
515 }
516