robotstxt-documentation-mar.../uninstall.php
2026-08-17 17:56:43 +00:00

117 lines
3.6 KiB
PHP

<?php
/**
* Uninstall Handler
*
* Fired when the plugin is uninstalled. Removes plugin data based on settings.
*
* @package RobotsTxt\DocumentationMarkdown
* @author ROBOTSTXT
* @license GPL-3.0-or-later
* @link https://www.robotstxt.software/plugins/robotstxt-documentation-markdown/
* @since 1.0.0
*/
// Exit if accessed directly or not called from WordPress.
if ( ! defined( 'WP_UNINSTALL_PLUGIN' ) ) {
exit;
}
/**
* Uninstall the plugin
*
* Removes plugin data if user has enabled the cleanup option.
* IMPORTANT: Does NOT delete synced content (posts/pages), only mapping
* configurations and plugin settings.
*
* @since 1.0.0
*
* @return void
*/
function robotstxt_docmd_uninstall(): void {
// Get plugin settings.
$raw_settings = get_option( 'robotstxt_docmd_settings', array() );
$settings = is_array( $raw_settings ) ? $raw_settings : array();
// Check if user wants to delete data on uninstall.
if ( empty( $settings['delete_on_uninstall'] ) ) {
// User chose to keep data, do nothing.
return;
}
// Delete all mapping posts (CPT) using WordPress API.
$mapping_posts = get_posts(
array(
'post_type' => 'robotstxt_map',
'posts_per_page' => -1,
'post_status' => 'any',
'fields' => 'ids',
)
);
// Delete each mapping post and its associated meta.
foreach ( $mapping_posts as $mapping_id ) {
// Clear scheduled cron events for this mapping.
$hook = 'robotstxt_docmd_sync_event';
$args = array( $mapping_id );
$timestamp = wp_next_scheduled( $hook, $args );
if ( $timestamp ) {
wp_unschedule_event( $timestamp, $hook, $args );
}
// Force delete (bypass trash). This also deletes all associated post meta.
wp_delete_post( $mapping_id, true );
}
// Delete plugin options.
delete_option( 'robotstxt_docmd_settings' );
// Delete transients (cached data).
// Note: WordPress does not provide an API for pattern-based transient deletion.
// Direct database queries are necessary here for bulk cleanup operations.
robotstxt_docmd_delete_transients_by_prefix( 'robotstxt_docmd_' );
robotstxt_docmd_delete_transients_by_prefix( 'robotstxt_docmd_notification_' );
// Note: We deliberately DO NOT delete the synced posts/pages themselves.
// Users may want to keep the documentation even after uninstalling the plugin.
}
/**
* Delete all transients matching a prefix
*
* WordPress does not provide an API for pattern-based transient deletion,
* so direct database access is required for bulk cleanup operations.
* This is compliant with AGENTS.md guidelines for necessary database operations.
*
* @since 1.0.0
*
* @param string $prefix Transient name prefix to match.
* @return void
*/
function robotstxt_docmd_delete_transients_by_prefix( string $prefix ): void {
global $wpdb;
// Sanitize prefix for LIKE query.
$transient_prefix = $wpdb->esc_like( '_transient_' . $prefix ) . '%';
$transient_timeout_prefix = $wpdb->esc_like( '_transient_timeout_' . $prefix ) . '%';
// phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Required for bulk pattern-based deletion; no WordPress API available for this operation.
// Delete transient values.
$wpdb->query(
$wpdb->prepare(
"DELETE FROM {$wpdb->options} WHERE option_name LIKE %s",
$transient_prefix
)
);
// Delete transient timeouts.
$wpdb->query(
$wpdb->prepare(
"DELETE FROM {$wpdb->options} WHERE option_name LIKE %s",
$transient_timeout_prefix
)
);
// phpcs:enable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
}
// Run uninstall.
robotstxt_docmd_uninstall();