plugin_name = $plugin_name;
$this->version = $version;
}
/**
* Register hooks
*/
public function init()
{
// Add "Edit HTML" button to post row actions
add_filter('post_row_actions', array($this, 'add_edit_html_button'), 10, 2);
add_filter('page_row_actions', array($this, 'add_edit_html_button'), 10, 2);
// Add admin menu page for the editor
add_action('admin_menu', array($this, 'add_editor_page'));
// Register AJAX handlers
add_action('wp_ajax_metasync_save_html', array($this, 'ajax_save_html'));
add_action('wp_ajax_metasync_upload_image', array($this, 'ajax_upload_image'));
}
/**
* Add "Edit HTML" button to row actions
*
* @param array $actions Row actions
* @param WP_Post $post Post object
* @return array Modified actions
*/
public function add_edit_html_button($actions, $post)
{
// Check if this is a raw HTML page
$has_raw_html = get_post_meta($post->ID, '_metasync_raw_html_enabled', true);
if ($has_raw_html) {
$edit_url = admin_url('admin.php?page=' . Metasync_Admin::$page_slug . '-html-editor&post_id=' . $post->ID);
$label = Metasync::get_whitelabel_company_name() ?: 'SearchAtlas';
$actions['edit_html'] = sprintf(
'%s',
esc_url($edit_url),
esc_attr(sprintf(__('Edit with %s Visual Editor', 'metasync'), $label)),
__('Edit HTML', 'metasync')
);
}
return $actions;
}
/**
* Add editor admin page
*/
public function add_editor_page()
{
$label = Metasync::get_whitelabel_company_name() ?: 'SearchAtlas';
$page_title = sprintf(__('%s HTML Editor', 'metasync'), $label);
add_submenu_page(
'', // Hidden from menu
$page_title,
$page_title,
'edit_pages',
Metasync_Admin::$page_slug . '-html-editor',
array($this, 'render_editor_page')
);
}
/**
* Render the visual editor page
*/
public function render_editor_page()
{
// Check permissions
if (!current_user_can('edit_pages')) {
wp_die(__('You do not have sufficient permissions to access this page.'));
}
// Get post ID
$post_id = isset($_GET['post_id']) ? intval($_GET['post_id']) : 0;
if (!$post_id) {
wp_die(__('Invalid page ID.'));
}
// Get post
$post = get_post($post_id);
if (!$post) {
wp_die(__('Page not found.'));
}
// Check if raw HTML is enabled
$has_raw_html = get_post_meta($post_id, '_metasync_raw_html_enabled', true);
if (!$has_raw_html) {
wp_die(__('This page is not a raw HTML page.'));
}
// Get HTML content
$html_content = get_post_meta($post_id, '_metasync_raw_html_content', true);
if (empty($html_content)) {
$html_content = '
Start editing...
';
}
// Get label for branding
$label = Metasync::get_whitelabel_company_name() ?: 'SearchAtlas AI';
// Enqueue editor assets
$this->enqueue_editor_assets();
// Render editor UI
include plugin_dir_path(__FILE__) . 'partials/metasync-html-editor-page.php';
}
/**
* Enqueue editor assets (GrapesJS + custom scripts)
*/
private function enqueue_editor_assets()
{
// Font Awesome for icons
wp_enqueue_style(
'font-awesome',
'https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css',
array(),
'6.4.0'
);
// GrapesJS core
wp_enqueue_style(
'grapesjs',
'https://unpkg.com/grapesjs@0.21.7/dist/css/grapes.min.css',
array(),
'0.21.7'
);
wp_enqueue_script(
'grapesjs',
'https://unpkg.com/grapesjs@0.21.7/dist/grapes.min.js',
array(),
'0.21.7',
true
);
// GrapesJS Plugins
wp_enqueue_script(
'grapesjs-blocks-basic',
'https://unpkg.com/grapesjs-blocks-basic',
array('grapesjs'),
null,
true
);
// Custom editor JS (with timestamp for cache busting)
wp_enqueue_script(
'metasync-html-editor',
plugins_url('js/metasync-html-editor.js', __FILE__),
array('jquery', 'grapesjs'),
$this->version . '.' . time(),
true
);
// Custom editor CSS (with timestamp for cache busting)
wp_enqueue_style(
'metasync-html-editor',
plugins_url('css/metasync-html-editor.css', __FILE__),
array('grapesjs'),
$this->version . '.' . time()
);
// Localize script with data
wp_localize_script('metasync-html-editor', 'metasyncEditor', array(
'ajax_url' => admin_url('admin-ajax.php'),
'nonce' => wp_create_nonce('metasync_html_editor'),
'post_id' => isset($_GET['post_id']) ? intval($_GET['post_id']) : 0,
'preview_url' => get_permalink(isset($_GET['post_id']) ? intval($_GET['post_id']) : 0),
'back_url' => admin_url('edit.php?post_type=page'),
'i18n' => array(
'saving' => __('Saving...', 'metasync'),
'saved' => __('Saved!', 'metasync'),
'error' => __('Error saving', 'metasync'),
'confirm_exit' => __('You have unsaved changes. Are you sure you want to leave?', 'metasync'),
)
));
}
/**
* AJAX handler for saving HTML
*/
public function ajax_save_html()
{
// Check nonce
check_ajax_referer('metasync_html_editor', 'nonce');
// Check permissions
if (!current_user_can('edit_pages')) {
wp_send_json_error(array('message' => __('Permission denied', 'metasync')));
}
// Get data
$post_id = isset($_POST['post_id']) ? intval($_POST['post_id']) : 0;
$html_content = isset($_POST['html']) ? wp_kses_post($_POST['html']) : '';
if (!$post_id || empty($html_content)) {
wp_send_json_error(array('message' => __('Invalid data', 'metasync')));
}
// Save HTML content
update_post_meta($post_id, '_metasync_raw_html_content', $html_content);
// Update modified date
wp_update_post(array(
'ID' => $post_id,
'post_modified' => current_time('mysql'),
'post_modified_gmt' => current_time('mysql', 1)
));
wp_send_json_success(array(
'message' => __('Page saved successfully', 'metasync'),
'preview_url' => get_permalink($post_id)
));
}
/**
* AJAX handler for uploading images
*/
public function ajax_upload_image()
{
// Check nonce
check_ajax_referer('metasync_html_editor', 'nonce');
// Check permissions
if (!current_user_can('upload_files')) {
wp_send_json_error(array('message' => __('Permission denied', 'metasync')));
}
// Handle file upload
if (!isset($_FILES['file'])) {
wp_send_json_error(array('message' => __('No file uploaded', 'metasync')));
}
require_once(ABSPATH . 'wp-admin/includes/image.php');
require_once(ABSPATH . 'wp-admin/includes/file.php');
require_once(ABSPATH . 'wp-admin/includes/media.php');
$attachment_id = media_handle_upload('file', 0);
if (is_wp_error($attachment_id)) {
wp_send_json_error(array('message' => $attachment_id->get_error_message()));
}
$image_url = wp_get_attachment_url($attachment_id);
wp_send_json_success(array(
'url' => $image_url,
'id' => $attachment_id
));
}
}