PluginProbe
Tiered Pricing Table for WooCommerce / trunk
Tiered Pricing Table for WooCommerce vtrunk
7.1.7 7.1.5 7.1.4 7.1.1 6.5.0 6.4.0 6.1.0 trunk 1.0 1.1 2.0 2.0.1 2.0.2 2.1 2.1.1 2.1.2 2.2.0 2.2.1 2.2.2 2.2.3 2.3.0 2.3.1 2.3.2 2.3.3 2.3.4 All 90 releases
tier-pricing-table / src / Settings / Settings.php

Settings.php in Tiered Pricing Table for WooCommerce trunk, at src/Settings/Settings.php

387 lines 12.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace TierPricingTable\Settings;
4
5 use TierPricingTable\Core\ServiceContainerTrait;
6 use TierPricingTable\Settings\CustomOptions\TPTDisplayType;
7 use TierPricingTable\Settings\CustomOptions\TPTLinkButton;
8 use TierPricingTable\Settings\CustomOptions\TPTTableColumnsField;
9 use TierPricingTable\Settings\CustomOptions\TPTQuantityMeasurementField;
10 use TierPricingTable\Settings\CustomOptions\TPTFeatureFlagOption;
11 use TierPricingTable\Settings\CustomOptions\TPTIntegrationOption;
12 use TierPricingTable\Settings\CustomOptions\TPTSwitchOption;
13 use TierPricingTable\Settings\CustomOptions\TPTTextTemplate;
14 use TierPricingTable\Settings\Sections\Advanced\AdvancedSection;
15 use TierPricingTable\Settings\Sections\CalculationLogic\CalculationLogic;
16 use TierPricingTable\Settings\Sections\GeneralSection\GeneralSection;
17 use TierPricingTable\Settings\Sections\Integrations\IntegrationSection;
18 use TierPricingTable\Settings\Sections\Multicurrency\MulticurrencySection;
19 use TierPricingTable\Settings\Sections\ProductAddons\ProductAddonsSection;
20 use TierPricingTable\Settings\Sections\SectionAbstract;
21 use TierPricingTable\TierPricingTablePlugin;
22 /**
23 * Class Settings
24 *
25 * @package TierPricingTable\Settings
26 */
27 class Settings {
28 use ServiceContainerTrait;
29 const SETTINGS_PREFIX = 'tier_pricing_table_';
30
31 const SETTINGS_PAGE = 'tiered_pricing_table_settings';
32
33 const DEFAULT_SECTION = 'general';
34
35 /**
36 * Settings
37 *
38 * @var array
39 */
40 private $settings = array();
41
42 /**
43 * Settings sections
44 *
45 * @var SectionAbstract[]
46 */
47 protected $sections = array();
48
49 /**
50 * Settings constructor.
51 */
52 public function __construct() {
53 $this->initCustomOptions();
54 $this->hooks();
55 if ( !tpt_fs()->can_use_premium_code() ) {
56 new PremiumSettingsManager();
57 }
58 if ( !tpt_fs()->can_use_premium_code() ) {
59 $template = 'upgrade-banner.php';
60 add_action( 'woocommerce_settings_' . self::SETTINGS_PAGE, function () use($template) {
61 $this->getContainer()->getFileManager()->includeTemplate( 'admin/banners/' . $template, [
62 'upgradeUrl' => tpt_fs_activation_url(),
63 'contactUsUrl' => TierPricingTablePlugin::getContactUsURL(),
64 'documentationUrl' => TierPricingTablePlugin::getDocumentationURL(),
65 ] );
66 } );
67 }
68 if ( tpt_fs()->can_use_premium_code() && !tpt_fs()->is_premium() ) {
69 add_action( 'woocommerce_settings_' . self::SETTINGS_PAGE, function () {
70 $this->getContainer()->getFileManager()->includeTemplate( 'admin/banners/free-version-used-premium-available.php' );
71 } );
72 }
73 add_action( 'admin_enqueue_scripts', function () {
74 $assetName = self::SETTINGS_PAGE . '_script';
75 wp_register_script(
76 $assetName,
77 $this->getContainer()->getFileManager()->locateJSAsset( 'admin/settings' ),
78 array('jquery'),
79 TierPricingTablePlugin::VERSION,
80 true
81 );
82 wp_enqueue_script( $assetName );
83 } );
84 }
85
86 protected function initCustomOptions() {
87 $this->getContainer()->add( 'settings.tpt_switch_option', new TPTSwitchOption() );
88 $this->getContainer()->add( 'settings.tpt_integration_option', new TPTIntegrationOption() );
89 $this->getContainer()->add( 'settings.tpt_feature_flag_option', new TPTFeatureFlagOption() );
90 $this->getContainer()->add( 'settings.tpt_text_template', new TPTTextTemplate() );
91 $this->getContainer()->add( 'settings.tpt_display_type', new TPTDisplayType() );
92 $this->getContainer()->add( 'settings.tpt_link_button', new TPTLinkButton() );
93 $this->getContainer()->add( 'settings.tpt_quantity_measurement', new TPTQuantityMeasurementField() );
94 $this->getContainer()->add( 'settings.tpt_multiple_fields', new TPTTableColumnsField() );
95 }
96
97 protected function initSections() {
98 }
99
100 /**
101 * Handle updating settings
102 */
103 public function updateSettings() {
104 woocommerce_update_options( $this->settings );
105 $this->getContainer()->getCache()->purge();
106 }
107
108 /**
109 * Order the settings sections deterministically: configuration first, then display, features,
110 * feature toggles, third-party sections, and maintenance last. Without this the tab order is an
111 * accident of hook registration, because every addon splices its section in relative to another.
112 *
113 * Sections with an unknown slug (third-party) keep their relative order and land before Tools.
114 *
115 * @param array $sections
116 *
117 * @return array
118 */
119 protected function sortSections( array $sections ) : array {
120 $order = (array) apply_filters( 'tiered_pricing_table/settings/sections_order', array(
121 'general' => 10,
122 'calculation_logic' => 20,
123 'shop-loop-display' => 30,
124 'tier-labels' => 40,
125 'request-a-quote' => 50,
126 'advanced' => 60,
127 'integrations' => 70,
128 'multicurrency' => 80,
129 'product-addons' => 90,
130 'tools' => 110,
131 ) );
132 // Stable sort: usort() is only guaranteed stable on PHP 8+, so tie-break on the original index.
133 $indexed = array();
134 foreach ( array_values( $sections ) as $index => $section ) {
135 $indexed[] = array($order[$section->getSlug()] ?? 100, $index, $section);
136 }
137 usort( $indexed, function ( $a, $b ) {
138 return ( $a[0] <=> $b[0] ?: $a[1] <=> $b[1] );
139 } );
140 return array_column( $indexed, 2 );
141 }
142
143 /**
144 * Init all settings
145 */
146 public function initSettings() {
147 $this->sections = apply_filters( 'tiered_pricing_table/settings/sections', array(
148 new GeneralSection(),
149 new CalculationLogic(),
150 new AdvancedSection(),
151 new MulticurrencySection(),
152 new ProductAddonsSection(),
153 new IntegrationSection()
154 ) );
155 $this->sections = $this->sortSections( $this->sections );
156 foreach ( $this->sections as $section ) {
157 if ( $section->isActive() ) {
158 $this->settings = $section->getSettings();
159 break;
160 }
161 }
162 }
163
164 /**
165 * Register hooks
166 */
167 public function hooks() {
168 add_action( 'init', array($this, 'initSettings') );
169 add_filter( 'woocommerce_settings_tabs_' . self::SETTINGS_PAGE, array($this, 'addTieredPricingTableSettings') );
170 add_filter( 'woocommerce_settings_tabs_array', array($this, 'addSettingsTab'), 50 );
171 add_action( 'woocommerce_update_options_' . self::SETTINGS_PAGE, array($this, 'updateSettings') );
172 add_action( 'woocommerce_settings_' . self::SETTINGS_PAGE, array($this, 'renderSections'), 99 );
173 }
174
175 public function renderSections() {
176 // Opening a section clears its "unread" indicator (store-wide)
177 foreach ( $this->sections as $section ) {
178 if ( $section->isActive() ) {
179 $section->markBadgeSeen();
180 }
181 }
182 ?>
183 <style>
184 h2 {
185 margin-top: 2em;
186 font-size: 1.45em;
187 }
188 </style>
189
190 <ul class="subsubsub" style="font-size: 1.1em; margin-top: 3px">
191 <?php
192 $sectionsCount = count( $this->sections );
193 ?>
194 <?php
195 foreach ( $this->sections as $index => $section ) {
196 ?>
197 <li>
198 <?php
199 if ( !$section->isActive() ) {
200 ?>
201 <a href="<?php
202 echo esc_attr( $section->getURL() );
203 ?>">
204 <?php
205 if ( $section->isIntegration() ) {
206 ?>
207 <small style="width: 10px; height: 10px; display: inline-block; margin-right: 10px;">
208 <span class="dashicons dashicons-admin-plugins"></span>
209 </small>
210 <b><?php
211 echo esc_html( $section->getName() );
212 ?></b>
213 <?php
214 } else {
215 ?>
216 <?php
217 echo esc_html( $section->getName() );
218 ?>
219 <?php
220 if ( $section->isBadgeUnseen() ) {
221 ?>
222 <span class="tpt-unread-badge" aria-hidden="true">1</span><span class="screen-reader-text"><?php
223 esc_html_e( 'New', 'tier-pricing-table' );
224 ?></span>
225 <?php
226 }
227 ?>
228 <?php
229 }
230 ?>
231
232 </a>
233 <?php
234 } else {
235 ?>
236
237 <?php
238 if ( $section->getSectionCSS() ) {
239 ?>
240 <style>
241 <?php
242 echo esc_html( $section->getSectionCSS() );
243 ?>
244 </style>
245 <?php
246 }
247 ?>
248
249 <a class="current" href="#">
250 <?php
251 echo esc_html( $section->getName() );
252 ?>
253 </a>
254 <?php
255 }
256 ?>
257 <?php
258 if ( $index < $sectionsCount - 1 ) {
259 ?>
260 |
261 <?php
262 }
263 ?>
264 </li>
265 <?php
266 }
267 ?>
268 </ul>
269 <br class="clear">
270 <?php
271 }
272
273 /**
274 * Add own settings tab
275 *
276 * @param $settingsTabs
277 *
278 * @return array
279 */
280 public static function addSettingsTab( $settingsTabs ) : array {
281 $settingsTabs = ( is_array( $settingsTabs ) ? $settingsTabs : array() );
282 $settingsTabs[self::SETTINGS_PAGE] = __( 'Tiered Pricing', 'tier-pricing-table' );
283 return $settingsTabs;
284 }
285
286 /**
287 * Add settings to WooCommerce
288 */
289 public function addTieredPricingTableSettings() {
290 woocommerce_admin_fields( $this->settings );
291 }
292
293 /**
294 * Get setting by name
295 *
296 * @param string $optionName
297 * @param mixed $default
298 *
299 * @return mixed
300 */
301 public function get( string $optionName, $default = null ) {
302 return get_option( self::SETTINGS_PREFIX . $optionName, $default );
303 }
304
305 public static function deleteOptions() {
306 GeneralSection::deleteOptions();
307 AdvancedSection::deleteOptions();
308 IntegrationSection::deleteOptions();
309 }
310
311 /**
312 * Get url to settings page
313 *
314 * @return string
315 */
316 public function getLink() : string {
317 return admin_url( 'admin.php?page=wc-settings&tab=tiered_pricing_table_settings' );
318 }
319
320 public static function hex2rgba( $color, $opacity = false ) : string {
321 $default = 'rgb(0,0,0)';
322 if ( empty( $color ) ) {
323 return $default;
324 }
325 if ( '#' === $color[0] ) {
326 $color = substr( $color, 1 );
327 }
328 if ( strlen( $color ) == 6 ) {
329 $hex = array($color[0] . $color[1], $color[2] . $color[3], $color[4] . $color[5]);
330 } elseif ( strlen( $color ) == 3 ) {
331 $hex = array($color[0] . $color[0], $color[1] . $color[1], $color[2] . $color[2]);
332 } else {
333 return $default;
334 }
335 $rgb = array_map( 'hexdec', $hex );
336 if ( $opacity ) {
337 if ( abs( $opacity ) > 1 ) {
338 $opacity = 1.0;
339 }
340 $output = 'rgba(' . implode( ',', $rgb ) . ',' . $opacity . ')';
341 } else {
342 $output = 'rgb(' . implode( ',', $rgb ) . ')';
343 }
344 return $output;
345 }
346
347 public static function shadeHexWithOpacity( $hex, $opacity, $bgHex = '#FFFFFF' ) {
348 // Normalize and parse the foreground hex
349 $hex = ltrim( $hex, '#' );
350 if ( strlen( $hex ) === 3 ) {
351 $hex = $hex[0] . $hex[0] . $hex[1] . $hex[1] . $hex[2] . $hex[2];
352 }
353 if ( strlen( $hex ) !== 6 ) {
354 return false;
355 }
356 // Normalize and parse the background hex
357 $bgHex = ltrim( $bgHex, '#' );
358 if ( strlen( $bgHex ) === 3 ) {
359 $bgHex = $bgHex[0] . $bgHex[0] . $bgHex[1] . $bgHex[1] . $bgHex[2] . $bgHex[2];
360 }
361 if ( strlen( $bgHex ) !== 6 ) {
362 return false;
363 }
364 // Clamp opacity
365 $opacity = max( 0, min( 1, $opacity ) );
366 // Extract RGB
367 $r = hexdec( substr( $hex, 0, 2 ) );
368 $g = hexdec( substr( $hex, 2, 2 ) );
369 $b = hexdec( substr( $hex, 4, 2 ) );
370 $bgR = hexdec( substr( $bgHex, 0, 2 ) );
371 $bgG = hexdec( substr( $bgHex, 2, 2 ) );
372 $bgB = hexdec( substr( $bgHex, 4, 2 ) );
373 // Blend with background using alpha compositing
374 $newR = round( $opacity * $r + (1 - $opacity) * $bgR );
375 $newG = round( $opacity * $g + (1 - $opacity) * $bgG );
376 $newB = round( $opacity * $b + (1 - $opacity) * $bgB );
377 // Return final hex
378 return sprintf(
379 '#%02X%02X%02X',
380 $newR,
381 $newG,
382 $newB
383 );
384 }
385
386 }
387