PluginProbe
Search Atlas SEO – OTTO AI SEO Automation for WordPress / 2.6.21
Search Atlas SEO – OTTO AI SEO Automation for WordPress v2.6.21
2.6.26 2.6.25 2.6.24 2.6.23 2.6.22 2.6.21 2.6.20 2.6.19 2.6.18 2.6.17 2.6.16 2.6.15 2.6.14 2.6.13 2.6.12 2.6.11 2.6.10 2.6.9 2.6.8 2.6.7 2.6.6 2.6.5 2.6.4 2.6.3 2.5.23 All 138 releases
metasync / admin / class-metasync-html-visual-editor.php

class-metasync-html-visual-editor.php in Search Atlas SEO – OTTO AI SEO Automation for WordPress 2.6.21, at admin/class-metasync-html-visual-editor.php

303 lines 8.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * MetaSync HTML Visual Editor
4 *
5 * Provides a visual editing interface for raw HTML pages with:
6 * - Click to edit text
7 * - Color picker for backgrounds/colors
8 * - Image uploader
9 * - Drag and drop reordering
10 * - Live preview
11 *
12 * @package Metasync
13 * @subpackage Metasync/admin
14 * @since 2.0.0
15 */
16
17 if (!defined('ABSPATH')) {
18 exit;
19 }
20
21 class Metasync_HTML_Visual_Editor
22 {
23 /**
24 * Plugin name
25 *
26 * @var string
27 */
28 private $plugin_name;
29
30 /**
31 * Plugin version
32 *
33 * @var string
34 */
35 private $version;
36
37 /**
38 * Initialize the class
39 *
40 * @param string $plugin_name Plugin name
41 * @param string $version Plugin version
42 */
43 public function __construct($plugin_name, $version)
44 {
45 $this->plugin_name = $plugin_name;
46 $this->version = $version;
47 }
48
49 /**
50 * Register hooks
51 */
52 public function init()
53 {
54 // Add "Edit HTML" button to post row actions
55 add_filter('post_row_actions', array($this, 'add_edit_html_button'), 10, 2);
56 add_filter('page_row_actions', array($this, 'add_edit_html_button'), 10, 2);
57
58 // Add admin menu page for the editor
59 add_action('admin_menu', array($this, 'add_editor_page'));
60
61 // Register AJAX handlers
62 add_action('wp_ajax_metasync_save_html', array($this, 'ajax_save_html'));
63 add_action('wp_ajax_metasync_upload_image', array($this, 'ajax_upload_image'));
64 }
65
66 /**
67 * Add "Edit HTML" button to row actions
68 *
69 * @param array $actions Row actions
70 * @param WP_Post $post Post object
71 * @return array Modified actions
72 */
73 public function add_edit_html_button($actions, $post)
74 {
75 // Check if this is a raw HTML page
76 $has_raw_html = get_post_meta($post->ID, '_metasync_raw_html_enabled', true);
77
78 if ($has_raw_html) {
79 $edit_url = admin_url('admin.php?page=' . Metasync_Admin::$page_slug . '-html-editor&post_id=' . $post->ID);
80 $label = Metasync::get_whitelabel_company_name() ?: 'SearchAtlas';
81
82 $actions['edit_html'] = sprintf(
83 '<a href="%s" title="%s">%s</a>',
84 esc_url($edit_url),
85 esc_attr(sprintf(__('Edit with %s Visual Editor', 'metasync'), $label)),
86 __('Edit HTML', 'metasync')
87 );
88 }
89
90 return $actions;
91 }
92
93 /**
94 * Add editor admin page
95 */
96 public function add_editor_page()
97 {
98 $label = Metasync::get_whitelabel_company_name() ?: 'SearchAtlas';
99 $page_title = sprintf(__('%s HTML Editor', 'metasync'), $label);
100
101 add_submenu_page(
102 '', // Hidden from menu
103 $page_title,
104 $page_title,
105 'edit_pages',
106 Metasync_Admin::$page_slug . '-html-editor',
107 array($this, 'render_editor_page')
108 );
109 }
110
111 /**
112 * Render the visual editor page
113 */
114 public function render_editor_page()
115 {
116 // Check permissions
117 if (!current_user_can('edit_pages')) {
118 wp_die(__('You do not have sufficient permissions to access this page.'));
119 }
120
121 // Get post ID
122 $post_id = isset($_GET['post_id']) ? intval($_GET['post_id']) : 0;
123
124 if (!$post_id) {
125 wp_die(__('Invalid page ID.'));
126 }
127
128 // Get post
129 $post = get_post($post_id);
130
131 if (!$post) {
132 wp_die(__('Page not found.'));
133 }
134
135 // Check if raw HTML is enabled
136 $has_raw_html = get_post_meta($post_id, '_metasync_raw_html_enabled', true);
137
138 if (!$has_raw_html) {
139 wp_die(__('This page is not a raw HTML page.'));
140 }
141
142 // Get HTML content
143 $html_content = get_post_meta($post_id, '_metasync_raw_html_content', true);
144
145 if (empty($html_content)) {
146 $html_content = '<html><body><h1>Start editing...</h1></body></html>';
147 }
148
149 // Get label for branding
150 $label = Metasync::get_whitelabel_company_name() ?: 'SearchAtlas AI';
151
152 // Enqueue editor assets
153 $this->enqueue_editor_assets();
154
155 // Render editor UI
156 include plugin_dir_path(__FILE__) . 'partials/metasync-html-editor-page.php';
157 }
158
159 /**
160 * Enqueue editor assets (GrapesJS + custom scripts)
161 */
162 private function enqueue_editor_assets()
163 {
164 // Font Awesome for icons
165 wp_enqueue_style(
166 'font-awesome',
167 'https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css',
168 array(),
169 '6.4.0'
170 );
171
172 // GrapesJS core
173 wp_enqueue_style(
174 'grapesjs',
175 'https://unpkg.com/grapesjs@0.21.7/dist/css/grapes.min.css',
176 array(),
177 '0.21.7'
178 );
179
180 wp_enqueue_script(
181 'grapesjs',
182 'https://unpkg.com/grapesjs@0.21.7/dist/grapes.min.js',
183 array(),
184 '0.21.7',
185 true
186 );
187
188 // GrapesJS Plugins
189 wp_enqueue_script(
190 'grapesjs-blocks-basic',
191 'https://unpkg.com/grapesjs-blocks-basic',
192 array('grapesjs'),
193 null,
194 true
195 );
196
197 // Custom editor JS (with timestamp for cache busting)
198 wp_enqueue_script(
199 'metasync-html-editor',
200 plugins_url('js/metasync-html-editor.js', __FILE__),
201 array('jquery', 'grapesjs'),
202 $this->version . '.' . time(),
203 true
204 );
205
206 // Custom editor CSS (with timestamp for cache busting)
207 wp_enqueue_style(
208 'metasync-html-editor',
209 plugins_url('css/metasync-html-editor.css', __FILE__),
210 array('grapesjs'),
211 $this->version . '.' . time()
212 );
213
214 // Localize script with data
215 wp_localize_script('metasync-html-editor', 'metasyncEditor', array(
216 'ajax_url' => admin_url('admin-ajax.php'),
217 'nonce' => wp_create_nonce('metasync_html_editor'),
218 'post_id' => isset($_GET['post_id']) ? intval($_GET['post_id']) : 0,
219 'preview_url' => get_permalink(isset($_GET['post_id']) ? intval($_GET['post_id']) : 0),
220 'back_url' => admin_url('edit.php?post_type=page'),
221 'i18n' => array(
222 'saving' => __('Saving...', 'metasync'),
223 'saved' => __('Saved!', 'metasync'),
224 'error' => __('Error saving', 'metasync'),
225 'confirm_exit' => __('You have unsaved changes. Are you sure you want to leave?', 'metasync'),
226 )
227 ));
228 }
229
230 /**
231 * AJAX handler for saving HTML
232 */
233 public function ajax_save_html()
234 {
235 // Check nonce
236 check_ajax_referer('metasync_html_editor', 'nonce');
237
238 // Check permissions
239 if (!current_user_can('edit_pages')) {
240 wp_send_json_error(array('message' => __('Permission denied', 'metasync')));
241 }
242
243 // Get data
244 $post_id = isset($_POST['post_id']) ? intval($_POST['post_id']) : 0;
245 $html_content = isset($_POST['html']) ? wp_kses_post($_POST['html']) : '';
246
247 if (!$post_id || empty($html_content)) {
248 wp_send_json_error(array('message' => __('Invalid data', 'metasync')));
249 }
250
251 // Save HTML content
252 update_post_meta($post_id, '_metasync_raw_html_content', $html_content);
253
254 // Update modified date
255 wp_update_post(array(
256 'ID' => $post_id,
257 'post_modified' => current_time('mysql'),
258 'post_modified_gmt' => current_time('mysql', 1)
259 ));
260
261 wp_send_json_success(array(
262 'message' => __('Page saved successfully', 'metasync'),
263 'preview_url' => get_permalink($post_id)
264 ));
265 }
266
267 /**
268 * AJAX handler for uploading images
269 */
270 public function ajax_upload_image()
271 {
272 // Check nonce
273 check_ajax_referer('metasync_html_editor', 'nonce');
274
275 // Check permissions
276 if (!current_user_can('upload_files')) {
277 wp_send_json_error(array('message' => __('Permission denied', 'metasync')));
278 }
279
280 // Handle file upload
281 if (!isset($_FILES['file'])) {
282 wp_send_json_error(array('message' => __('No file uploaded', 'metasync')));
283 }
284
285 require_once(ABSPATH . 'wp-admin/includes/image.php');
286 require_once(ABSPATH . 'wp-admin/includes/file.php');
287 require_once(ABSPATH . 'wp-admin/includes/media.php');
288
289 $attachment_id = media_handle_upload('file', 0);
290
291 if (is_wp_error($attachment_id)) {
292 wp_send_json_error(array('message' => $attachment_id->get_error_message()));
293 }
294
295 $image_url = wp_get_attachment_url($attachment_id);
296
297 wp_send_json_success(array(
298 'url' => $image_url,
299 'id' => $attachment_id
300 ));
301 }
302 }
303