Edit File by line
/home/zeestwma/ceyloniy.../wp-conte.../plugins/extendif.../app/Shared
File: Admin.php
<?php
[0] Fix | Delete
[1] Fix | Delete
/**
[2] Fix | Delete
* Help Center Script loader.
[3] Fix | Delete
*/
[4] Fix | Delete
[5] Fix | Delete
namespace Extendify\Shared;
[6] Fix | Delete
[7] Fix | Delete
defined('ABSPATH') || die('No direct access.');
[8] Fix | Delete
[9] Fix | Delete
use Extendify\Config;
[10] Fix | Delete
use Extendify\PartnerData;
[11] Fix | Delete
use Extendify\Shared\Controllers\UserSelectionController;
[12] Fix | Delete
use Extendify\Shared\DataProvider\ResourceData;
[13] Fix | Delete
use Extendify\Shared\Services\AdminMenuList;
[14] Fix | Delete
use Extendify\Shared\Services\ApexDomain\ApexDomain;
[15] Fix | Delete
use Extendify\Shared\Services\Escaper;
[16] Fix | Delete
use Extendify\Shared\Services\PluginDependencies\SimplyBook;
[17] Fix | Delete
use Extendify\SiteSettings;
[18] Fix | Delete
use Extendify\Shared\Controllers\ImageGenerationController;
[19] Fix | Delete
use Extendify\Shared\DataProvider\ProductsData;
[20] Fix | Delete
[21] Fix | Delete
/**
[22] Fix | Delete
* This class handles any file loading for the admin area.
[23] Fix | Delete
*/
[24] Fix | Delete
[25] Fix | Delete
class Admin
[26] Fix | Delete
{
[27] Fix | Delete
/**
[28] Fix | Delete
* Adds various actions to set up the page
[29] Fix | Delete
*
[30] Fix | Delete
* @return void
[31] Fix | Delete
*/
[32] Fix | Delete
public function __construct()
[33] Fix | Delete
{
[34] Fix | Delete
\add_action('init', [$this, 'addExtraMetaFields']);
[35] Fix | Delete
\add_action('admin_enqueue_scripts', [$this, 'loadGlobalScripts']);
[36] Fix | Delete
\add_action('wp_enqueue_scripts', [$this, 'loadGlobalScripts']);
[37] Fix | Delete
\add_action('wp_ajax_search-install-plugins', [$this, 'recordPluginsSearchTerms'], -1);
[38] Fix | Delete
\add_action('rest_api_init', [$this, 'recordBlocksSearchTerms']);
[39] Fix | Delete
\add_action('wp_ajax_query-themes', [$this, 'recordThemesSearchTerms'], -1);
[40] Fix | Delete
AdminMenuList::init();
[41] Fix | Delete
\add_action('simplybook_activation', [SimplyBook::class, 'getIndustryCode'], 10, 0);
[42] Fix | Delete
}
[43] Fix | Delete
[44] Fix | Delete
// phpcs:disable Generic.Metrics.CyclomaticComplexity.TooHigh
[45] Fix | Delete
/**
[46] Fix | Delete
* Adds scripts to every page
[47] Fix | Delete
*
[48] Fix | Delete
* @return void
[49] Fix | Delete
*/
[50] Fix | Delete
public function loadGlobalScripts()
[51] Fix | Delete
{
[52] Fix | Delete
\wp_enqueue_media();
[53] Fix | Delete
[54] Fix | Delete
$this->updateUserMeta();
[55] Fix | Delete
[56] Fix | Delete
$version = constant('EXTENDIFY_DEVMODE') ? uniqid() : Config::$version;
[57] Fix | Delete
[58] Fix | Delete
/**
[59] Fix | Delete
* Enqueue shared JavaScript files if they exist in the asset manifest
[60] Fix | Delete
* Ensures proper loading order: vendors -> common
[61] Fix | Delete
*/
[62] Fix | Delete
[63] Fix | Delete
// Enqueue the vendor chunk first.
[64] Fix | Delete
if (isset(Config::$assetManifest['extendify-vendors.js'])) {
[65] Fix | Delete
wp_enqueue_script(
[66] Fix | Delete
'extendify-vendors',
[67] Fix | Delete
EXTENDIFY_BASE_URL . 'public/build/' . Config::$assetManifest['extendify-vendors.js'],
[68] Fix | Delete
[],
[69] Fix | Delete
$version,
[70] Fix | Delete
true
[71] Fix | Delete
// Load in footer.
[72] Fix | Delete
);
[73] Fix | Delete
}
[74] Fix | Delete
[75] Fix | Delete
// Enqueue the common chunk next, dependent on vendors.
[76] Fix | Delete
if (isset(Config::$assetManifest['extendify-common.js'])) {
[77] Fix | Delete
wp_enqueue_script(
[78] Fix | Delete
'extendify-common',
[79] Fix | Delete
EXTENDIFY_BASE_URL . 'public/build/' . Config::$assetManifest['extendify-common.js'],
[80] Fix | Delete
['extendify-vendors'],
[81] Fix | Delete
$version,
[82] Fix | Delete
true
[83] Fix | Delete
);
[84] Fix | Delete
}
[85] Fix | Delete
[86] Fix | Delete
/*
[87] Fix | Delete
* Loads a unique runtime generated by Webpack to manage all the other generated scripts.
[88] Fix | Delete
* Without this runtime, the other Extendify scripts won't load.
[89] Fix | Delete
*/
[90] Fix | Delete
$scriptAssetPath = EXTENDIFY_PATH . 'public/build/' . Config::$assetManifest['extendify-runtime.php'];
[91] Fix | Delete
$fallback = [
[92] Fix | Delete
'dependencies' => [],
[93] Fix | Delete
'version' => $version,
[94] Fix | Delete
];
[95] Fix | Delete
$scriptAsset = file_exists($scriptAssetPath) ? require $scriptAssetPath : $fallback;
[96] Fix | Delete
[97] Fix | Delete
foreach ($scriptAsset['dependencies'] as $style) {
[98] Fix | Delete
\wp_enqueue_style($style);
[99] Fix | Delete
}
[100] Fix | Delete
[101] Fix | Delete
\wp_enqueue_script(
[102] Fix | Delete
Config::$slug . '-runtime-scripts',
[103] Fix | Delete
EXTENDIFY_BASE_URL . 'public/build/' . Config::$assetManifest['extendify-runtime.js'],
[104] Fix | Delete
$scriptAsset['dependencies'],
[105] Fix | Delete
$scriptAsset['version'],
[106] Fix | Delete
true
[107] Fix | Delete
);
[108] Fix | Delete
[109] Fix | Delete
$scriptAssetPath = EXTENDIFY_PATH . 'public/build/' . Config::$assetManifest['extendify-shared.php'];
[110] Fix | Delete
$fallback = [
[111] Fix | Delete
'dependencies' => [],
[112] Fix | Delete
'version' => $version,
[113] Fix | Delete
];
[114] Fix | Delete
$scriptAsset = file_exists($scriptAssetPath) ? require $scriptAssetPath : $fallback;
[115] Fix | Delete
[116] Fix | Delete
foreach ($scriptAsset['dependencies'] as $style) {
[117] Fix | Delete
\wp_enqueue_style($style);
[118] Fix | Delete
}
[119] Fix | Delete
[120] Fix | Delete
\wp_enqueue_script(
[121] Fix | Delete
Config::$slug . '-shared-scripts',
[122] Fix | Delete
EXTENDIFY_BASE_URL . 'public/build/' . Config::$assetManifest['extendify-shared.js'],
[123] Fix | Delete
$scriptAsset['dependencies'],
[124] Fix | Delete
$scriptAsset['version'],
[125] Fix | Delete
true
[126] Fix | Delete
);
[127] Fix | Delete
[128] Fix | Delete
$siteProfile = \get_option('extendify_site_profile', []);
[129] Fix | Delete
$siteProfile = is_string($siteProfile) ? json_decode($siteProfile, true) : $siteProfile;
[130] Fix | Delete
$siteProfile = is_array($siteProfile) ? $siteProfile : [];
[131] Fix | Delete
$map = [
[132] Fix | Delete
'aiSiteType' => 'type',
[133] Fix | Delete
'aiTitle' => 'title',
[134] Fix | Delete
'aiDescription' => 'description',
[135] Fix | Delete
'aiObjective' => 'objective',
[136] Fix | Delete
'aiSiteCategory' => 'category',
[137] Fix | Delete
'aiStructure' => 'structure',
[138] Fix | Delete
'aiKeywords' => 'imageSearchTerms',
[139] Fix | Delete
'logoObjectName' => 'logoObjectName',
[140] Fix | Delete
];
[141] Fix | Delete
// Converts legacy site profile to new one
[142] Fix | Delete
foreach ($map as $old => $new) {
[143] Fix | Delete
if (!array_key_exists($new, $siteProfile)) {
[144] Fix | Delete
$siteProfile[$new] = $siteProfile[$old] ?? null;
[145] Fix | Delete
}
[146] Fix | Delete
}
[147] Fix | Delete
[148] Fix | Delete
$partnerData = PartnerData::getPartnerData();
[149] Fix | Delete
$userConsent = get_user_meta(get_current_user_id(), 'extendify_ai_consent', true);
[150] Fix | Delete
$htmlAllowlist = [
[151] Fix | Delete
'a' => [
[152] Fix | Delete
'target' => [],
[153] Fix | Delete
'href' => [],
[154] Fix | Delete
'rel' => [],
[155] Fix | Delete
],
[156] Fix | Delete
];
[157] Fix | Delete
[158] Fix | Delete
if (!function_exists('get_plugins')) {
[159] Fix | Delete
require_once ABSPATH . 'wp-admin/includes/plugin.php';
[160] Fix | Delete
}
[161] Fix | Delete
[162] Fix | Delete
\wp_add_inline_script(
[163] Fix | Delete
Config::$slug . '-shared-scripts',
[164] Fix | Delete
'window.extSharedData = ' . \wp_json_encode([
[165] Fix | Delete
'root' => \esc_url_raw(rest_url(Config::$slug . '/' . Config::$apiVersion)),
[166] Fix | Delete
'homeUrl' => \esc_url_raw(\get_home_url()),
[167] Fix | Delete
'adminUrl' => \esc_url_raw(\admin_url()),
[168] Fix | Delete
'nonce' => \esc_attr(\wp_create_nonce('wp_rest')),
[169] Fix | Delete
'devbuild' => (bool) constant('EXTENDIFY_DEVMODE'),
[170] Fix | Delete
'assetPath' => \esc_url(EXTENDIFY_URL . 'public/assets'),
[171] Fix | Delete
'siteId' => \esc_attr(\get_option('extendify_site_id', '')),
[172] Fix | Delete
'siteCreatedAt' => \esc_attr(SiteSettings::getSiteCreatedAt()),
[173] Fix | Delete
'themeSlug' => \esc_attr(\get_option('stylesheet')),
[174] Fix | Delete
'version' => \esc_attr(Config::$version),
[175] Fix | Delete
'siteTitle' => \esc_attr(\get_bloginfo('name')),
[176] Fix | Delete
'siteProfile' => $siteProfile,
[177] Fix | Delete
'wpLanguage' => \esc_attr(\get_locale()),
[178] Fix | Delete
'wpVersion' => \esc_attr(\get_bloginfo('version')),
[179] Fix | Delete
'isBlockTheme' => function_exists('wp_is_block_theme') ? (bool) wp_is_block_theme() : false,
[180] Fix | Delete
'userId' => \esc_attr(\get_current_user_id()),
[181] Fix | Delete
'partnerLogo' => \esc_attr(PartnerData::$logo),
[182] Fix | Delete
'partnerId' => \esc_attr(PartnerData::$id),
[183] Fix | Delete
'partnerName' => \esc_attr(PartnerData::$name),
[184] Fix | Delete
'launchDataLegacy' => \wp_json_encode((UserSelectionController::get()->get_data() ?? [])),
[185] Fix | Delete
'resourceData' => \wp_json_encode((new ResourceData())->getData()),
[186] Fix | Delete
'showAIConsent' => isset($partnerData['showAIConsent']) ? (bool) $partnerData['showAIConsent'] : false,
[187] Fix | Delete
'showChat' => (bool) (PartnerData::setting('showChat') || constant('EXTENDIFY_DEVMODE')),
[188] Fix | Delete
'useAgentOnboarding' => (bool) (
[189] Fix | Delete
PartnerData::setting('useAgentOnboarding') ||
[190] Fix | Delete
constant('EXTENDIFY_DEVMODE')
[191] Fix | Delete
),
[192] Fix | Delete
'showAIPageCreation' => (bool) (
[193] Fix | Delete
PartnerData::setting('showAIPageCreation') || constant('EXTENDIFY_DEVMODE')
[194] Fix | Delete
),
[195] Fix | Delete
'showAILogo' => (bool) PartnerData::setting('showAILogo'),
[196] Fix | Delete
'showImprint' => array_map('esc_attr', (array) PartnerData::setting('showImprint')),
[197] Fix | Delete
'consentTermsCustom' => \wp_kses((html_entity_decode(($partnerData['consentTermsCustom'] ?? ''))
[198] Fix | Delete
?? ''), $htmlAllowlist),
[199] Fix | Delete
'userGaveConsent' => $userConsent ? (bool) $userConsent : false,
[200] Fix | Delete
'installedPlugins' => array_map('esc_attr', array_keys(\get_plugins())),
[201] Fix | Delete
'activePlugins' => array_map('esc_attr', array_values(\get_option('active_plugins', []))),
[202] Fix | Delete
'frontPage' => \esc_attr(\get_option('page_on_front', 0)),
[203] Fix | Delete
'globalStylesPostID' => \esc_attr(\WP_Theme_JSON_Resolver::get_user_global_styles_post_id()),
[204] Fix | Delete
'showLocalizedCopy' => (bool) array_key_exists('showLocalizedCopy', $partnerData),
[205] Fix | Delete
'activity' => \wp_json_encode(\get_option('extendify_shared_activity', null)),
[206] Fix | Delete
'showDraft' => isset($partnerData['showDraft']) ? (bool) $partnerData['showDraft'] : false,
[207] Fix | Delete
'showLaunch' => Config::$showLaunch,
[208] Fix | Delete
'phpVersion' => \esc_attr(PHP_VERSION),
[209] Fix | Delete
'apexDomain' => PartnerData::setting('enableApexDomain')
[210] Fix | Delete
? rawurlencode(ApexDomain::getApexDomain(\get_home_url()))
[211] Fix | Delete
: null,
[212] Fix | Delete
'launchCompletedAt' => \esc_attr(\get_option('extendify_onboarding_completed', false)),
[213] Fix | Delete
'showSiteQuestions' => (bool) (
[214] Fix | Delete
PartnerData::setting('showLaunchQuestions') || Config::preview('launch-questions')
[215] Fix | Delete
),
[216] Fix | Delete
'products' => ProductsData::get(),
[217] Fix | Delete
'showAIAgents' => (bool) (PartnerData::setting('showAIAgents') || Config::preview('ai-agent')),
[218] Fix | Delete
'pluginGroupId' => Escaper::recursiveEscAttr(PartnerData::setting('pluginGroupId')),
[219] Fix | Delete
'adminPagesMenuList' => get_option('_transient_extendify_admin_pages_menu', []),
[220] Fix | Delete
'globalState' => ImageGenerationController::get()->get_data(),
[221] Fix | Delete
]),
[222] Fix | Delete
'before'
[223] Fix | Delete
);
[224] Fix | Delete
[225] Fix | Delete
\wp_set_script_translations('extendify-common', 'extendify-local', EXTENDIFY_PATH . 'languages/js');
[226] Fix | Delete
\wp_set_script_translations(
[227] Fix | Delete
Config::$slug . '-shared-scripts',
[228] Fix | Delete
'extendify-local',
[229] Fix | Delete
EXTENDIFY_PATH . 'languages/js'
[230] Fix | Delete
);
[231] Fix | Delete
[232] Fix | Delete
\wp_enqueue_style(
[233] Fix | Delete
Config::$slug . '-shared-common-styles',
[234] Fix | Delete
EXTENDIFY_BASE_URL . 'public/build/' . Config::$assetManifest['extendify-shared.css'],
[235] Fix | Delete
[],
[236] Fix | Delete
Config::$version,
[237] Fix | Delete
'all'
[238] Fix | Delete
);
[239] Fix | Delete
$cssColorVars = PartnerData::cssVariableMapping();
[240] Fix | Delete
$cssString = implode('; ', array_map(function ($k, $v) {
[241] Fix | Delete
return "$k: $v";
[242] Fix | Delete
}, array_keys($cssColorVars), $cssColorVars));
[243] Fix | Delete
\wp_add_inline_style(
[244] Fix | Delete
Config::$slug . '-shared-common-styles',
[245] Fix | Delete
wp_strip_all_tags(":root { $cssString; }")
[246] Fix | Delete
);
[247] Fix | Delete
}
[248] Fix | Delete
[249] Fix | Delete
/**
[250] Fix | Delete
* Adds additional meta fields to post types
[251] Fix | Delete
*
[252] Fix | Delete
* @return void
[253] Fix | Delete
*/
[254] Fix | Delete
public function addExtraMetaFields()
[255] Fix | Delete
{
[256] Fix | Delete
// Add a tag to pages that were made with Launch.
[257] Fix | Delete
register_post_meta('page', 'made_with_extendify_launch', [
[258] Fix | Delete
'single' => true,
[259] Fix | Delete
'type' => 'boolean',
[260] Fix | Delete
'show_in_rest' => true,
[261] Fix | Delete
]);
[262] Fix | Delete
register_post_meta('post', 'made_with_extendify_launch', [
[263] Fix | Delete
'single' => true,
[264] Fix | Delete
'type' => 'boolean',
[265] Fix | Delete
'show_in_rest' => true,
[266] Fix | Delete
]);
[267] Fix | Delete
}
[268] Fix | Delete
[269] Fix | Delete
/**
[270] Fix | Delete
* Records plugin search terms from the WordPress plugin search page
[271] Fix | Delete
* Stores terms in the 'extendify_plugin_search_terms' option
[272] Fix | Delete
*
[273] Fix | Delete
* @return void
[274] Fix | Delete
*/
[275] Fix | Delete
public function recordPluginsSearchTerms()
[276] Fix | Delete
{
[277] Fix | Delete
// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.NonceVerification.Missing
[278] Fix | Delete
$searchTerm = isset($_POST['s']) ? \sanitize_text_field(\wp_unslash(urldecode($_POST['s']))) : '';
[279] Fix | Delete
if (empty($searchTerm)) {
[280] Fix | Delete
return;
[281] Fix | Delete
}
[282] Fix | Delete
[283] Fix | Delete
$searchTerms = \get_option('extendify_plugin_search_terms', []);
[284] Fix | Delete
$searchTerms[] = $searchTerm;
[285] Fix | Delete
$searchTerms = array_unique($searchTerms);
[286] Fix | Delete
[287] Fix | Delete
\update_option('extendify_plugin_search_terms', $searchTerms);
[288] Fix | Delete
}
[289] Fix | Delete
[290] Fix | Delete
/**
[291] Fix | Delete
* Records block search terms from the WordPress the editor's block search
[292] Fix | Delete
* Stores terms in the 'extendify_block_search_terms' option
[293] Fix | Delete
*
[294] Fix | Delete
* @return void
[295] Fix | Delete
*/
[296] Fix | Delete
public function recordBlocksSearchTerms()
[297] Fix | Delete
{
[298] Fix | Delete
// Exits early if it is not a REST API request.
[299] Fix | Delete
if (!\wp_is_serving_rest_request()) {
[300] Fix | Delete
return;
[301] Fix | Delete
}
[302] Fix | Delete
[303] Fix | Delete
// Exits early if it is not a GET request.
[304] Fix | Delete
if (isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] !== 'GET') {
[305] Fix | Delete
return;
[306] Fix | Delete
}
[307] Fix | Delete
[308] Fix | Delete
$wp = $GLOBALS['wp'];
[309] Fix | Delete
[310] Fix | Delete
$restRoute = ($wp->query_vars['rest_route'] ?? '');
[311] Fix | Delete
// Exits early if it's not the blocks search route.
[312] Fix | Delete
if ($restRoute !== '/wp/v2/block-directory/search') {
[313] Fix | Delete
return;
[314] Fix | Delete
}
[315] Fix | Delete
[316] Fix | Delete
$searchTerm = \sanitize_text_field(\wp_unslash(($wp->query_vars['term'] ?? '')));
[317] Fix | Delete
// Exits early if the search term is empty or is not user input.
[318] Fix | Delete
if (empty($searchTerm) || str_starts_with($searchTerm, 'block:')) {
[319] Fix | Delete
return;
[320] Fix | Delete
}
[321] Fix | Delete
[322] Fix | Delete
// Get current search term from the url and merge it with existing search terms.
[323] Fix | Delete
$searchTerms = \get_option('extendify_block_search_terms', []);
[324] Fix | Delete
\update_option('extendify_block_search_terms', array_merge($searchTerms, [$searchTerm]));
[325] Fix | Delete
}
[326] Fix | Delete
[327] Fix | Delete
/**
[328] Fix | Delete
* Updates the user meta to disable the welcome guide from the Gutenberg editor
[329] Fix | Delete
* and close the pattern modal.
[330] Fix | Delete
*
[331] Fix | Delete
* @return void
[332] Fix | Delete
*/
[333] Fix | Delete
public function updateUserMeta()
[334] Fix | Delete
{
[335] Fix | Delete
$currentPreferences = get_user_meta(get_current_user_id(), 'wp_persisted_preferences', true);
[336] Fix | Delete
if (!$currentPreferences) {
[337] Fix | Delete
$currentPreferences = [];
[338] Fix | Delete
}
[339] Fix | Delete
[340] Fix | Delete
$postPreferences = array_key_exists('core/edit-post', $currentPreferences)
[341] Fix | Delete
? $currentPreferences['core/edit-post']
[342] Fix | Delete
: [];
[343] Fix | Delete
$corePreferences = array_key_exists('core', $currentPreferences) ? $currentPreferences['core'] : [];
[344] Fix | Delete
[345] Fix | Delete
$newPreferences = array_merge($currentPreferences, [
[346] Fix | Delete
'core/edit-post' => array_merge($postPreferences, ['welcomeGuide' => false]),
[347] Fix | Delete
'core' => array_merge($corePreferences, ['enableChoosePatternModal' => false]),
[348] Fix | Delete
'_modified' => wp_date('Y-m-d\TH:i:s.v\Z'),
[349] Fix | Delete
]);
[350] Fix | Delete
[351] Fix | Delete
update_user_meta(get_current_user_id(), 'wp_persisted_preferences', $newPreferences);
[352] Fix | Delete
}
[353] Fix | Delete
[354] Fix | Delete
/**
[355] Fix | Delete
* Records search terms used when browsing themes in the admin interface.
[356] Fix | Delete
*
[357] Fix | Delete
* This method listens for the 'query-themes' AJAX action, extracts the search term
[358] Fix | Delete
* from the request, and stores it in the 'extendify_theme_search_terms' option.
[359] Fix | Delete
* Duplicate terms are filtered out.
[360] Fix | Delete
*
[361] Fix | Delete
* @return void
[362] Fix | Delete
*/
[363] Fix | Delete
public function recordThemesSearchTerms()
[364] Fix | Delete
{
[365] Fix | Delete
// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.NonceVerification.Missing
[366] Fix | Delete
$searchTerm = \sanitize_text_field(\wp_unslash(urldecode(($_POST['request']['search'] ?? ''))));
[367] Fix | Delete
if (empty($searchTerm)) {
[368] Fix | Delete
return;
[369] Fix | Delete
}
[370] Fix | Delete
[371] Fix | Delete
$searchTerms = \get_option('extendify_theme_search_terms', []);
[372] Fix | Delete
$searchTerms[] = $searchTerm;
[373] Fix | Delete
$searchTerms = array_unique($searchTerms);
[374] Fix | Delete
[375] Fix | Delete
\update_option('extendify_theme_search_terms', $searchTerms);
[376] Fix | Delete
}
[377] Fix | Delete
}
[378] Fix | Delete
[379] Fix | Delete
It is recommended that you Edit text format, this type of Fix handles quite a lot in one request
Function