Skip to content
Merged
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
12 changes: 8 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<p align="center">
<img src="https://img.shields.io/badge/EveryAlt-1.1.0-7c3aed?style=for-the-badge&labelColor=5b21b6" alt="EveryAlt 1.1.0" />
<img src="https://img.shields.io/badge/EveryAlt-1.1.1-7c3aed?style=for-the-badge&labelColor=5b21b6" alt="EveryAlt 1.1.1" />
<img src="https://img.shields.io/badge/WordPress-5.5%2B-21759b?style=flat-square&logo=wordpress" alt="WordPress" />
<img src="https://img.shields.io/badge/PHP-7.0%2B-777BB4?style=flat-square&logo=php" alt="PHP" />
<img src="https://img.shields.io/badge/license-GPLv2-green?style=flat-square" alt="License" />
Expand Down Expand Up @@ -72,14 +72,14 @@ Choose a model in **Settings**. Every model reads the image itself and writes th

| Model | Provider | Input / 1M tokens | Output / 1M tokens |
|-------|----------|------------------:|-------------------:|
| **GPT-5.4 nano** (default) | OpenAI | $0.20 | $1.25 |
| **GPT-6 Luna** (default) | OpenAI | $0.10 | $0.50 |
| **Gemini 3.1 Flash-Lite** | Google Gemini | $0.25 | $1.50 |
| **DeepSeek V4.1 Flash** | DeepInfra | $0.20 | $0.60 |
| **GLM-5.3-Flash** | DeepInfra | $0.15 | $0.50 |

Prices are each provider’s published regular rates as of September 2026 and can change: [OpenAI pricing](https://openai.com/api/pricing/) · [Gemini pricing](https://ai.google.dev/gemini-api/docs/pricing) · [DeepInfra pricing](https://deepinfra.com/pricing). The actual cost of every image is recorded on the **Logs** tab.
Prices are each provider’s published regular rates as of October 2026 and can change: [OpenAI pricing](https://openai.com/api/pricing/) · [Gemini pricing](https://ai.google.dev/gemini-api/docs/pricing) · [DeepInfra pricing](https://deepinfra.com/pricing). The actual cost of every image is recorded on the **Logs** tab.

> **Upgrading from 1.0.x?** Earlier versions used `gpt-5-nano`, which OpenAI is retiring. Existing installs switch to **GPT-5.4 nano** automatically. Your OpenAI key keeps working.
> **Upgrading?** OpenAI is retiring `gpt-5-nano` and GPT-5.4 nano (shutdown April 1, 2027). Installs using either switch to **GPT-6 Luna**, OpenAI's recommended replacement, automatically. Your OpenAI key keeps working, and if you chose Gemini or DeepInfra, that choice is kept.

### Getting a key

Expand Down Expand Up @@ -149,6 +149,10 @@ The plugin uses the `everyalt` text domain and ships with a `.pot` in `languages

## 📝 Changelog

### 1.1.1
- **Changed** the default OpenAI model is now **GPT-6 Luna**, OpenAI's recommended replacement for GPT-5.4 nano (which shuts down April 1, 2027). It's half the price per token ($0.10 input / $0.50 output per 1M tokens), and EveryAlt turns its reasoning off, as alt text doesn't need it. Sites using GPT-5.4 nano switch automatically; sites using Gemini or DeepInfra keep their choice.
- **Improved** the "prices as of" date in Settings is now set in one place and shown in each site's language, so future price updates don't need retranslating.

### 1.1.0
- **Accessibility (WCAG 2.1 AA).** A full review of every screen, with all failures fixed:
- Review tabs: alt text and title fields now have labels; Save, Regenerate, and Edit identify which image they act on.
Expand Down
9 changes: 7 additions & 2 deletions admin/class-everyalt-admin.php
Original file line number Diff line number Diff line change
Expand Up @@ -231,8 +231,13 @@ public function every_alt_maybe_upgrade() {
break;
}
}
// gpt-5-nano is being retired; installs from before model selection move to GPT-5.4 nano.
// Installs from before model selection start on the default model.
add_option( Every_Alt_Providers::MODEL_OPTION, Every_Alt_Providers::DEFAULT_MODEL );
// A saved model that has since been retired (e.g. GPT-5.4 nano) moves to the default. Other
// choices, such as Gemini or DeepInfra, are left alone.
if ( array_key_exists( get_option( Every_Alt_Providers::MODEL_OPTION ), Every_Alt_Providers::retired_models() ) ) {
update_option( Every_Alt_Providers::MODEL_OPTION, Every_Alt_Providers::DEFAULT_MODEL );
}
update_option( 'every_alt_version', $this->version );
}

Expand Down Expand Up @@ -320,7 +325,7 @@ private function get_api_key() {
}

/**
* Display name of the selected model, e.g. "GPT-5.4 nano (OpenAI)".
* Display name of the selected model, e.g. "GPT-6 Luna (OpenAI)".
*
* @return string
*/
Expand Down
4 changes: 2 additions & 2 deletions admin/class-everyalt-openai.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ class Every_Alt_OpenAI {
/** @var array Provider definition from Every_Alt_Providers::providers(). */
private $provider_def;

/** @var string Model ID sent in the request (e.g. gpt-5.4-nano). */
/** @var string Model ID sent in the request (e.g. gpt-6-luna). */
private $model;

/**
Expand All @@ -72,7 +72,7 @@ public function __construct( $api_key, $model_def = null ) {
}

/**
* Display name of the model in use, e.g. "GPT-5.4 nano (OpenAI)", for logs.
* Display name of the model in use, e.g. "GPT-6 Luna (OpenAI)", for logs.
*
* @return string
*/
Expand Down
12 changes: 10 additions & 2 deletions admin/partials/everyalt-options-display.php
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,15 @@
<?php endforeach; ?>
</fieldset>
<p class="description">
<?php esc_html_e( 'All models read the image and write alt text and titles the same way. Prices are each provider’s published rates as of September 2026 and may change. You pay the provider directly; EveryAlt never bills you. The actual cost of each image is recorded on the Logs tab.', 'everyalt' ); ?>
<?php
echo esc_html(
sprintf(
/* translators: %s: month and year the prices were checked, e.g. October 2026 */
__( 'All models read the image and write alt text and titles the same way. Prices are each provider’s published rates as of %s and may change. You pay the provider directly; EveryAlt never bills you. The actual cost of each image is recorded on the Logs tab.', 'everyalt' ),
Every_Alt_Providers::prices_as_of()
)
);
?>
</p>
<p class="description">
<?php
Expand Down Expand Up @@ -519,7 +527,7 @@
<?php
$everyalt_parts = array();
foreach ( $everyalt_row['models'] as $everyalt_slug => $everyalt_m ) {
$everyalt_label = isset( $everyalt_models[ $everyalt_slug ] ) ? $everyalt_models[ $everyalt_slug ]['label'] : $everyalt_slug;
$everyalt_label = Every_Alt_Providers::model_label( $everyalt_slug );
$everyalt_parts[] = sprintf( '%s: %s (%s)', $everyalt_label, Every_Alt_Usage::format_usd( $everyalt_m['cost'] ), number_format_i18n( $everyalt_m['requests'] ) );
}
echo esc_html( implode( ' · ', $everyalt_parts ) );
Expand Down
4 changes: 2 additions & 2 deletions everyalt.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
* Plugin Name: EveryAlt
* Plugin URI: https://everyalt.com
* Description: Instantly generate alternative text for all your images.
* Version: 1.1.0
* Version: 1.1.1
* Author: HDC
* Author URI: https://hdc.net
* License: GPL-2.0+
Expand Down Expand Up @@ -50,7 +50,7 @@
* Start at version 1.0.0 and use SemVer - https://semver.org
* Rename this for your plugin and update it as you release new versions.
*/
define( 'EVERY_ALT_VERSION', '1.1.0' );
define( 'EVERY_ALT_VERSION', '1.1.1' );

/**
* The code that runs during plugin activation.
Expand Down
60 changes: 51 additions & 9 deletions includes/class-everyalt-providers.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
* (280 tokens per image instead of 1,120) and reports thinking tokens separately. Every_Alt_OpenAI builds
* both request styles; every provider receives the image inline as base64.
*
* Prices are the providers' published regular (non-promotional) rates in USD per 1M tokens, as of September 2026.
* Prices are the providers' published regular (non-promotional) rates in USD per 1M tokens, as of
* PRICES_AS_OF. Update that date whenever prices here are re-checked.
* They are used for the cost estimates shown in Settings and Logs, and can be overridden with the
* everyalt_input_token_price_per_million / everyalt_output_token_price_per_million filters.
*
Expand All @@ -23,8 +24,11 @@ class Every_Alt_Providers {
/** Option holding the selected model slug (a key of models()). */
const MODEL_OPTION = 'every_alt_model';

/** Model used when none has been chosen (and for installs upgrading from gpt-5-nano). */
const DEFAULT_MODEL = 'openai-gpt-5.4-nano';
/** Date the prices in models() were last checked against the providers' pricing pages (Y-m-d). */
const PRICES_AS_OF = '2026-10-02';

/** Model used when none has been chosen, or when the saved model has been retired. */
const DEFAULT_MODEL = 'openai-gpt-6-luna';

/**
* Providers, keyed by provider slug.
Expand Down Expand Up @@ -92,13 +96,14 @@ public static function providers() {
*/
public static function models() {
return array(
'openai-gpt-5.4-nano' => array(
'openai-gpt-6-luna' => array(
'provider' => 'openai',
'model' => 'gpt-5.4-nano',
'label' => 'GPT-5.4 nano',
'input_price' => 0.20,
'output_price' => 1.25,
'params' => array(),
'model' => 'gpt-6-luna',
'label' => 'GPT-6 Luna',
'input_price' => 0.10,
'output_price' => 0.50,
// Luna models default to medium reasoning; alt text doesn't need it, and it's billed as output.
'params' => array( 'reasoning_effort' => 'none' ),
),
'gemini-3.1-flash-lite' => array(
'provider' => 'gemini',
Expand Down Expand Up @@ -129,6 +134,43 @@ public static function models() {
);
}

/**
* PRICES_AS_OF as a localized month and year, e.g. "October 2026", "octubre de 2026", "2026年10月".
*
* @return string
*/
public static function prices_as_of() {
/* translators: PHP date format for the month prices were last checked, e.g. "F Y" (October 2026). See https://www.php.net/manual/datetime.format.php */
return date_i18n( _x( 'F Y', 'prices as-of date format', 'everyalt' ), strtotime( self::PRICES_AS_OF ) );
}

/**
* Models that were offered in earlier versions, slug => label. Kept so logs and spending history
* still show a readable name; they can't be selected, and a saved one falls back to DEFAULT_MODEL.
*
* @return array
*/
public static function retired_models() {
return array(
'openai-gpt-5.4-nano' => 'GPT-5.4 nano',
);
}

/**
* Display label for a model slug, including retired models (falls back to the slug itself).
*
* @param string $slug
* @return string
*/
public static function model_label( $slug ) {
$models = self::models();
$retired = self::retired_models();
if ( isset( $models[ $slug ] ) ) {
return $models[ $slug ]['label'];
}
return isset( $retired[ $slug ] ) ? $retired[ $slug ] : (string) $slug;
}

/**
* Format a per-1M-token price with 2 decimals, or 3 when needed (0.20, 1.50, 0.075).
*
Expand Down
Binary file modified languages/everyalt-de_DE.mo
Binary file not shown.
Loading
Loading