????
| Current Path : /home/arabianr/public_html/wp-content/plugins/simplybook/app/Controllers/ |
| Current File : /home/arabianr/public_html/wp-content/plugins/simplybook/app/Controllers/AdminController.php |
<?php
namespace SimplyBook\Controllers;
use Carbon\Carbon;
use SimplyBook\Traits\HasViews;
use SimplyBook\Traits\HasAllowlistControl;
use SimplyBook\Interfaces\ControllerInterface;
use SimplyBook\Support\Helpers\Storages\RequestStorage;
use SimplyBook\Support\Helpers\Storages\EnvironmentConfig;
class AdminController implements ControllerInterface
{
use HasViews;
use HasAllowlistControl;
private EnvironmentConfig $env;
private RequestStorage $request;
private string $restApiAction = 'resp_rest_api_notice_form_submit';
private string $restApiNonceName = 'resp_rest_api_notice_nonce';
private string $restApiAccessibleOptionName = 'simplybook_rest_api_accessible';
private string $restApiValidationTimeOptionName = 'simplybook_rest_api_validation_time';
public function __construct(EnvironmentConfig $env, RequestStorage $request)
{
$this->env = $env;
$this->request = $request;
}
public function register(): void
{
if ($this->adminAccessAllowed() === false) {
return;
}
add_filter('plugin_action_links_' . $this->env->getString('plugin.base_file'), [$this, 'addPluginSettingsAction']);
add_action('admin_notices', [$this, 'showRestApiNotice']);
add_action('admin_init', [$this, 'processRestApiNoticeFormSubmit']);
}
/**
* Add settings and support link to the plugin page
*/
public function addPluginSettingsAction(array $links): array
{
if ($this->userCanManage() === false) {
return $links;
}
$settings_link = '<a href="' . $this->env->getUrl('plugin.dashboard_url') . '">' . esc_html__('Settings', 'simplybook') . '</a>';
array_unshift($links, $settings_link);
//support
$support = '<a rel="noopener noreferrer" target="_blank" href="' . esc_attr($this->env->getUrl('simplybook.support_url')) . '">' . esc_html__('Support', 'simplybook') . '</a>';
array_unshift($links, $support);
return $links;
}
/**
* Show notice about the disabled REST API for logged-out users.
*/
public function showRestApiNotice(): void
{
if ($this->shouldRenderRestApiNotice() === false) {
return;
}
$notice = sprintf(
// translators: %1$s and %2$s are replaced with opening and closing tags to bold the text
__('The %1$sSimplyBook.me%2$s plugin relies on the %1$sWordPress REST API%2$s to register new accounts. However, the REST API is currently inaccessible to logged-out users. Please ensure that the REST API is enabled and publicly accessible.', 'simplybook'),
'<strong>',
'</strong>'
);
$this->render('admin/rest-api-notice', [
'restApiMessage' => $notice,
'restApiAction' => $this->restApiAction,
'restApiNonceName' => $this->restApiNonceName,
]);
}
/**
* Process the dismissal of the REST API notice form submit.
*/
public function processRestApiNoticeFormSubmit(): void
{
if ($this->request->isEmpty('global.simplybook_rest_api_notice_form')) {
return;
}
$nonce = $this->request->get('global.' . $this->restApiNonceName);
if (wp_verify_nonce($nonce, $this->restApiAction) === false) {
return; // Invalid nonce
}
update_option('simplybook_rest_api_notice_dismissed', '1', false);
}
/**
* Method determines if the REST API notice should be rendered. The REST API
* is needed to be able to receive the webhook callbacks from SimplyBook.me
* while creating a new account.
*
* Returns false when:
* - The user has dismissed the notice
* - The onboarding is already completed (account created)
*
* Returns true when:
* - The REST API is inaccessible (not 200 response code)
*/
private function shouldRenderRestApiNotice(): bool
{
$cacheName = 'rsp_simplybook_rest_api_inaccessible';
$cacheValue = wp_cache_get($cacheName, 'simplybook', false, $found);
if ($found) {
return (bool) $cacheValue;
}
// Dismissed notice or completed onboarding? No notice.
// Accessible and cached? No notice.
if (
$this->isRestApiNoticeDismissed()
|| $this->isOnboardingCompleted()
|| $this->restApiIsAccessibleAndCachedForOneDay()
) {
wp_cache_set($cacheName, false, 'simplybook', 50);
return false;
}
// Validate again after one day, or each admin_init when inaccessible
$restApiAccessible = $this->validateRestApi();
update_option($this->restApiAccessibleOptionName, $restApiAccessible);
update_option($this->restApiValidationTimeOptionName, time(), false);
wp_cache_set($cacheName, $restApiAccessible, 'simplybook', 50);
return $restApiAccessible === false;
}
/**
* Check if the REST API is accessible by making a request to the REST API
* endpoint and checking the response code to be 200.
*/
private function validateRestApi(): bool
{
$response = wp_remote_get(rest_url(), ['sslverify' => false]);
return ! is_wp_error($response) ||
wp_remote_retrieve_response_code($response) === 200;
}
/**
* Check if the one-day cached REST API accessibility is still valid. We
* only check if we've actually assessed that the REST API is accessible
* previously. This method makes sure we don't make unnecessary requests
* to the REST API endpoint if we already know it's accessible.
*/
private function restApiIsAccessibleAndCachedForOneDay(): bool
{
$restApiAccessibleCached = get_option($this->restApiAccessibleOptionName, false);
if ($restApiAccessibleCached === false) {
// Don't use cache if not set OR if the REST API is not accessible
return false;
}
$validationTime = Carbon::createFromTimestamp(
get_option($this->restApiValidationTimeOptionName, time())
);
$oneDayAgo = Carbon::now()->subDay();
return $validationTime->isAfter($oneDayAgo);
}
/**
* Check if the REST API notice is dismissed. This is used to determine if
* the notice should be shown or not.
*/
private function isRestApiNoticeDismissed(): bool
{
return (bool) get_option('simplybook_rest_api_notice_dismissed', false);
}
/**
* Check if the onboarding is completed.
* @todo This should be moved to a trait or a service, as it is used in
* multiple places.
*/
private function isOnboardingCompleted(): bool
{
return (bool) get_option('simplybook_onboarding_completed', false);
}
}