PluginProbe ʕ •ᴥ•ʔ
Superb Addons: Blocks, Patterns, Pre-built Pages, Sliders, Popups, Free Forms, Animations & More / 4.2.0
Superb Addons: Blocks, Patterns, Pre-built Pages, Sliders, Popups, Free Forms, Animations & More v4.2.0
4.2.0 4.1.0 4.0.9 4.0.8 4.0.7 4.0.6 4.0.5 4.0.4 4.0.3 4.0.2 4.0.1 4.0.0 trunk 1.0.0 2.0.0 2.0.1 2.0.2 2.0.3 3.0 3.0.1 3.0.2 3.0.5 3.0.6 3.0.7 3.0.8 3.0.9 3.1.0 3.1.2 3.1.3 3.2.0 3.2.1 3.2.2 3.2.4 3.2.5 3.2.7 3.2.8 3.2.9 3.3.0 3.3.1 3.3.2 3.4.0 3.4.1 3.4.2 3.4.5 3.4.6 3.5.0 3.5.1 3.5.2 3.5.3 3.5.4 3.5.6 3.5.7 3.5.8 3.5.9 3.6.0 3.6.1 3.6.2 3.7.0 3.7.1
superb-blocks / src / data / controllers / class-link-controller.php
superb-blocks / src / data / controllers Last commit date
class-cache-controller.php 3 weeks ago class-css-controller.php 3 weeks ago class-domainshift-controller.php 3 weeks ago class-key-controller.php 3 weeks ago class-link-controller.php 1 day ago class-log-controller.php 3 weeks ago class-option-controller.php 3 weeks ago class-rest-controller.php 2 weeks ago
class-link-controller.php
186 lines
1 <?php
2
3 namespace SuperbAddons\Data\Controllers;
4
5 use SuperbAddons\Admin\Utils\AdminLinkSource;
6
7 defined('ABSPATH') || exit();
8
9 class LinkController
10 {
11 // Modal presentation buckets: two independent toggles on the rich
12 // modal layout, reported together as one variant string.
13 const VARIANT_GROUP = 'modal-v4';
14 const BONUS_SALT = 'modal-v4-bonus';
15 const CTA_SALT = 'modal-v4-cta';
16
17 const SEED_OPTION = 'superbaddons_pre_activation';
18
19 // Delayed admin notice content buckets, hashed independently.
20 // v3: md5 hashing, same content as v2.
21 const NOTICE_GROUP = 'notice-v3';
22 const NOTICE_SALT = 'notice-v3';
23 const NOTICE_VARIANT_DISCOUNT = 'discount';
24 const NOTICE_VARIANT_BENEFITS = 'benefits';
25
26 const NOTICE_FILE_DISCOUNT = 'addons-notice.php';
27 const NOTICE_FILE_BENEFITS = 'addons-notice-benefits.php';
28
29 // Admin navigation CTA buckets: direct link vs opening the modal,
30 // hashed independently. v2: md5 hashing, same behaviour as v1.
31 const NAV_GROUP = 'nav-v2';
32 const NAV_SALT = 'nav-v2';
33 const NAV_VARIANT_DIRECT = 'nav-direct';
34 const NAV_VARIANT_MODAL = 'nav-modal';
35
36 private static $cached = null;
37 private static $notice_variant = null;
38 private static $nav_variant = null;
39
40 /**
41 * @return array { active: bool, group: string, variant: string, bonusLine: bool, ctaAll: bool }
42 */
43 public static function GetState()
44 {
45 if (self::$cached !== null) {
46 return self::$cached;
47 }
48
49 $bonus_line = self::Bucket(self::BONUS_SALT) === 1;
50 $cta_all = self::Bucket(self::CTA_SALT) === 1;
51
52 // active is unconditionally true for every install. The JS link builder
53 // reads it to decide whether to append the su_exp/su_var params.
54 self::$cached = array(
55 'active' => true,
56 'group' => self::VARIANT_GROUP,
57 'variant' => ($bonus_line ? 'bonus' : 'plain') . '-' . ($cta_all ? 'all' : 'prem'),
58 'bonusLine' => $bonus_line,
59 'ctaAll' => $cta_all,
60 );
61 return self::$cached;
62 }
63
64 public static function GetVariant()
65 {
66 $state = self::GetState();
67 return $state['variant'];
68 }
69
70 public static function GetLinkExpArgs($experiment = 'upsell')
71 {
72 if ($experiment === 'notice') {
73 return self::GetNoticeExpArgs();
74 }
75 if ($experiment === 'nav') {
76 return self::GetNavExpArgs();
77 }
78
79 $state = self::GetState();
80 if (empty($state['active'])) {
81 return array();
82 }
83 return array(
84 'su_exp' => $state['group'],
85 'su_var' => $state['variant'],
86 );
87 }
88
89 /**
90 * @return array { active, group, variant, bonusLine, ctaAll, sourceExperiments }
91 */
92 public static function GetJsConfig()
93 {
94 $state = self::GetState();
95 // Links built for these sources carry their own group/variant instead
96 // of the modal group's.
97 $state['sourceExperiments'] = array(
98 AdminLinkSource::NAVIGATION_CTA => array(
99 'group' => self::NAV_GROUP,
100 'variant' => self::GetNavVariant(),
101 ),
102 );
103 return $state;
104 }
105
106 public static function Localize($handle)
107 {
108 wp_localize_script($handle, 'superbAddonsUpsell', self::GetJsConfig());
109 }
110
111 public static function GetNoticeVariant()
112 {
113 if (self::$notice_variant !== null) {
114 return self::$notice_variant;
115 }
116
117 self::$notice_variant = self::Bucket(self::NOTICE_SALT) === 1
118 ? self::NOTICE_VARIANT_BENEFITS
119 : self::NOTICE_VARIANT_DISCOUNT;
120 return self::$notice_variant;
121 }
122
123 public static function GetNoticeContentFile()
124 {
125 return self::GetNoticeVariant() === self::NOTICE_VARIANT_BENEFITS
126 ? self::NOTICE_FILE_BENEFITS
127 : self::NOTICE_FILE_DISCOUNT;
128 }
129
130 public static function GetNoticeExpArgs()
131 {
132 return array(
133 'su_exp' => self::NOTICE_GROUP,
134 'su_var' => self::GetNoticeVariant(),
135 );
136 }
137
138 public static function GetNavVariant()
139 {
140 if (self::$nav_variant !== null) {
141 return self::$nav_variant;
142 }
143
144 self::$nav_variant = self::Bucket(self::NAV_SALT) === 1
145 ? self::NAV_VARIANT_MODAL
146 : self::NAV_VARIANT_DIRECT;
147 return self::$nav_variant;
148 }
149
150 public static function NavOpensModal()
151 {
152 return self::GetNavVariant() === self::NAV_VARIANT_MODAL;
153 }
154
155 public static function GetNavExpArgs()
156 {
157 return array(
158 'su_exp' => self::NAV_GROUP,
159 'su_var' => self::GetNavVariant(),
160 );
161 }
162
163 // Salted per bucket so each result is independent of the others
164 // (including earlier salts on the same seed).
165 // md5 rather than crc32: crc32 is linear, so with a fixed-length seed (the
166 // install timestamp) the parities of two prefix-salted crc32 values differ
167 // by a constant and every bucket ends up identical.
168 // Four hex chars keep hexdec() inside int range on 32-bit PHP.
169 private static function Bucket($salt)
170 {
171 return hexdec(substr(md5($salt . '|' . self::SeedValue()), 0, 4)) % 2;
172 }
173
174 private static function SeedValue()
175 {
176 $seed = get_option(self::SEED_OPTION, '');
177 // The seed option can be missing (e.g. removed by a full plugin reset).
178 // Fall back to a stable per-site value rather than writing on a read
179 // path or lumping every seedless install into one bucket.
180 if ($seed === '' || $seed === false) {
181 $seed = home_url();
182 }
183 return (string) $seed;
184 }
185 }
186