PluginProbe ʕ •ᴥ•ʔ
Everest Forms – Contact Form, Payment Form, Quiz, Survey & Custom Form Builder with AI / 3.6.0
Everest Forms – Contact Form, Payment Form, Quiz, Survey & Custom Form Builder with AI v3.6.0
3.6.0 3.5.3 3.5.2 3.5.1 3.5.0 3.4.8 3.4.7 3.4.6 1.1.0 1.1.1 1.1.2 1.1.3 1.1.4 1.1.5 1.1.5.1 1.1.6 1.1.7 1.1.8 1.1.9 1.2.0 1.2.1 1.2.2 1.2.3 1.2.4 1.3.0 1.3.1 1.3.2 1.3.3 1.3.4 1.4.0 1.4.1 1.4.2 1.4.3 1.4.4 1.4.5 1.4.6 1.4.7 1.4.8 1.4.9 1.5.0 1.5.1 1.5.10 1.5.2 1.5.3 1.5.4 1.5.5 1.5.6 1.5.7 1.5.8 1.5.9 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 1.6.5 1.6.6 1.6.6.1 1.6.7 1.7.0 1.7.0.1 1.7.0.2 1.7.0.3 1.7.1 1.7.2 1.7.2.1 1.7.2.2 1.7.3 1.7.4 1.7.5 1.7.5.1 1.7.5.2 1.7.6 1.7.7 1.7.7.1 1.7.7.2 1.7.8 1.7.9 1.8.0 1.8.0.1 1.8.1 1.8.2 1.8.2.1 1.8.2.2 1.8.2.3 1.8.3 1.8.4 1.8.5 1.8.6 1.8.7 1.8.8 1.8.9 1.9.0 1.9.0.1 1.9.1 1.9.2 1.9.3 1.9.4 1.9.4.1 1.9.5 1.9.6 1.9.7 1.9.8 1.9.9 2.0.0 2.0.0.1 2.0.1 2.0.2 2.0.3 2.0.3.1 2.0.4 2.0.4.1 2.0.5 2.0.6 2.0.7 2.0.8 2.0.8.1 2.0.9 3.0.0 3.0.0.1 3.0.1 3.0.2 3.0.3 3.0.3.1 3.0.4 3.0.4.1 3.0.4.2 3.0.5 3.0.5.1 3.0.5.2 3.0.6 3.0.6.1 3.0.7.1 3.0.8 3.0.8.1 3.0.9 3.0.9.1 3.0.9.2 3.0.9.3 3.0.9.4 3.0.9.5 3.1.0 3.1.1 3.1.2 3.2.0 3.2.1 3.2.2 3.2.3 3.2.4 3.2.5 3.2.6 3.3.0 3.4.0 3.4.1 3.4.2 3.4.2.1 3.4.3 3.4.4 3.4.5 trunk 1.0 1.0.1 1.0.2 1.0.3
everest-forms / vendor / themegrill / themegrill-sdk / src / Modules / Licenser.php
everest-forms / vendor / themegrill / themegrill-sdk / src / Modules Last commit date
Announcements.php 6 months ago Licenser.php 1 month ago Logger.php 6 months ago Notification.php 6 months ago Rollback.php 6 months ago ScriptLoader.php 6 months ago UninstallFeedback.php 6 months ago Updater.php 1 month ago
Licenser.php
274 lines
1 <?php
2 /**
3 * License management module for ThemeGrill SDK.
4 *
5 * Handles activate / deactivate / check against api.themegrill.com.
6 * Requires the product file to declare:
7 * Requires License: yes
8 * TG Item ID: 123
9 *
10 * @package ThemeGrillSDK
11 * @subpackage Modules
12 * @copyright Copyright (c) 2025, ThemeGrill
13 * @license http://opensource.org/licenses/gpl-3.0.php GNU Public License
14 * @since 1.0.1
15 */
16
17 namespace ThemeGrillSDK\Modules;
18
19 use ThemeGrillSDK\Common\AbstractModule;
20 use ThemeGrillSDK\Product;
21
22 if ( ! defined( 'ABSPATH' ) ) {
23 exit;
24 }
25
26 /**
27 * Licenser module for ThemeGrill SDK.
28 */
29 class Licenser extends AbstractModule {
30
31 /**
32 * Licensing API base path.
33 */
34 const LICENSES_PATH = 'licenses/';
35
36 /**
37 * How long to cache a license check (seconds).
38 */
39 const CACHE_TTL = 43200; // 12 hours
40
41 /**
42 * Check if the module should load for this product.
43 *
44 * @param Product $product Product to check.
45 *
46 * @return bool
47 */
48 public function can_load( $product ) {
49 return $product->requires_license() && $product->get_item_id() > 0;
50 }
51
52 /**
53 * Bootstrap the module.
54 *
55 * @param Product $product Product to load.
56 *
57 * @return Licenser
58 */
59 public function load( $product ) {
60 $this->product = $product;
61
62 // Feed stored status into Logger's license_status filter.
63 add_filter( $product->get_key() . '_license_status', array( $this, 'get_stored_status' ) );
64
65 // Periodic background check.
66 $cron_key = $product->get_key() . '_license_check';
67 if ( ! wp_next_scheduled( $cron_key ) ) {
68 wp_schedule_event( time(), 'daily', $cron_key );
69 }
70 add_action( $cron_key, array( $this, 'background_check' ) );
71
72 // Clean up cron on deactivation.
73 if ( $product->is_plugin() ) {
74 register_deactivation_hook( $product->get_basefile(), array( $this, 'clear_cron' ) );
75 } elseif ( $product->is_theme() ) {
76 add_action( 'switch_theme', array( $this, 'clear_cron' ) );
77 }
78
79 return $this;
80 }
81
82 // -------------------------------------------------------------------------
83 // Public API
84 // -------------------------------------------------------------------------
85
86 /**
87 * Activate a license key for the current site.
88 *
89 * @param string $license_key The license key to activate.
90 * @param string $site_url The site URL to activate against.
91 *
92 * @return array Response from the API.
93 */
94 public function activate( $license_key, $site_url = '' ) {
95 if ( '' === $site_url ) {
96 $site_url = home_url();
97 }
98
99 $response = $this->request(
100 'activate',
101 array(
102 'license_key' => $license_key,
103 'item_id' => $this->product->get_item_id(),
104 'site_url' => $site_url,
105 )
106 );
107
108 if ( ! empty( $response['success'] ) ) {
109 update_option( $this->product->get_key() . '_license', $license_key );
110 $this->store_status( $response['license'] ?? 'active', $response );
111 }
112
113 return $response;
114 }
115
116 /**
117 * Deactivate a license key for the current site.
118 *
119 * @param string $license_key The license key to deactivate.
120 * @param string $site_url The site URL to deactivate.
121 *
122 * @return array Response from the API.
123 */
124 public function deactivate( $license_key, $site_url = '' ) {
125 if ( '' === $site_url ) {
126 $site_url = home_url();
127 }
128
129 $response = $this->request(
130 'deactivate',
131 array(
132 'license_key' => $license_key,
133 'item_id' => $this->product->get_item_id(),
134 'site_url' => $site_url,
135 )
136 );
137
138 if ( ! empty( $response['success'] ) ) {
139 $this->store_status( 'inactive', $response );
140 }
141
142 return $response;
143 }
144
145 /**
146 * Check license validity. Caches result for 12 hours.
147 *
148 * @param string $license_key The license key to check.
149 * @param string $site_url Optional site URL for site-active check.
150 *
151 * @return array Response from the API.
152 */
153 public function check( $license_key, $site_url = '' ) {
154 $body = array(
155 'license_key' => $license_key,
156 'item_id' => $this->product->get_item_id(),
157 );
158
159 if ( '' !== $site_url ) {
160 $body['site_url'] = $site_url;
161 }
162
163 $response = $this->request( 'check', $body );
164
165 $status = $response['license'] ?? 'inactive';
166 $this->store_status( $status, $response );
167
168 return $response;
169 }
170
171 /**
172 * Return the stored license status string.
173 *
174 * @param string $default Fallback value (used as filter default).
175 *
176 * @return string
177 */
178 public function get_stored_status( $default = '' ) {
179 $status = get_option( $this->product->get_key() . '_license_status', $default );
180 return (string) $status;
181 }
182
183 /**
184 * True when the locally cached status is 'active'.
185 *
186 * @return bool
187 */
188 public function is_valid() {
189 return $this->get_stored_status() === 'valid';
190 }
191
192 // -------------------------------------------------------------------------
193 // Internal
194 // -------------------------------------------------------------------------
195
196 /**
197 * Remove the scheduled license check cron event.
198 */
199 public function clear_cron() {
200 $cron_key = $this->product->get_key() . '_license_check';
201 $timestamp = wp_next_scheduled( $cron_key );
202 if ( $timestamp ) {
203 wp_unschedule_event( $timestamp, $cron_key );
204 }
205 }
206
207 /**
208 * Background cron: re-check the stored license key.
209 */
210 public function background_check() {
211 $key = $this->product->get_license();
212 if ( empty( $key ) || 'free' === $key ) {
213 return;
214 }
215 $this->check( $key, home_url() );
216 }
217
218 /**
219 * POST to a licensing endpoint.
220 *
221 * @param string $action 'activate' | 'deactivate' | 'check'
222 * @param array $body
223 *
224 * @return array
225 */
226 private function request( $action, array $body ) {
227 $url = Product::API_URL . self::LICENSES_PATH . $action;
228
229 $result = wp_remote_post(
230 $url,
231 array(
232 'timeout' => 15,
233 'headers' => array( 'Content-Type' => 'application/json' ),
234 'body' => wp_json_encode( $body ),
235 'data_format' => 'body',
236 )
237 );
238
239 if ( is_wp_error( $result ) ) {
240 return array(
241 'success' => false,
242 'error' => $result->get_error_message(),
243 );
244 }
245
246 $data = json_decode( wp_remote_retrieve_body( $result ), true );
247
248 if ( ! is_array( $data ) ) {
249 return array(
250 'success' => false,
251 'error' => 'invalid_response',
252 );
253 }
254
255 // activate/deactivate wrap payload in a `data` key; check returns flat.
256 if ( isset( $data['data'] ) && is_array( $data['data'] ) ) {
257 return $data['data'];
258 }
259
260 return $data;
261 }
262
263 /**
264 * Persist license status and full response data.
265 *
266 * @param string $status
267 * @param array $data
268 */
269 private function store_status( $status, array $data ) {
270 update_option( $this->product->get_key() . '_license_status', $status );
271 update_option( $this->product->get_key() . '_license_data', (object) $data );
272 }
273 }
274