PluginProbe ʕ •ᴥ•ʔ
Weight Based Shipping Table Rate for WooCommerce – Flexible Shipping / 6.10.0
Weight Based Shipping Table Rate for WooCommerce – Flexible Shipping v6.10.0
6.10.0 6.9.1 6.9.0 6.8.1 6.8.0 6.7.4 6.7.3 6.7.2 6.7.0 4.21.7 4.22.0 4.22.1 4.23.0 4.23.1 4.23.2 4.23.3 4.24.0 4.24.1 4.24.10 4.24.11 4.24.12 4.24.13 4.24.14 4.24.15 4.24.16 4.24.17 4.24.18 4.24.19 4.24.2 4.24.4 4.24.6 4.24.7 4.24.8 4.24.9 4.25.0 4.25.1 4.25.2 4.25.4 4.25.5 4.25.6 4.25.7 4.25.8 4.3.0 4.3.1 4.4.0 4.4.1 4.5.0 4.5.1 4.6.0 4.6.1 4.7.0 4.7.1 4.7.2 4.8.0 4.8.1 4.8.3 4.8.4 4.8.5 4.9.0 5.0.0 5.0.1 5.0.2 5.0.3 5.0.4 5.0.5 5.0.6 5.0.7 5.0.8 5.0.9 5.1.0 5.1.1 5.1.2 5.1.3 5.2.0 5.3.0 5.3.1 5.3.3 5.3.4 5.3.5 6.0.0 6.1.0 6.1.1 6.1.2 6.2.0 6.2.1 6.2.2 6.2.3 6.2.4 6.3.0 trunk 6.4.0 1.4 6.4.1 1.4.1 6.4.2 1.5 6.4.3 1.6 6.4.5 1.6.1 6.5.0 1.6.2 6.5.1 1.7 6.5.2 1.8 6.5.3 1.9 6.5.4 1.9.1 6.5.5 1.9.10 6.5.6 1.9.11 6.5.7 1.9.12 6.5.8 1.9.2 6.6.0 1.9.3 6.6.1 1.9.4 6.6.2 1.9.5 1.9.6 1.9.7 1.9.8 1.9.9 2.0 2.0.1 2.1 2.1.1 2.1.10 2.1.2 2.1.3 2.1.4 2.1.5 2.1.6 2.1.7 2.1.8 2.1.9 3.0.6 3.0.7 3.1 3.1.1 3.1.10 3.1.11 3.1.12 3.1.2 3.1.3 3.1.4 3.1.5 3.1.6 3.1.7 3.1.8 3.1.9 3.10.0 3.11.0 3.11.1 3.11.2 3.11.3 3.11.4 3.12.0 3.13.0 3.14.0 3.14.1 3.14.2 3.14.3 3.14.4 3.15.0 3.16.0 3.16.1 3.16.2 3.16.3 3.16.4 3.16.5 3.2.0 3.3.1 3.3.10 3.3.11 3.3.12 3.3.13 3.3.14 3.3.2 3.3.3 3.3.4 3.3.5 3.3.6 3.3.7 3.3.8 3.3.9 3.4.0 3.5.0 3.5.1 3.6.0 3.6.1 3.6.2 3.6.3 3.6.4 3.7.0 3.8.0 3.9.0 3.9.1 3.9.10 3.9.11 3.9.12 3.9.13 3.9.15 3.9.16 3.9.17 3.9.18 3.9.19 3.9.2 3.9.20 3.9.21 3.9.3 3.9.4 3.9.5 3.9.6 3.9.7 3.9.9 4.0.0 4.0.1 4.0.10 4.0.2 4.0.3 4.0.4 4.0.5 4.0.6 4.0.7 4.0.8 4.0.9 4.1.0 4.1.1 4.1.2 4.1.3 4.1.4 4.10.0 4.10.1 4.11.0 4.11.1 4.11.2 4.11.3 4.11.4 4.11.5 4.11.6 4.11.7 4.11.8 4.11.9 4.12.0 4.13.0 4.13.1 4.13.2 4.13.3 4.14.0 4.14.1 4.14.2 4.15.0 4.16.0 4.16.1 4.16.2 4.17.0 4.18.0 4.18.1 4.18.2 4.18.3 4.18.4 4.18.5 4.18.6 4.19.0 4.19.1 4.2.0 4.20.0 4.20.1 4.20.2 4.20.3 4.21.0 4.21.1 4.21.2 4.21.3 4.21.4 4.21.5
flexible-shipping / src / WPDesk / FS / TableRate / ShippingMethodSingle.php
flexible-shipping / src / WPDesk / FS / TableRate Last commit date
AI 3 days ago Beacon 3 days ago ContextualInfo 3 days ago Debug 3 days ago Exception 3 days ago FreeShipping 3 days ago ImporterExporter 3 days ago Order 3 days ago Rates 3 days ago Rule 3 days ago ShippingMethod 3 days ago ShippingMethodsIntegration 3 days ago Tax 3 days ago views 3 days ago Beacon.php 3 days ago DefaultRulesSettings.php 3 days ago MultiCurrency.php 3 days ago RulesSettingsField.php 3 days ago RulesTableSettings.php 3 days ago ShippingMethodSingle.php 3 days ago UserFeedback.php 3 days ago
ShippingMethodSingle.php
508 lines
1 <?php
2 /**
3 * Class ShippingMethodSimple
4 *
5 * @package WPDesk\FS\TableRate\
6 */
7
8 namespace WPDesk\FS\TableRate;
9
10 use FSVendor\Psr\Log\LoggerInterface;
11 use FSVendor\WPDesk\FS\TableRate\Logger\NoticeLogger;
12 use FSVendor\WPDesk\FS\TableRate\Logger\ShippingMethodLogger;
13 use FSVendor\WPDesk\FS\TableRate\Settings\MethodSettingsFactory;
14 use WC_Shipping_Method;
15 use WPDesk\FS\TableRate\FreeShipping\LffsNoticeTextFormatValidator;
16 use WPDesk\FS\TableRate\FreeShipping\NoticeTextSettings;
17 use WPDesk\FS\TableRate\FreeShipping\Tracker\ThresholdAlertTracker;
18 use WPDesk\FS\TableRate\Rule\Condition\ConditionsFactory;
19 use WPDesk\FS\TableRate\Rule\Cost\RuleAdditionalCostFactory;
20 use WPDesk\FS\TableRate\Rule\Cost\RuleCostFieldsFactory;
21 use WPDesk\FS\TableRate\ShippingMethod\CommonMethodSettings;
22 use WPDesk\FS\TableRate\ShippingMethod\FreeShippingThresholdRuleValidator;
23 use WPDesk\FS\TableRate\ShippingMethod\RateCalculatorFactory;
24 use WPDesk\FS\TableRate\ShippingMethod\SingleMethodSettings;
25 use WPDesk\FS\TableRate\Tax\TaxCalculator;
26 use WPDesk_Flexible_Shipping;
27
28 /**
29 * Shipping method flexible_shipping_single
30 */
31 class ShippingMethodSingle extends WC_Shipping_Method {
32
33 const SHIPPING_METHOD_ID = 'flexible_shipping_single';
34
35 /**
36 * Logger provided by Flexible Shipping plugin.
37 *
38 * @var LoggerInterface
39 */
40 protected static $fs_logger;
41
42 /**
43 * @var bool
44 */
45 private $is_html_ads_loaded = false;
46
47 /**
48 * @var string[]
49 */
50 private $field_validation_errors = [];
51
52 /**
53 * ShippingMethodSingle constructor.
54 *
55 * @param int $instance_id .
56 */
57 public function __construct( $instance_id = 0 ) {
58 $this->instance_id = absint( $instance_id );
59
60 $this->id = self::SHIPPING_METHOD_ID;
61 $this->init();
62 }
63
64 /**
65 * Init.
66 */
67 protected function init() {
68 $this->supports = [
69 'shipping-zones',
70 'instance-settings',
71 ];
72 $this->init_instance_form_fields( false );
73 $this->method_title = __( 'Flexible Shipping', 'flexible-shipping' );
74 $this->method_description = __( 'A single Flexible Shipping method.', 'flexible-shipping' );
75 if ( $this->instance_id ) {
76 $docs_link = get_locale() === 'pl_PL' ? 'https://octol.io/fs-docs-pl' : 'https://octol.io/fs-docs';
77 // Translators: docs link.
78 $this->method_description = sprintf( __( 'A single Flexible Shipping method. Learn %1$show to configure FS shipping method &rarr;%2$s', 'flexible-shipping' ), '<a href="' . $docs_link . '" target="_blank">', '</a>' );
79 }
80 $this->title = $this->get_instance_option( 'method_title', $this->method_title );
81 $this->instance_settings['title'] = $this->title;
82 $this->tax_status = $this->get_instance_option( 'tax_status' );
83 }
84
85 /**
86 * @param bool $with_integration_settings .
87 */
88 public function init_instance_form_fields( $with_integration_settings = false ) {
89 $this->instance_form_fields = ( new SingleMethodSettings() )->get_settings_fields( $this->instance_settings, $with_integration_settings );
90 }
91
92 /**
93 * @param array $form_fields .
94 * @param bool $echo .
95 *
96 * @return string
97 */
98 public function generate_settings_html( $form_fields = [], $echo = true ) {
99 $this->init_instance_form_fields( true );
100 $form_fields = $this->get_instance_form_fields();
101 if ( $echo ) {
102 parent::generate_settings_html( $form_fields, $echo );
103 } else {
104 return parent::generate_settings_html( $form_fields, $echo );
105 }
106 }
107
108
109 /**
110 * Generate Title HTML.
111 *
112 * @param string $key Field key.
113 * @param array $data Field data.
114 *
115 * @return string
116 * @since 1.0.0
117 */
118 public function generate_title_html( $key, $data ) {
119 $field_key = $this->get_field_key( $key );
120 $defaults = [
121 'title' => '',
122 'class' => '',
123 ];
124
125 $data = wp_parse_args( $data, $defaults );
126
127 ob_start();
128 ?>
129 </table>
130 <h3 class="wc-settings-sub-title <?php echo esc_attr( $data['class'] ); ?>"
131 id="<?php echo esc_attr( $field_key ); ?>"><?php echo wp_kses_post( $data['title'] ); ?></h3>
132 <?php if ( ! empty( $data['description'] ) ) : ?>
133 <p><?php echo wp_kses_post( $data['description'] ); ?></p>
134 <?php endif; ?>
135
136 <table class="form-table">
137 <?php
138
139 return ob_get_clean();
140 }
141
142 /**
143 * Generate Price Input HTML.
144 *
145 * @param string $key Field key.
146 * @param array $data Field data.
147 *
148 * @return string
149 */
150 public function generate_price_html( $key, $data ) {
151 if ( CommonMethodSettings::METHOD_FREE_SHIPPING === $key ) {
152 $data = $this->append_free_shipping_threshold_validation_error( $data );
153 }
154
155 if ( CommonMethodSettings::METHOD_FREE_SHIPPING !== $key || empty( $data['error_message'] ) ) {
156 return parent::generate_price_html( $key, $data );
157 }
158
159 $field_key = $this->get_field_key( $key );
160 $defaults = [
161 'title' => '',
162 'disabled' => false,
163 'class' => '',
164 'css' => '',
165 'placeholder' => '',
166 'type' => 'text',
167 'desc_tip' => false,
168 'description' => '',
169 'custom_attributes' => [],
170 'error_message' => '',
171 ];
172
173 $data = wp_parse_args( $data, $defaults );
174
175 do_action( ThresholdAlertTracker::DISPLAYED_ACTION );
176
177 ob_start();
178 include __DIR__ . '/views/html-price-with-validation-error.php';
179
180 return ob_get_clean();
181 }
182
183 /**
184 * @param array $field_settings Free shipping threshold field settings.
185 *
186 * @return array
187 */
188 private function append_free_shipping_threshold_validation_error( array $field_settings ) {
189 $method_rules = $this->get_method_rules_for_threshold_validation();
190 $threshold = $this->get_option( CommonMethodSettings::METHOD_FREE_SHIPPING );
191
192 if ( ( new FreeShippingThresholdRuleValidator() )->is_valid( $threshold, $method_rules ) ) {
193 return $field_settings;
194 }
195
196 $field_settings['class'] = trim( ( $field_settings['class'] ?? '' ) . ' fs-free-shipping-threshold-error' );
197 $field_settings['css'] = trim( ( $field_settings['css'] ?? '' ) . ' border-color: #d63638; box-shadow: 0 0 0 1px #d63638;' );
198 $field_settings['custom_attributes']['aria-invalid'] = 'true';
199 $field_settings['error_message'] = $this->get_free_shipping_threshold_validation_message( $threshold );
200
201 return $field_settings;
202 }
203
204 /**
205 * @return array
206 */
207 private function get_method_rules_for_threshold_validation() {
208 $method_rules = $this->get_option( CommonMethodSettings::METHOD_RULES, [] );
209
210 if ( is_string( $method_rules ) ) {
211 $decoded_method_rules = json_decode( $method_rules, true );
212
213 return is_array( $decoded_method_rules ) ? $decoded_method_rules : [];
214 }
215
216 return is_array( $method_rules ) ? $method_rules : [];
217 }
218
219 /**
220 * @return string
221 */
222 private function get_free_shipping_threshold_validation_message( $threshold ) {
223 $docs_url = 'pl_PL' === get_user_locale() ? 'https://octol.io/fs-shipping-threshold-pl' : 'https://octol.io/fs-shipping-threshold';
224 $threshold_amount = $this->format_price_for_threshold_validation_message( $threshold );
225 $zero_amount = $this->format_price_for_threshold_validation_message( 0 );
226
227 if ( 'pl_PL' === get_user_locale() ) {
228 return sprintf(
229 // Translators: documentation link opening tag, closing tag, free shipping threshold amount, zero cost amount.
230 __( 'Upewnij się, że zakres od progu darmowej wysyłki wzwyż jest również pokryty odpowiedni�
231 reguł�
232 w tabeli poniżej, np. KIEDY: Cena jest od %3$s do [puste], koszt wynosi %4$s.<br />%1$sDowiedz się, jak skonfigurować próg darmowej wysyłki w regułach obliczania kosztów %2$s', 'flexible-shipping' ),
233 '<a href="' . esc_url( $docs_url ) . '" target="_blank">',
234 '</a>',
235 esc_html( $threshold_amount ),
236 esc_html( $zero_amount )
237 );
238 }
239
240 return sprintf(
241 // Translators: documentation link opening tag, closing tag, free shipping threshold amount, zero cost amount.
242 __( 'Make sure the range from the free shipping threshold upwards is also covered by the corresponding rule in the table below, e.g. WHEN: Price is from %3$s to [empty], rule cost is %4$s.<br />%1$sLearn how to configure the free shipping threshold in the cost calculation rules %2$s', 'flexible-shipping' ),
243 '<a href="' . esc_url( $docs_url ) . '" target="_blank">',
244 '</a>',
245 esc_html( $threshold_amount ),
246 esc_html( $zero_amount )
247 );
248 }
249
250 /**
251 * @param mixed $price Price amount.
252 *
253 * @return string
254 */
255 private function format_price_for_threshold_validation_message( $price ) {
256 $formatted_price = wp_strip_all_tags( wc_price( (float) $price ) );
257 $formatted_price = html_entity_decode( $formatted_price, ENT_QUOTES, get_bloginfo( 'charset' ) );
258
259 return trim( str_replace( html_entity_decode( '&nbsp;', ENT_QUOTES, get_bloginfo( 'charset' ) ), ' ', $formatted_price ) );
260 }
261
262 /**
263 * .
264 */
265 public function init_instance_settings() {
266 parent::init_instance_settings();
267 if ( isset( $this->instance_settings['method_rules'] ) && ! is_array( $this->instance_settings['method_rules'] ) && is_string( $this->instance_settings['method_rules'] ) ) {
268 $this->instance_settings['method_rules'] = json_decode( $this->instance_settings['method_rules'], true );
269 }
270 $this->instance_settings['id_for_shipping'] = $this->get_rate_id();
271 $this->instance_settings['title'] = $this->title;
272 }
273
274 /**
275 * @return bool
276 */
277 public function process_admin_options() {
278 $this->init_instance_form_fields( true );
279 $filter_name = 'woocommerce_shipping_' . $this->id . '_instance_settings_values';
280 $filter_callback = [ $this, 'process_integrations_settings' ];
281 add_filter( $filter_name, $filter_callback );
282 $processed = parent::process_admin_options();
283 remove_filter( $filter_name, $filter_callback );
284 if ( $this->instance_id ) {
285 do_action( 'flexible_shipping_method_updated', $this->instance_id );
286 }
287
288 return $processed;
289 }
290
291 /**
292 * @param array $settings .
293 *
294 * @return array
295 */
296 public function process_integrations_settings( $settings ) {
297 $settings = apply_filters( 'flexible_shipping_process_admin_options', $settings );
298 $settings['method_logo_id'] = absint( $settings['method_logo_id'] ?? 0 );
299
300 return $settings;
301 }
302
303 /**
304 * Admin options.
305 */
306 public function admin_options() {
307 parent::admin_options();
308 do_action( 'flexible_shipping_method_script', self::SHIPPING_METHOD_ID, $this->instance_id );
309 }
310
311 /**
312 * Renders shipping rules settings.
313 *
314 * @param string $key .
315 * @param array $data .
316 *
317 * @return string
318 */
319 public function generate_shipping_rules_html( $key, $data ) {
320 $field_key = $this->get_field_key( $key );
321 $method_rules_settings = $this->get_option( $key, '[]' );
322 $rules_settings = new RulesSettingsField(
323 $field_key,
324 $field_key,
325 $data['title'],
326 $data,
327 ! is_array( $method_rules_settings ) ? json_decode( $method_rules_settings, true ) : $method_rules_settings,
328 $this->instance_settings
329 );
330
331 return $rules_settings->render();
332 }
333
334 /**
335 * @param string $key .
336 * @param array $value .
337 *
338 * @return string
339 */
340 public function validate_shipping_rules_field( $key, $value ) {
341 $rules_settings_processor = new Rule\Settings\SettingsProcessor(
342 ( null === $value || ! is_array( $value ) ) ? [] : $value,
343 ( new ConditionsFactory() )->get_conditions(),
344 ( new RuleCostFieldsFactory() )->get_fields(),
345 ( new Rule\Cost\RuleAdditionalCostFieldsFactory( ( new RuleAdditionalCostFactory() )->get_additional_costs() ) )->get_fields(),
346 ( new Rule\SpecialAction\SpecialActionFieldsFactory( ( new Rule\SpecialAction\SpecialActionFactory() )->get_special_actions() ) )->get_fields()
347 );
348
349 return json_encode( $rules_settings_processor->prepare_settings(), JSON_PRETTY_PRINT );
350 }
351
352 /**
353 * @param string $key Field key.
354 * @param string $value Posted value.
355 *
356 * @return string
357 */
358 public function validate_method_free_shipping_notice_text_field( $key, $value ) {
359 $value = parent::validate_textarea_field( $key, $value );
360
361 if ( ( new LffsNoticeTextFormatValidator() )->is_valid( $value ) ) {
362 return $value;
363 }
364
365 $error_message = $this->get_lffs_notice_text_validation_error_message();
366 $this->field_validation_errors[ $key ] = $error_message;
367 $this->add_error( $error_message );
368
369 return $this->get_option( $key, '' );
370 }
371
372 /**
373 * @param string $key Field key.
374 * @param array $data Field data.
375 *
376 * @return string
377 */
378 public function generate_textarea_html( $key, $data ) {
379 $html = parent::generate_textarea_html( $key, $data );
380
381 if ( NoticeTextSettings::FIELD_NAME !== $key || empty( $this->field_validation_errors[ $key ] ) ) {
382 return $html;
383 }
384
385 return str_replace(
386 '</fieldset>',
387 '<p class="description fs-lffs-notice-text-error-message" style="color:#b32d2e;margin-top:4px;">' . wp_kses_post( $this->field_validation_errors[ $key ] ) . '</p></fieldset>',
388 $html
389 );
390 }
391
392 /**
393 * @return string
394 */
395 private function get_lffs_notice_text_validation_error_message(): string {
396 return sprintf(
397 // Translators: code tag opening, code tag closing.
398 __( 'The LFFS notice text contains an invalid placeholder format. Use %1$s%%1$s%2$s to display the amount left for free shipping.', 'flexible-shipping' ),
399 '<code>',
400 '</code>'
401 );
402 }
403
404 /**
405 * Field key.
406 * For compatibility with integrations scripts.
407 *
408 * @param string $key .
409 *
410 * @return string
411 */
412 public function get_field_key( $key ) {
413 return $this->plugin_id . WPDesk_Flexible_Shipping::METHOD_ID . '_' . $key;
414 }
415
416 /**
417 * Get method rules.
418 *
419 * @return array
420 */
421 public function get_method_rules() {
422 return $this->get_instance_option( 'method_rules', [] );
423 }
424
425 /**
426 * @param string $key .
427 * @param string $value .
428 *
429 * @return bool
430 */
431 public function update_instance_option( $key, $value = '' ) {
432 if ( empty( $this->instance_settings ) ) {
433 $this->init_instance_settings();
434 }
435
436 $this->instance_settings[ $key ] = $value;
437
438 return update_option( $this->get_instance_option_key(), apply_filters( 'woocommerce_shipping_' . $this->id . '_instance_settings_values', $this->instance_settings, $this ), 'yes' );
439 }
440
441 /**
442 * @param array $package .
443 */
444 public function calculate_shipping( $package = [] ) {
445 $rate_calculator = RateCalculatorFactory::create_for_shipping_method( $this, $package );
446
447 $method_settings = MethodSettingsFactory::create_from_array( $this->instance_settings );
448
449 $logger = $this->prepare_shipping_method_calculation_logger( $method_settings );
450
451 $rate_calculator->set_logger( $logger );
452 $calculated_rate = $rate_calculator->calculate_rate( $method_settings, $this->get_rate_id(), is_user_logged_in() );
453
454 if ( ! empty( $calculated_rate ) && $this->should_add_rate( $calculated_rate ) ) {
455 $calculated_rate = ( new TaxCalculator( $method_settings, \WC_Tax::get_shipping_tax_rates() ) )->append_taxes_to_rate_if_enabled( $calculated_rate, WC()->cart->get_customer()->get_is_vat_exempt() );
456 $this->add_rate( $calculated_rate );
457 $logger->debug( __( 'Shipping cost added.', 'flexible-shipping' ), $logger->get_results_context() );
458 }
459
460 $logger->show_notice_if_enabled();
461 }
462
463 /**
464 * @param array $calculated_rate .
465 *
466 * @return bool
467 */
468 private function should_add_rate( array $calculated_rate ) {
469 return ! ( 'yes' === $this->get_instance_option( 'method_visibility', 'no' ) && ! is_user_logged_in() );
470 }
471
472 /**
473 * Set logger. This logger is set by Flexible Shipping plugin.
474 *
475 * @param LoggerInterface $fs_logger .
476 */
477 public static function set_fs_logger( LoggerInterface $fs_logger ) {
478 static::$fs_logger = $fs_logger;
479 }
480
481 /**
482 * @param \FSVendor\WPDesk\FS\TableRate\Settings\MethodSettings $shipping_method_settings .
483 *
484 * @return Logger\ShippingMethodLogger
485 */
486 private function prepare_shipping_method_calculation_logger( $shipping_method_settings ) {
487 $method_debug_mode = $shipping_method_settings->get_debug_mode();
488 $shipping_method_title = $shipping_method_settings->get_title();
489 $shipping_method_url = admin_url(
490 'admin.php?page=wc-settings&tab=shipping&instance_id=' . sanitize_key( $this->instance_id ) . '&action=edit&method_id=' . sanitize_key( $shipping_method_settings->get_id() )
491 );
492 if ( null !== static::$fs_logger ) {
493 $fs_logger = static::$fs_logger;
494 } else {
495 $fs_logger = NullLogger();
496 }
497
498 return new ShippingMethodLogger(
499 $fs_logger,
500 new NoticeLogger(
501 $shipping_method_title,
502 $shipping_method_url,
503 'yes' === $method_debug_mode && current_user_can( 'manage_woocommerce' )
504 )
505 );
506 }
507 }
508