| Current File : /home/digitaw/www/wp-content/plugins/simple-history/dropins/class-import-dropin.php |
<?php
namespace Simple_History\Dropins;
use Simple_History\Existing_Data_Importer;
use Simple_History\Helpers;
use Simple_History\Menu_Page;
use Simple_History\Services\Admin_Pages;
use Simple_History\Services\Auto_Backfill_Service;
use Simple_History\Services\Import_Handler;
/**
* Dropin Name: Backfill
* Dropin Description: Adds a tab with backfill options under the Tools menu to generate history from existing WordPress data
* Dropin URI: https://simple-history.com/
* Author: Pär Thernström
*/
class Import_Dropin extends Dropin {
/** @var string Slug for the backfill menu tab. */
const MENU_SLUG = 'simple_history_tools_backfill';
/**
* @inheritdoc
*/
public function loaded() {
add_action( 'admin_menu', array( $this, 'add_menu' ), 31 );
}
/**
* Add backfill subtab under Tools > Tools tab.
*/
public function add_menu() {
if ( ! Helpers::setting_show_as_menu_page() ) {
return;
}
$admin_page_location = Helpers::get_menu_page_location();
// Determine parent based on location.
// When location is 'top' or 'bottom', use the Tools main tab object.
// When inside dashboard/tools, use the Tools menu page slug directly.
if ( in_array( $admin_page_location, [ 'top', 'bottom' ], true ) ) {
$tools_parent = Tools_Menu_Dropin::get_tools_main_tab();
if ( ! $tools_parent ) {
$tools_parent = Tools_Menu_Dropin::TOOLS_TAB_SLUG;
}
} else {
$tools_parent = Tools_Menu_Dropin::MENU_SLUG;
}
// Build menu title with New badge.
$menu_title = _x( 'Backfill', 'backfill subtab name', 'simple-history' )
. ' <span class="sh-Badge sh-Badge--new">' . esc_html__( 'New', 'simple-history' ) . '</span>';
( new Menu_Page() )
->set_page_title( _x( 'Backfill History', 'backfill subtab title', 'simple-history' ) )
->set_menu_title( $menu_title )
->set_menu_slug( self::MENU_SLUG )
->set_callback( [ $this, 'output_backfill_page' ] )
->set_order( 3 )
->set_parent( $tools_parent )
->add();
}
/**
* Output for the backfill tab on the tools page.
*
* In the free version, this shows:
* - Auto-backfill status information
* - Premium upsell for manual backfill functionality
*
* Premium users get the full backfill GUI via the premium dropin.
*/
public function output_backfill_page() {
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
echo Admin_Pages::header_output();
$auto_backfill_status = Auto_Backfill_Service::get_status();
$retention_days = Helpers::get_clear_history_interval();
// Get total backfilled events count.
$importer = new Existing_Data_Importer( $this->simple_history );
$backfilled_events_count = $importer->get_backfilled_events_count();
// Check if delete was just completed.
// phpcs:ignore WordPress.Security.NonceVerification.Recommended
$delete_completed = isset( $_GET['delete-completed'] ) && $_GET['delete-completed'] === '1';
// phpcs:ignore WordPress.Security.NonceVerification.Recommended
$events_deleted = isset( $_GET['events-deleted'] ) ? intval( $_GET['events-deleted'] ) : 0;
// Check if re-run was just scheduled.
// phpcs:ignore WordPress.Security.NonceVerification.Recommended
$rerun_scheduled = isset( $_GET['rerun-scheduled'] ) && $_GET['rerun-scheduled'] === '1';
?>
<div class="wrap">
<?php
echo wp_kses(
Helpers::get_settings_section_title_output(
__( 'Backfill history', 'simple-history' ),
'sync_arrow_down'
),
array(
'span' => array(
'class' => array(),
),
)
);
?>
<?php
if ( $delete_completed ) {
?>
<div class="notice notice-success is-dismissible">
<p>
<strong><?php esc_html_e( 'Delete completed!', 'simple-history' ); ?></strong><br>
<?php
printf(
/* translators: %d: Number of events deleted */
esc_html__( 'Deleted %d backfilled events.', 'simple-history' ),
(int) $events_deleted
);
?>
</p>
</div>
<?php
}
if ( $rerun_scheduled ) {
?>
<div class="notice notice-success is-dismissible">
<p>
<strong><?php esc_html_e( 'Auto-backfill scheduled!', 'simple-history' ); ?></strong><br>
<?php esc_html_e( 'The automatic backfill has been scheduled and will run shortly.', 'simple-history' ); ?>
</p>
</div>
<?php
}
?>
<p>
<?php
esc_html_e(
'Backfill generates history entries from existing WordPress data. This scans your posts, pages, and users to create log entries based on their creation and modification dates.',
'simple-history'
);
?>
</p>
<p>
<?php
esc_html_e(
'Note: Backfilled entries contain basic information and are less detailed than events logged in real-time, which capture the full context of each action.',
'simple-history'
);
?>
</p>
<p>
<strong>
<?php
printf(
/* translators: %s: Number of backfilled events */
esc_html__( 'Currently %s backfilled events in the history log.', 'simple-history' ),
'<code>' . esc_html( number_format_i18n( $backfilled_events_count ) ) . '</code>'
);
?>
</strong>
</p>
<div class="sh-SettingsCard">
<h3 class="sh-SettingsCard-title"><?php esc_html_e( 'Automatic Backfill', 'simple-history' ); ?></h3>
<p>
<?php
printf(
/* translators: %d: Number of items limit */
esc_html__( 'On fresh installations, Simple History automatically backfills history from existing content, limited to %d items per content type.', 'simple-history' ),
(int) Auto_Backfill_Service::DEFAULT_LIMIT
);
?>
</p>
<?php
$is_cron_scheduled = wp_next_scheduled( Auto_Backfill_Service::CRON_HOOK );
$has_auto_backfill_run = $auto_backfill_status && ! empty( $auto_backfill_status['completed'] );
$is_existing_site = ! $has_auto_backfill_run && ! $is_cron_scheduled;
if ( $has_auto_backfill_run ) {
// Date is stored in GMT, append UTC so strtotime interprets it correctly.
$completed_timestamp = strtotime( $auto_backfill_status['completed_at'] . ' UTC' );
$completed_date = wp_date(
get_option( 'date_format' ) . ' ' . get_option( 'time_format' ),
$completed_timestamp
);
?>
<div class="sh-StatusBox sh-StatusBox--success">
<p>
<strong>
<?php
printf(
/* translators: %s: Date and time */
esc_html__( 'Auto-backfill completed on %s', 'simple-history' ),
esc_html( $completed_date )
);
?>
</strong>
</p>
<ul>
<li>
<?php
printf(
/* translators: %d: Number of events */
esc_html__( 'Post events created: %d', 'simple-history' ),
(int) ( $auto_backfill_status['post_events_created'] ?? 0 )
);
?>
</li>
<li>
<?php
printf(
/* translators: %d: Number of events */
esc_html__( 'User events created: %d', 'simple-history' ),
(int) ( $auto_backfill_status['user_events_created'] ?? 0 )
);
?>
</li>
</ul>
<p>
<?php esc_html_e( 'Need older content? Use Manual Backfill to import beyond these limits.', 'simple-history' ); ?>
</p>
</div>
<?php
} elseif ( $is_cron_scheduled ) {
?>
<div class="sh-StatusBox sh-StatusBox--warning">
<p>
<?php esc_html_e( 'Auto-backfill is scheduled and will run shortly.', 'simple-history' ); ?>
</p>
</div>
<?php
} elseif ( $is_existing_site ) {
?>
<div class="sh-StatusBox sh-StatusBox--info">
<p>
<?php esc_html_e( 'Auto-backfill did not run because Simple History was installed before this feature was added. Use Manual Backfill below to import existing content.', 'simple-history' ); ?>
</p>
</div>
<?php
}
?>
</div>
<div class="sh-SettingsCard">
<h3 class="sh-SettingsCard-title"><?php esc_html_e( 'Manual Backfill', 'simple-history' ); ?></h3>
<p>
<?php
esc_html_e(
'Manual backfill lets you generate history entries from all public post types (posts, pages, and custom post types), attachments, and users.',
'simple-history'
);
?>
</p>
<p>
<?php
esc_html_e(
'Unlike the automatic backfill, there are no limits on date range or number of items.',
'simple-history'
);
?>
</p>
<?php
/**
* Action hook for adding manual backfill controls.
*
* Premium add-on hooks here to add its backfill GUI.
*
* @param Import_Dropin $dropin The import dropin instance.
* @param int $retention_days The retention days setting.
*/
do_action( 'simple_history/backfill/manual_backfill_section', $this, $retention_days );
/**
* Filter whether to show the premium teaser for manual backfill.
*
* Premium add-on returns false to hide this teaser since it provides the full GUI.
*
* @param bool $show_teaser Whether to show the premium teaser. Default true.
*/
$show_premium_teaser = apply_filters( 'simple_history/backfill/show_premium_teaser', true );
if ( $show_premium_teaser ) {
// Get approximate count of items that could be backfilled.
$preview_importer = new Existing_Data_Importer( $this->simple_history );
$preview_counts = $preview_importer->get_preview_counts();
$total_items_count = array_sum( $preview_counts['post_types'] ) + $preview_counts['users'];
echo wp_kses_post(
Helpers::get_premium_feature_teaser(
sprintf(
/* translators: %s: Number of items */
__( 'Import %s Missing Events', 'simple-history' ),
number_format_i18n( $total_items_count )
),
[
__( 'Import anytime, not just on first install', 'simple-history' ),
__( 'Choose content types: posts, pages, users, attachments', 'simple-history' ),
__( 'No item limits – recover your complete history', 'simple-history' ),
],
'premium_backfill_tools',
__( 'Import Full History', 'simple-history' )
)
);
}
?>
</div>
<?php
$this->output_backfill_page_dev_tools( $retention_days );
?>
</div>
<?php
}
/**
* Output developer tools section for the backfill page.
*
* Only visible when dev mode is enabled. Provides tools for:
* - Deleting all backfilled data
* - Re-running the automatic backfill
*
* @param int $retention_days The retention days setting.
*/
public function output_backfill_page_dev_tools( $retention_days ) {
if ( ! Helpers::dev_mode_is_enabled() ) {
return;
}
$importer = new Existing_Data_Importer( $this->simple_history );
$backfilled_events_count = $importer->get_backfilled_events_count();
?>
<div class="sh-DevToolsBox">
<h3 class="sh-DevToolsBox-heading">
<span class="dashicons dashicons-admin-tools"></span>
<?php esc_html_e( 'Developer Tools', 'simple-history' ); ?>
</h3>
<p class="description sh-DevToolsBox-description">
<?php esc_html_e( 'These tools are only visible when dev mode is enabled. Use them to test and debug the backfill functionality.', 'simple-history' ); ?>
</p>
<h4 class="sh-DevToolsBox-section">
<?php esc_html_e( 'Delete backfilled data', 'simple-history' ); ?>
</h4>
<p>
<?php
esc_html_e(
'Remove all backfilled entries from the history log. This is useful for testing or if you want to re-run the backfill with different settings.',
'simple-history'
);
?>
</p>
<p>
<?php
printf(
/* translators: %s: number of backfilled events */
esc_html__( 'Currently there are %s backfilled events in the log.', 'simple-history' ),
'<strong>' . esc_html( number_format_i18n( $backfilled_events_count ) ) . '</strong>'
);
?>
</p>
<p class="description">
<?php
printf(
/* translators: %s: context key name */
esc_html__( 'Backfilled events are identified by the %s context key that is added when events are created during backfill.', 'simple-history' ),
'<code>' . esc_html( Existing_Data_Importer::BACKFILLED_CONTEXT_KEY ) . '</code>'
);
?>
</p>
<?php
if ( $backfilled_events_count > 0 ) {
?>
<p class="description sh-DevToolsBox-warning">
<strong><?php esc_html_e( 'Warning:', 'simple-history' ); ?></strong>
<?php esc_html_e( 'This action cannot be undone. Only backfilled entries will be deleted. Naturally logged events will not be affected.', 'simple-history' ); ?>
</p>
<form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" onsubmit="return confirm('<?php echo esc_js( __( 'Are you sure you want to delete all backfilled entries? This action cannot be undone.', 'simple-history' ) ); ?>');">
<?php wp_nonce_field( Import_Handler::DELETE_ACTION_NAME, 'simple_history_delete_nonce' ); ?>
<input type="hidden" name="action" value="<?php echo esc_attr( Import_Handler::DELETE_ACTION_NAME ); ?>">
<?php submit_button( __( 'Delete Backfilled Data', 'simple-history' ), 'delete', 'submit', false ); ?>
</form>
<?php
}
?>
<h4 class="sh-DevToolsBox-section sh-DevToolsBox-section--bordered">
<?php esc_html_e( 'Re-run automatic backfill', 'simple-history' ); ?>
</h4>
<p>
<?php
esc_html_e(
'Reset the auto-backfill status and schedule it to run again. This is useful for testing or after deleting backfilled data.',
'simple-history'
);
?>
</p>
<?php
// Get preview of what would be imported.
// Use the same post types as Auto_Backfill_Service.
$preview_post_types = get_post_types( [ 'public' => true ], 'names' );
$preview_post_types[] = 'attachment';
/**
* Filter the post types to preview for auto-backfill.
*
* @param array $preview_post_types Post types to preview.
*/
$preview_post_types = apply_filters( 'simple_history/auto_backfill/post_types', $preview_post_types );
$preview = $importer->get_auto_backfill_preview(
[
'post_types' => $preview_post_types,
'include_users' => true,
'limit' => Auto_Backfill_Service::DEFAULT_LIMIT,
'days_back' => $retention_days,
]
);
?>
<details class="sh-PreviewDetails">
<summary>
<?php
printf(
/* translators: %d: Number of events that would be created */
esc_html__( 'Preview: %d events would be created', 'simple-history' ),
(int) $preview['total']
);
?>
</summary>
<p class="description sh-PreviewDetails-description">
<?php
printf(
/* translators: 1: Number of days, 2: Limit per type */
esc_html__( 'Date range: last %1$d days. Limit: %2$d per type.', 'simple-history' ),
(int) $preview['days_back'],
(int) $preview['limit_per_type']
);
?>
</p>
<table class="widefat striped sh-tableAuto">
<thead>
<tr>
<th><?php esc_html_e( 'Type', 'simple-history' ); ?></th>
<th class="sh-textRight"><?php esc_html_e( 'Available', 'simple-history' ); ?></th>
<th class="sh-textRight"><?php esc_html_e( 'Already logged', 'simple-history' ); ?></th>
<th class="sh-textRight"><?php esc_html_e( 'Events to create', 'simple-history' ); ?></th>
</tr>
</thead>
<tbody>
<?php
foreach ( $preview['post_types'] as $type_name => $type_data ) {
?>
<tr>
<td><?php echo esc_html( $type_data['label'] ); ?></td>
<td class="sh-textRight"><?php echo esc_html( number_format_i18n( $type_data['available'] ) ); ?></td>
<td class="sh-textRight"><?php echo esc_html( number_format_i18n( $type_data['already_logged'] ) ); ?></td>
<td class="sh-textRight"><strong><?php echo esc_html( number_format_i18n( $type_data['would_import'] ) ); ?></strong></td>
</tr>
<?php
}
if ( is_array( $preview['users'] ) ) {
?>
<tr>
<td><?php esc_html_e( 'Users', 'simple-history' ); ?></td>
<td class="sh-textRight"><?php echo esc_html( number_format_i18n( $preview['users']['available'] ) ); ?></td>
<td class="sh-textRight"><?php echo esc_html( number_format_i18n( $preview['users']['already_logged'] ) ); ?></td>
<td class="sh-textRight"><strong><?php echo esc_html( number_format_i18n( $preview['users']['would_import'] ) ); ?></strong></td>
</tr>
<?php
}
?>
</tbody>
<tfoot>
<tr>
<th><?php esc_html_e( 'Total', 'simple-history' ); ?></th>
<th colspan="2"></th>
<th class="sh-textRight"><strong><?php echo esc_html( number_format_i18n( $preview['total'] ) ); ?></strong></th>
</tr>
</tfoot>
</table>
</details>
<form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>">
<?php wp_nonce_field( Import_Handler::RERUN_ACTION_NAME, 'simple_history_rerun_nonce' ); ?>
<input type="hidden" name="action" value="<?php echo esc_attr( Import_Handler::RERUN_ACTION_NAME ); ?>">
<?php submit_button( __( 'Re-run Auto Backfill', 'simple-history' ), 'secondary', 'submit', false ); ?>
</form>
</div>
<?php
}
}