diff --git a/docs/channels/entries.md b/docs/channels/entries.md
index ae384cdc..cd2d6902 100755
--- a/docs/channels/entries.md
+++ b/docs/channels/entries.md
@@ -1261,33 +1261,52 @@ Handy conditional for displaying markup or content based on whether or not the e
### `{if no_results}`
- {if no_results} content {/if}
+ {if no_results} There are no entries available {/if}
-You may use this conditional for displaying a message in the case when no entries are returned. The contents inside of the conditional will be displayed in cases where there are no results returned for the tag.
+You will use this conditional frequently to display alternative content when no entries are returned. The content inside the conditional will be displayed when no results are returned for the tag with the given parameters.
- {if no_results}
There are no entries available.
{/if}
-
-Further, you may specify that another Template be shown in a case when there are no results. In order to do that, you must use the redirect=variable
+Further, you may specify that another page should be shown when there are no results. In order to do that, you use the [redirect= variable](templates/globals/single-variables.md#redirect).
{if no_results} {redirect="channel/noresult"} {/if}
-Lastly, if you want to simply display your 404 page (with 404 headers) when no entries are returned, simply use "404" as the template name.
+Lastly, if you want to simply display your [custom Not Found page](general/404pages.md#404-pages) (with proper 404 headers) when no entries are returned, simply use "404" as the template name.
{if no_results} {redirect="404"} {/if}
-NOTE: **Note:** If you have several nested tags, each one would need to include a `{if no_results}` pair to be parsed correctly.
+NOTE: **Note:** If you have nested tag loops that each check for no results, the outer one will "claim" and process the first (and only the first) `{if no_results}` block before the inner tag loop has a chance, unless the conditional is prefixed (which not every tag provides).
-For instance, if you have a Grid field with an `{if no_results}` block, the parent `{exp:channel:entries}` tag pair would need to include an `{if no_results}` block as well:
+For instance, if you have a Relationship field with an `{if no_results}` block, and the parent `{exp:channel:entries}` tag pair needs to include an `{if no_results}` block as well, you should use this format:
```
{exp:channel:entries channel="blog"}
+ {my_relationship_field}
+ {if my_relationship_field:no_results} Relationship is empty {/if}
+ {my_relationship_field:title}
+ {/my_relationship_field}
{if no_results} No entries {/if}
+{/exp:channel:entries}
+```
+
+NOTE: **Note:** To test whether a Grid or File Grid field is empty, use [:total_rows](fieldtypes/grid.md#total_rows-1). For a Members field, use [:total_rows](fieldtypes/member.md#total_rows). For a Fluid field, use [:total_fields](fieldtypes/fluid.md#total_fields).
+
+```
+{exp:channel:entries channel="blog"}
+ {if my_grid_field:total_rows == 0} Grid is empty {/if}
{my_grid_field}
- {if no_results} Grid is empty {/if}
{my_grid_field:text}
{/my_grid_field}
+ {if my_fluid_field:total_fields == 0} Fluid field is empty {/if}
+ {my_fluid_field}
+ {my_fluid_field:text}
+ {content}
+ {/my_fluid_field:text}
+ {/my_fluid_field}
+ {if no_results} No entries {/if}
{/exp:channel:entries}
```
+NOTE: **Note:** It is invalid syntax to use `{if:else}` with the `{if no_results}` conditional. Results (no pun intended) may be unpredictable.
+
+
### `{if not_category_request}`
{if not_category_request} content {/if}
@@ -1326,7 +1345,7 @@ You may test whether an entry is set to be "sticky". You may also test whether i
Variable pairs contain an opening and closing tag as well as content in between. Example:
- {date_heading}
{entry_date format="%Y %m %d"}
{/date_heading}
+ {date_heading}
{entry_date format="%Y %m %d"}
{/date_heading}
The reason variable pairs have an opening and closing pair is because the information between the pairs can be shown or not shown if the criteria for each tag is met.
@@ -1334,7 +1353,7 @@ In the case of the "date_heading" pair, for example, it only appears at a certai
### `{date_footer}`
- {date_footer display="daily"}
That's all from today!
{/date_footer}
+ {date_footer display="daily"}
That's all from today!
{/date_footer}
The date footer can be used to show a footer at certain intervals. The interval can be set to show hourly, daily, weekly, monthly, or yearly. An optional "display" parameter can be used to set the display interval:
@@ -1354,7 +1373,7 @@ NOTE: **Note:** You can use as many date_footers as you want in the same tag. Th
### `{date_heading}`
- {date_heading}
{entry_date format="%Y %m %d"}
{/date_heading}
+ {date_heading}
{entry_date format="%Y %m %d"}
{/date_heading}
The date heading can be used to show a heading at certain intervals. The interval can be set to show hourly, daily, weekly, monthly, or yearly.
@@ -1493,7 +1512,7 @@ This variable will be replaced by a URL to the specified Template Group/Template
If you want the category links to point to your site index instead of a particular template group/template, you can use SITE_INDEX instead:
- {categories} {category_name} {/categories}
+ {categories} {category_name} {/categories}
#### Custom Category Fields
diff --git a/docs/cli/usage.md b/docs/cli/usage.md
index d2bdd21f..47f0e88f 100644
--- a/docs/cli/usage.md
+++ b/docs/cli/usage.md
@@ -1,41 +1,35 @@
# CLI Usage
-Commands can be called in the terminal of your choice in the format of:
+Commands to control and report on many of the core operations of ExpressionEngine can be issued via the terminal of your choice in the format of:
-`$ php system/ee/eecli.php hello`
+`$ php system/ee/eecli.php version`
-This will call `eecli` with a command of `hello`. This is the Hello World of ExpressionEngine commands, and will display:
+Assuming you're in the directory that contains the system folder, this will have `php` use ExpressionEngine's Command Line Interface tool, `eecli`, to run the `version` command.
-`Hello world`
-
-Commands can also request confirmation:
+This is the most basic of ExpressionEngine commands, and will display something similar to:
```
-$ php system/ee/eecli.php hello -c
-
-Hello world
-Are you liking these questions? (yes/no) [no]
-yes
-That's good to hear!
+ExpressionEngine Version: 7.5.25
+Build: 20260623
+PHP Version: 8.2.32
```
+You may also be able to use the CLI with PHP implied. Command line usage is a broad topic, and the details of your system may vary.
-Commands are also able to take interaction:
+`$ ./system/ee/eecli.php version`
-```
-$ php system/ee/eecli.php hello -i
+Commands can be interactive and ask you questions as they run. For example, this command will walk you through setting up the files and framework for a custom EE add-on:
-Hello world
-What's your name? Andy
-Pleasure to meet you, Andy!
```
+$ php system/ee/eecli.php make:addon
-WARN: **Important:** The CLI is available to every user that has SSH or terminal access to your site's webserver. It does not handle authorization inside ExpressionEngine and is relying on your server's authorization method instead.
-
-If you want to disable CLI globally, it can be done by setting `cli_enabled` [configuration override](general/system-configuration-overrides.md#cli_enabled) to `n`.
+Let's build your add-on!
+What is the name of your add-on?
+etc.
+```
## List All Commands
-To view a list of all available commands, you may use the list command:
+To view a list of all available commands, use the list command:
`php system/ee/eecli.php list`
@@ -44,41 +38,56 @@ This will return a basic list of all available system and user-generated command
```
$ php system/ee/eecli.php list
+------------------------------------------------------------------
| Command | Description |
------------------------------------------------------------------
-| hello | The most basic of commands |
| list | Lists all available commands |
-| update | Updates ExpressionEngine |
+| addons:install | Installs add-on and all its components |
+| backup:database | Backup the database |
+| channels:list | Lists all channels in the system |
| cache:clear | Clears all ExpressionEngine caches |
+| config:config | Updates config values in config.php file |
...
```
+## Command Line Security
+
+WARN: **Important:** Unless disabled, the CLI is enabled by default and available to any person who has SSH or terminal access to your site's web server and who can run PHP scripts. The CLI does not handle authorization using ExpressionEngine's member system. It relies entirely on your server's authorization methods and simply treats a CLI user as a generic superuser.
+
+EE is available via the CLI even when EE is set to offline mode -- this mirrors a superadmin's access permissions in the control panel and makes it possible to perform maintenance and upgrades when a site is offline.
+
+If you want to disable CLI globally, this can be done by setting `cli_enabled` [configuration override](general/system-configuration-overrides.md#cli_enabled) to `n` or by running the following command:
+
+`$ php eecli.php config:config -c cli_enabled -v n`
+
+(This would be a poor choice of command to use to test the CLI.)
+
+You can also enable and disable the CLI from [Security & Privacy Settings](control-panel/settings/security-privacy.md#enable-the-command-line-interface) in the Control Panel.
+
## Get Help
-You can get help information on any command by using the `--help` or `-h` parameter when running the command.
+You can get help information for any command by using the `--help` or `-h` parameter
```
-$ php system/ee/eecli.php hello -h
+$ php system/ee/eecli.php config:config -h
SUMMARY
- Hello World -- This is a sample command used to test the CLI
+ Update Config Values -- Gives the ability to update config values
USAGE
- Hello World php eecli.php hello
+ Update Config Values php eecli.php config:config -c is_system_on -v n
DESCRIPTION
- The most basic of commands
+ Updates config values in config.php file
OPTIONS
- --verbose
- -v
- Hello world, but longer
-
- --interactive
- -i
- Let's interact!
+ --config-variable=
+ -c
+ The config item to modify
- --confirm
- -c
- Test the confirmation
+ --value=
+ -v
+ The value to set the config item to
```
+
+Additional details may also be available here in the ExpressionEngine Docs or on the add-on developer's website.
diff --git a/docs/control-panel/create.md b/docs/control-panel/create.md
index ea9aa0d4..359e7907 100755
--- a/docs/control-panel/create.md
+++ b/docs/control-panel/create.md
@@ -192,12 +192,16 @@ Saves the entry and returns the [Entry Manager](control-panel/entry-manager.md)
### Preview
-A live preview of the entry is available if the relevant channel's [Preview URL](control-panel/channels.md#settings-tab) is set **or** the [Pages Module](add-ons/pages.md) or [Structure](add-ons/structure/overview.md) is installed and configured with a URI and template.
+A dynamic, live preview of an entry can be simultaneously displayed while you edit. The preview button opens a split browser window that displays a live preview of the entry you are editing.
-If neither is set, the preview button will have an exclamation mark (!) and will link to channel preferences page where Preview URL can be set.
+The template used to display the preview is based on configured Pages/Structure fields if the [Pages Module](add-ons/pages.md) or [Structure](add-ons/structure/overview.md) is installed and configured with a URI and template -- or the relevant channel's [Preview URL](control-panel/channels.md#settings-tab) setting otherwise.
-The preview will open a split screen that allows a live preview of edits. The template used to display the preview is based on configured Pages/Structure fields if set and the channel preview URL otherwise.
+If neither of these is set, the preview button will have an exclamation mark (!) and it will link to channel preferences page where Preview URL can be set.
-When the preview is triggered, it is being displayed side-by-side with edit screen. The size of preview container can be adjusted with mouse dragging its border. The preview is dynamically being updated as you change the fields.
+NOTE: **Note:** Commonly, the channel preview template is set to be the same template that the live entry, but in certain cases it's useful to use a different, customized preview template. Pages/Structure do not have this flexibility.
+
+NOTE: **Note:** Use the [`{is_live_preview_request}`](globals/single-variables.md#is_live_preview_request) conditional to only display certain content or to modify certain attributes only when previewing an entry. For example, `{if is_live_preview_request}status="open|closed" show_future_entries="yes"{/if}` will preview an entry that is closed or set to publish in the future.
+
+Once the preview is triggered, it will continue to be displayed side-by-side with edit screen until you close it. The size of preview window can be adjusted with the mouse by dragging its border. The preview contents will dynamically update as you change the contents of any field.
Live Preview does require the [HTTP Authorization Header be enabled](troubleshooting/error-messages.md#http-authorization-header-missing).
diff --git a/docs/fieldtypes/fluid.md b/docs/fieldtypes/fluid.md
index 094ce051..d4207876 100755
--- a/docs/fieldtypes/fluid.md
+++ b/docs/fieldtypes/fluid.md
@@ -341,10 +341,12 @@ A fluid field can handle the output of all of those fields, as many as they add,
## Fluid Field Notes
-- The `{if no_results}` tag is not valid within the prefixed variable pairs.
-- Count variables available in some variable pairs (grid and relationship) restart at 1 each loop. So the total_results for a relationship tag pair would refer to the total number of relationships for that specific instance of the relationship field.
- All native fields aside from a Fluid field can be included in a Fluid field.
+- The `{if no_results}` conditional tag is not valid for use in controlling the display of fluid fields. To test if the overall field has any content, use [:total_fields](/fieldtypes/fluid.md#total_fields) outside of the fluid field loop: `{if my_fluid_field:total_fields == 0} Fluid field is empty {/if}`
+
+- Count variables available in some variable pairs (grid and relationship) restart at 1 each loop. So the total_results for a relationship tag pair would refer to the total number of relationships for that specific instance of the relationship field.
+
## Field Examples
### Checkbox and Multi Select Fields
diff --git a/docs/fieldtypes/grid.md b/docs/fieldtypes/grid.md
index 1ab8d783..e508471e 100755
--- a/docs/fieldtypes/grid.md
+++ b/docs/fieldtypes/grid.md
@@ -15,7 +15,7 @@ lang: ee
[TOC]
-The Grid field in ExpressionEngine provides a way to group fieldtypes in repeatable rows. This is useful for when you need to group a subset of data in your channel entry form that may or may not have a varying number of rows. You can select a minimum and a maximum amount of rows to allow data entry for, or it can be virtually infinite.
+The Grid field in ExpressionEngine provides a way to enter and organize content in repeatable rows using many of the other fieldtypes. This is useful when you need to group a subset of information in your channel entry form in a logical manner, especially when that infomation may have varying numbers of rows. You can set a minimum and/or a maximum number of rows, or it can be virtually infinite.

@@ -23,21 +23,21 @@ The Grid field in ExpressionEngine provides a way to group fieldtypes in repeata
#### Minimum Rows
-Specifies the minimum number of rows this Grid will have. For example, if you enter `3`, the publish form will load with three rows ready to be populated and will not allow the publisher to have less than three rows in this Grid field.
+Specifies the minimum number of rows this grid will have. For example, if you enter `3`, the publish form will load with three empty rows ready to be populated and will not allow the publisher to delete any rows if there are only three.
#### Maximum Rows
-Specifies the maximum number of rows this Grid can have. For example, if you enter `10`, the publish form will not allow the publisher to add any more than ten rows to this Grid field.
+Specifies the maximum number of rows this grid can have. For example, if you enter `10`, the publish form will not allow the publisher to add any more than ten rows to this grid field.
-#### Allow reordering
+#### Allow Reordering
-Enables moving the Grid rows with drag & drop to change the order
+Enables moving the grid rows with drag & drop to change the order.
#### Show Row Numbers
Enables the display of row count alongside each row in the data grid.
-#### Grid layout
+#### Grid Layout
Tip: Grid Field Layout
@@ -52,24 +52,41 @@ Tip: Grid Field Layout
### Grid Fields
-Here, you specify the columns you want in your Grid field. All [native fieldtypes](fieldtypes/overview.md) are available to add and have many of the [same configuration options](control-panel/field-manager/field-manager-settings.md#createedit-field) as full fields do.
+Here, you specify the columns (a.k.a. Grid Fields) you want in your main grid field. All [native fieldtypes](fieldtypes/overview.md) are available to be part of a Grid field -- with the exception of Grid itself, [File Grid](fieldtypes/file-grid.md) and [Fluid](fieldtypes/fluid.md). Grid Fields within a grid may have [slightly different configuration options available](control-panel/field-manager/field-manager-settings.md#createedit-field) than they do as full fields.
+
+#### Creating and Editing Grid Fields
+
+To add a new Grid Field (column) click the "plus" icon. You must always have one field in your grid.
+
+You can collapse or show the settings for each field by clicking on the triangle in the box.
+
+Re-order the fields by grabbing the drag handle (three horizontal lines).
+
+Make a copy of the field by clicking the "copy" icon -- two superimposed squares.
+
+#### Grid Field General Options
+
+Just as with other field types, you can specify whether a grid field is required or not. This applies to every row in the grid.
+
+For some fieldtypes, you can choose whether its content should be included in search. The overall grid field must also be set to Include in Search, or else this setting will not have any effect. If you change the search inclusion status of an existing grid field or column, you will need to [re-index your content](control-panel/utilities/data-operations.md#search-reindex).
+
+You may set a minimum width for each grid field. When the grid is set to display horizontally, any grid field with a minimum width will have that width applied to it; fields without any minimum width will be given the remaining space.
+
## Template Tags
-Contents of a Grid field are accessed via a variable pair surrounding prefixed variables representing each column. For example, if you have a field `gallery` with an `image` and `credit` fields, your template code may look like this:
+Contents of a Grid Field are accessed via prefixed variables representing each column, surrounded by a variable pair. For example, if you have a grid field called `awards` with `name`, `details`, and `year_awarded` fields, your template code may look like this:
- {gallery}
-
-
- Photo by {gallery:credit}
-
- {gallery:description}
- {/gallery}
+ {awards}
+
{awards:name} - {awards:year_awarded}
+ {awards:details}
+ {/awards}
-Grid has a number of parameters and other variables available in order to get the information you need out of it.
## Parameters
+Grid has a number of parameters and other variables available in order to get the information you need out of it.
+
[TOC=3]
### `backspace=`
@@ -82,7 +99,7 @@ Just like the backspace parameter on the [Channel Entries](channels/entries.md)
dynamic_parameters="orderby|limit|sort"
-The [Dynamic Parameters](channels/dynamic-parameters.md) feature permits a Grid field tag's parameters to be set "on the fly" using POST data data submitted via a form. A practical use for this is to create some display options in a form on your page that your visitors can use to select their preferred page view.
+The [Dynamic Parameters](channels/dynamic-parameters.md) feature permits a grid field tag's parameters to be set "on the fly" using POST data submitted via a form. A practical use for this is to offer display options in a form on your page that your visitors can then use to select their preferred page view.
NOTE: **Note:** This feature will only work if page caching is turned OFF for the template in which it is being used.
@@ -98,13 +115,13 @@ Allows the output of the tag pair to order rows in a fixed order of row IDs.
limit="5"
-Limits the number of rows output by the tag pair to the number specified here. The limit will default to 100 rows if a value is not specified.
+Limits the number of rows output by the tag pair to the number specified. The limit will default to 100 rows if a value is not specified.
### `offset=`
offset="1"
-Offsets the number of rows output by the tag pair to the number specified here.
+Offsets the number of rows output by the tag pair by the number specified.
### `orderby=`
@@ -112,7 +129,7 @@ Offsets the number of rows output by the tag pair to the number specified here.
Allows the output of the tag pair to be ordered by a specific column, defaults to row order as set on the channel entry publish form. Entering `random` will return the rows in a random order.
-NOTE: **Note:** Unlike `exp:channel:entries`, you can only use one column at a time for sorting.
+NOTE: **Note:** Unlike `exp:channel:entries`, you can only use one column at a time for sorting -- though this limitation was removed in 7.5.23.
### `row_id=`
@@ -144,71 +161,71 @@ Specifies the direction of the sorting of the tag output. Defaults to ascending.
### `count`
- {gallery:count}
+ {grid_field:count}
-The "count" out of the current rows being displayed. If five rows are being displayed, then for the fourth entry the `count` variable would have a value of "4".
+The "count" of the current row being displayed. If five rows are being displayed, then for the fourth entry the `count` variable would have a value of "4".
### `field_row_count`
- {gallery:field_row_count}
+ {grid_field:field_row_count}
The count of the row inside the field regardless of tag output.
### `field_row_index`
- {gallery:field_row_index}
+ {grid_field:field_row_index}
The index of the row inside the field regardless of tag output.
### `field_total_rows`
- {gallery:field_total_rows}
+ {grid_field:field_total_rows}
-The total number of rows in the field regardless of tag output criteria.
+The total number of rows in the field regardless of tag output.
### `index`
- {gallery:index}
+ {grid_field:index}
-The count of the rows but starting at zero.
+The count of the row being displayed but starting at zero.
### `prev_row`
- {gallery:prev_row}
- Previous photo
- {/gallery:prev_row}
+ {grid_field:prev_row}
+ Previous Award
+ {/grid_field:prev_row}
-Used as a tag pair within the parent Grid field tag pair, provides access to data in the previous row in the dataset.
+When used as a tag pair within the parent grid field tag pair, provides access to data in the previous row in the dataset.
### `next_row`
- {gallery:next_row}
- Next photo
- {/gallery:next_row}
+ {grid_field:next_row}
+ Next Award
+ {/grid_field:next_row}
-Used as a tag pair within the parent Grid field tag pair, provides access to data in the next row in the dataset.
+When used as a tag pair within the parent grid field tag pair, provides access to data in the next row in the dataset.
### `row_id`
- {gallery:row_id}
+ {grid_field:row_id}
The database ID of the current row.
### `switch=`
- {gallery:switch="odd|even"}
+ {grid_field:switch="odd|even"}
-Identical to the [switch variable](channels/entries.md#switch) available in the [Channel Entries](channels/entries.md) tag pair, but prefixed for your Grid field.
+Identical to the [switch variable](channels/entries.md#switch) available in the [Channel Entries](channels/entries.md) tag pair, but prefixed for your grid field.
### `total_rows`
- {gallery:total_rows}
+ {grid_field:total_rows}
The total number of rows being returned by the current display criteria.
## Modifiers
-All modifiers have access to the tag parameters available to the primary tag which are listed above.
+All these modifiers can be used with the tag parameters available to the primary tag, which are listed above.
### `:average`
@@ -236,9 +253,9 @@ Given a column name containing numeric data, returns the sum of the column value
### `:table`
- {grid_field:table cellspacing="0" cellpadding="0"}
+ {grid_field:table cellspacing="0" cellpadding="0" set_classes="y"}
-Outputs the data in the Grid field as a table. All parameters available to the primary tag are available in addition to these:
+Outputs the data in the grid field as a table. All parameters available to the primary tag are available in addition to these:
- **border=** Sets border attribute on the table's HTML element
- **cellspacing=** Sets cellspacing attribute on the table's HTML element
@@ -246,19 +263,23 @@ Outputs the data in the Grid field as a table. All parameters available to the p
- **class=** Sets class attribute on the table's HTML element
- **id=** Sets ID attribute on the table's HTML element
- **set_classes=** If set to 'y', adds column name to the class attribute of each cell.
-- **set_widths=** If set to 'y', sets the same column widths configured for each column in the Grid field's settings.
+- **set_widths=** If set to 'y', sets the same column widths configured for each column in the grid field's settings.
- **width=** Sets width attribute on the table's HTML element
### `:total_rows`
{grid_field:total_rows search:height=">55"}
-When outside of a Grid field tag pair, this modifier can be used to get the total number of rows in a field given a specific criteria.
+When outside of a grid field tag pair, this modifier can be used to get the total number of rows in a field given a specific criteria. Useful for determining if there are any grid rows at all: `{if grid_field:total_rows == 0} Grid is empty {/if}`. When using parameters, wrap the tag in curly braces. Quotes around the numeric result are optional:
+
+ {if "{grid_field:total_rows search:height='>55'}" == 0} No rows with tall things {/if}
+
+NOTE: **Note:** Grid can process `{if no_results}` when existing rows are excluded by parameters such as `offset`, but a field with no stored rows returns without processing it. Use `:total_rows` to check whether the field has any rows. When nested in `{exp:channel:entries}`, put the Channel Entries `{if no_results}` block before the Grid tag pair.
### `:next_row`
{grid_field:next_row row_id="{segment_3}"}
- Next up: {grid_field:title}
+ Next up: {grid_field:title}
{/grid_field:next_row}
Given a row ID, this tag pair will provide access to the next row in the field criteria. The `row_id` may be populated via a segment variable.
@@ -266,7 +287,7 @@ Given a row ID, this tag pair will provide access to the next row in the field c
### `:prev_row`
{grid_field:prev_row row_id="5"}
- Previous: {grid_field:title}
+ Previous: {grid_field:title}
{/grid_field:prev_row}
Given a row ID, this tag pair will provide access to the previous row in the field criteria. The `row_id` may be populated via a segment variable.
diff --git a/docs/installation/changelog.md b/docs/installation/changelog.md
index 40edd5b0..6a4ecff4 100755
--- a/docs/installation/changelog.md
+++ b/docs/installation/changelog.md
@@ -8,6 +8,47 @@
-->
# ExpressionEngine v7 Change Log
+## Version 7.5.27
+(Release: September 21st, 2026)
+
+NOTE: **Important:** This version includes important security updates.
+
+
+
+**Bug Fixes** 💃🐛
+
+- Fixed layout loop indexes and indexed array lookups after rendering a Multi Select pair without `{index}` [#5389](https://github.com/ExpressionEngine/ExpressionEngine/pull/5389)
+- Fixed Grid and File Grid cloning after a validation error so retrying the save does not reassign the original field's columns [#5391](https://github.com/ExpressionEngine/ExpressionEngine/pull/5391)
+- Fixed watermarks being applied to auto-generated thumbnails and other image manipulations that were not configured to use them [#5373](https://github.com/ExpressionEngine/ExpressionEngine/pull/5373)
+- Fixed the Control Panel email newline setting so selecting CRLF also applies to quoted-printable email encoding when no explicit `email_crlf` override is configured [#5398](https://github.com/ExpressionEngine/ExpressionEngine/pull/5398)
+- Fixed unnecessary filesystem exceptions when optional global variable directories do not exist [#5400](https://github.com/ExpressionEngine/ExpressionEngine/pull/5400)
+- Fixed database backup progress moving backward when MySQL underestimates a table's row count [#5401](https://github.com/ExpressionEngine/ExpressionEngine/pull/5401)
+- Fixed the default post-install message template to display the current copyright year on new installations [#5371](https://github.com/ExpressionEngine/ExpressionEngine/pull/5371)
+- Improved updater authorization and compatibility across Control Panel session types [#5405](https://github.com/ExpressionEngine/ExpressionEngine/pull/5405)
+- Improved member profile variable handling and conditional parsing in member profile and member list templates [#5405](https://github.com/ExpressionEngine/ExpressionEngine/pull/5405)
+- Improved member import validation and role assignment handling, including rejecting member IDs that are already in use [#5405](https://github.com/ExpressionEngine/ExpressionEngine/pull/5405)
+- Updated Control Panel permissions for database backups, SQL queries, Search and Replace, and Pro Search shortcut management. Submitting SQL queries and using Search and Replace now require a Super Admin [#5405](https://github.com/ExpressionEngine/ExpressionEngine/pull/5405)
+- Improved rendering of Pro Search labels, channel title instructions, and custom Control Panel homepage settings [#5405](https://github.com/ExpressionEngine/ExpressionEngine/pull/5405)
+- Improved comment author links and text handling when saving comment edits [#5405](https://github.com/ExpressionEngine/ExpressionEngine/pull/5405)
+- Improved request validation when removing menu items and MSM sites [#5405](https://github.com/ExpressionEngine/ExpressionEngine/pull/5405)
+- Improved Structure page title handling in template variables [#5405](https://github.com/ExpressionEngine/ExpressionEngine/pull/5405)
+- Improved Pro Variables Table data handling while preserving support for existing stored values [#5405](https://github.com/ExpressionEngine/ExpressionEngine/pull/5405)
+
+**Developers** 💻
+
+- Added the `ee_html_escape()` helper for escaping literal text in HTML content and quoted attributes, and an `inlineHtml()` text formatter for limited inline formatting [#5405](https://github.com/ExpressionEngine/ExpressionEngine/pull/5405)
+- Expanded regression coverage for layout parsing, Grid cloning, email configuration, installer and updater flows, member management, Control Panel permissions, comments, Pro Search, Pro Variables, and Structure [#5389](https://github.com/ExpressionEngine/ExpressionEngine/pull/5389) [#5391](https://github.com/ExpressionEngine/ExpressionEngine/pull/5391) [#5398](https://github.com/ExpressionEngine/ExpressionEngine/pull/5398) [#5405](https://github.com/ExpressionEngine/ExpressionEngine/pull/5405)
+- Updated the project README with a clearer overview of ExpressionEngine, installation guidance, and links to documentation and community resources [#5402](https://github.com/ExpressionEngine/ExpressionEngine/pull/5402)
+
## Version 7.5.26
(Release: July 22nd, 2026)
@@ -85,7 +126,7 @@ NOTE: **Important:** This version includes important security updates.
- Improved Moblog field handling and expanded related test coverage [#5327](https://github.com/ExpressionEngine/ExpressionEngine/pull/5327)
- Improved member breadcrumb and ignore-list handling with expanded test coverage [#5333](https://github.com/ExpressionEngine/ExpressionEngine/pull/5333)
-- Added automated coverage for Channel Form field variables, File field Grid validation, Structure parent IDs, add-on removal, random string generation, member tag queries, and Moblog handling
+- Added automated coverage for Channel Form field variables, File field Grid validation, Structure parent IDs, add-on removal, random string generation, member tag queries, and Moblog handling
## Version 7.5.24
(Release: June 8th, 2026)