PluginProbe
Extendify / 2.2.0
Extendify v2.2.0
3.2.0 3.1.6 3.1.5 3.1.4 3.1.3 3.1.2 3.1.1 3.1.0 3.0.6 3.0.5 3.0.4 trunk 0.1.0 0.10.0 0.10.1 0.10.2 0.11.0 0.11.1 0.2.0 0.3.0 0.3.1 0.4.0 0.5.0 0.6.0 0.7.0 All 126 releases
extendify / app / Agent / Admin.php

Admin.php in Extendify 2.2.0, at app/Agent/Admin.php

330 lines 12.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * Admin.
5 */
6
7 namespace Extendify\Agent;
8
9 defined('ABSPATH') || die('No direct access.');
10
11 use Extendify\Agent\Controllers\ChatHistoryController;
12 use Extendify\Agent\Controllers\TourController;
13 use Extendify\Agent\Controllers\WorkflowHistoryController;
14 use Extendify\Config;
15 use Extendify\Shared\Services\Escaper;
16 use Extendify\Agent\TagBlocks;
17 use Extendify\Agent\TagTemplateParts;
18 use Extendify\Agent\Controllers\SiteNavigationController;
19 use Extendify\Shared\DataProvider\ProductsData;
20
21 /**
22 * This class handles any file loading for the admin area.
23 */
24 class Admin
25 {
26 /**
27 * Adds various actions to set up the page
28 *
29 * @return void
30 */
31 public function __construct()
32 {
33 \add_action('admin_enqueue_scripts', [$this, 'loadScriptsAndStyles']);
34 \add_action('wp_enqueue_scripts', [$this, 'loadScriptsAndStyles']);
35 ChatHistoryController::init();
36 WorkflowHistoryController::init();
37
38 // Tag blocks so we can identify them later
39 TagBlocks::init();
40 TagTemplateParts::init();
41
42 // Add the site navigation ids to the navigation blocks
43 SiteNavigationController::init();
44 }
45
46 /**
47 * Adds various JS scripts and styles
48 *
49 * @return void
50 */
51 public function loadScriptsAndStyles()
52 {
53 $version = constant('EXTENDIFY_DEVMODE') ? uniqid() : Config::$version;
54 $scriptAssetPath = EXTENDIFY_PATH . 'public/build/' . Config::$assetManifest['extendify-agent.php'];
55 $fallback = [
56 'dependencies' => [],
57 'version' => $version,
58 ];
59 $scriptAsset = file_exists($scriptAssetPath) ? require $scriptAssetPath : $fallback;
60
61 foreach ($scriptAsset['dependencies'] as $style) {
62 \wp_enqueue_style($style);
63 }
64
65 \wp_enqueue_script(
66 Config::$slug . '-agent-scripts',
67 EXTENDIFY_BASE_URL . 'public/build/' . Config::$assetManifest['extendify-agent.js'],
68 array_merge([Config::$slug . '-shared-scripts'], $scriptAsset['dependencies']),
69 $scriptAsset['version'],
70 true
71 );
72
73 $context = [
74 'adminPage' => function_exists('get_current_screen') && ($screen = get_current_screen())
75 ? \esc_attr($screen->id)
76 : null,
77 'postId' => (int) $this->getCurrentPostId(),
78 'postTitle' => \esc_attr(\get_the_title($this->getCurrentPostId())),
79 'postType' => \esc_attr(\get_post_type($this->getCurrentPostId())),
80 'isFrontPage' => (bool) \is_front_page(),
81 'postStatus' => \esc_attr(\get_post_status((int) $this->getCurrentPostId())),
82 'isBlogPage' => (bool) \is_home(),
83 'themeSlug' => \esc_attr(\wp_get_theme()->get_stylesheet()),
84 'hasThemeVariations' => (bool) $this->hasThemeVariations(),
85 'isBlockTheme' => function_exists('wp_is_block_theme') ? (bool) wp_is_block_theme() : false,
86 'wordPressVersion' => \esc_attr(\get_bloginfo('version')),
87 'usingBlockEditor' => function_exists('use_block_editor_for_post') ?
88 (bool) use_block_editor_for_post($this->getCurrentPostId()) :
89 false,
90 'activePlugins' => array_values(\get_option('active_plugins', [])),
91 ];
92 $recommendations = ProductsData::get() ?? [];
93 $pluginRecommendations = array_filter($recommendations, function ($item) {
94 return in_array('ai-agent', $item['slots'] ?? [], true) && $item['ctaType'] === 'plugin';
95 });
96 $mappedPluginRecommendations = array_values(array_map(function ($item) {
97 return [
98 'title' => $item['title'] ?? '',
99 'slug' => $item['slug'] ?? '',
100 'description' => $item['aiDescription'] ?? $item['description'] ?? '',
101 ];
102 }, $pluginRecommendations));
103 $agentContext = [
104 'availableAdminPages' => get_option('_transient_extendify_admin_pages_menu', []),
105 'pluginRecommendations' => $mappedPluginRecommendations,
106 ];
107 $abilities = [
108 'canEditPost' => (bool) \current_user_can('edit_post', \get_queried_object_id()),
109 // TODO: this may be true for a user, while they still can't edit every post
110 // So we would need to clarify this in the instructions, and
111 // include a step that fetches the page they want to edit
112 'canEditPosts' => (bool) \current_user_can('edit_posts'),
113 'canEditThemes' => (bool) \current_user_can('edit_theme_options'),
114 'canActivatePlugins' => (bool) \current_user_can('activate_plugins'),
115 'canInstallPlugins' => (bool) \current_user_can('install_plugins'),
116 'canEditUsers' => (bool) \current_user_can('edit_users'),
117 'canEditSettings' => (bool) \current_user_can('manage_options'),
118 'canUploadMedia' => (bool) \current_user_can('upload_files'),
119 ];
120
121 \wp_add_inline_script(
122 Config::$slug . '-agent-scripts',
123 'window.extAgentData = ' . \wp_json_encode([
124 // Add context about where they are
125 'context' => $context,
126 // Context that the Agent might need when returning a response,
127 // but not for handling the workflow.
128 'agentContext' => $agentContext,
129 // List of abilities the AI can perform for this user.
130 // For example, we could check whether their theme has variations.
131 'abilities' => $abilities,
132 // List of suggestions the AI can make for this user.
133 // For example, we could check whether they need to set up a specific plugin.
134 'suggestions' => $this->getSuggestions($context, $abilities),
135 'chatHistory' => Escaper::recursiveEscAttr(ChatHistoryController::getChatHistory()),
136 'workflowHistory' => Escaper::recursiveEscAttr(WorkflowHistoryController::getWorkflowHistory()),
137 'userData' => [
138 'tourData' => \wp_json_encode(TourController::get()->get_data()),
139 ],
140 ]),
141 'before'
142 );
143
144 \wp_set_script_translations(
145 Config::$slug . '-agent-scripts',
146 'extendify-local',
147 EXTENDIFY_PATH . 'languages/js'
148 );
149
150 \wp_enqueue_style(
151 Config::$slug . '-agent-styles',
152 EXTENDIFY_BASE_URL . 'public/build/' . Config::$assetManifest['extendify-agent.css'],
153 [],
154 Config::$version,
155 'all'
156 );
157 }
158 /**
159 * Get the current post ID based on the context.
160 *
161 * @return int
162 */
163 private function getCurrentPostId()
164 {
165 if (is_admin() && function_exists('get_current_screen')) {
166 $screen = get_current_screen();
167 if ($screen && $screen->base === 'post') {
168 global $post;
169 if ($post) {
170 return (int) $post->ID;
171 }
172 }
173 }
174 if (\is_front_page()) {
175 return (\get_option('show_on_front') === 'page') ? (int) \get_option('page_on_front') : 0;
176 }
177 if (\is_home()) {
178 return (int) \get_option('page_for_posts');
179 }
180 return (int) \get_queried_object_id();
181 }
182
183 /**
184 * Scan the style dirs to locate if they have variations.
185 * Ported from here:
186 * https://github.com/WordPress/wordpress-develop/blob/trunk/src/wp-includes/class-wp-theme-json-resolver.php#L810
187 *
188 * @return bool
189 */
190 private function hasThemeVariations()
191 {
192 $base_directory = get_stylesheet_directory() . '/styles';
193 $template_directory = get_template_directory() . '/styles';
194
195 if (is_dir($base_directory) && glob($base_directory . '/*.json', GLOB_NOSORT)) {
196 return true;
197 }
198
199 // Only check parent if it's different from child
200 if (
201 $template_directory !== $base_directory &&
202 is_dir($template_directory) &&
203 glob($template_directory . '/*.json', GLOB_NOSORT)
204 ) {
205 return true;
206 }
207
208 return false;
209 }
210
211 /**
212 * Get suggestions for the user.
213 *
214 * @param array $context - The context of the current page and site.
215 * @param array $abilities - The abilities of the user.
216 * @return array
217 */
218 private function getSuggestions($context, $abilities)
219 {
220 $suggestions = [
221 [
222 'icon' => 'video',
223 'message' => __('What tours are available?', 'extendify-local'),
224 ]
225 ];
226
227 if ($context['postStatus']) {
228 $suggestions [] = [
229 'icon' => ($context['postStatus'] === 'draft') ? 'published' : 'drafts',
230 'message' => ($context['postStatus'] === 'draft')
231 ? __('Publish this page', 'extendify-local')
232 : __('Unpublish this page', 'extendify-local') ,
233 ];
234 }
235
236 if ($abilities['canEditSettings']) {
237 $suggestions[] = [
238 'icon' => 'edit',
239 'message' => __('I want to change my site title', 'extendify-local'),
240 "feature" => true,
241 ];
242
243 $suggestions[] = [
244 'icon' => 'typography',
245 'message' => __('I want to change my theme fonts', 'extendify-local'),
246 "feature" => true,
247 ];
248 }
249
250 // If they have theme variations, suggest they can change the theme styling.
251 if ($context['hasThemeVariations']) {
252 $suggestions[] = [
253 'icon' => 'styles',
254 'message' => __('I want to change my theme styling', 'extendify-local'),
255 "feature" => true,
256 ];
257 }
258
259 if ($context['postId'] && $abilities['canEditPost'] && $context['usingBlockEditor']) {
260 $suggestions[] = [
261 'icon' => 'edit',
262 'message' => __('Edit text on this page', 'extendify-local'),
263 "feature" => true,
264 ];
265 }
266
267 if ($abilities['canEditPost']) {
268 $suggestions[] = [
269 'icon' => 'help',
270 'message' => __('How can I create a post?', 'extendify-local'),
271 ];
272 $suggestions[] = [
273 'icon' => 'help',
274 'message' => __('How can I create a page?', 'extendify-local'),
275 ];
276 }
277
278 if ($abilities['canActivatePlugins']) {
279 $suggestions[] = [
280 'icon' => 'help',
281 'message' => __('How can I install a plugin?', 'extendify-local'),
282 ];
283 }
284
285 if ($abilities['canEditThemes']) {
286 $suggestions[] = [
287 'icon' => 'help',
288 'message' => __('How can I change my theme?', 'extendify-local'),
289 ];
290 $suggestions[] = [
291 'icon' => 'help',
292 'message' => __('How can I change the site footer?', 'extendify-local'),
293 ];
294 $suggestions[] = [
295 'icon' => 'help',
296 'message' => __('How can I change the site header?', 'extendify-local'),
297 ];
298 }
299
300 if ($abilities['canUploadMedia']) {
301 $suggestions[] = [
302 'icon' => 'help',
303 'message' => __('How can I upload an image?', 'extendify-local'),
304 ];
305 $suggestions[] = [
306 'icon' => 'help',
307 'message' => __('How can I change the site icon?', 'extendify-local'),
308 ];
309 }
310
311 if ($abilities['canEditSettings']) {
312 $suggestions[] = [
313 'icon' => 'help',
314 'message' => __('How can I change my site title?', 'extendify-local'),
315 ];
316 $suggestions[] = [
317 'icon' => 'help',
318 'message' => __('How can I change my site tagline?', 'extendify-local'),
319 ];
320 $suggestions[] = [
321 'icon' => 'help',
322 'message' => __('How can I change my site language?', 'extendify-local'),
323 ];
324 }
325
326 shuffle($suggestions);
327 return $suggestions;
328 }
329 }
330