default_settings());
}
}
public function default_settings(): array {
return [
'auto_resize' => 1,
'webp' => 0,
'keep_original' => 1,
'presets' => [
['name' => 'Card Thumbnail', 'slug' => 'card-thumb', 'width' => 480, 'height' => 320, 'crop' => 1],
['name' => 'Content Medium', 'slug' => 'content-medium', 'width' => 960, 'height' => 0, 'crop' => 0],
['name' => 'Hero Banner', 'slug' => 'hero-banner', 'width' => 1600, 'height' => 900, 'crop' => 1],
['name' => 'Square Social', 'slug' => 'square-social', 'width' => 1080, 'height' => 1080, 'crop' => 1],
],
];
}
public function get_settings(): array {
$settings = get_option(self::OPTION, []);
return wp_parse_args(is_array($settings) ? $settings : [], $this->default_settings());
}
public function admin_menu(): void {
add_media_page(
__('Smart Image Resizer', 'smart-image-resizer'),
__('Image Resizer', 'smart-image-resizer'),
'upload_files',
'smart-image-resizer',
[$this, 'render_admin_page']
);
}
public function admin_assets(string $hook): void {
if ($hook !== 'media_page_smart-image-resizer') {
return;
}
wp_enqueue_style('sir-admin', plugin_dir_url(__FILE__) . 'assets/admin.css', [], '0.1.0');
}
public function handle_admin_actions(): void {
if (!is_admin() || empty($_POST['sir_action'])) {
return;
}
if (!current_user_can('upload_files')) {
wp_die(esc_html__('You do not have permission to resize images.', 'smart-image-resizer'));
}
check_admin_referer(self::NONCE_ACTION);
$action = sanitize_key($_POST['sir_action']);
if ($action === 'save_settings') {
$this->save_settings_from_post();
wp_safe_redirect(add_query_arg(['page' => 'smart-image-resizer', 'sir_notice' => 'settings_saved'], admin_url('upload.php')));
exit;
}
if ($action === 'bulk_resize') {
$preset_slug = sanitize_title(wp_unslash($_POST['preset_slug'] ?? ''));
$limit = max(1, min(50, absint($_POST['limit'] ?? 20)));
$result = $this->bulk_resize($preset_slug, $limit);
set_transient('sir_last_bulk_result_' . get_current_user_id(), $result, MINUTE_IN_SECONDS * 5);
wp_safe_redirect(add_query_arg(['page' => 'smart-image-resizer', 'sir_notice' => 'bulk_done'], admin_url('upload.php')));
exit;
}
}
private function save_settings_from_post(): void {
$presets = [];
$names = array_map('sanitize_text_field', wp_unslash($_POST['preset_name'] ?? []));
$slugs = array_map('sanitize_title', wp_unslash($_POST['preset_slug'] ?? []));
$widths = array_map('absint', wp_unslash($_POST['preset_width'] ?? []));
$heights = array_map('absint', wp_unslash($_POST['preset_height'] ?? []));
$crops = isset($_POST['preset_crop']) ? array_map('absint', wp_unslash($_POST['preset_crop'])) : [];
for ($i = 0; $i < 6; $i++) {
$name = trim($names[$i] ?? '');
$slug = sanitize_title($slugs[$i] ?? $name);
$width = $widths[$i] ?? 0;
$height = $heights[$i] ?? 0;
if (!$name || !$slug || $width < 1) {
continue;
}
$presets[] = [
'name' => $name,
'slug' => $slug,
'width' => $width,
'height' => $height,
'crop' => !empty($crops[$i]) ? 1 : 0,
];
}
if (!$presets) {
$presets = $this->default_settings()['presets'];
}
update_option(self::OPTION, [
'auto_resize' => !empty($_POST['auto_resize']) ? 1 : 0,
'webp' => !empty($_POST['webp']) ? 1 : 0,
'keep_original' => 1,
'presets' => $presets,
]);
}
public function render_admin_page(): void {
$settings = $this->get_settings();
$presets = array_values($settings['presets']);
$notice = sanitize_key($_GET['sir_notice'] ?? '');
$last = get_transient('sir_last_bulk_result_' . get_current_user_id());
?>
' . esc_html__('No resize jobs yet. Upload an image or run a bulk job to see activity here.', 'smart-image-resizer') . '';
return;
}
echo '';
foreach (array_slice(array_reverse($logs), 0, 8) as $log) {
printf('- %s%s
', esc_html($log['title'] ?? 'Image'), esc_html($log['message'] ?? 'Resized'));
}
echo '
';
}
public function resize_on_upload(int $attachment_id): void {
$settings = $this->get_settings();
if (empty($settings['auto_resize']) || !wp_attachment_is_image($attachment_id)) {
return;
}
foreach ($settings['presets'] as $preset) {
$this->resize_attachment($attachment_id, $preset, !empty($settings['webp']));
}
}
public function bulk_resize(string $preset_slug, int $limit): array {
$settings = $this->get_settings();
$preset = null;
foreach ($settings['presets'] as $candidate) {
if ($candidate['slug'] === $preset_slug) {
$preset = $candidate;
break;
}
}
if (!$preset) {
return ['resized' => 0, 'skipped' => 0, 'errors' => 1];
}
$ids = get_posts([
'post_type' => 'attachment',
'post_mime_type' => 'image',
'post_status' => 'inherit',
'posts_per_page' => $limit,
'fields' => 'ids',
'orderby' => 'date',
'order' => 'DESC',
]);
$result = ['resized' => 0, 'skipped' => 0, 'errors' => 0];
foreach ($ids as $id) {
$status = $this->resize_attachment((int) $id, $preset, !empty($settings['webp']));
if ($status === true) {
$result['resized']++;
} elseif ($status === 'exists') {
$result['skipped']++;
} else {
$result['errors']++;
}
}
return $result;
}
private function resize_attachment(int $attachment_id, array $preset, bool $make_webp = false) {
$file = get_attached_file($attachment_id);
if (!$file || !file_exists($file)) {
return false;
}
$editor = wp_get_image_editor($file);
if (is_wp_error($editor)) {
return false;
}
$info = pathinfo($file);
$slug = sanitize_title($preset['slug']);
$width = absint($preset['width']);
$height = absint($preset['height']);
$dest = trailingslashit($info['dirname']) . $info['filename'] . '-' . $slug . '-' . $width . 'x' . ($height ?: 'auto') . '.' . strtolower($info['extension']);
$existing = get_post_meta($attachment_id, self::META_KEY, true);
$existing = is_array($existing) ? $existing : [];
if (file_exists($dest)) {
return 'exists';
}
$resized = $editor->resize($width, $height ?: null, !empty($preset['crop']));
if (is_wp_error($resized)) {
return false;
}
$saved = $editor->save($dest);
if (is_wp_error($saved) || empty($saved['path'])) {
return false;
}
$existing[$slug] = [
'path' => $saved['path'],
'file' => wp_basename($saved['path']),
'width' => $saved['width'] ?? $width,
'height' => $saved['height'] ?? $height,
'created' => current_time('mysql'),
];
if ($make_webp && function_exists('imagewebp')) {
$webp_editor = wp_get_image_editor($saved['path']);
if (!is_wp_error($webp_editor)) {
$webp_dest = preg_replace('/\.[^.]+$/', '.webp', $saved['path']);
$webp_saved = $webp_editor->save($webp_dest, 'image/webp');
if (!is_wp_error($webp_saved) && !empty($webp_saved['path'])) {
$existing[$slug]['webp'] = wp_basename($webp_saved['path']);
}
}
}
update_post_meta($attachment_id, self::META_KEY, $existing);
$this->add_log(get_the_title($attachment_id), sprintf('Created %s at %sx%s', $preset['name'], $existing[$slug]['width'], $existing[$slug]['height']));
return true;
}
private function add_log(string $title, string $message): void {
$logs = get_option(self::LOG_OPTION, []);
$logs[] = ['time' => current_time('mysql'), 'title' => $title ?: 'Untitled image', 'message' => $message];
update_option(self::LOG_OPTION, array_slice($logs, -30));
}
}
Smart_Image_Resizer::instance();