Skip to content
● Grav 2.2 is out: 2x faster cold starts and 96% less memory on big sites. Read the announcement →
Downloads

Everything Grav

Download Grav

Grav Core is the base package with core functionality and a few essential starting pages. Grav Core + Admin also includes the Administration Panel plugin. Both are easy to get started with — check out our Basic Tutorial and Guide to the Administration Panel.

STABLE · v2.2.3 · updated 7 hours ago

Latest stable release

Production-ready. The version we recommend for every new site and every upgrade of an existing one.

Get Started

1

Quick installation

  1. Download either the Grav Core or Grav Core + Admin2 plugin installation package.
  2. Extract the zip file into your webroot.
  3. Point your browser at your local webserver: http://yoursite.com
2

How to install the Admin2 plugin

If you have not already installed the admin plugin, you can do so easily with GPM:

$

This will install the admin plugin plus its dependencies (api & login). After this is complete, point your browser to your Grav installation and you will be prompted to create a new admin user.

Changelog

v2.2.3 Latest 7 hours ago
    • Updated Twig to 3.30 (through Grav's getgrav/Twig fork), which brings upstream's fixes since 3.29, among them faster object attribute reads and macros declared by a parent template, a for loop variable that was undefined inside a nested loop's sequence, and the spread operator now rejected outside sequences, mappings and call arguments.
    • Theme and plugin templates now compile without any of the Twig sandbox's checks, which only ever apply to Twig in page content, so pages render faster (about half the Twig time on a busy listing template, within a few percent of running with no sandbox at all). Twig in page content, and any template rendered with the sandbox switched on, is checked exactly as before. That includes a theme template that was already loaded when a {% sandbox %} block or a sandboxed include reaches it, along with its blocks, macros and parent: it renders from a separately compiled copy with every check in place, so it gives the same output, and blocks the same things, as before. This uses a new opt-in feature of Grav's Twig fork (getgrav/Twig), so it needs that fork's matching commit.
    • Grav's Twig now refuses a template loaded by a different Twig environment when one is passed to include() or {% include %}, the same as Twig itself does, instead of rendering it with the other environment's settings. A template object from Grav's own environment passed on its own now renders instead of failing with a type error.
v2.2.2 2 days ago
    • The .htaccess and Caddy configs now let browsers keep the Admin panel's bundled files for a year, since their names change whenever they do. On Apache, copy the new block from webserver-configs/htaccess.txt into an existing site's .htaccess to get it (getgrav/grav-plugin-admin2#181)
    • Upgrading Grav from the admin on Windows, for example under Laragon, no longer deletes index.php and leaves the site showing a 404 page (forum)
    • An upgrade no longer blocks most of the Twig sandbox, such as date, max and batch, on sites whose security.twig_sandbox lists only add entries. Sites an earlier upgrade already did this to get those defaults back.
    • A fresh install now records the current upgrade level, so its first upgrade no longer reruns fixes meant for older installs.
    • [security] Updated the bundled DOM sanitizer to 1.0.18, which closes several ways a crafted stylesheet could hide an external resource reference using CSS escapes, such as a backslash-newline line continuation (GHSA-94fv-h7hv-365q).
    • Commands run by the scheduler, such as a plugin's bin/plugin worker, now run in the same environment as the scheduler, so a site started with bin/grav scheduler --env <host> no longer runs its jobs without the settings in user/env/<host>/config.
    • With pages.media_route_urls enabled, page files whose names contain a space or an accented character, such as foo bar.pdf or bär.png, no longer return a 404 (#4332)
    • An image used more than once in Markdown no longer picks up the query parameters, #fragment or style of the earlier uses, and keeps its retina srcset after an earlier use was cropped or resized. Thanks @wakqasahmed (#3567, #4333)
    • The content XSS check now also flags a javascript: link with a space after the colon, and no longer misses a link when the text elsewhere contains an encoded character it could not decode. Thanks @manus-pi
    • The private key file user/config/security-private.php is now created readable only by the site's own user, instead of being locked down a moment after it is written. Thanks @shxtterme
    • Modular sections on Flex-stored pages now re-run their Twig on every request, the same as regular pages already did, so one visitor's output is never reused for another.
    • On Apache, the file-type rules for images/, assets/, user/, system/ and vendor/ now also apply when a path follows the file name. Upgrading adds the rule to an existing site's .htaccess. Thanks @ma4ter
    • [security] With image URL actions turned on, the image pixel limit now measures the image each resize actually produces, including one-dimension, percentage and zoomCrop resizes. Thanks @manus-pi
    • [security] A form defined in page frontmatter now reads config-*@ values through the same filter as page Twig, so it can only show configuration that page Twig may read. Thanks @manus-use and @Hama1cco
    • [security] Dynamic-data directives in a form defined in page frontmatter now go through the allowed-callable check when the form builds its defaults and validates, not only when it first loads.
    • [security] Renaming a field while a page-authored Flex form is merged no longer lets it skip the allowed-callable check. Thanks @manus-use
v2.2.1 5 days ago
    • The .htaccess files under user/ no longer use mod_rewrite, so hosts that broke on them, such as some shared Apache setups, serve the admin, theme files and images again. Upgrading replaces the copies Grav wrote and leaves edited ones alone (#4309)
v2.2.0 6 days ago
    • Rebuilding the pages cache no longer writes a compiled file for every page, so the first request after a cache clear is much faster on large sites.
    • A pages rebuild no longer loads a compiled file for every page into OPcache, so large sites stop pushing the rest of Grav's cached code out of memory.
    • A pages rebuild reuses the page headers it read last time, so rebuilding after editing one page stays as quick as before.
    • Checking whether pages changed now looks only at the page folders and files Grav already knows about instead of scanning the whole pages folder, which makes requests on large sites faster.
    • Only one request at a time checks whether pages changed, and the others keep using the last result meanwhile.
    • When the pages cache has to be rebuilt, one request rebuilds it and the others wait and use its result instead of all rebuilding at once.
    • Saving or deleting a page through Grav now updates the pages cache on the next request instead of waiting for the change check, and plugins can do the same by calling Pages::markChanged().
    • That change notice is kept in a small file rather than the cache, so a page saved from the command line is picked up by the website even when the two use different cache drivers.
    • A new pages.frontmatter.native_yaml setting reads page frontmatter with the much faster YAML extension when the server has it installed. It is off by default because the extension reads unquoted dates and yes/no differently.
    • Translations are now prepared one language at a time, when a request first needs that language, so the first request after a cache clear no longer reads every language that core and the plugins ship.
    • Editing a language file now rebuilds only that language instead of every language.
    • The pages cache is smaller because it no longer keeps a second, raw copy of every page's frontmatter.
    • Listing every page, which the sitemap and @page.descendants collections do, is several times faster on large sites.
    • Page ETags are calculated with a much faster hash.
    • Configuration and translation caches built by a request are loaded into OPcache after the response has been sent, instead of making that request wait.
    • Rebuilding the pages cache after an edit no longer reads the pages and folders that did not change, so on large sites it takes about half the time it did before.
    • With pages.lazy_index on, lists of pages such as menus, taxonomy pages, @page.descendants collections and the sitemap load their pages in a few batches instead of one at a time.
    • pages.lazy_index now defaults to auto, which uses the page index on sites with 1,000 pages or more and the classic pages cache on smaller ones, so large sites load pages faster and use far less memory without any setup.
    • Plugin classes load faster because Grav now asks only the plugin autoloaders that can have the class, in the same order as before.
    • A modular page can set cache_modules: true to cache its modules' output, while modules with their own Twig or a form, logged-in visitors and form submissions are always rendered fresh.
    • A new session.lazy setting, off by default, starts the session only when a visitor needs one, so anonymous page views can go out without a session cookie and be cached by a proxy or CDN.
    • CSS minification now uses wikimedia/minify, which understands modern CSS and is about 15 to 25 times faster on real stylesheets.
    • Sites on Apache older than 2.4.8, common on Plesk and CentOS 7 hosts, no longer answer 500 for everything under user/ after upgrading, and upgrading fixes the .htaccess files earlier releases wrote there (grav-plugin-admin2#179)
    • Plugins' onShutdown work runs again after Admin Next saves on sites with session.read_and_close on, when another plugin had already finished the response.
    • Deleting or renaming a page folder is now picked up without clearing the cache.
    • The file change check no longer counts files that only contain .md somewhere in their name, such as page.md.bak, or whose name merely ends in yaml.
    • Searching Flex pages now matches a page's route as well as its title, slug and menu.
    • calc() inside @media, @supports and @container conditions keeps its spacing when CSS is minified, so browsers no longer drop those blocks.
    • A stylesheet with a quote that is never closed is now served unminified instead of losing the rules that follow it.
v2.1.12 1 week ago
    • SVG fills that point at a gradient on the same page, such as fill: url(#linear-gradient), keep working with CSS pipelining on. Thanks @wakqasahmed #2784
    • CSS pipelining no longer breaks url() values that aren't file paths, such as about:blank or blob: links, and now correctly rewrites paths written as URL(...) or with spaces inside the brackets.
v2.1.11 1 week ago
    • Files under .well-known/ are now served when running Grav with the built-in PHP server (bin/grav server), matching the shipped web server configs. Thanks @wakqasahmed #4016
    • Themes whose stylesheets use @import, such as Learn2, look right again with CSS pipelining and minification on. 2.1.10 could move a block of the theme's styles to the top of the combined file along with the import. Thanks @Gazoo #4330
v2.2.3 Latest 7 hours ago
    • Updated Twig to 3.30 (through Grav's getgrav/Twig fork), which brings upstream's fixes since 3.29, among them faster object attribute reads and macros declared by a parent template, a for loop variable that was undefined inside a nested loop's sequence, and the spread operator now rejected outside sequences, mappings and call arguments.
    • Theme and plugin templates now compile without any of the Twig sandbox's checks, which only ever apply to Twig in page content, so pages render faster (about half the Twig time on a busy listing template, within a few percent of running with no sandbox at all). Twig in page content, and any template rendered with the sandbox switched on, is checked exactly as before. That includes a theme template that was already loaded when a {% sandbox %} block or a sandboxed include reaches it, along with its blocks, macros and parent: it renders from a separately compiled copy with every check in place, so it gives the same output, and blocks the same things, as before. This uses a new opt-in feature of Grav's Twig fork (getgrav/Twig), so it needs that fork's matching commit.
    • Grav's Twig now refuses a template loaded by a different Twig environment when one is passed to include() or {% include %}, the same as Twig itself does, instead of rendering it with the other environment's settings. A template object from Grav's own environment passed on its own now renders instead of failing with a type error.
v2.2.2 2 days ago
    • The .htaccess and Caddy configs now let browsers keep the Admin panel's bundled files for a year, since their names change whenever they do. On Apache, copy the new block from webserver-configs/htaccess.txt into an existing site's .htaccess to get it (getgrav/grav-plugin-admin2#181)
    • Upgrading Grav from the admin on Windows, for example under Laragon, no longer deletes index.php and leaves the site showing a 404 page (forum)
    • An upgrade no longer blocks most of the Twig sandbox, such as date, max and batch, on sites whose security.twig_sandbox lists only add entries. Sites an earlier upgrade already did this to get those defaults back.
    • A fresh install now records the current upgrade level, so its first upgrade no longer reruns fixes meant for older installs.
    • [security] Updated the bundled DOM sanitizer to 1.0.18, which closes several ways a crafted stylesheet could hide an external resource reference using CSS escapes, such as a backslash-newline line continuation (GHSA-94fv-h7hv-365q).
    • Commands run by the scheduler, such as a plugin's bin/plugin worker, now run in the same environment as the scheduler, so a site started with bin/grav scheduler --env <host> no longer runs its jobs without the settings in user/env/<host>/config.
    • With pages.media_route_urls enabled, page files whose names contain a space or an accented character, such as foo bar.pdf or bär.png, no longer return a 404 (#4332)
    • An image used more than once in Markdown no longer picks up the query parameters, #fragment or style of the earlier uses, and keeps its retina srcset after an earlier use was cropped or resized. Thanks @wakqasahmed (#3567, #4333)
    • The content XSS check now also flags a javascript: link with a space after the colon, and no longer misses a link when the text elsewhere contains an encoded character it could not decode. Thanks @manus-pi
    • The private key file user/config/security-private.php is now created readable only by the site's own user, instead of being locked down a moment after it is written. Thanks @shxtterme
    • Modular sections on Flex-stored pages now re-run their Twig on every request, the same as regular pages already did, so one visitor's output is never reused for another.
    • On Apache, the file-type rules for images/, assets/, user/, system/ and vendor/ now also apply when a path follows the file name. Upgrading adds the rule to an existing site's .htaccess. Thanks @ma4ter
    • [security] With image URL actions turned on, the image pixel limit now measures the image each resize actually produces, including one-dimension, percentage and zoomCrop resizes. Thanks @manus-pi
    • [security] A form defined in page frontmatter now reads config-*@ values through the same filter as page Twig, so it can only show configuration that page Twig may read. Thanks @manus-use and @Hama1cco
    • [security] Dynamic-data directives in a form defined in page frontmatter now go through the allowed-callable check when the form builds its defaults and validates, not only when it first loads.
    • [security] Renaming a field while a page-authored Flex form is merged no longer lets it skip the allowed-callable check. Thanks @manus-use
v2.2.1 5 days ago
    • The .htaccess files under user/ no longer use mod_rewrite, so hosts that broke on them, such as some shared Apache setups, serve the admin, theme files and images again. Upgrading replaces the copies Grav wrote and leaves edited ones alone (#4309)
v2.2.0 6 days ago
    • Rebuilding the pages cache no longer writes a compiled file for every page, so the first request after a cache clear is much faster on large sites.
    • A pages rebuild no longer loads a compiled file for every page into OPcache, so large sites stop pushing the rest of Grav's cached code out of memory.
    • A pages rebuild reuses the page headers it read last time, so rebuilding after editing one page stays as quick as before.
    • Checking whether pages changed now looks only at the page folders and files Grav already knows about instead of scanning the whole pages folder, which makes requests on large sites faster.
    • Only one request at a time checks whether pages changed, and the others keep using the last result meanwhile.
    • When the pages cache has to be rebuilt, one request rebuilds it and the others wait and use its result instead of all rebuilding at once.
    • Saving or deleting a page through Grav now updates the pages cache on the next request instead of waiting for the change check, and plugins can do the same by calling Pages::markChanged().
    • That change notice is kept in a small file rather than the cache, so a page saved from the command line is picked up by the website even when the two use different cache drivers.
    • A new pages.frontmatter.native_yaml setting reads page frontmatter with the much faster YAML extension when the server has it installed. It is off by default because the extension reads unquoted dates and yes/no differently.
    • Translations are now prepared one language at a time, when a request first needs that language, so the first request after a cache clear no longer reads every language that core and the plugins ship.
    • Editing a language file now rebuilds only that language instead of every language.
    • The pages cache is smaller because it no longer keeps a second, raw copy of every page's frontmatter.
    • Listing every page, which the sitemap and @page.descendants collections do, is several times faster on large sites.
    • Page ETags are calculated with a much faster hash.
    • Configuration and translation caches built by a request are loaded into OPcache after the response has been sent, instead of making that request wait.
    • Rebuilding the pages cache after an edit no longer reads the pages and folders that did not change, so on large sites it takes about half the time it did before.
    • With pages.lazy_index on, lists of pages such as menus, taxonomy pages, @page.descendants collections and the sitemap load their pages in a few batches instead of one at a time.
    • pages.lazy_index now defaults to auto, which uses the page index on sites with 1,000 pages or more and the classic pages cache on smaller ones, so large sites load pages faster and use far less memory without any setup.
    • Plugin classes load faster because Grav now asks only the plugin autoloaders that can have the class, in the same order as before.
    • A modular page can set cache_modules: true to cache its modules' output, while modules with their own Twig or a form, logged-in visitors and form submissions are always rendered fresh.
    • A new session.lazy setting, off by default, starts the session only when a visitor needs one, so anonymous page views can go out without a session cookie and be cached by a proxy or CDN.
    • CSS minification now uses wikimedia/minify, which understands modern CSS and is about 15 to 25 times faster on real stylesheets.
    • Sites on Apache older than 2.4.8, common on Plesk and CentOS 7 hosts, no longer answer 500 for everything under user/ after upgrading, and upgrading fixes the .htaccess files earlier releases wrote there (grav-plugin-admin2#179)
    • Plugins' onShutdown work runs again after Admin Next saves on sites with session.read_and_close on, when another plugin had already finished the response.
    • Deleting or renaming a page folder is now picked up without clearing the cache.
    • The file change check no longer counts files that only contain .md somewhere in their name, such as page.md.bak, or whose name merely ends in yaml.
    • Searching Flex pages now matches a page's route as well as its title, slug and menu.
    • calc() inside @media, @supports and @container conditions keeps its spacing when CSS is minified, so browsers no longer drop those blocks.
    • A stylesheet with a quote that is never closed is now served unminified instead of losing the rules that follow it.
v2.1.12 1 week ago
    • SVG fills that point at a gradient on the same page, such as fill: url(#linear-gradient), keep working with CSS pipelining on. Thanks @wakqasahmed #2784
    • CSS pipelining no longer breaks url() values that aren't file paths, such as about:blank or blob: links, and now correctly rewrites paths written as URL(...) or with spaces inside the brackets.
v2.1.11 1 week ago
    • Files under .well-known/ are now served when running Grav with the built-in PHP server (bin/grav server), matching the shipped web server configs. Thanks @wakqasahmed #4016
    • Themes whose stylesheets use @import, such as Learn2, look right again with CSS pipelining and minification on. 2.1.10 could move a block of the theme's styles to the top of the combined file along with the import. Thanks @Gazoo #4330