Grav 1.7 introduces a few new features, improvements, bug fixes and provides many architectural changes which pave the road towards Grav 2.0. Here are a few highlights:
webp
image format, lazy loading and more.{% cache %}
tag and improved performance especially in admin.IMPORTANT: For most people, Grav 1.7 should be a simple upgrade without any issues, but like any upgrade, it is recommended to take a backup of your site and test the upgrade in a testing environment before upgrading your live site.
This behavior is a result of the new default of auto-escaping being true in Grav 1.7. This is a security enhancement, and if you are upgrading from a version prior to 1.7, we automatically enable Twig Compatibility setting in the system configuration to ensure your old Twig code will continue to function. If you manually update to 1.7 or upgrade in any way that does not go through the GPM self upgrade process, you should set this setting yourself.
Check out the Twig section of this guide for full details...
As we have upgraded to a newer version of Symfony framework, the YAML parser is stricter than it was in versions prior to 1.7. To handle this we have included an older version of the parser that is available when enabling Yaml Compatibility. This is automatically handled for you if you upgrade to Grav 1.7 via GPM, but if you have upgraded manually, you will need to set this value yourself.
Check out the YAML section of this guide for full details...
If your admin is displaying with untranslated strings in the interface, it's most likely because you have previously disabled Language Translations. This was buggy in previous versions of Grav and disabling it, didn't actually disable translations throughout the admin as intended. This is fixed in Grav 1.7 and this setting is doing what it is intended to do, show the translation codes in uppercase rather than the translated strings themselves.
Check out the Troubleshooting section for the fix.
In Grav 1.7 we introduced Flex Pages as the new default page management UI. Also, to optimize performance, we stopped initializing pages on every admin call. Switching back to regular Grav Pages might temporarily resolve your issue. This is done by editing the FlexObjects plugin and disabling Pages (Admin).
To properly address the issue, custom plugins should be updated to support both Grav Pages and Flex Pages by using PageInterface
and also should explicitly Pages when required.
Check out the Pages section and Admin Section of this guide for full details...
There have also been some specific plugin issues that have already been discovered. Check out the Troubleshooting section of this page for specific issues with plugins.
Grav 1.7.8 adds support for defining any blueprint in your theme. This means that if you have page blueprints in blueprints/pages/
folder, standard blueprint locations are used, just like in plugins. Unfortunately some older themes may have a mix of files in blueprints/
and blueprint/pages
, which breaks the detection and causes either missing fields in admin when editing the pages or a fatal error: Loop detected while extending blueprint file
.
If either of these errors happen, check out the Troubleshooting section for the fix.
Grav 1.7 requires PHP 7.3.6 or later version. The recommended version is the latest PHP 7.4 release.
IMPORTANT: Grav 1.7 YAML parser is more strict and your site may break if you have syntax errors in your configuration files or page headers. However, if you update your existing site using bin/gpm
or Admin Plugin
upgrade process keeps most of the broken YAML syntax working.
To revert to the old behavior you need to make sure you have following setting in user/config/system.yaml
:
strict_mode:
yaml_compat: true
or in Admin under Configuration → Advanced -> YAML Compatibility
TIP: Grav 1.6 Upgrade Guide has a dedicated YAML Parsing section to help you to fix these issues.
By default, Grav 1.7 uses a Symfony 4.4 YAML parser, which follows the YAML standard specification more closely than the older versions of Grav. This means that YAML files which previously worked just fine, may cause errors resulting from being invalid YAML. However, Grav will by default still fall back to the older 3.4 version of the parser to keep your site up and running.
TIP: You should run CLI command bin/grav yamllinter
or visit in Admin > Tools > Reports before and after upgrade and fix all the YAML related warnings and errors.
IMPORTANT: Grav 1.7 enables Twig Auto-Escaping by default. However, if you update your existing site using bin/gpm
or Admin Plugin
upgrade process keeps the existing auto-escape settings.
To revert to the old behavior you need to make sure you have following settings in user/config/system.yaml
:
twig:
autoescape: false
strict_mode:
twig_compat: true
or in Admin under Configuration → Advanced -> Twig Compatibility
And please remember to clear cache after doing this!
TIP: Grav 1.6 Upgrade Guide has a dedicated Twig section. It is very important to read it first!
Twig template engine has been updated to version 1.43, but it also supports Twig 2.13. In order to support this newer version of Twig, you need to update any old syntax in your Twig templates. Grav 1.6 Upgrade Guide helps you to do this.
Additional changes in templating are:
{% cache %}
Twig tag eliminating need for twigcache
extension.array_diff()
twig functiontemplate_from_string()
twig functionsvg_image()
twig function to make it easier to 'include' SVG source in Twigurl()
twig function to take third parameter (true
) to return URL on non-existing file instead of returning false|array
twig filter to work with iterators and objects with toArray()
methodauthorize()
twig function to work better with nested rule parameters|yaml_serialize
twig filter: added support for JsonSerializable
objects and other array-like objectsexternal.html.twig
, default.html.twig
, and modular.html.twig
{% script 'file.js' at 'bottom' %}
instead of in 'bottom'
which is brokenIMPORTANT: Grav 1.7 changes the behavior of Strict Validation. However, if you update your existing site using bin/gpm
or Admin Plugin
upgrade process keeps the existing strict mode behaviour.
Strict mode Improvements: Inside forms, declaring validation: strict
was not as strict as we hoped because of a bug. The strict mode should prevent forms from sending any extra fields and this was fixed into Grav 1.7. Unfortunately many of the old forms declared to be strict even if they had extra data in them.
To revert to the old behavior you need to make sure you have following setting in user/config/system.yaml
:
strict_mode:
blueprint_compat: true
XSS Injection Detection is now enabled in all the frontend forms by default. Check the documentation on how to disable or customize the checks per form and per field.
Because of this, we added new configuration option system.strict_mode.blueprint_compat: true
to maintain old validation: strict
behavior. It is recommended to turn off this setting to improve site security, but before doing that, please search through all your forms if you were using validation: strict
feature. If you were, either remove the line or test if the form still works.
NOTE: This backwards compatibility fallback mechanism will be removed in Grav 2.0
Important: Grav 1.7 moves environments into user://env
folder. The old location still works, but it is better to move environments into a single location future features may rely on it.
Grav 1.7 also adds support for Server Based Environment Configuration and Server Based Multi-Site Configuration. This feature comes handy if you want to use for example docker containers and you want to make them independent of the domain you happen to use. Or if do not want to store secrets in the configuration, but to store them in your server setup.
In addition setup.php
file can now be in either GRAV_ROOT/setup.php
or GRAV_ROOT/GRAV_USER_PATH/setup.php
. The second location makes it easier to use environments with git repositories containing only user folder.
Admin has now new Accounts Administration using Flex Users:
NOTE: Flex Users feature is not yet used in the frontend of your site.
The existing Pages Administration has been greatly improved with Flex Pages:
BACKWARDS COMPATIBILITY BREAK: We fixed 404 error page when you go to non-routable page with routable, visible child pages under it. Now you get redirected to the first routable, visible child page instead. This is probably what you wanted in the first place.
NOTE: Flex Pages feature is not yet used in the frontend of your site.
Grav 1.7 changed the behavior of how the multi-language fallbacks work for the pages.
Previously if the page did not exist with the requested language, the old implementation looked up the next supported language. This meant that the untranslated page was always displayed, but the page could be using some unknown language to the reader.
The new behavior is to fall back only to the default language of the site. This default behavior can be overridden by setting fallback languages per language by using system.languages.content_fallback
configuration option.
If the page does not exist in any of the fallback languages, 404 Not Found will be displayed instead.
BACKWARDS COMPATIBILITY BREAK: Please add correct fallback languages for the page content in system.yaml
or admin: Configuration > System > Languages > Content Language Fallback.
Media handling has been greatly improved in Grav 1.7. Some highlights are:
webp
image formatloading=lazy
attributes on images. Can be set in system.images.defaults
or per md image with ?loading=lazy
noprocess
specific items only in Link/Image Excerpts, e.g. http://foo.com/page?id=foo&target=_blank&noprocess=id
Some highlights are:
--env
and --lang
parameters to set the environment and the used language respectively (-e
does not work anymore)bin/grav server
CLI command to easily run Symfony or PHP built-in web serversScheduler
cron command check and more useful CLI information-r <job-id>
option for Scheduler CLI command to force-run a jobbin/grav yamllinter
CLI command by adding an option to find YAML Linting issues from the whole site or custom folderAdded new configuration option to keep default language in .md
files if set to false
languages.include_default_lang_file_extension
: true|falseAdded new configuration option to set fallback content languages individually for every language
languages.content_fallback
: See Language ConfigurationAdded new configuration option to choose between debugbar and clockwork
debugger.provider
: clockwork|debugbarAdded new configuration option to hide potentially sensitive information
debugger.censored
: false|trueAdded new configuration option to maintain old validation: strict
behavior
strict_mode.blueprint_compat
: true|falseAdded system configuration support for HTTP_X_FORWARDED
headers (host disabled by default)
http_x_forwarded.protocol
: true|falsehttp_x_forwarded.host
: true|falsehttp_x_forwarded.port
: true|falsehttp_x_forwarded.ip
: true|falseAdded new configuration option security.sanitize_svg
to remove potentially dangerous code from SVG files
sanitize_svg
: true|falseUpgraded bin/composer.phar
to 2.0.2
which is all new and much faster
Please add composer.json
file to your plugin and run composer update --no-dev
(and remember to keep it updated):
composer.json
{
"name": "getgrav/grav-plugin-example",
"type": "grav-plugin",
"description": "Example plugin for Grav CMS",
"keywords": ["example", "plugin"],
"homepage": "https://github.com/getgrav/grav-plugin-example",
"license": "MIT",
"authors": [
{
"name": "...",
"email": "...",
"homepage": "...",
"role": "Developer"
}
],
"support": {
"issues": "https://github.com/getgrav/grav-plugin-example/issues",
"docs": "https://github.com/getgrav/grav-plugin-example/blob/master/README.md"
},
"require": {
"php": ">=7.1.3"
},
"autoload": {
"psr-4": {
"Grav\\Plugin\\Example\\": "classes/",
"Grav\\Plugin\\Console\\": "cli/"
},
"classmap": [
"example.php"
]
},
"config": {
"platform": {
"php": "7.1.3"
}
}
}
See Composer schema
Please use autoloader instead of require
in the code:
example.php
/**
* @return array
*/
public static function getSubscribedEvents(): array
{
return [
'onPluginsInitialized' => [
// This is only required in Grav 1.6. Grav 1.7 automatically calls $plugin->autolaod() method.
['autoload', 100000],
]
];
}
/**
* Composer autoload.
*
* @return \Composer\Autoload\ClassLoader
*/
public function autoload(): \Composer\Autoload\ClassLoader
{
return require __DIR__ . '/vendor/autoload.php';
}
Plugins & Themes: Call $plugin->autoload()
and $theme->autoload()
automatically when object gets initialized
Make sure your code does not use require
or include
for loading classes
blueprints.yaml
)Please add:
slug: folder-name
type: plugin|theme
Make sure you update your dependencies. I recommend setting Grav to either 1.6 or 1.7 and update your code/vendor to PHP 7.1
dependencies:
- { name: grav, version: '>=1.6.0' }
Added themes
to cached blueprints and configuration
Grav 1.7.8 adds support for defining any blueprint in your theme. Move all files and folders in blueprints/
into blueprints/pages/
to keep your theme forward compatible. Also remember to update minimum Grav dependency to >=1.7.8
.
Session::regenerateId()
method to properly prevent session fixation issuesuser.authorize()
now requires user to be authorized (passed 2FA check), unless the rule contains login
in its name.
Added support for more advanced ACL (CRUD)
BC BREAK user.authorize()
and Flex object.isAuthorized()
now have two deny states: false
and null
.
Make sure you do not have strict checks against false: $user->authorize($action) === false
(PHP) or user.authorize(action) is same as(false)
(Twig).
For the negative checks you should be using !user->authorize($action)
(PHP) or not user.authorize(action)
(Twig).
The change has been done to allow strong deny rules by chaining the actions if previous ones do not match: user.authorize(action1) ?? user.authorize(action2) ?? user.authorize(action3)
.
Note that Twig function authorize()
will still keeps the old behavior!
Added default templates for external.html.twig
, default.html.twig
, and modular.html.twig
Admin uses Flex Pages
by default (can be disabled from Flex-Objects
plugin)
Added page specific admin permissions support for Flex Pages
Added root page support for Flex Pages
Fixed wrong Pages::dispatch()
calls (with redirect) when we really meant to call Pages::find()
Added Pages::getCollection()
method
Moved collection()
and evaluate()
logic from Page
class into Pages
class
DEPRECATED $page->modular()
in favor of $page->isModule()
DEPRECATED PageCollectionInterface::nonModular()
in favor of PageCollectionInterface::pages()
DEPRECATED PageCollectionInterface::modular()
in favor of PageCollectionInterface::modules()
BC BREAK Fixed Page::modular()
and Page::modularTwig()
returning null
for folders and other non-initialized pages. Should not affect your code unless you were checking against false
or null
.
BC BREAK Always use \Grav\Common\Page\Interfaces\PageInterface
instead of \Grav\Common\Page\Page
in method signatures
Admin now uses Flex Pages
by default, collection will behave in slightly different way
BC BREAK $page->topParent()
may return page itself instead of null
BC BREAK $page->header()
may now \Grav\Common\Page\Header
return object instead of stdClass
, you need to handle both (Flex vs regular)
MediaTrait::freeMedia()
method to free media (and memory)Media
by using PSR-7Getters
, accessing $media->$filename
no longer works, use $media[$filename]
instead!Excerpts::processLinkHtml()
methodFlex Users
in the frontend (not recommended to use yet)Flex Users
by default (can be disabled from Flex-Objects
plugin)Flex Users
: obey blueprints and allow Flex to be used in admin onlyFlex Users
: user and group ACL now supports deny permissionsUserInterface::authorize()
to return null
having the same meaning as false
if access is denied because of no matching rule\Grav\Common\User\Group
in favor of $grav['user_groups']
, which contains Flex UserGroup collection\Grav\Common\User\Interfaces\UserInterface
instead of \Grav\Common\User\User
in method signaturesFramework
Flex classes directly, it's better to use or extend classes under Grav\Common\Flex\Types\Generic
namespace$grav['flex']
to access all registered Flex Directories
FlexRegisterEvent
which triggers when $grav['flex']
is being accessed the first timehasFlexFeature()
method to test if FlexObject
or FlexCollection
implements a given featuregetFlexFeatures()
method to return all features that FlexObject
or FlexCollection
implementsFlexObject::refresh()
method to make sure object is up to dateFlexStorage::getMetaData()
to get updated object meta information for listed keysFlexDirectoryInterface
interfacesame_as
to Flex ObjectsFlex Pages
method $page->header()
returns \Grav\Common\Page\Header
object, old Page
class still returns stdClass
PageCollectionInterface::nonModular()
into PageCollectionInterface::pages()
and deprecated the old methodPageCollectionInterface::modular()
into PageCollectionInterface::modules()
and deprecated the old methodFlexDirectory::getObject()
can now be called without any parameters to create a new objectFlexDirectory::update()
and FlexDirectory::remove()
Grav\Common\Flex
FlexStorageInterface::getStoragePath()
and getMediaPath()
can now return nullFlexStorageInterface::getMetaData()
edit_list.html.twig
file to a form field in order to customize look in the listing viewRoute
classLanguage::getPageExtensions()
to get full list of supported page language extensionsLanguage::getFallbackPageExtensions()
to fall back only to default language instead of going through all languagesuser/env
folderSerializable
methods are now final and cannot be overridden.flatten_array
filter to form field validationsecurity@: or: [admin.super, admin.pages]
in blueprints (nested AND/OR mode support)validate: value_type: bool|int|float|string|trim
to array
to filter all the values inside the arrayIf your plugins has blueprints folder, initializing it in the event will be too late. Do this instead:
class MyPlugin extends Plugin
{
/** @var array */
public $features = [
'blueprints' => 0, // Use priority 0
];
}
Symfony EventDispatcher
directly instead of rockettheme/toolbox
wrapper.$grav->dispatchEvent()
method for PSR-14 eventsPluginsLoadedEvent
which triggers after plugins have been loaded but not yet initializedSessionStartEvent
which triggers when session is startedFlexRegisterEvent
which triggers when $grav['flex']
is being accessed the first timePermissionsRegisterEvent
which triggers when $grav['permissions']
is being accessed the first timeonAfterCacheClear
eventCheck onAdminTwigTemplatePaths
event, it should NOT be:
public function onAdminTwigTemplatePaths($event)
{
// This code breaks all the other plugins in admin, including Flex Objects
$event['paths'] = [__DIR__ . '/admin/themes/grav/templates'];
}
but:
public function onAdminTwigTemplatePaths($event)
{
// Add plugin template path for admin.
$paths = $event['paths'];
$paths[] = __DIR__ . '/admin/themes/grav/templates';
$event['paths'] = $paths;
}
3.5.1
Utils::functionExists()
: PHP 8 compatible function_exists()
Utils::isAssoc()
and Utils::isNegative()
helper methodsUtils::simpleTemplate()
method for very simple variable templatingUtils::fullPath()
to get the full path to a file be it stream, relative, etc.CSVFormatter::decode()
Security::sanitizeSVG()
function$grav->close()
method to properly terminate the request with a responseFolder::countChildren()
method to determine if a folder has child foldersFile
Route::getBase()
methodRoute
objects immutable. This means that you need to do: {% set route = route.withExtension('.html') %}
(for all withX
methods) to keep the updated version.Content-Encoding
handling in Apache when content compression is disabledUri::getAllHeaders()
compatibility functionJsonFormatter
options to be passed as a stringserve()
method:$this->setLanguage($langCode);
before doing anything else if you want to set the language (or use default)$this->initializeGrav();
Already called if you're in bin/plugin
, otherwise you may need to call this one$this->initializePlugins();
This initializes grav, plugins (up to onPluginsInitialized
)$this->initializeThemes();
This initializes grav, plugins and theme$this->initializePages();
This initializes grav, plugins, theme and everything needed by pagesbin/grav yamllinter
to find any YAML parsing errors in your site (including your plugins and themes).Added Content Editor
option to user account blueprint
BC BREAK Admin will not initialize frontend pages anymore, this has been done to greatly speed up Admin plugin.
Please call $grav['admin']->enablePages()
or {% do admin.enablePages() %}
if you need to access frontend pages. This call can be safely made multiple times.
If you're using Flex Pages
, please use Flex Directory instead, it will make your code so much faster.
Admin now uses Flex for editing Accounts
and Pages
. If your plugin hooks into either of those, please make sure they still work.
Admin cache is enabled by default, make sure your plugin clears cache when needed. Please avoid clearing all cache!
init()
method, classes without it will stop working in the future.ERROR: flex-objects.html.twig template not found for page
If you get this error after upgrading to Grav 1.7, it might be related to a plugin called content-edit
. If you disable this plugin, the error should resolve itself. Grav Issue #3169
If your admin plugin looks like this:
The fix is very easy, and can be done even when not fully translated. Simply navigate to PLUGIN_ADMIN.CONFIGURATION
and then in PLUGIN_ADMIN.LANGUAGES
, set PLUGIN_ADMIN.LANGUAGE_TRANLATIONS
to PLUGIN_ADMIN.YES
:
If you cannot see your custom fields when editing the page, your theme is using two conflicting locations for page blueprints.
If the theme was not created by you, please report a bug to the theme author.
To fix the bug, you need to move all files and folders in your theme from blueprints/
to blueprints/pages/
(requires Grav 1.7.8+). Alternatively if the theme must support older versions of Grav, do the opposite.
The easiest fix for loop error is to move the files into their proper location, please see the above issue.
Alternatively you can fix the issue by changing the broken page blueprint from:
extends@:
type: [NAME]
context: 'blueprints://pages'
where [NAME]
is the filename (without the file extension) of the blueprint itself, to:
extends@: self@
It has been reported that after upgrading to latest Grav 1.7 and Admin 1.10, some admin pages appear broken and not fully styled. THis could be related to the imagecreate
plugin. Disabling this plugin is not enough, you must completely remove the plugin, and then the error should resolve itself. Admin Issue #2035
While we recommend resolving any issues you may have to ensure that Grav 1.7 and future updates will be an easy upgrade, there are going to be scenarios where you have custom plugin functionality, or don't have the developer resources handy, and just need to get back to Grav 1.6 quickly.
If you have CLI access to the site, this can be done by running these commands from the root of your Grav 1.7 site:
wget -q https://getgrav.org/download/core/grav-update/1.6.31 -O tmp/grav-update-v1.6.31.zip
wget -q https://getgrav.org/download/plugins/admin/1.9.19 -O tmp/grav-plugin-admin-v1.9.19.zip
unzip tmp/grav-update-v1.6.31.zip -d tmp
unzip tmp/grav-plugin-admin-v1.9.19.zip -d tmp
cp -rf tmp/getgrav-grav-plugin-admin-5d86394/* user/plugins/admin/
cp -rf tmp/grav-update/* ./
Basically it does a direct-install of the latest version of Grav 1.6 and Admin 1.9 on top of your current installation. It doesn't touch the user/
folder so your content and plugins are not impacted.
For those who do not have CLI access, download grav-update-v1.6.31.zip and grav-plugin-admin-1.9.19.zip files using the links given here. Unzip the files into your filesystem. Then use your favorite FTP/SFTP client to copy all the Grav files to your WEBROOT
and Admin files into WEBROOT/user/plugins/admin
.
Found errors? Think you can improve this documentation? Simply click the Edit link at the top of the page, and then the icon on Github to make your changes.
Powered by Grav + with by Trilby Media.