| 1 |
<?php |
| 2 |
/** |
| 3 |
* Give License handler |
| 4 |
* |
| 5 |
* @package Give |
| 6 |
* @subpackage Admin/License |
| 7 |
* @copyright Copyright (c) 2016, GiveWP |
| 8 |
* @license https://opensource.org/licenses/gpl-license GNU Public License |
| 9 |
* @since 1.0 |
| 10 |
*/ |
| 11 |
|
| 12 |
// Exit if accessed directly. |
| 13 |
use Give\Log\Log; |
| 14 |
use Give\Vendors\StellarWP\AdminNotices\AdminNotices; |
| 15 |
|
| 16 |
if ( ! defined('ABSPATH') ) { |
| 17 |
exit; |
| 18 |
} |
| 19 |
|
| 20 |
if ( ! class_exists('Give_License') ) : |
| 21 |
|
| 22 |
/** |
| 23 |
* Give_License Class |
| 24 |
* |
| 25 |
* This class simplifies the process of adding license information |
| 26 |
* to new Give add-ons. |
| 27 |
* |
| 28 |
* @since 1.0 |
| 29 |
*/ |
| 30 |
class Give_License |
| 31 |
{ |
| 32 |
|
| 33 |
/** |
| 34 |
* File |
| 35 |
* |
| 36 |
* @access private |
| 37 |
* @since 1.0 |
| 38 |
* |
| 39 |
* @var string |
| 40 |
*/ |
| 41 |
private $file; |
| 42 |
|
| 43 |
/** |
| 44 |
* License |
| 45 |
* |
| 46 |
* @access private |
| 47 |
* @since 1.0 |
| 48 |
* |
| 49 |
* @var string |
| 50 |
*/ |
| 51 |
private $license; |
| 52 |
|
| 53 |
/** |
| 54 |
* The license bundled with the premium add-on. |
| 55 |
* |
| 56 |
* @since 3.21.0 |
| 57 |
* |
| 58 |
* @var string|null |
| 59 |
*/ |
| 60 |
private $bundled_license; |
| 61 |
|
| 62 |
/** |
| 63 |
* Item name |
| 64 |
* |
| 65 |
* @access private |
| 66 |
* @since 1.0 |
| 67 |
* |
| 68 |
* @var string |
| 69 |
*/ |
| 70 |
private $item_name; |
| 71 |
|
| 72 |
/** |
| 73 |
* Item ID |
| 74 |
* |
| 75 |
* @access private |
| 76 |
* @since 2.2.4 |
| 77 |
* |
| 78 |
* @var int |
| 79 |
*/ |
| 80 |
private $item_id; |
| 81 |
|
| 82 |
/** |
| 83 |
* License Information object. |
| 84 |
* |
| 85 |
* @access private |
| 86 |
* @since 1.7 |
| 87 |
* |
| 88 |
* @var object |
| 89 |
*/ |
| 90 |
private $license_data; |
| 91 |
|
| 92 |
/** |
| 93 |
* Item shortname |
| 94 |
* |
| 95 |
* @access private |
| 96 |
* @since 1.0 |
| 97 |
* |
| 98 |
* @var string |
| 99 |
*/ |
| 100 |
private $item_shortname; |
| 101 |
|
| 102 |
/** |
| 103 |
* Version |
| 104 |
* |
| 105 |
* @access private |
| 106 |
* @since 1.0 |
| 107 |
* |
| 108 |
* @var string |
| 109 |
*/ |
| 110 |
private $version; |
| 111 |
|
| 112 |
/** |
| 113 |
* Author |
| 114 |
* |
| 115 |
* @access private |
| 116 |
* @since 1.0 |
| 117 |
* |
| 118 |
* @var string |
| 119 |
*/ |
| 120 |
private $author; |
| 121 |
|
| 122 |
/** |
| 123 |
* Plugin basename (as provided by plugin_basename() function) |
| 124 |
* |
| 125 |
* @var string |
| 126 |
*/ |
| 127 |
private $plugin_basename; |
| 128 |
|
| 129 |
/** |
| 130 |
* Plugin directory name |
| 131 |
* |
| 132 |
* @access private |
| 133 |
* @since 2.5.0 |
| 134 |
* |
| 135 |
* @var string |
| 136 |
*/ |
| 137 |
private $plugin_dirname; |
| 138 |
|
| 139 |
/** |
| 140 |
* Website URL |
| 141 |
* |
| 142 |
* @access private |
| 143 |
* @since 1.0 |
| 144 |
* |
| 145 |
* @var string |
| 146 |
*/ |
| 147 |
private static $site_url = 'https://givewp.com/'; |
| 148 |
|
| 149 |
/** |
| 150 |
* API URL |
| 151 |
* |
| 152 |
* @access private |
| 153 |
* @since 1.0 |
| 154 |
* |
| 155 |
* @var string |
| 156 |
*/ |
| 157 |
private static $api_url = 'https://givewp.com/edd-sl-api/'; |
| 158 |
|
| 159 |
/** |
| 160 |
* array of licensed addons |
| 161 |
* |
| 162 |
* @since 3.21.0 store the Give_License instances, not just the plugin basenames |
| 163 |
* @since 2.1.4 |
| 164 |
* @access private |
| 165 |
* |
| 166 |
* @var Give_License[] |
| 167 |
*/ |
| 168 |
private static $licensed_addons = []; |
| 169 |
|
| 170 |
/** |
| 171 |
* Account URL |
| 172 |
* |
| 173 |
* @access private |
| 174 |
* @since 1.7 |
| 175 |
* |
| 176 |
* @var null|string |
| 177 |
*/ |
| 178 |
private static $account_url = 'http://docs.givewp.com/settings-account'; |
| 179 |
|
| 180 |
/** |
| 181 |
* Downloads URL |
| 182 |
* |
| 183 |
* @access private |
| 184 |
* @since 2.5.0 |
| 185 |
* |
| 186 |
* @var null|string |
| 187 |
*/ |
| 188 |
private static $downloads_url = 'http://docs.givewp.com/settings-downloads'; |
| 189 |
|
| 190 |
/** |
| 191 |
* Checkout URL |
| 192 |
* |
| 193 |
* @access private |
| 194 |
* @since 1.7 |
| 195 |
* |
| 196 |
* @var null|string |
| 197 |
*/ |
| 198 |
private static $checkout_url = 'https://givewp.com/checkout/'; |
| 199 |
|
| 200 |
/** |
| 201 |
* Class Constructor |
| 202 |
* |
| 203 |
* Set up the Give License Class. |
| 204 |
* |
| 205 |
* @access public |
| 206 |
* |
| 207 |
* @since 3.17.2 removed unused auto_updater_obj property assignment |
| 208 |
* @since 1.0 |
| 209 |
* |
| 210 |
* @param string $_file |
| 211 |
* @param string $_item_name |
| 212 |
* @param string $_version |
| 213 |
* @param string $_author |
| 214 |
* @param string $_optname |
| 215 |
* @param string $_api_url |
| 216 |
* @param string $_checkout_url |
| 217 |
* @param string $_account_url |
| 218 |
* @param int $_item_id |
| 219 |
* |
| 220 |
* @since 3.21.0 adds plugin_basename property |
| 221 |
*/ |
| 222 |
public function __construct( |
| 223 |
$_file, |
| 224 |
$_item_name, |
| 225 |
$_version, |
| 226 |
$_author, |
| 227 |
$_optname = null, |
| 228 |
$_api_url = null, |
| 229 |
$_checkout_url = null, |
| 230 |
$_account_url = null, |
| 231 |
$_item_id = null |
| 232 |
) { |
| 233 |
|
| 234 |
// Only load in wp-admin. |
| 235 |
if ( ! is_admin() ) { |
| 236 |
return; |
| 237 |
} |
| 238 |
|
| 239 |
if ( is_numeric( $_item_id ) ) { |
| 240 |
$this->item_id = absint( $_item_id ); |
| 241 |
} |
| 242 |
|
| 243 |
$this->file = $_file; |
| 244 |
$this->item_name = $_item_name; |
| 245 |
$this->plugin_basename = plugin_basename($this->file); |
| 246 |
$this->plugin_dirname = dirname( plugin_basename( $this->file ) ); |
| 247 |
$this->item_shortname = self::get_short_name( $this->item_name ); |
| 248 |
$this->license_data = self::get_license_by_plugin_dirname( $this->plugin_dirname ); |
| 249 |
$this->version = $_version; |
| 250 |
$this->license = ! empty( $this->license_data['license_key'] ) ? $this->license_data['license_key'] : ''; |
| 251 |
$this->bundled_license = self::get_bundled_license($this->file); |
| 252 |
$this->author = $_author; |
| 253 |
self::$api_url = is_null( $_api_url ) ? self::$api_url : $_api_url; |
| 254 |
self::$checkout_url = is_null( $_checkout_url ) ? self::$checkout_url : $_checkout_url; |
| 255 |
self::$account_url = is_null( $_account_url ) ? self::$account_url : $_account_url; |
| 256 |
|
| 257 |
// Add plugin to registered licenses list. |
| 258 |
array_push(self::$licensed_addons, $this); |
| 259 |
} |
| 260 |
|
| 261 |
/** |
| 262 |
* Get plugin shortname |
| 263 |
* |
| 264 |
* @param $plugin_name |
| 265 |
* |
| 266 |
* @return string |
| 267 |
* @since 2.1.0 |
| 268 |
* @access public |
| 269 |
*/ |
| 270 |
public static function get_short_name( $plugin_name ) { |
| 271 |
$plugin_name = trim( str_replace( 'Give - ', '', $plugin_name ) ); |
| 272 |
$plugin_name = 'give_' . preg_replace( '/[^a-zA-Z0-9_\s]/', '', str_replace( ' ', '_', strtolower( $plugin_name ) ) ); |
| 273 |
|
| 274 |
return $plugin_name; |
| 275 |
} |
| 276 |
|
| 277 |
/** |
| 278 |
* Checks to see if the license was bundled with the add-on and if so, returns it. This is meant to be a |
| 279 |
* convenience, so any errors are ignored and the user can still manually enter their license key. |
| 280 |
* |
| 281 |
* @since 3.21.0 |
| 282 |
*/ |
| 283 |
public static function get_bundled_license(string $plugin_file): ?string |
| 284 |
{ |
| 285 |
$license = null; |
| 286 |
$file_path = plugin_dir_path($plugin_file) . 'PLUGIN_LICENSE.php'; |
| 287 |
if (is_readable($file_path)) { |
| 288 |
$license = include $file_path; |
| 289 |
} |
| 290 |
|
| 291 |
return $license ?: null; |
| 292 |
} |
| 293 |
|
| 294 |
/** |
| 295 |
* This sorts through all the registered add-ons and checks to see if any of them have bundled licenses, but |
| 296 |
* aren't set up with a license key. If so, it will attempt to activate the license key for them. |
| 297 |
* |
| 298 |
* It's likely that many add-ons will have the same license key which is a plan, so the license key will only be |
| 299 |
* activated once for all add-ons using it. |
| 300 |
* |
| 301 |
* If any sort of error occurs, an admin notice will be shown to the user providing the error and instructions |
| 302 |
* to manually activate the license key. |
| 303 |
* |
| 304 |
* Note: much of this code is taken directly from give_get_license_info_handler() |
| 305 |
* |
| 306 |
* @since 3.21.0 |
| 307 |
*/ |
| 308 |
public static function activate_bundled_licenses(): void |
| 309 |
{ |
| 310 |
$unactivated_bundled_licenses = []; |
| 311 |
foreach (self::$licensed_addons as $addon) { |
| 312 |
if ($addon->bundled_license && empty($addon->license)) { |
| 313 |
// Store a unique associative array where the key is the license key and the value is an array of |
| 314 |
// addons using that license |
| 315 |
if ( ! isset($unactivated_bundled_licenses[$addon->bundled_license])) { |
| 316 |
$unactivated_bundled_licenses[$addon->bundled_license] = []; |
| 317 |
} |
| 318 |
|
| 319 |
$unactivated_bundled_licenses[$addon->bundled_license][] = $addon; |
| 320 |
} |
| 321 |
} |
| 322 |
|
| 323 |
if (empty($unactivated_bundled_licenses)) { |
| 324 |
return; |
| 325 |
} |
| 326 |
|
| 327 |
$show_failed_activation_notice = static function ($license_key, $reason) { |
| 328 |
AdminNotices::show( |
| 329 |
"license-bundle-activation-error-$license_key", |
| 330 |
"An error occurred while attempting to activate license <code>$license_key</code>. $reason. Please activate the license manually." |
| 331 |
)->autoParagraph()->asError()->dismissible(); |
| 332 |
}; |
| 333 |
|
| 334 |
foreach ($unactivated_bundled_licenses as $license => $addons) { |
| 335 |
$check_license_res = self::request_license_api( |
| 336 |
[ |
| 337 |
'edd_action' => 'check_license', |
| 338 |
'license' => $license, |
| 339 |
], |
| 340 |
true |
| 341 |
); |
| 342 |
$is_plan_license = ! empty($check_license_res['is_all_access_pass']); |
| 343 |
|
| 344 |
if (is_wp_error($check_license_res)) { |
| 345 |
$show_failed_activation_notice($license, $check_license_res->get_error_message()); |
| 346 |
continue; |
| 347 |
} |
| 348 |
|
| 349 |
if ( ! $check_license_res['success']) { |
| 350 |
$reason = $check_license_res['error'] ?? 'The licensing server was unreachable'; |
| 351 |
$show_failed_activation_notice( $license, $reason ); |
| 352 |
continue; |
| 353 |
} |
| 354 |
|
| 355 |
if ( ! $is_plan_license) { |
| 356 |
if (count($addons) > 1) { |
| 357 |
$show_failed_activation_notice( |
| 358 |
$license, |
| 359 |
'A single add-on license cannot be used for multiple add-ons' |
| 360 |
); |
| 361 |
continue; |
| 362 |
} |
| 363 |
|
| 364 |
if ($check_license_res['plugin_slug'] !== $addons[0]->plugin_dirname) { |
| 365 |
$show_failed_activation_notice( |
| 366 |
$license, |
| 367 |
'The license is not valid for this add-on' |
| 368 |
); |
| 369 |
continue; |
| 370 |
} |
| 371 |
} |
| 372 |
|
| 373 |
$activate_license_res = self::request_license_api( |
| 374 |
[ |
| 375 |
'edd_action' => 'activate_license', |
| 376 |
'item_name' => $check_license_res['item_name'], |
| 377 |
'license' => $license, |
| 378 |
], |
| 379 |
true |
| 380 |
); |
| 381 |
|
| 382 |
if (is_wp_error($activate_license_res)) { |
| 383 |
$show_failed_activation_notice($license, $activate_license_res->get_error_message()); |
| 384 |
continue; |
| 385 |
} |
| 386 |
|
| 387 |
$check_license_res['license'] = $activate_license_res['license']; |
| 388 |
$check_license_res['site_count'] = $activate_license_res['site_count']; |
| 389 |
$check_license_res['activations_left'] = $activate_license_res['activations_left']; |
| 390 |
$licenses = get_option('give_licenses', []); |
| 391 |
|
| 392 |
if ($is_plan_license) { |
| 393 |
$addonSlugs = self::getAddonSlugsFromAllAccessPassLicense($check_license_res); |
| 394 |
foreach ($licenses as $license_key => $data) { |
| 395 |
if (in_array($data['plugin_slug'], $addonSlugs, true) || ! empty($data['is_all_access_pass'])) { |
| 396 |
unset($licenses[$license_key]); |
| 397 |
} |
| 398 |
} |
| 399 |
} |
| 400 |
|
| 401 |
$licenses[$check_license_res['license_key']] = $check_license_res; |
| 402 |
update_option('give_licenses', $licenses); |
| 403 |
} |
| 404 |
|
| 405 |
// Have WordPress check for updates |
| 406 |
give_refresh_licenses(); |
| 407 |
} |
| 408 |
|
| 409 |
/** |
| 410 |
* Activate License |
| 411 |
* |
| 412 |
* Activate the license key. |
| 413 |
* |
| 414 |
* @access public |
| 415 |
* @return void |
| 416 |
* @since 1.0 |
| 417 |
*/ |
| 418 |
public function activate_license() { |
| 419 |
} |
| 420 |
|
| 421 |
/** |
| 422 |
* Deactivate License |
| 423 |
* |
| 424 |
* Deactivate the license key. |
| 425 |
* |
| 426 |
* @access public |
| 427 |
* @return void |
| 428 |
* @since 1.0 |
| 429 |
*/ |
| 430 |
public function deactivate_license() { |
| 431 |
} |
| 432 |
|
| 433 |
|
| 434 |
/** |
| 435 |
* Get license information. |
| 436 |
* |
| 437 |
* @param string $edd_action |
| 438 |
* @param bool $response_in_array |
| 439 |
* |
| 440 |
* @return mixed |
| 441 |
* @deprecated 2.5.0 Use self::request_license_api instead. |
| 442 |
* |
| 443 |
* @since 1.8.9 |
| 444 |
* @access public |
| 445 |
*/ |
| 446 |
public function get_license_info($edd_action = '', $response_in_array = false) |
| 447 |
{ |
| 448 |
if ( empty($edd_action) ) { |
| 449 |
return false; |
| 450 |
} |
| 451 |
|
| 452 |
give_doing_it_wrong(__FUNCTION__, 'Use self::request_license_api instead from GiveWP 2.5.0'); |
| 453 |
|
| 454 |
// Data to send to the API. |
| 455 |
$api_params = [ |
| 456 |
'edd_action' => $edd_action, // never change from "edd_" to "give_"! |
| 457 |
'license' => $this->license, |
| 458 |
'item_name' => urlencode($this->item_name), |
| 459 |
]; |
| 460 |
|
| 461 |
return self::request_license_api($api_params, $response_in_array); |
| 462 |
} |
| 463 |
|
| 464 |
/** |
| 465 |
* Return licensed addons info |
| 466 |
* |
| 467 |
* Note: note only for internal logic |
| 468 |
* |
| 469 |
* @since 3.21.1 use array_map to safely access the private property |
| 470 |
* @since 3.21.0 plucks the basename for backwards compatibility |
| 471 |
* @since 2.1.4 |
| 472 |
* @return string[] |
| 473 |
*/ |
| 474 |
static function get_licensed_addons(): array |
| 475 |
{ |
| 476 |
return array_map( static function ( Give_License $license ) { |
| 477 |
return $license->plugin_basename; |
| 478 |
}, self::$licensed_addons ); |
| 479 |
} |
| 480 |
|
| 481 |
/** |
| 482 |
* Check if license key attached to subscription |
| 483 |
* |
| 484 |
* @since 2.5.0 |
| 485 |
* |
| 486 |
* @param string $license_key |
| 487 |
* |
| 488 |
* @return array |
| 489 |
*/ |
| 490 |
static function is_subscription($license_key = '') |
| 491 |
{ |
| 492 |
// Check if current license is part of subscription or not. |
| 493 |
$subscriptions = get_option('give_subscriptions'); |
| 494 |
$subscription = []; |
| 495 |
|
| 496 |
if ( $subscriptions ) { |
| 497 |
foreach ($subscriptions as $subs) { |
| 498 |
if ( in_array($license_key, $subs['licenses']) ) { |
| 499 |
$subscription = $subs; |
| 500 |
break; |
| 501 |
} |
| 502 |
} |
| 503 |
} |
| 504 |
|
| 505 |
return $subscription; |
| 506 |
} |
| 507 |
|
| 508 |
/** |
| 509 |
* Get license information. |
| 510 |
* |
| 511 |
* @since 1.8.9 |
| 512 |
* @since 2.18.0 log failed license api request information |
| 513 |
* |
| 514 |
* @param bool $response_in_array |
| 515 |
* |
| 516 |
* @param array $api_params |
| 517 |
* |
| 518 |
* @return array|WP_Error |
| 519 |
*/ |
| 520 |
public static function request_license_api($api_params = [], $response_in_array = false) |
| 521 |
{ |
| 522 |
// Bailout. |
| 523 |
if ( empty($api_params['edd_action']) ) { |
| 524 |
return new WP_Error('give-invalid-edd-action', __('Valid edd_action not defined', 'give')); |
| 525 |
} |
| 526 |
|
| 527 |
// Data to send to the API. |
| 528 |
$default_api_params = [ |
| 529 |
// 'edd_action' => $edd_action, never change from "edd_" to "give_"! |
| 530 |
// 'license' => $this->license, |
| 531 |
// 'item_name' => urlencode( $this->item_name ), |
| 532 |
'url' => home_url(), |
| 533 |
]; |
| 534 |
|
| 535 |
$api_params = wp_parse_args($api_params, $default_api_params); |
| 536 |
|
| 537 |
// Call the API. |
| 538 |
$response = wp_remote_post( |
| 539 |
self::get_api_url(), |
| 540 |
apply_filters( |
| 541 |
'give_request_license_api_args', |
| 542 |
[ |
| 543 |
'timeout' => 15, |
| 544 |
'sslverify' => false, |
| 545 |
'body' => $api_params, |
| 546 |
] |
| 547 |
) |
| 548 |
); |
| 549 |
|
| 550 |
$statusCode = wp_remote_retrieve_response_code($response); |
| 551 |
$body = json_decode(wp_remote_retrieve_body($response), $response_in_array); |
| 552 |
|
| 553 |
if ( 200 !== $statusCode ) { |
| 554 |
Log::http( |
| 555 |
'License Api request failed', |
| 556 |
[ |
| 557 |
'category' => 'License', |
| 558 |
'api url' => self::get_api_url(), |
| 559 |
'request' => $api_params, |
| 560 |
'status code' => $statusCode, |
| 561 |
'response' => $response |
| 562 |
] |
| 563 |
); |
| 564 |
} |
| 565 |
|
| 566 |
// Make sure there are no errors. |
| 567 |
if ( is_wp_error($response) ) { |
| 568 |
return $response; |
| 569 |
} |
| 570 |
|
| 571 |
return $body; |
| 572 |
} |
| 573 |
|
| 574 |
/** |
| 575 |
* Get license by plugin dirname |
| 576 |
* |
| 577 |
* @param string $plugin_dirname |
| 578 |
* |
| 579 |
* @return array |
| 580 |
* |
| 581 |
* @since 4.15.0 add support for Harbor unified licenses |
| 582 |
* @since 2.5.0 |
| 583 |
* @access public |
| 584 |
*/ |
| 585 |
public static function get_license_by_plugin_dirname( $plugin_dirname ) { |
| 586 |
$license = []; |
| 587 |
$give_licenses = get_option( 'give_licenses', [] ); |
| 588 |
|
| 589 |
if ( ! empty( $give_licenses ) ) { |
| 590 |
foreach ( $give_licenses as $give_license ) { |
| 591 |
|
| 592 |
// Logic to match all access pass license to add-on. |
| 593 |
$compares = $give_license['is_all_access_pass'] |
| 594 |
? $give_license['download'] |
| 595 |
|
| 596 |
// Prevent PHP notice if somehow automatic update does not run properly. |
| 597 |
// Because plugin_slug will only define in updated license rest api response. |
| 598 |
: [ [ 'plugin_slug' => ! empty( $give_license['plugin_slug'] ) ? $give_license['plugin_slug'] : '' ] ]; |
| 599 |
|
| 600 |
foreach ( $compares as $compare ) { |
| 601 |
if ( ! empty( $compare['plugin_slug'] ) && $plugin_dirname === $compare['plugin_slug'] ) { |
| 602 |
$license = $give_license; |
| 603 |
break; |
| 604 |
} |
| 605 |
} |
| 606 |
} |
| 607 |
} |
| 608 |
|
| 609 |
// Fall back to Harbor feature availability when no legacy license is found. |
| 610 |
if ( empty( $license ) && lw_harbor_is_feature_available( $plugin_dirname ) ) { |
| 611 |
$license = [ 'license' => 'valid' ]; |
| 612 |
} |
| 613 |
|
| 614 |
return $license; |
| 615 |
} |
| 616 |
|
| 617 |
|
| 618 |
/** |
| 619 |
* Get checkout url |
| 620 |
* |
| 621 |
* @return string|null |
| 622 |
* @since 2.5.0 |
| 623 |
*/ |
| 624 |
public static function get_checkout_url() { |
| 625 |
return self::$checkout_url; |
| 626 |
} |
| 627 |
|
| 628 |
/** |
| 629 |
* Get account url |
| 630 |
* |
| 631 |
* @return string|null |
| 632 |
* @since 2.5.0 |
| 633 |
*/ |
| 634 |
public static function get_account_url() { |
| 635 |
return self::$account_url; |
| 636 |
} |
| 637 |
|
| 638 |
/** |
| 639 |
* Get downloads url |
| 640 |
* |
| 641 |
* @return string|null |
| 642 |
* @since 2.5.0 |
| 643 |
*/ |
| 644 |
public static function get_downloads_url() { |
| 645 |
return self::$downloads_url; |
| 646 |
} |
| 647 |
|
| 648 |
/** |
| 649 |
* Get account url |
| 650 |
* |
| 651 |
* @since 3.20.0 allows to override the API URL via constant |
| 652 |
* @since 2.5.0 |
| 653 |
*/ |
| 654 |
public static function get_website_url(): ?string |
| 655 |
{ |
| 656 |
if (defined('GIVE_SITE_URL')) { |
| 657 |
return GIVE_SITE_URL; |
| 658 |
} |
| 659 |
|
| 660 |
return self::$site_url; |
| 661 |
} |
| 662 |
|
| 663 |
|
| 664 |
/** |
| 665 |
* Get plugin information by id. |
| 666 |
* Note: only for internal use |
| 667 |
* |
| 668 |
* @param string $plugin_slug |
| 669 |
* |
| 670 |
* @return array |
| 671 |
* @since 2.5.0 |
| 672 |
*/ |
| 673 |
public static function get_plugin_by_slug( $plugin_slug ) { |
| 674 |
$give_plugins = give_get_plugins(); |
| 675 |
$matching_list = wp_list_pluck( $give_plugins, 'Dir', 'Path' ); |
| 676 |
$is_match_found = array_search( $plugin_slug, $matching_list, true ); |
| 677 |
|
| 678 |
return $is_match_found ? $give_plugins[ $is_match_found ] : []; |
| 679 |
} |
| 680 |
|
| 681 |
/** |
| 682 |
* Get plugin information by id. |
| 683 |
* Note: only for internal use |
| 684 |
* |
| 685 |
* @param string $plugin_slug |
| 686 |
* |
| 687 |
* @return string |
| 688 |
* @since 2.5.0 |
| 689 |
*/ |
| 690 |
public static function build_plugin_name_from_slug( $plugin_slug ) { |
| 691 |
$plugin_name = str_replace( [ '-', 'give ' ], [ ' ', 'Give - ' ], $plugin_slug ); |
| 692 |
|
| 693 |
return ucwords( $plugin_name ); |
| 694 |
} |
| 695 |
|
| 696 |
/** |
| 697 |
* Render license section |
| 698 |
* |
| 699 |
* @return string |
| 700 |
* @since 2.5.0 |
| 701 |
*/ |
| 702 |
public static function render_licenses_list() { |
| 703 |
$give_plugins = give_get_plugins( [ 'only_premium_add_ons' => true ] ); |
| 704 |
$give_licenses = get_option( 'give_licenses', [] ); |
| 705 |
$licenses_without_addon = $give_licenses; |
| 706 |
|
| 707 |
// Get all access pass licenses |
| 708 |
$all_access_pass_licenses = []; |
| 709 |
$all_access_pass_addon_list = []; |
| 710 |
foreach ( $give_licenses as $key => $give_license ) { |
| 711 |
if ( $give_license['is_all_access_pass'] ) { |
| 712 |
$all_access_pass_licenses[ $key ] = $give_license; |
| 713 |
|
| 714 |
unset( $licenses_without_addon[ $key ] ); |
| 715 |
|
| 716 |
foreach ( $give_license['download'] as $download ) { |
| 717 |
$all_access_pass_addon_list[] = $download['plugin_slug']; |
| 718 |
} |
| 719 |
} |
| 720 |
} |
| 721 |
|
| 722 |
$html = [ |
| 723 |
'unlicensed' => '', |
| 724 |
'licensed' => '', |
| 725 |
'licenses_without_addon' => '', |
| 726 |
'all_access_licensed' => '', |
| 727 |
]; |
| 728 |
|
| 729 |
if ( ! empty( $give_plugins ) ) { |
| 730 |
foreach ( $give_plugins as $give_plugin ) { |
| 731 |
if ( in_array( $give_plugin['Dir'], $all_access_pass_addon_list ) ) { |
| 732 |
continue; |
| 733 |
} |
| 734 |
|
| 735 |
$addon_license = self::get_license_by_plugin_dirname( $give_plugin['Dir'] ); |
| 736 |
$html_arr_key = 'unlicensed'; |
| 737 |
|
| 738 |
if ( $addon_license ) { |
| 739 |
$html_arr_key = 'licensed'; |
| 740 |
unset( $licenses_without_addon[ $addon_license['license_key'] ] ); |
| 741 |
} |
| 742 |
|
| 743 |
$html[ "{$html_arr_key}" ] .= self::html_by_plugin( $give_plugin ); |
| 744 |
} |
| 745 |
} |
| 746 |
|
| 747 |
if ( ! empty( $all_access_pass_licenses ) ) { |
| 748 |
foreach ( $all_access_pass_licenses as $key => $all_access_pass_license ) { |
| 749 |
$html['all_access_licensed'] .= self::html_by_license( $all_access_pass_license ); |
| 750 |
} |
| 751 |
} |
| 752 |
|
| 753 |
if ( ! empty( $licenses_without_addon ) ) { |
| 754 |
foreach ( $licenses_without_addon as $key => $license ) { |
| 755 |
if ( in_array( $license['plugin_slug'], $all_access_pass_addon_list ) ) { |
| 756 |
continue; |
| 757 |
} |
| 758 |
$html['licenses_without_addon'] .= self::html_by_license( $license ); |
| 759 |
} |
| 760 |
} |
| 761 |
|
| 762 |
ksort( $html ); |
| 763 |
|
| 764 |
// After sorting order will be all_access_licensed -> licensed -> unlicensed |
| 765 |
|
| 766 |
return implode( '', $html ); |
| 767 |
} |
| 768 |
|
| 769 |
/** |
| 770 |
* Get add-on item html |
| 771 |
* Note: only for internal use |
| 772 |
* |
| 773 |
* @param $plugin |
| 774 |
* |
| 775 |
* @return string |
| 776 |
* @since 2.5.0 |
| 777 |
*/ |
| 778 |
public static function html_by_plugin( $plugin ) { |
| 779 |
// Bailout. |
| 780 |
if ( empty( $plugin ) ) { |
| 781 |
return ''; |
| 782 |
} |
| 783 |
|
| 784 |
ob_start(); |
| 785 |
$license = self::get_license_by_plugin_dirname( $plugin['Dir'] ); |
| 786 |
|
| 787 |
$default_plugin = [ |
| 788 |
'ChangeLogSlug' => $plugin['Dir'], |
| 789 |
'DownloadURL' => '', |
| 790 |
]; |
| 791 |
|
| 792 |
if ( false !== strpos( $default_plugin['ChangeLogSlug'], '-gateway' ) ) { |
| 793 |
// We found that each gateway addon does not have `-gateway` in changelog file slug |
| 794 |
$default_plugin['ChangeLogSlug'] = str_replace( '-gateway', '', $default_plugin['ChangeLogSlug'] ); |
| 795 |
} |
| 796 |
|
| 797 |
if ( $license ) { |
| 798 |
$license['renew_url'] = self::$checkout_url . "?edd_license_key={$license['license_key']}"; |
| 799 |
$default_plugin['ChangeLogSlug'] = $license['readme']; |
| 800 |
$default_plugin['DownloadURL'] = $license['download']; |
| 801 |
} |
| 802 |
|
| 803 |
$plugin['License'] = $license = wp_parse_args( |
| 804 |
$license, |
| 805 |
[ |
| 806 |
'item_name' => str_replace( 'give-', '', $plugin['Dir'] ), |
| 807 |
'purchase_link' => $plugin['PluginURI'], |
| 808 |
] |
| 809 |
); |
| 810 |
|
| 811 |
$plugin = wp_parse_args( $plugin, $default_plugin ); |
| 812 |
?> |
| 813 |
<div class="give-addon-wrap"> |
| 814 |
<div class="give-addon-inner"> |
| 815 |
<?php echo self::html_license_row( $license, $plugin ); ?> |
| 816 |
<?php echo self::html_plugin_row( $plugin ); ?> |
| 817 |
</div> |
| 818 |
</div> |
| 819 |
<?php |
| 820 |
|
| 821 |
return ob_get_clean(); |
| 822 |
} |
| 823 |
|
| 824 |
/** |
| 825 |
* Get add-on item html |
| 826 |
* Note: only for internal use |
| 827 |
* |
| 828 |
* @param array $license |
| 829 |
* |
| 830 |
* @return string |
| 831 |
* @since 2.5.0 |
| 832 |
*/ |
| 833 |
private static function html_by_license( $license ) { |
| 834 |
ob_start(); |
| 835 |
|
| 836 |
$license['renew_url'] = self::$checkout_url . "?edd_license_key={$license['license_key']}"; |
| 837 |
?> |
| 838 |
<div class="give-addon-wrap"> |
| 839 |
<div class="give-addon-inner"> |
| 840 |
<?php |
| 841 |
echo self::html_license_row( $license ); |
| 842 |
|
| 843 |
$addons = $license['download']; |
| 844 |
|
| 845 |
if ( empty( $license['is_all_access_pass'] ) ) { |
| 846 |
$addons = [ $license ]; |
| 847 |
} |
| 848 |
|
| 849 |
foreach ( $addons as $addon ) { |
| 850 |
$default_plugin = [ |
| 851 |
// In single license key we will get item_name instead of name. |
| 852 |
'Name' => ! empty( $addon['item_name'] ) ? $addon['item_name'] : $addon['name'], |
| 853 |
|
| 854 |
'ChangeLogSlug' => $addon['readme'], |
| 855 |
'Version' => $addon['current_version'], |
| 856 |
'Status' => 'not installed', |
| 857 |
|
| 858 |
// In single license key we will get download instead of file. |
| 859 |
'DownloadURL' => ! empty( $addon['download'] ) ? $addon['download'] : $addon['file'], |
| 860 |
|
| 861 |
]; |
| 862 |
|
| 863 |
$plugin = wp_parse_args( |
| 864 |
self::get_plugin_by_slug( $addon['plugin_slug'] ), |
| 865 |
$default_plugin |
| 866 |
); |
| 867 |
|
| 868 |
$plugin['Name'] = false !== strpos( $plugin['Name'], 'Give' ) |
| 869 |
? $plugin['Name'] |
| 870 |
: self::build_plugin_name_from_slug( $addon['plugin_slug'] ); |
| 871 |
|
| 872 |
$plugin['License'] = $license; |
| 873 |
|
| 874 |
echo self::html_plugin_row( $plugin ); |
| 875 |
} |
| 876 |
?> |
| 877 |
</div> |
| 878 |
</div> |
| 879 |
<?php |
| 880 |
|
| 881 |
return ob_get_clean(); |
| 882 |
} |
| 883 |
|
| 884 |
|
| 885 |
/** |
| 886 |
* license row html |
| 887 |
* |
| 888 |
* @param array $license |
| 889 |
* @param array $plugin |
| 890 |
* |
| 891 |
* @return string |
| 892 |
* @since 2.5.0 |
| 893 |
*/ |
| 894 |
private static function html_license_row( $license, $plugin = [] ) { |
| 895 |
ob_start(); |
| 896 |
|
| 897 |
$is_license = $license && ! empty( $license['license_key'] ); |
| 898 |
$license_key = $is_license ? $license['license_key'] : ''; |
| 899 |
$license_is_inactive = $license_key && ! in_array( $license['license'], [ 'valid', 'expired' ] ); |
| 900 |
$expires_timestamp = $is_license ? strtotime( $license['expires'] ) : ''; |
| 901 |
$is_license_expired = $is_license && ( 'expired' === $license['license'] || $expires_timestamp < time() ); |
| 902 |
$addon_dir = ! empty( $plugin['Dir'] ) ? $plugin['Dir'] : ( ! empty( $license['plugin_slug'] ) ? $license['plugin_slug'] : '' ); |
| 903 |
?> |
| 904 |
<div class="give-license-row give-clearfix"> |
| 905 |
<div class="give-license-notice-container"></div> |
| 906 |
<div class="give-license-top give-clearfix"> |
| 907 |
|
| 908 |
<div class="give-license-top-column give-license-key-field-wrap"> |
| 909 |
|
| 910 |
<div class="give-license__key<?php echo $license_key ? ' give-has-license-key' : ''; ?>"> |
| 911 |
<?php $value = $license_key ? give_hide_char( $license['license_key'], 5 ) : ''; ?> |
| 912 |
<label for="give-license-addon-key-field" class="give-license-top-header"><?php _e( 'License Key', 'give' ); ?></label> |
| 913 |
<input id="give-license-addon-key-field" type="text" autocomplete="off" value="<?php echo $value; ?>"<?php echo $value ? ' readonly' : ''; ?>> |
| 914 |
<?php if ( ! $license_key ) : ?> |
| 915 |
<button class="give-button__license-activate button-primary" data-addon="<?php echo $addon_dir; ?>"> |
| 916 |
<?php _e( 'Activate', 'give' ); ?> |
| 917 |
</button> |
| 918 |
<?php elseif ( $license_is_inactive ) : ?> |
| 919 |
<button class="give-button__license-reactivate button-primary" data-addon="<?php echo $addon_dir; ?>" data-license="<?php echo $license['license_key']; ?>"> |
| 920 |
<?php _e( 'Reactivate', 'give' ); ?> |
| 921 |
</button> |
| 922 |
<?php else : ?> |
| 923 |
|
| 924 |
<?php |
| 925 |
echo sprintf( |
| 926 |
'<button class="give-license__deactivate button button-secondary" data-license-key="%2$s" data-item-name="%3$s" data-plugin-dirname="%5$s" data-nonce="%4$s">%1$s</button>', |
| 927 |
__( 'Deactivate', 'give' ), |
| 928 |
$license['license_key'], |
| 929 |
$license['item_name'], |
| 930 |
wp_create_nonce( "give-deactivate-license-{$license['item_name']}" ), |
| 931 |
! empty( $license['plugin_slug'] ) ? $license['plugin_slug'] : '' |
| 932 |
); |
| 933 |
?> |
| 934 |
|
| 935 |
<?php endif; ?> |
| 936 |
|
| 937 |
<div class="give-license__status"> |
| 938 |
<?php |
| 939 |
echo $license_key && ! $license_is_inactive |
| 940 |
? sprintf( |
| 941 |
'<span class="dashicons dashicons-%2$s"></span> %1$s', |
| 942 |
$is_license_expired |
| 943 |
? __( 'License is expired. Please activate your license key.', 'give' ) |
| 944 |
: __( 'License is active and you are receiving updates and support.', 'give' ), |
| 945 |
$is_license_expired |
| 946 |
? 'no' |
| 947 |
: 'yes' |
| 948 |
) |
| 949 |
: sprintf( |
| 950 |
'<span class="dashicons dashicons-no"></span> %1$s %2$s', |
| 951 |
__( 'License is inactive.', 'give' ), |
| 952 |
$license_is_inactive |
| 953 |
? sprintf( |
| 954 |
__( 'Please <a href="%1$s" target="_blank">Visit your dashboard</a> to check this license details and activate this license to receive updates and support.', 'give' ), |
| 955 |
self::get_account_url() |
| 956 |
) |
| 957 |
: __( 'Please activate your license key.', 'give' ) |
| 958 |
); |
| 959 |
?> |
| 960 |
</div> |
| 961 |
</div> |
| 962 |
</div> |
| 963 |
|
| 964 |
<div class="give-license-top-column give-license-info-field-wrap"> |
| 965 |
<h3 class="give-license-top-header"><?php _e( 'License Information', 'give' ); ?></h3> |
| 966 |
<?php |
| 967 |
// @todo: handle all license status; |
| 968 |
if ( $license_key ) : |
| 969 |
?> |
| 970 |
|
| 971 |
<?php if ( $license_key ) : ?> |
| 972 |
<?php |
| 973 |
echo sprintf( |
| 974 |
'<p class="give-license-renewal-date"><span class="dashicons dashicons-calendar-alt"></span> <strong>%1$s</strong> %2$s</p>', |
| 975 |
$is_license_expired ? __( 'Expired:', 'give' ) : __( 'Renews:', 'give' ), |
| 976 |
date( give_date_format(), $expires_timestamp ) |
| 977 |
); |
| 978 |
?> |
| 979 |
<?php endif; ?> |
| 980 |
|
| 981 |
<?php |
| 982 |
if ( $is_license_expired ) { |
| 983 |
// @todo: need to test renew license link |
| 984 |
echo sprintf( |
| 985 |
'<a href="%1$s" target="_blank">%2$s</a>', |
| 986 |
$license['renew_url'], |
| 987 |
__( 'Renew to manage sites', 'give' ) |
| 988 |
); |
| 989 |
} elseif ( $license_key ) { |
| 990 |
if ( ! $license['activations_left'] ) { |
| 991 |
echo sprintf( |
| 992 |
'<span class="give-license-activations-left">%1$s</span>', |
| 993 |
__( 'No activations remaining', 'give' ) |
| 994 |
); |
| 995 |
} else { |
| 996 |
echo sprintf( |
| 997 |
'<span class="give-license-activations-left"><span class="give-license-activations-remaining-icon wp-ui-highlight">%1$s</span> %2$s</span>', |
| 998 |
$license['activations_left'], |
| 999 |
_n( 'Activation Remaining', 'Activations Remaining', $license['activations_left'], 'give' ) |
| 1000 |
); |
| 1001 |
} |
| 1002 |
} |
| 1003 |
?> |
| 1004 |
<?php else : ?> |
| 1005 |
|
| 1006 |
<p class="give-field-description"><?php _e( 'This is an unlicensed add-on and is not receiving updates or support. Please activate your license key to fix the issue.', 'give' ); ?></p> |
| 1007 |
|
| 1008 |
<?php endif; ?> |
| 1009 |
</div> |
| 1010 |
|
| 1011 |
<div class="give-license-top-column"> |
| 1012 |
<h3 class="give-license-top-header"><?php _e( 'License Actions', 'give' ); ?></h3> |
| 1013 |
|
| 1014 |
<?php |
| 1015 |
// Purchase license link. |
| 1016 |
if ( ! $license_key ) : |
| 1017 |
?> |
| 1018 |
<?php |
| 1019 |
echo sprintf( |
| 1020 |
'<a class="give-button button-secondary" href="%1$s" target="_blank">%2$s</a>', |
| 1021 |
$license['purchase_link'], |
| 1022 |
__( 'Purchase License', 'give' ) |
| 1023 |
); |
| 1024 |
?> |
| 1025 |
<?php endif; ?> |
| 1026 |
|
| 1027 |
<?php |
| 1028 |
// Manage license link on GiveWP.com |
| 1029 |
if ( ! $is_license_expired && $license_key ) { |
| 1030 |
echo sprintf( |
| 1031 |
'<a href="%1$spurchase-history/?license_id=%2$s&action=manage_licenses&payment_id=%3$s" target="_blank" class="give-license-action-link">%4$s</a>', |
| 1032 |
trailingslashit( self::get_website_url() ), |
| 1033 |
$license['license_id'], |
| 1034 |
$license['payment_id'], |
| 1035 |
__( 'Manage License', 'give' ) |
| 1036 |
); |
| 1037 |
echo sprintf( |
| 1038 |
'<a href="%1$spriority-support/" target="_blank" class="give-license-action-link">%2$s</a>', |
| 1039 |
trailingslashit( self::get_website_url() ), |
| 1040 |
__( 'Access Support', 'give' ) |
| 1041 |
); |
| 1042 |
} |
| 1043 |
?> |
| 1044 |
|
| 1045 |
</div> |
| 1046 |
</div> |
| 1047 |
</div> |
| 1048 |
<?php |
| 1049 |
return ob_get_clean(); |
| 1050 |
} |
| 1051 |
|
| 1052 |
|
| 1053 |
/** |
| 1054 |
* Plugin row html |
| 1055 |
* |
| 1056 |
* @param array $plugin |
| 1057 |
* |
| 1058 |
* @return string |
| 1059 |
* @since 2.5.0 |
| 1060 |
*/ |
| 1061 |
public static function html_plugin_row( $plugin ) { |
| 1062 |
// Bailout. |
| 1063 |
if ( ! $plugin ) { |
| 1064 |
return ''; |
| 1065 |
} |
| 1066 |
|
| 1067 |
$is_license = $plugin['License'] && ! empty( $plugin['License']['license_key'] ); |
| 1068 |
$expires_timestamp = $is_license ? strtotime( $plugin['License']['expires'] ) : ''; |
| 1069 |
$is_license_expired = $is_license && ( 'expired' === $plugin['License']['license'] || $expires_timestamp < time() ); |
| 1070 |
ob_start(); |
| 1071 |
?> |
| 1072 |
<div class="give-addon-info-wrap give-clearfix"> |
| 1073 |
|
| 1074 |
<div class="give-addon-info-left"> |
| 1075 |
<span class="give-addon-name"> |
| 1076 |
<?php echo $plugin['Name']; ?> |
| 1077 |
</span> |
| 1078 |
<span class="give-addon-version"> |
| 1079 |
<?php echo sprintf( '%1$s %2$s', __( 'Version', 'give' ), $plugin['Version'] ); ?> |
| 1080 |
</span> |
| 1081 |
</div> |
| 1082 |
|
| 1083 |
<div class="give-addon-info-right"> |
| 1084 |
<?php |
| 1085 |
echo sprintf( |
| 1086 |
'<a href="%1$s" class="give-ajax-modal give-addon-view-changelog" title="%3$s">%2$s</a>', |
| 1087 |
give_modal_ajax_url( |
| 1088 |
[ |
| 1089 |
'url' => filter_var( $plugin['ChangeLogSlug'], FILTER_VALIDATE_URL ) |
| 1090 |
? urldecode_deep( $plugin['ChangeLogSlug'] ) |
| 1091 |
: urlencode_deep( give_get_addon_readme_url( $plugin['ChangeLogSlug'] ) ), |
| 1092 |
'show_changelog' => 1, |
| 1093 |
] |
| 1094 |
), |
| 1095 |
__( 'View Changelog', 'give' ), |
| 1096 |
__( 'Changelog of', 'give' ) . " {$plugin['Name']}" |
| 1097 |
); |
| 1098 |
?> |
| 1099 |
|
| 1100 |
<?php |
| 1101 |
// Activation status. |
| 1102 |
if ( in_array( $plugin['Status'], [ 'active', 'inactive' ] ) ) { |
| 1103 |
echo sprintf( |
| 1104 |
'<span class="give-addon-activation-status give-addon-activation-status__%1$s">%1$s</span>', |
| 1105 |
'active' === $plugin['Status'] ? __( 'activated', 'give' ) : __( 'installed', 'give' ) |
| 1106 |
); |
| 1107 |
} |
| 1108 |
|
| 1109 |
printf( |
| 1110 |
'<%3$s class="give-button button button-secondary button-small" href="%1$s"%4$s><span class="dashicons dashicons-download"></span>%2$s</%3$s>', |
| 1111 |
$plugin['DownloadURL'], |
| 1112 |
__( 'Download', 'give' ), |
| 1113 |
$is_license_expired || ! $plugin['DownloadURL'] ? 'button' : 'a', |
| 1114 |
$is_license_expired || ! $plugin['DownloadURL'] ? ' disabled' : '' |
| 1115 |
); |
| 1116 |
?> |
| 1117 |
</div> |
| 1118 |
</div> |
| 1119 |
<?php |
| 1120 |
|
| 1121 |
return ob_get_clean(); |
| 1122 |
} |
| 1123 |
|
| 1124 |
|
| 1125 |
/** |
| 1126 |
* Get refresh license status |
| 1127 |
* |
| 1128 |
* @return mixed|void |
| 1129 |
* @since 2.5.0 |
| 1130 |
*/ |
| 1131 |
public static function refresh_license_status() { |
| 1132 |
return get_option( |
| 1133 |
'give_licenses_refreshed_last_checked', |
| 1134 |
[ |
| 1135 |
'compare' => date( 'Ymd' ), |
| 1136 |
'time' => time(), |
| 1137 |
'count' => 0, |
| 1138 |
] |
| 1139 |
); |
| 1140 |
} |
| 1141 |
|
| 1142 |
/** |
| 1143 |
* Get all download slugs from all access pass key. |
| 1144 |
* Note: only for internal use and will be refactored in the future. |
| 1145 |
* |
| 1146 |
* @param array $license All access pass license data |
| 1147 |
* |
| 1148 |
* @return string[] |
| 1149 |
* @since 2.6.3 |
| 1150 |
*/ |
| 1151 |
public static function getAddonSlugsFromAllAccessPassLicense( $license ) { |
| 1152 |
$result = []; |
| 1153 |
|
| 1154 |
foreach ( $license['download'] as $download ) { |
| 1155 |
$result[] = $download['plugin_slug']; |
| 1156 |
} |
| 1157 |
|
| 1158 |
return $result; |
| 1159 |
} |
| 1160 |
|
| 1161 |
/** |
| 1162 |
* Returns the API URL for license requests, checking for a constant first. |
| 1163 |
* |
| 1164 |
* @since 3.20.0 |
| 1165 |
*/ |
| 1166 |
public static function get_api_url(): string |
| 1167 |
{ |
| 1168 |
if (defined('GIVE_LICENSE_API_URL')) { |
| 1169 |
return GIVE_LICENSE_API_URL; |
| 1170 |
} |
| 1171 |
|
| 1172 |
return self::$api_url; |
| 1173 |
} |
| 1174 |
} |
| 1175 |
|
| 1176 |
endif; // end class_exists check. |
| 1177 |
|