init_hooks();
}
/**
* Initialize all hooks
*/
private function init_hooks() {
// Post/page update hooks
add_action('save_post', array($this, 'on_save_post'), 20, 3);
add_action('delete_post', array($this, 'on_delete_post'), 10);
add_action('trash_post', array($this, 'on_delete_post'), 10);
add_action('transition_post_status', array($this, 'on_status_change'), 10, 3);
// Comment hooks
add_action('comment_post', array($this, 'on_comment_change'), 10, 2);
add_action('edit_comment', array($this, 'on_comment_edit'), 10);
add_action('delete_comment', array($this, 'on_comment_delete'), 10);
add_action('wp_set_comment_status', array($this, 'on_comment_status_change'), 10, 2);
// Global change hooks - clear entire cache
add_action('switch_theme', array($this, 'on_global_change'));
add_action('customize_save_after', array($this, 'on_global_change'));
add_action('update_option_sidebars_widgets', array($this, 'on_global_change'));
add_action('wp_update_nav_menu', array($this, 'on_global_change'));
// Plugin/theme update hooks - regenerate after other plugins update, skip for this plugin
add_action('upgrader_process_complete', array($this, 'on_plugin_update'), 10, 2);
// WooCommerce hooks (if active)
add_action('woocommerce_product_set_stock', array($this, 'on_woo_product_change'));
add_action('woocommerce_variation_set_stock', array($this, 'on_woo_product_change'));
// Admin bar indicator for cache status
add_action('admin_bar_menu', array($this, 'add_admin_bar_indicator'), 100);
add_action('wp_head', array($this, 'admin_bar_styles'));
add_action('admin_head', array($this, 'admin_bar_styles'));
add_action('wp_footer', array($this, 'admin_bar_scripts'));
add_action('admin_footer', array($this, 'admin_bar_scripts'));
// AJAX handlers for admin bar actions
add_action('wp_ajax_wp_to_html_adminbar_clear', array($this, 'ajax_adminbar_clear'));
add_action('wp_ajax_wp_to_html_adminbar_regenerate', array($this, 'ajax_adminbar_regenerate'));
add_action('wp_ajax_wp_to_html_adminbar_regenerate_page', array($this, 'ajax_adminbar_regenerate_page'));
add_action('wp_ajax_wp_to_html_adminbar_clear_regenerate', array($this, 'ajax_adminbar_clear_regenerate'));
}
/**
* Handle post save
*
* @param int $post_id Post ID
* @param WP_Post $post Post object
* @param bool $update Whether this is an update
*/
public function on_save_post($post_id, $post, $update) {
// Don't process revisions
if (wp_is_post_revision($post_id)) {
return;
}
// Don't process autosaves
if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
return;
}
// Only process pages and posts (and custom post types that are public)
$allowed_types = $this->get_allowed_post_types();
if (!in_array($post->post_type, $allowed_types)) {
return;
}
$generator = WP_To_HTML_Generator::get_instance();
// If the post is published, regenerate the cache
if ($post->post_status === 'publish') {
// Schedule regeneration to run after all other save operations
wp_schedule_single_event(time() + 5, 'wp_to_html_regenerate_post', array($post_id));
} else {
// Post is not published, delete the cache
$generator->delete_cache($post_id);
}
}
/**
* Handle post deletion
*
* @param int $post_id Post ID
*/
public function on_delete_post($post_id) {
$generator = WP_To_HTML_Generator::get_instance();
$generator->delete_cache($post_id);
}
/**
* Handle post status transitions
*
* @param string $new_status New status
* @param string $old_status Old status
* @param WP_Post $post Post object
*/
public function on_status_change($new_status, $old_status, $post) {
$generator = WP_To_HTML_Generator::get_instance();
// If unpublishing, delete cache
if ($old_status === 'publish' && $new_status !== 'publish') {
$generator->delete_cache($post->ID);
}
// If publishing, generate cache
if ($new_status === 'publish' && $old_status !== 'publish') {
wp_schedule_single_event(time() + 5, 'wp_to_html_regenerate_post', array($post->ID));
}
}
/**
* Handle new comment
*
* @param int $comment_id Comment ID
* @param int|string $comment_approved Approval status
*/
public function on_comment_change($comment_id, $comment_approved) {
$comment = get_comment($comment_id);
if ($comment) {
$generator = WP_To_HTML_Generator::get_instance();
$generator->delete_cache($comment->comment_post_ID);
}
}
/**
* Handle comment edit
*
* @param int $comment_id Comment ID
*/
public function on_comment_edit($comment_id) {
$comment = get_comment($comment_id);
if ($comment) {
$generator = WP_To_HTML_Generator::get_instance();
$generator->delete_cache($comment->comment_post_ID);
}
}
/**
* Handle comment deletion
*
* @param int $comment_id Comment ID
*/
public function on_comment_delete($comment_id) {
$comment = get_comment($comment_id);
if ($comment) {
$generator = WP_To_HTML_Generator::get_instance();
$generator->delete_cache($comment->comment_post_ID);
}
}
/**
* Handle comment status change
*
* @param int $comment_id Comment ID
* @param string $status New status
*/
public function on_comment_status_change($comment_id, $status) {
$comment = get_comment($comment_id);
if ($comment) {
$generator = WP_To_HTML_Generator::get_instance();
$generator->delete_cache($comment->comment_post_ID);
}
}
/**
* Handle global changes that affect all pages
*/
public function on_global_change() {
$generator = WP_To_HTML_Generator::get_instance();
$generator->clear_all_cache();
}
/**
* Handle plugin/theme updates
*
* Regenerates cache when other plugins are updated, but skips when this plugin is updated
*
* @param WP_Upgrader $upgrader Upgrader instance
* @param array $options Update options including type and plugins
*/
public function on_plugin_update($upgrader, $options) {
// Only handle plugin updates
if (!isset($options['type']) || $options['type'] !== 'plugin') {
return;
}
// Get the list of plugins being updated
$plugins = array();
if (isset($options['plugins'])) {
$plugins = (array) $options['plugins'];
} elseif (isset($options['plugin'])) {
$plugins = array($options['plugin']);
}
// Check if our plugin is in the update list
$our_plugin = 'WP-to-HTML/wp-to-html.php';
$our_plugin_alt = plugin_basename(WP_TO_HTML_PLUGIN_DIR . 'wp-to-html.php');
foreach ($plugins as $plugin) {
if ($plugin === $our_plugin || $plugin === $our_plugin_alt) {
// This plugin is being updated - don't clear or regenerate
return;
}
}
// Other plugins are being updated - clear cache and regenerate
$generator = WP_To_HTML_Generator::get_instance();
$generator->clear_all_cache();
// Set pending status for plugin update regeneration
WP_To_HTML_Cron::set_regeneration_status(array(
'status' => 'pending',
'source' => 'plugin_update',
'started' => time(),
'message' => __('Waiting for plugin update to complete...', 'wp-to-html'),
));
// Schedule regeneration to run after the update completes
wp_schedule_single_event(time() + 10, 'wp_to_html_regenerate_all', array('plugin_update'));
}
/**
* Handle WooCommerce product changes
*
* @param WC_Product $product Product object
*/
public function on_woo_product_change($product) {
// Products are excluded by default, but clear cache just in case
if (is_object($product) && method_exists($product, 'get_id')) {
$generator = WP_To_HTML_Generator::get_instance();
$generator->delete_cache($product->get_id());
}
}
/**
* Get allowed post types for static generation
*
* @return array List of post type slugs
*/
private function get_allowed_post_types() {
$post_types = get_post_types(array(
'public' => true,
), 'names');
// Remove excluded types
$excluded = array('attachment', 'product', 'product_variation');
return array_diff($post_types, $excluded);
}
/**
* Add admin bar indicator for cache status
*
* @param WP_Admin_Bar $admin_bar Admin bar instance
*/
public function add_admin_bar_indicator($admin_bar) {
// Only show for users who can manage options
if (!current_user_can('manage_options')) {
return;
}
$settings = WP_To_HTML::get_settings();
$generator = WP_To_HTML_Generator::get_instance();
// Determine if we're on the frontend viewing a singular page
$is_frontend_singular = !is_admin() && is_singular();
if ($is_frontend_singular) {
// Frontend: Show page-specific status and regenerate option
$post_id = get_the_ID();
if (!$post_id) {
return;
}
$post = get_post($post_id);
// Determine cache status
$exclusion_reason = $generator->should_exclude($post);
$has_cache = $generator->has_cache($post_id);
if (!$settings['enabled']) {
$status = 'disabled';
$icon = '⏸';
$title = __('WP-to-HTML: Disabled', 'wp-to-html');
$color = '#72777c';
} elseif ($exclusion_reason) {
$status = 'excluded';
$icon = '⚠';
$title = sprintf(__('WP-to-HTML: Excluded - %s', 'wp-to-html'), $exclusion_reason);
$color = '#dba617';
} elseif ($has_cache) {
$status = 'cached';
$icon = '⚡';
$title = __('WP-to-HTML: Cached (Static HTML)', 'wp-to-html');
$color = '#00a32a';
} else {
$status = 'not-cached';
$icon = '○';
$title = __('WP-to-HTML: Not Cached Yet', 'wp-to-html');
$color = '#72777c';
}
$admin_bar->add_node(array(
'id' => 'wp-to-html-status',
'title' => '' . $icon . ' ' . esc_html($title) . '',
'href' => admin_url('options-general.php?page=wp-to-html'),
'meta' => array(
'class' => 'wp-to-html-admin-bar-item wp-to-html-status-' . $status,
),
));
// Add submenu items for frontend
$admin_bar->add_node(array(
'id' => 'wp-to-html-settings',
'parent' => 'wp-to-html-status',
'title' => __('⚙️ Settings', 'wp-to-html'),
'href' => admin_url('options-general.php?page=wp-to-html'),
));
// Only show regenerate if not excluded
if (!$exclusion_reason && $settings['enabled']) {
$admin_bar->add_node(array(
'id' => 'wp-to-html-regenerate-page',
'parent' => 'wp-to-html-status',
'title' => __('🔄 Regenerate This Page', 'wp-to-html'),
'href' => '#',
'meta' => array(
'class' => 'wp-to-html-action-regenerate-page',
'onclick' => 'return false;',
'data-post-id' => $post_id,
),
));
}
} else if (is_admin()) {
// Backend: Show global actions
$stats = $generator->get_cache_stats();
$icon = '⚡';
// Don't show "(0 cached)" - only show count if there are cached pages
if ($stats['total_files'] > 0) {
$title = sprintf(__('WP-to-HTML (%d cached)', 'wp-to-html'), $stats['total_files']);
} else {
$title = __('WP-to-HTML', 'wp-to-html');
}
$admin_bar->add_node(array(
'id' => 'wp-to-html-status',
'title' => '' . $icon . ' ' . esc_html($title) . '',
'href' => admin_url('options-general.php?page=wp-to-html'),
'meta' => array(
'class' => 'wp-to-html-admin-bar-item',
),
));
// Add submenu items for backend
$admin_bar->add_node(array(
'id' => 'wp-to-html-settings',
'parent' => 'wp-to-html-status',
'title' => __('⚙️ Settings', 'wp-to-html'),
'href' => admin_url('options-general.php?page=wp-to-html'),
));
$admin_bar->add_node(array(
'id' => 'wp-to-html-clear',
'parent' => 'wp-to-html-status',
'title' => __('🗑️ Clear All Cache', 'wp-to-html'),
'href' => '#',
'meta' => array(
'class' => 'wp-to-html-action-clear',
'onclick' => 'return false;',
),
));
$admin_bar->add_node(array(
'id' => 'wp-to-html-regenerate',
'parent' => 'wp-to-html-status',
'title' => __('🔄 Regenerate All', 'wp-to-html'),
'href' => '#',
'meta' => array(
'class' => 'wp-to-html-action-regenerate',
'onclick' => 'return false;',
),
));
$admin_bar->add_node(array(
'id' => 'wp-to-html-clear-regenerate',
'parent' => 'wp-to-html-status',
'title' => __('✨ Clear & Regenerate All', 'wp-to-html'),
'href' => '#',
'meta' => array(
'class' => 'wp-to-html-action-clear-regenerate',
'onclick' => 'return false;',
),
));
}
}
/**
* Add admin bar styles for the cache indicator
*/
public function admin_bar_styles() {
if (!is_admin_bar_showing() || !current_user_can('manage_options')) {
return;
}
?>
clear_all_cache();
wp_send_json_success(array(
'message' => __('Cache cleared successfully', 'wp-to-html'),
));
}
/**
* AJAX handler for regenerating all from admin bar
*/
public function ajax_adminbar_regenerate() {
check_ajax_referer('wp_to_html_adminbar', 'nonce');
if (!current_user_can('manage_options')) {
wp_send_json_error(__('Permission denied', 'wp-to-html'));
}
// Set initial status
WP_To_HTML_Cron::set_regeneration_status(array(
'status' => 'running',
'source' => 'admin_bar',
'started' => time(),
'total' => 0,
'processed' => 0,
'converted' => 0,
'skipped' => 0,
'errors' => 0,
));
$bulk = WP_To_HTML_Bulk::get_instance();
$results = $bulk->convert_all();
// Set complete status
WP_To_HTML_Cron::set_regeneration_status(array(
'status' => 'complete',
'source' => 'admin_bar',
'completed' => time(),
'total' => $results['total'],
'processed' => $results['total'],
'converted' => $results['converted'],
'skipped' => $results['skipped'],
'errors' => $results['errors'],
));
wp_send_json_success(array(
'message' => __('Regeneration complete', 'wp-to-html'),
'converted' => $results['converted'],
'skipped' => $results['skipped'],
'errors' => $results['errors'],
));
}
/**
* AJAX handler for regenerating a single page from admin bar
*/
public function ajax_adminbar_regenerate_page() {
check_ajax_referer('wp_to_html_adminbar', 'nonce');
if (!current_user_can('manage_options')) {
wp_send_json_error(__('Permission denied', 'wp-to-html'));
}
$post_id = isset($_POST['post_id']) ? intval($_POST['post_id']) : 0;
if (!$post_id) {
wp_send_json_error(__('Invalid post ID', 'wp-to-html'));
}
$generator = WP_To_HTML_Generator::get_instance();
$result = $generator->generate($post_id);
if (is_wp_error($result)) {
wp_send_json_error($result->get_error_message());
}
wp_send_json_success(array(
'message' => __('Page regenerated successfully', 'wp-to-html'),
));
}
/**
* AJAX handler for clearing cache and regenerating all from admin bar
*/
public function ajax_adminbar_clear_regenerate() {
check_ajax_referer('wp_to_html_adminbar', 'nonce');
if (!current_user_can('manage_options')) {
wp_send_json_error(__('Permission denied', 'wp-to-html'));
}
// First clear the cache
$generator = WP_To_HTML_Generator::get_instance();
$generator->clear_all_cache();
// Then regenerate all
$bulk = WP_To_HTML_Bulk::get_instance();
$results = $bulk->convert_all();
wp_send_json_success(array(
'message' => __('Cache cleared and regeneration complete', 'wp-to-html'),
'converted' => $results['converted'],
'skipped' => $results['skipped'],
'errors' => $results['errors'],
));
}
}
// Register the scheduled event handlers
add_action('wp_to_html_regenerate_post', function($post_id) {
$generator = WP_To_HTML_Generator::get_instance();
$generator->generate($post_id);
});
// Register handler for regenerating all pages after plugin updates
add_action('wp_to_html_regenerate_all', function($source = 'plugin_update') {
// Set running status
WP_To_HTML_Cron::set_regeneration_status(array(
'status' => 'running',
'source' => $source,
'started' => time(),
'total' => 0,
'processed' => 0,
'converted' => 0,
'skipped' => 0,
'errors' => 0,
));
$bulk = WP_To_HTML_Bulk::get_instance();
$results = $bulk->convert_all();
// Set complete status
WP_To_HTML_Cron::set_regeneration_status(array(
'status' => 'complete',
'source' => $source,
'completed' => time(),
'total' => $results['total'],
'processed' => $results['total'],
'converted' => $results['converted'],
'skipped' => $results['skipped'],
'errors' => $results['errors'],
));
});