Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions assets/admin.css
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,9 @@
width: 0%;
}

/* Simple separators between certain settings rows */
.form-table tr.aviflosu-separator-top th,
.form-table tr.aviflosu-separator-top td { border-top: 1px solid #dcdcde; }

/* removed hr-based separators; using row border class instead */

11 changes: 11 additions & 0 deletions assets/admin.js
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,17 @@
function initAll() {
initTabs();
initStatus();
// Disable/enable schedule time based on checkbox
var scheduleToggle = document.querySelector('#aviflosu_convert_via_schedule');
var scheduleTime = document.querySelector('#aviflosu_schedule_time');
function syncScheduleState() {
if (!scheduleToggle || !scheduleTime) return;
scheduleTime.disabled = !scheduleToggle.checked;
}
if (scheduleToggle && scheduleTime) {
scheduleToggle.addEventListener('change', syncScheduleState);
syncScheduleState();
}

// Convert-now button (AJAX queue + switch to Status with spinner + polling)
var convertBtn = document.querySelector('#avif-local-support-convert-now');
Expand Down
123 changes: 82 additions & 41 deletions includes/class-avif-suite.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ public function init(): void
add_action('admin_enqueue_scripts', [$this, 'enqueue_admin_assets']);
add_filter('plugin_action_links_' . plugin_basename(\AVIFLOSU_PLUGIN_FILE), [$this, 'add_settings_link']);
add_action('admin_post_aviflosu_upload_test', [$this, 'handle_upload_test']);
add_action('admin_post_aviflosu_reset_defaults', [$this, 'handle_reset_defaults']);
add_action('wp_ajax_aviflosu_scan_missing', [$this, 'ajax_scan_missing']);
add_action('wp_ajax_aviflosu_convert_now', [$this, 'ajax_convert_now']);
add_action('wp_ajax_aviflosu_delete_all_avifs', [$this, 'ajax_delete_all_avifs']);
Expand Down Expand Up @@ -148,6 +149,7 @@ function (): void {
. '<input id="aviflosu_enable_support" type="checkbox" name="aviflosu_enable_support" value="1" ' . checked(true, $value, false) . ' /> '
. esc_html__('Add AVIF sources to JPEG images on the front end', 'avif-local-support')
. '</label>';
// spacing handled via CSS row borders
},
'avif-local-support',
'aviflosu_main',
Expand All @@ -168,12 +170,13 @@ function (): void {
$value = (bool) get_option('aviflosu_convert_on_upload', true);
echo '<label for="aviflosu_convert_on_upload">'
. '<input id="aviflosu_convert_on_upload" type="checkbox" name="aviflosu_convert_on_upload" value="1" ' . checked(true, $value, false) . ' /> '
. esc_html__('Recommended; may slow uploads on some servers', 'avif-local-support')
. esc_html__('Convert images to AVIF immediately after upload', 'avif-local-support')
. '</label>';
echo '<p class="description">' . esc_html__('Recommended for completeness; can add a small delay to uploads on some servers.', 'avif-local-support') . '</p>';
},
'avif-local-support',
'aviflosu_conversion',
[ 'label_for' => 'aviflosu_convert_on_upload' ]
[ 'label_for' => 'aviflosu_convert_on_upload', 'class' => 'aviflosu-separator-top' ]
);

add_settings_field(
Expand All @@ -184,9 +187,11 @@ function (): void {
$time = (string) get_option('aviflosu_schedule_time', '01:00');
echo '<label for="aviflosu_convert_via_schedule">'
. '<input id="aviflosu_convert_via_schedule" type="checkbox" name="aviflosu_convert_via_schedule" value="1" ' . checked(true, $enabled, false) . ' /> '
. esc_html__('Scan daily and convert missing AVIFs', 'avif-local-support')
. esc_html__('Daily conversion', 'avif-local-support')
. '</label> ';
echo '<input id="aviflosu_schedule_time" type="time" name="aviflosu_schedule_time" value="' . \esc_attr($time) . '" aria-label="' . esc_attr__('Time', 'avif-local-support') . '" />';
echo ' <a href="#tools" class="button-link">' . esc_html__('Convert missing AVIFs', 'avif-local-support') . '</a>';
echo '<p class="description" style="margin-top:6px;">' . esc_html__('Scan daily and convert JPEGs that are missing AVIFs.', 'avif-local-support') . '</p>';
},
'avif-local-support',
'aviflosu_conversion',
Expand All @@ -204,67 +209,65 @@ function (): void {
},
'avif-local-support',
'aviflosu_conversion',
[ 'label_for' => 'aviflosu_quality' ]
[ 'label_for' => 'aviflosu_quality', 'class' => 'aviflosu-separator-top' ]
);

// New: Speed slider (0-10)
// New: Speed slider (0-8)
add_settings_field(
'avif_local_support_speed',
__('Speed (0–10)', 'avif-local-support'),
__('Speed (0–8)', 'avif-local-support'),
function (): void {
$value = (int) get_option('aviflosu_speed', 1);
$value = max(0, min(10, $value));
echo '<input id="aviflosu_speed" type="range" name="aviflosu_speed" min="0" max="10" value="' . \esc_attr((string) $value) . '" oninput="this.nextElementSibling.innerText=this.value" /> ';
$value = max(0, min(8, $value));
echo '<input id="aviflosu_speed" type="range" name="aviflosu_speed" min="0" max="8" value="' . \esc_attr((string) $value) . '" oninput="this.nextElementSibling.innerText=this.value" /> ';
echo '<span>' . \esc_html((string) $value) . '</span>';
echo '<p class="description">' . esc_html__('Lower = smaller files (slower). Higher = faster (larger files).', 'avif-local-support') . '</p>';
},
'avif-local-support',
'aviflosu_conversion',
[ 'label_for' => 'aviflosu_speed' ]
);

// New: Chroma subsampling (radio)
// Advanced: Group subsampling and bit depth inside disclosure
add_settings_field(
'avif_local_support_subsampling',
__('Chroma subsampling', 'avif-local-support'),
'avif_local_support_advanced',
__('Advanced', 'avif-local-support'),
function (): void {
$value = (string) get_option('aviflosu_subsampling', '420');
$allowed = ['420' => '4:2:0', '422' => '4:2:2', '444' => '4:4:4'];
echo '<fieldset id="aviflosu_subsampling">';
foreach ($allowed as $key => $label) {
$subsampling = (string) get_option('aviflosu_subsampling', '420');
$bitDepth = (string) get_option('aviflosu_bit_depth', '8');
$allowedSub = ['420' => '4:2:0', '422' => '4:2:2', '444' => '4:4:4'];
$allowedBits = ['8' => '8-bit', '10' => '10-bit', '12' => '12-bit'];
echo '<details>';
echo '<summary>' . esc_html__('Chroma subsampling and bit depth', 'avif-local-support') . '</summary>';
echo '<div style="margin-top:8px">';
echo ' <div style="margin-bottom:8px">';
echo ' <label><strong>' . esc_html__('Chroma subsampling', 'avif-local-support') . '</strong></label>';
echo ' <fieldset id="aviflosu_subsampling">';
foreach ($allowedSub as $key => $label) {
$id = 'aviflosu_subsampling_' . $key;
echo '<label for="' . \esc_attr($id) . '" style="margin-right:12px;">';
echo '<input type="radio" name="aviflosu_subsampling" id="' . \esc_attr($id) . '" value="' . \esc_attr($key) . '" ' . checked($key, $value, false) . ' /> ' . \esc_html($label) . '&nbsp;&nbsp;';
echo '<input type="radio" name="aviflosu_subsampling" id="' . \esc_attr($id) . '" value="' . \esc_attr($key) . '" ' . checked($key, $subsampling, false) . ' /> ' . \esc_html($label) . '&nbsp;&nbsp;';
echo '</label>';
}
echo '</fieldset>';
echo '<p class="description">' . esc_html__('4:2:0 is most compatible and smallest; 4:4:4 preserves more color detail.', 'avif-local-support') . '</p>';
},
'avif-local-support',
'aviflosu_conversion',
[ 'label_for' => 'aviflosu_subsampling' ]
);

// New: Bit depth (radio)
add_settings_field(
'avif_local_support_bit_depth',
__('Bit depth', 'avif-local-support'),
function (): void {
$value = (string) get_option('aviflosu_bit_depth', '8');
$allowed = ['8' => '8-bit', '10' => '10-bit', '12' => '12-bit'];
echo '<fieldset id="aviflosu_bit_depth">';
foreach ($allowed as $key => $label) {
echo ' </fieldset>';
echo ' <p class="description">' . esc_html__('4:2:0 is most compatible and smallest; 4:4:4 preserves more color detail.', 'avif-local-support') . '</p>';
echo ' </div>';
echo ' <div>';
echo ' <label><strong>' . esc_html__('Bit depth', 'avif-local-support') . '</strong></label>';
echo ' <fieldset id="aviflosu_bit_depth">';
foreach ($allowedBits as $key => $label) {
$id = 'aviflosu_bit_depth_' . $key;
echo '<label for="' . \esc_attr($id) . '" style="margin-right:12px;">';
echo '<input type="radio" name="aviflosu_bit_depth" id="' . \esc_attr($id) . '" value="' . \esc_attr($key) . '" ' . checked($key, $value, false) . ' /> ' . \esc_html($label) . '&nbsp;&nbsp;';
echo '<input type="radio" name="aviflosu_bit_depth" id="' . \esc_attr($id) . '" value="' . \esc_attr($key) . '" ' . checked($key, $bitDepth, false) . ' /> ' . \esc_html($label) . '&nbsp;&nbsp;';
echo '</label>';
}
echo '</fieldset>';
echo '<p class="description">' . esc_html__('8-bit is standard; higher bit depths may increase file size and require broader support.', 'avif-local-support') . '</p>';
echo ' </fieldset>';
echo ' <p class="description">' . esc_html__('8-bit is standard; higher bit depths may increase file size and require broader support.', 'avif-local-support') . '</p>';
echo ' </div>';
echo '</div>';
echo '</details>';
},
'avif-local-support',
'aviflosu_conversion',
[ 'label_for' => 'aviflosu_bit_depth' ]
'aviflosu_conversion'
);
}

Expand Down Expand Up @@ -321,13 +324,18 @@ public function render_admin_page(): void
echo '<div id="avif-local-support-tab-settings" class="avif-local-support-tab active">';
echo ' <div class="metabox-holder">';
echo ' <div class="postbox">';
echo ' <h2 class="hndle"><span>' . esc_html__('Settings', 'avif-local-support') . '</span></h2>';
echo ' <div class="inside">';
echo ' <form action="options.php" method="post">';
settings_fields('aviflosu_settings');
do_settings_sections('avif-local-support');
submit_button();
echo ' </form>';
// Restore defaults button
echo ' <form action="' . esc_url(admin_url('admin-post.php')) . '" method="post" style="margin-top:8px;">';
echo ' <input type="hidden" name="action" value="aviflosu_reset_defaults" />';
wp_nonce_field('aviflosu_reset_defaults');
echo ' <button type="submit" class="button">' . esc_html__('Restore defaults', 'avif-local-support') . '</button>';
echo ' </form>';
echo ' </div>';
echo ' </div>';
echo ' </div>';
Expand Down Expand Up @@ -358,6 +366,14 @@ public function render_admin_page(): void
echo ' <div class="postbox">';
echo ' <h2 class="hndle"><span>' . esc_html__('Test conversion', 'avif-local-support') . '</span></h2>';
echo ' <div class="inside">';
// Show conversion environment summary
$lib = extension_loaded('imagick') ? 'Imagick' : (function_exists('imageavif') ? 'GD' : 'None');
$quality = (int) get_option('aviflosu_quality', 85);
$speed = max(0, min(8, (int) get_option('aviflosu_speed', 1)));
$subsampling = (string) get_option('aviflosu_subsampling', '420');
$subLabel = ($subsampling === '444') ? '4:4:4' : (($subsampling === '422') ? '4:2:2' : '4:2:0');
$bitDepth = (string) get_option('aviflosu_bit_depth', '8');
echo '<p><strong>' . esc_html__('Conversion environment', 'avif-local-support') . ':</strong> ' . esc_html($lib) . ' · ' . esc_html(sprintf(__('quality %d, speed %d, subsampling %s, %s‑bit', 'avif-local-support'), $quality, $speed, $subLabel, $bitDepth)) . '</p>';
echo ' <p class="description">' . esc_html__('Upload a JPEG to preview resized images and the AVIFs generated by your current settings. The file is added to the Media Library.', 'avif-local-support') . '</p>';
echo ' <form action="' . esc_url(admin_url('admin-post.php')) . '" method="post" enctype="multipart/form-data" style="display:flex;flex-direction:column;align-items:flex-start;gap:8px">';
echo ' <input type="hidden" name="action" value="aviflosu_upload_test" />';
Expand All @@ -377,7 +393,7 @@ public function render_admin_page(): void
if ($attachment && $attachment->post_type === 'attachment') {
$results = $this->converter->convertAttachmentNow($testId);
$editLink = get_edit_post_link($testId);
echo '<hr />';
echo '<div style="border-top:1px solid #dcdcde;margin:12px 0"></div>';
echo '<p><strong>' . esc_html__('Test results for attachment:', 'avif-local-support') . '</strong> ' . sprintf('<a href="%s">%s</a>', esc_url($editLink ?: '#'), esc_html(get_the_title($testId) ?: (string) $testId)) . '</p>';
echo '<table class="widefat striped" style="max-width:960px">';
echo ' <thead><tr>'
Expand Down Expand Up @@ -589,6 +605,31 @@ public function handle_upload_test(): void
exit;
}

public function handle_reset_defaults(): void
{
if (!current_user_can('manage_options')) {
wp_die(esc_html__('You do not have permission to do this.', 'avif-local-support'));
}
check_admin_referer('aviflosu_reset_defaults');

// Reset options to defaults
update_option('aviflosu_enable_support', true);
update_option('aviflosu_convert_on_upload', true);
update_option('aviflosu_convert_via_schedule', true);
update_option('aviflosu_schedule_time', '01:00');
update_option('aviflosu_quality', 85);
update_option('aviflosu_speed', 1);
update_option('aviflosu_subsampling', '420');
update_option('aviflosu_bit_depth', '8');
update_option('aviflosu_cache_duration', 3600);

// Ensure schedule matches defaults
$this->converter->maybe_schedule_daily();

\wp_safe_redirect(\add_query_arg('avif-local-support-reset', '1', \admin_url('options-general.php?page=avif-local-support#settings')));
exit;
}

public function add_settings_link(array $links): array
{
$settings_link = sprintf('<a href="%s">%s</a>', esc_url(admin_url('options-general.php?page=avif-local-support')), __('Settings', 'avif-local-support'));
Expand Down
2 changes: 1 addition & 1 deletion includes/class-converter.php
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ private function checkMissingAvif(string $path): void
private function convertToAvif(string $sourcePath, string $avifPath, ?array $targetDimensions): void
{
$quality = max(0, min(100, (int) get_option('aviflosu_quality', 85)));
$speedSetting = max(0, min(10, (int) get_option('aviflosu_speed', 1)));
$speedSetting = max(0, min(8, (int) get_option('aviflosu_speed', 1)));
// Always preserve metadata and ICC by default (options removed from UI)
$preserveMeta = true;
$preserveICC = true;
Expand Down