monorepo/native/wordpress/maple-fonts-wp/uninstall.php
2026-01-30 22:33:40 -05:00

123 lines
3.7 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
/**
* Uninstall script for Maple Local Fonts.
*
* This file is executed when the plugin is deleted from WordPress.
* It removes all fonts imported by this plugin and cleans up any data.
*
* @package Maple_Local_Fonts
*/
// If uninstall not called from WordPress, exit.
if (!defined('WP_UNINSTALL_PLUGIN')) {
exit;
}
/**
* Clean up all plugin data on uninstall.
*
* Uses batched processing to prevent memory exhaustion on sites with many fonts.
*/
function mlf_uninstall() {
$font_dir = wp_get_font_dir();
$batch_size = 50; // Process 50 fonts at a time to prevent memory issues
$processed = 0;
$max_iterations = 100; // Safety limit: max 5000 fonts (100 × 50)
// Process fonts in batches
for ($i = 0; $i < $max_iterations; $i++) {
$fonts = get_posts([
'post_type' => 'wp_font_family',
'posts_per_page' => $batch_size,
'post_status' => 'any',
'meta_key' => '_mlf_imported',
'meta_value' => '1',
'fields' => 'ids', // Only get IDs for memory efficiency
]);
// No more fonts to process
if (empty($fonts)) {
break;
}
// Get all font faces for this batch in a single query
$all_faces = get_posts([
'post_type' => 'wp_font_face',
'posts_per_page' => $batch_size * 20, // Max ~20 faces per font
'post_status' => 'any',
'post_parent__in' => $fonts,
]);
// Delete font face files and posts
foreach ($all_faces as $face) {
$settings = json_decode($face->post_content, true);
if (isset($settings['src'])) {
// Convert file:. URL to path
$src = $settings['src'];
$src = str_replace('file:./', '', $src);
$file_path = trailingslashit($font_dir['path']) . basename($src);
// Validate path and extension before deletion
if (mlf_uninstall_validate_font_path($file_path, $font_dir)
&& pathinfo($file_path, PATHINFO_EXTENSION) === 'woff2'
&& file_exists($file_path)) {
wp_delete_file($file_path);
}
}
wp_delete_post($face->ID, true);
}
// Delete family posts
foreach ($fonts as $font_id) {
wp_delete_post($font_id, true);
}
$processed += count($fonts);
// Free memory
unset($fonts, $all_faces);
// If we got fewer than batch_size, we're done
if (count($fonts) < $batch_size) {
break;
}
}
// Clear caches
delete_transient('wp_font_library_fonts');
delete_transient('mlf_imported_fonts_list');
}
/**
* Validate that a path is within the WordPress fonts directory.
*
* @param string $path Full path to validate.
* @param array $font_dir Font directory info.
* @return bool True if path is safe, false otherwise.
*/
function mlf_uninstall_validate_font_path($path, $font_dir) {
$fonts_path = wp_normalize_path(trailingslashit($font_dir['path']));
// Resolve to real path (handles ../ etc)
$real_path = realpath($path);
// If realpath fails, file doesn't exist yet - validate the directory
if ($real_path === false) {
$dir = dirname($path);
$real_dir = realpath($dir);
if ($real_dir === false) {
return false;
}
$real_path = wp_normalize_path($real_dir . '/' . basename($path));
} else {
$real_path = wp_normalize_path($real_path);
}
// Must be within fonts directory
return strpos($real_path, $fonts_path) === 0;
}
// Run uninstall
mlf_uninstall();