├── assets ├── scss │ ├── core │ │ ├── _forms.scss │ │ ├── _reset.scss │ │ └── _typography.scss │ ├── objects │ │ └── _grid.scss │ ├── templates │ │ ├── _page.scss │ │ ├── _archive.scss │ │ ├── _single.scss │ │ └── _search.scss │ ├── components │ │ ├── _global-footer.scss │ │ ├── _global-footer-menu.scss │ │ ├── _global-header.scss │ │ ├── _pagination.scss │ │ ├── _navigation.scss │ │ └── _search-form.scss │ ├── settings │ │ └── _settings.scss │ ├── overrides │ │ └── _block-editor.scss │ ├── helpers │ │ ├── _colour.scss │ │ ├── _typography.scss │ │ ├── _aspect-ratio.scss │ │ └── _font-faces.scss │ ├── editor.scss │ └── main.scss └── js │ ├── main.js │ └── editor.js ├── templates ├── partials │ ├── side-nav.php │ ├── article.php │ ├── pager.php │ ├── entry-meta.php │ ├── article-list-item.php │ ├── breadcrumb.php │ ├── head.php │ ├── navigation.php │ ├── search-form.php │ ├── global-footer.php │ └── global-header.php ├── index.php ├── single.php ├── functions.php ├── style.css ├── page.php ├── home.php ├── archive.php ├── 404.php ├── layouts │ └── main.php ├── theme.json └── search.php ├── .gitattributes ├── vendor.phar ├── app ├── load.php ├── Posts │ ├── PostTypes.php │ └── CustomFields.php ├── Theme │ ├── TitleTag.php │ ├── Menus.php │ ├── Media.php │ ├── Widgets.php │ ├── WpHead.php │ ├── Tables.php │ └── Scripts.php ├── Blocks │ └── BlockEditor.php ├── di.php └── Lib │ └── Whippet │ └── TemplateTags.php ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── static ├── lib │ └── govuk-frontend │ │ └── dist │ │ └── govuk │ │ └── assets │ │ ├── images │ │ ├── favicon.ico │ │ ├── govuk-icon-180.png │ │ ├── govuk-icon-192.png │ │ ├── govuk-icon-512.png │ │ ├── govuk-opengraph-image.png │ │ ├── favicon.svg │ │ ├── govuk-icon-mask.svg │ │ └── govuk-crest.svg │ │ ├── rebrand │ │ ├── images │ │ │ ├── favicon.ico │ │ │ ├── govuk-icon-180.png │ │ │ ├── govuk-icon-192.png │ │ │ ├── govuk-icon-512.png │ │ │ ├── govuk-opengraph-image.png │ │ │ ├── favicon.svg │ │ │ ├── govuk-icon-mask.svg │ │ │ └── govuk-crest.svg │ │ └── manifest.json │ │ ├── fonts │ │ ├── bold-affa96571d-v2.woff │ │ ├── bold-b542beb274-v2.woff2 │ │ ├── light-94a07e06a1-v2.woff2 │ │ └── light-f591b13f7d-v2.woff │ │ └── manifest.json ├── editor.min.js └── editor.min.css.map ├── peridot.php ├── .php_cs ├── .github ├── dependabot.yml └── workflows │ └── theme.yml ├── spec ├── posts │ ├── post_types.spec.php │ └── custom_fields.spec.php ├── blocks │ └── block_editor.spec.php ├── lib │ └── whippet │ │ └── template_tags.spec.php └── theme │ ├── title_tag.spec.php │ ├── menus.spec.php │ ├── media.spec.php │ ├── widgets.spec.php │ ├── wp_head.spec.php │ ├── tables.spec.php │ └── scripts.spec.php ├── composer.json ├── COPYING.md ├── package.json ├── README.md ├── .gitignore └── CHANGELOG.md /assets/scss/core/_forms.scss: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/scss/core/_reset.scss: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/scss/objects/_grid.scss: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/scss/templates/_page.scss: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /templates/partials/side-nav.php: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | /static/** -diff 2 | -------------------------------------------------------------------------------- /assets/scss/templates/_archive.scss: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/scss/templates/_single.scss: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /templates/index.php: -------------------------------------------------------------------------------- 1 | Don't use the index template. -------------------------------------------------------------------------------- /vendor.phar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dxw/govuk-theme/HEAD/vendor.phar -------------------------------------------------------------------------------- /assets/scss/components/_global-footer.scss: -------------------------------------------------------------------------------- 1 | .global-footer { 2 | 3 | } 4 | -------------------------------------------------------------------------------- /assets/scss/settings/_settings.scss: -------------------------------------------------------------------------------- 1 | $govuk-page-width: 1200px !default; 2 | -------------------------------------------------------------------------------- /assets/js/main.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const GOVUKFrontend = require('govuk-frontend') 4 | GOVUKFrontend.initAll() 5 | -------------------------------------------------------------------------------- /app/load.php: -------------------------------------------------------------------------------- 1 | register(); 8 | -------------------------------------------------------------------------------- /assets/scss/helpers/_colour.scss: -------------------------------------------------------------------------------- 1 | @function tint($color, $percentage) { 2 | @return mix(white, $color, $percentage); 3 | } 4 | 5 | @function shade($color, $percentage) { 6 | @return mix(black, $color, $percentage); 7 | } 8 | -------------------------------------------------------------------------------- /app/Posts/PostTypes.php: -------------------------------------------------------------------------------- 1 | exclude('vendor') 5 | ->exclude('assets') 6 | ->exclude('static') 7 | ->exclude('templates') 8 | ->exclude('node_modules') 9 | ->in(__DIR__); 10 | 11 | return \Dxw\PhpCsFixerConfig\Config::create() 12 | ->setFinder($finder); 13 | -------------------------------------------------------------------------------- /app/Theme/Menus.php: -------------------------------------------------------------------------------- 1 | 2 |
3 |

4 |
5 | 6 |
7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | --- 2 | version: 2 3 | updates: 4 | - package-ecosystem: github-actions 5 | directory: "/" 6 | schedule: 7 | interval: daily 8 | - package-ecosystem: composer 9 | directory: "/" 10 | schedule: 11 | interval: daily 12 | open-pull-requests-limit: 0 13 | - package-ecosystem: npm 14 | directory: "/" 15 | schedule: 16 | interval: daily 17 | open-pull-requests-limit: 0 18 | -------------------------------------------------------------------------------- /assets/scss/helpers/_aspect-ratio.scss: -------------------------------------------------------------------------------- 1 | @mixin aspect-ratio($width, $height) { 2 | position: relative; 3 | height: 0; 4 | padding-bottom: ($height / $width) * 100%; 5 | 6 | > * { 7 | position: absolute; 8 | top: 0; 9 | left: 0; 10 | right: 0; 11 | bottom: 0; 12 | 13 | @supports (object-fit: cover) { 14 | width: 100%; 15 | height: 100%; 16 | object-fit: cover; 17 | } 18 | } 19 | } 20 | 21 | -------------------------------------------------------------------------------- /templates/partials/article.php: -------------------------------------------------------------------------------- 1 |
> 2 |
3 |

4 | 5 |
6 | 7 |
8 | 9 | 10 | 11 | 12 |
13 |
14 | -------------------------------------------------------------------------------- /templates/home.php: -------------------------------------------------------------------------------- 1 |
2 |

3 |

4 |
5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 | 15 |
16 | -------------------------------------------------------------------------------- /assets/scss/components/_global-header.scss: -------------------------------------------------------------------------------- 1 | @media (min-width: 768px) { 2 | .govuk-header__container { 3 | display: flex; 4 | align-items: center; 5 | } 6 | 7 | .govuk-header__container .govuk-grid-column-two-thirds { 8 | float: right; 9 | } 10 | 11 | .govuk-header__container .govuk-button { 12 | margin-bottom: 0px; 13 | } 14 | } 15 | 16 | @media (max-width: 768px) { 17 | .govuk-grid-column-two-thirds { 18 | width: 100%; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /templates/partials/pager.php: -------------------------------------------------------------------------------- 1 | max_num_pages > 1) : ?> 2 | 3 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /assets/scss/helpers/_font-faces.scss: -------------------------------------------------------------------------------- 1 | @mixin font-face($font-family, $path, $weight, $style) { 2 | @font-face { 3 | font-display: swap; 4 | font-family: '#{$font-family}'; 5 | font-style: #{$style}; 6 | font-weight: #{$weight}; 7 | src: url('#{$path}.eot'); 8 | src: url('#{$path}.eot?#iefix') format('embedded-opentype'), 9 | url('#{$path}.woff2') format('woff2'), url('#{$path}.woff') format('woff'), 10 | url('#{$path}.ttf') format('truetype'), url('#{$path}.svg') format('svg'); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /assets/scss/components/_pagination.scss: -------------------------------------------------------------------------------- 1 | .govuk-pagination__container { 2 | display: flex; 3 | justify-content: center; 4 | ul { 5 | @extend .govuk-list; 6 | @include govuk-responsive-margin(5, "top"); 7 | @include govuk-responsive-margin(5, "bottom"); 8 | li { 9 | display: block; 10 | float: left; 11 | @include govuk-responsive-margin(3, "right"); 12 | &:last-of-type { 13 | margin-right: 0; 14 | } 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /assets/scss/core/_typography.scss: -------------------------------------------------------------------------------- 1 | h1 { 2 | @extend .govuk-heading-xl; 3 | } 4 | h2 { 5 | @extend .govuk-heading-l; 6 | } 7 | h3 { 8 | @extend .govuk-heading-m; 9 | } 10 | h4 { 11 | @extend .govuk-heading-s; 12 | } 13 | p { 14 | @extend .govuk-body; 15 | } 16 | a { 17 | @extend .govuk-link; 18 | } 19 | ul { 20 | @extend .govuk-list; 21 | @extend .govuk-list--bullet; 22 | } 23 | ol { 24 | @extend .govuk-list; 25 | @extend .govuk-list--number; 26 | } 27 | blockquote { 28 | @extend .govuk-inset-text; 29 | } 30 | -------------------------------------------------------------------------------- /templates/archive.php: -------------------------------------------------------------------------------- 1 |
2 |

w_template_title(); ?>

3 | 4 |

5 | 6 |
7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 |
18 | -------------------------------------------------------------------------------- /spec/posts/post_types.spec.php: -------------------------------------------------------------------------------- 1 | postTypes = new \Dxw\GovukTheme\Posts\PostTypes(); 6 | }); 7 | 8 | afterEach(function () { 9 | }); 10 | 11 | it('is registrable', function () { 12 | expect($this->postTypes)->toBeAnInstanceOf(\Dxw\Iguana\Registerable::class); 13 | }); 14 | 15 | describe('->register()', function () { 16 | xit('registers any custom post types', function () { 17 | $this->postTypes->register(); 18 | }); 19 | }); 20 | }); 21 | -------------------------------------------------------------------------------- /spec/posts/custom_fields.spec.php: -------------------------------------------------------------------------------- 1 | customFields = new \Dxw\GovukTheme\Posts\CustomFields(); 6 | }); 7 | 8 | afterEach(function () { 9 | }); 10 | 11 | it('is registrable', function () { 12 | expect($this->customFields)->toBeAnInstanceOf(\Dxw\Iguana\Registerable::class); 13 | }); 14 | 15 | describe('->register()', function () { 16 | xit('registers any custom fields', function () { 17 | $this->customFields->register(); 18 | }); 19 | }); 20 | }); 21 | -------------------------------------------------------------------------------- /templates/404.php: -------------------------------------------------------------------------------- 1 |
2 |

3 |
4 |
5 |
6 |

7 | 11 |

12 |
13 |
14 | -------------------------------------------------------------------------------- /assets/scss/components/_navigation.scss: -------------------------------------------------------------------------------- 1 | /* 2 | * COMPONENT: SERVICE NAVIGATION 3 | * 4 | * Table of contents 5 | * 6 | * - Default styles 7 | * 8 | */ 9 | .govuk-service-navigation li { 10 | @extend .govuk-service-navigation__item; 11 | } 12 | 13 | .govuk-service-navigation li a { 14 | @extend .govuk-service-navigation__link; 15 | } 16 | 17 | .govuk-service-navigation .current-menu-item { 18 | @extend .govuk-service-navigation__item--active; 19 | } 20 | 21 | .govuk-service-navigation .sub-nav { 22 | @extend .govuk-list--bullet; 23 | @media (min-width: 640px) { 24 | display: none; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /spec/blocks/block_editor.spec.php: -------------------------------------------------------------------------------- 1 | blockEditor = new BlockEditor(); 8 | }); 9 | 10 | describe('->register()', function () { 11 | it('adds and removes support for editor options', function () { 12 | allow('remove_theme_support')->toBeCalled(); 13 | expect('remove_theme_support')->toBeCalled()->once(); 14 | expect('remove_theme_support')->toBeCalled()->once()->with('core-block-patterns'); 15 | 16 | $this->blockEditor->register(); 17 | }); 18 | }); 19 | }); 20 | -------------------------------------------------------------------------------- /spec/lib/whippet/template_tags.spec.php: -------------------------------------------------------------------------------- 1 | '\Dxw\Iguana\Theme\Helpers'] 9 | ); 10 | $this->templateTags = new \Dxw\GovukTheme\Lib\Whippet\TemplateTags( 11 | $this->helpersMock 12 | ); 13 | }); 14 | 15 | afterEach(function () { 16 | }); 17 | 18 | describe('->w_template_title()', function () { 19 | xit('displays the title of the page', function () { 20 | $this->templateTags->w_template_title(); 21 | }); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /templates/partials/entry-meta.php: -------------------------------------------------------------------------------- 1 |
2 | 3 | , 4 | 5 | 6 |
7 | -------------------------------------------------------------------------------- /spec/theme/title_tag.spec.php: -------------------------------------------------------------------------------- 1 | titleTag = new \Dxw\GovukTheme\Theme\TitleTag(); 6 | }); 7 | 8 | afterEach(function () { 9 | }); 10 | 11 | it('is registrable', function () { 12 | expect($this->titleTag)->toBeAnInstanceOf(\Dxw\Iguana\Registerable::class); 13 | }); 14 | 15 | describe('->register()', function () { 16 | it('adds support for title tag', function () { 17 | allow('add_theme_support')->toBeCalled(); 18 | expect('add_theme_support')->toBeCalled()->once()->with('title-tag'); 19 | $this->titleTag->register(); 20 | }); 21 | }); 22 | }); 23 | -------------------------------------------------------------------------------- /assets/scss/components/_search-form.scss: -------------------------------------------------------------------------------- 1 | .search-form { 2 | display:table; 3 | } 4 | 5 | .search-form__input { 6 | display:table-cell; 7 | position:relative; 8 | border: 0; 9 | z-index: 2; 10 | &:focus { 11 | box-shadow: inset 0 0 0 2px; 12 | border: 0; 13 | } 14 | } 15 | 16 | .search-form__submit-wrapper { 17 | display: table-cell; 18 | position: relative; 19 | vertical-align: top; 20 | width: 1%; 21 | top: 2px; 22 | } 23 | 24 | .search-form__button { 25 | text-indent: -5000px; 26 | width: 40px; 27 | height: 40px; 28 | top: -2px; 29 | } 30 | 31 | .search-form__icon { 32 | position: absolute; 33 | display: block; 34 | left: 4px; 35 | top: 2px 36 | } 37 | -------------------------------------------------------------------------------- /spec/theme/menus.spec.php: -------------------------------------------------------------------------------- 1 | menus = new Menus(); 10 | }); 11 | 12 | afterEach(function () { 13 | }); 14 | 15 | it('is registrable', function () { 16 | expect($this->menus)->toBeAnInstanceOf(\Dxw\Iguana\Registerable::class); 17 | }); 18 | 19 | describe('->register()', function () { 20 | it('registers nav menus', function () { 21 | allow('register_nav_menu')->toBeCalled()->andReturn(null); 22 | expect('register_nav_menu')->toBeCalled()->times(2); 23 | $this->menus->register(); 24 | }); 25 | }); 26 | }); 27 | -------------------------------------------------------------------------------- /templates/partials/article-list-item.php: -------------------------------------------------------------------------------- 1 |
> 2 |
3 |

4 | 5 |
6 | 7 |
8 | 9 | 10 | 11 | 12 | of 13 |
14 |
15 | -------------------------------------------------------------------------------- /templates/partials/breadcrumb.php: -------------------------------------------------------------------------------- 1 | ID)); ?> 6 | 7 | 20 | 21 | -------------------------------------------------------------------------------- /static/lib/govuk-frontend/dist/govuk/assets/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "icons": [ 3 | { 4 | "src": "images/favicon.ico", 5 | "type": "image/x-icon", 6 | "sizes": "48x48" 7 | }, 8 | { 9 | "src": "images/favicon.svg", 10 | "type": "image/svg+xml", 11 | "sizes": "150x150", 12 | "purpose": "any" 13 | }, 14 | { 15 | "src": "images/govuk-icon-180.png", 16 | "type": "image/png", 17 | "sizes": "180x180", 18 | "purpose": "maskable" 19 | }, 20 | { 21 | "src": "images/govuk-icon-192.png", 22 | "type": "image/png", 23 | "sizes": "192x192", 24 | "purpose": "maskable" 25 | }, 26 | { 27 | "src": "images/govuk-icon-512.png", 28 | "type": "image/png", 29 | "sizes": "512x512", 30 | "purpose": "maskable" 31 | }, 32 | { 33 | "src": "images/govuk-icon-mask.svg", 34 | "type": "image/svg+xml", 35 | "sizes": "150x150", 36 | "purpose": "monochrome" 37 | } 38 | ] 39 | } 40 | -------------------------------------------------------------------------------- /static/lib/govuk-frontend/dist/govuk/assets/rebrand/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "icons": [ 3 | { 4 | "src": "images/favicon.ico", 5 | "type": "image/x-icon", 6 | "sizes": "48x48" 7 | }, 8 | { 9 | "src": "images/favicon.svg", 10 | "type": "image/svg+xml", 11 | "sizes": "150x150", 12 | "purpose": "any" 13 | }, 14 | { 15 | "src": "images/govuk-icon-180.png", 16 | "type": "image/png", 17 | "sizes": "180x180", 18 | "purpose": "maskable" 19 | }, 20 | { 21 | "src": "images/govuk-icon-192.png", 22 | "type": "image/png", 23 | "sizes": "192x192", 24 | "purpose": "maskable" 25 | }, 26 | { 27 | "src": "images/govuk-icon-512.png", 28 | "type": "image/png", 29 | "sizes": "512x512", 30 | "purpose": "maskable" 31 | }, 32 | { 33 | "src": "images/govuk-icon-mask.svg", 34 | "type": "image/svg+xml", 35 | "sizes": "150x150", 36 | "purpose": "monochrome" 37 | } 38 | ] 39 | } 40 | -------------------------------------------------------------------------------- /spec/theme/media.spec.php: -------------------------------------------------------------------------------- 1 | media = new \Dxw\GovukTheme\Theme\Media(); 8 | }); 9 | 10 | afterEach(function () { 11 | }); 12 | 13 | it('is registrable', function () { 14 | expect($this->media)->toBeAnInstanceOf(\Dxw\Iguana\Registerable::class); 15 | }); 16 | 17 | describe('->register()', function () { 18 | it('registers thumbnail sizes', function () { 19 | allow('set_post_thumbnail_size')->toBeCalled(); 20 | expect('set_post_thumbnail_size')->toBeCalled()->once()->with(Arg::toBeAn('integer'), Arg::toBeAn('integer'), Arg::toBeA('boolean')); 21 | allow('add_image_size')->toBeCalled(); 22 | expect('add_image_size')->toBeCalled()->times(2)->with(Arg::toBeA('string'), Arg::toBeAn('integer'), Arg::toBeAn('integer'), Arg::toBeA('boolean')); 23 | $this->media->register(); 24 | }); 25 | }); 26 | }); 27 | -------------------------------------------------------------------------------- /app/Theme/Widgets.php: -------------------------------------------------------------------------------- 1 | __('Primary'), 14 | 'id' => 'sidebar-primary', 15 | 'before_widget' => '
', 16 | 'after_widget' => '
', 17 | 'before_title' => '

', 18 | 'after_title' => '

', 19 | ]); 20 | 21 | register_sidebar([ 22 | 'name' => __('Footer'), 23 | 'id' => 'sidebar-footer', 24 | 'before_widget' => '
', 25 | 'after_widget' => '
', 26 | 'before_title' => '

', 27 | 'after_title' => '

', 28 | ]); 29 | } 30 | 31 | public function register() 32 | { 33 | add_action('widgets_init', [$this, 'widgetsInit']); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "dxw/govuk-theme", 3 | "homepage": "https://github.com/dxw/whippet-theme-template", 4 | "type": "library", 5 | "version": "0.1.1", 6 | "license": "MIT", 7 | "authors": [ 8 | { 9 | "name": "Harry Metcalfe", 10 | "email": "contact@dxw.com", 11 | "homepage": "https://www.dxw.com/" 12 | } 13 | ], 14 | "config": { 15 | "platform": { 16 | "php": "7.4.3" 17 | } 18 | }, 19 | "require-dev": { 20 | "dxw/phar-install": "^1.0", 21 | "mikey179/vfsstream": "^1.6", 22 | "dxw/php-cs-fixer-config": "^1.0", 23 | "kahlan/kahlan": "^4.7" 24 | }, 25 | "autoload": { 26 | "psr-4": { 27 | "Dxw\\GovukTheme\\": "app/" 28 | } 29 | }, 30 | "scripts": { 31 | "post-update-cmd": "vendor/bin/phar-install" 32 | }, 33 | "require": { 34 | "dxw/iguana": "^1.0", 35 | "dxw/iguana-theme": "^1.0", 36 | "dxw/iguana-extras": "^1.0" 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /templates/partials/head.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /COPYING.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright © 2016 dxw 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | -------------------------------------------------------------------------------- /app/Theme/WpHead.php: -------------------------------------------------------------------------------- 1 | static/main.min.js --debug && browserify assets/js/editor.js > static/editor.min.js --debug", 17 | "clean": "del ./static/*", 18 | "copy": "cpy govuk-frontend/dist/govuk/assets ../../static/lib --cwd=node_modules", 19 | "images": "imagemin assets/img/* --out-dir=static/img/", 20 | "scss": "sass assets/scss/main.scss:static/main.min.css assets/scss/editor.scss:static/editor.min.css --load-path=node_modules --style=compressed", 21 | "standard": "standard assets/js/main.js", 22 | "build": "npm-run-all clean images scss standard copy browserify", 23 | "watch:browserify": "watchify assets/js/main.js -o static/main.min.js --debug && watchify assets/js/editor.js -o static/editor.min.js --debug", 24 | "watch:scss": "npm run scss -- -w", 25 | "watch": "npm run build && npm-run-all -p watch:*" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /templates/layouts/main.php: -------------------------------------------------------------------------------- 1 | 2 | class=""> 3 | 4 | 5 | 6 | 7 | > 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 |
20 | w_requested_template(); ?> 21 |
22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /spec/theme/widgets.spec.php: -------------------------------------------------------------------------------- 1 | widgets = new \Dxw\GovukTheme\Theme\Widgets(); 8 | }); 9 | 10 | afterEach(function () { 11 | }); 12 | 13 | it('is registrable', function () { 14 | expect($this->widgets)->toBeAnInstanceOf(\Dxw\Iguana\Registerable::class); 15 | }); 16 | 17 | describe('->register()', function () { 18 | it('initialises the widgets', function () { 19 | allow('add_action')->toBeCalled(); 20 | expect('add_action')->toBeCalled()->once()->with('widgets_init', [$this->widgets, 'widgetsInit']); 21 | $this->widgets->register(); 22 | }); 23 | }); 24 | 25 | describe('->widgetsInit()', function () { 26 | it('registers any widgets in the theme ', function () { 27 | allow('__')->toBeCalled()->andRun(function ($a) { 28 | return $a; 29 | }); 30 | 31 | allow('register_sidebar')->toBeCalled(); 32 | expect('register_sidebar')->toBeCalled()->times(2)->with(Arg::toBeAn('array')); 33 | 34 | $this->widgets->widgetsInit(); 35 | }); 36 | }); 37 | }); 38 | -------------------------------------------------------------------------------- /app/di.php: -------------------------------------------------------------------------------- 1 | addInstance(new \Dxw\Iguana\Theme\Helpers()); 4 | $registrar->addInstance(new \Dxw\Iguana\Theme\LayoutRegister( 5 | $registrar->getInstance(\Dxw\Iguana\Theme\Helpers::class) 6 | )); 7 | $registrar->addInstance(new \Dxw\Iguana\Extras\UseAtom()); 8 | 9 | // Libraries and support code 10 | $registrar->addInstance(new \Dxw\GovukTheme\Lib\Whippet\TemplateTags( 11 | $registrar->getInstance(\Dxw\Iguana\Theme\Helpers::class) 12 | )); 13 | 14 | // Theme behaviour, media, assets and template tags 15 | $registrar->addInstance(new \Dxw\GovukTheme\Theme\Scripts( 16 | $registrar->getInstance(\Dxw\Iguana\Theme\Helpers::class) 17 | )); 18 | $registrar->addInstance(new \Dxw\GovukTheme\Theme\Media()); 19 | $registrar->addInstance(new \Dxw\GovukTheme\Theme\Menus()); 20 | $registrar->addInstance(new \Dxw\GovukTheme\Theme\Widgets()); 21 | $registrar->addInstance(new \Dxw\GovukTheme\Theme\TitleTag()); 22 | $registrar->addInstance(new \Dxw\GovukTheme\Theme\Tables()); 23 | $registrar->addInstance(new \Dxw\GovukTheme\Theme\WpHead()); 24 | 25 | // Post types and additional fields 26 | $registrar->addInstance(new \Dxw\GovukTheme\Posts\PostTypes()); 27 | $registrar->addInstance(new \Dxw\GovukTheme\Posts\CustomFields()); 28 | 29 | // Blocks 30 | $registrar->addInstance(new \Dxw\GovukTheme\Blocks\BlockEditor()); 31 | -------------------------------------------------------------------------------- /templates/partials/navigation.php: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | 5 | 6 | 7 | 8 | 9 | 26 |
27 |
28 |
29 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # GOV.UK Design System WordPress theme 2 | 3 | A WordPress theme built by [dxw](https://dxw.com) that implements the [GOV.UK Design System](https://design-system.service.gov.uk/), via [GOV.UK Frontend](https://github.com/alphagov/govuk-frontend). 4 | 5 | Currently, the theme applies v3 of GOV.UK Frontend. 6 | 7 | ## Developing the theme 8 | 9 | Install the dependencies: 10 | 11 | ``` 12 | npm install 13 | composer install 14 | ``` 15 | 16 | Compile the assets: 17 | 18 | ``` 19 | npm run build 20 | ``` 21 | 22 | Run the tests: 23 | 24 | ``` 25 | vendor/bin/kahlan spec 26 | ``` 27 | 28 | Run the linter: 29 | 30 | ``` 31 | vendor/bin/php-cs-fixer fix 32 | ``` 33 | 34 | ## Extending the theme 35 | 36 | This is intended to be used as a parent theme, which is then extended/re-skinned via a child theme. 37 | 38 | You can use the `govuk_theme_class` filter to help with this. It is applied to all `govuk-` prefixed classes, so you can use this to either append a custom class to specific instances where those classes are applied, append a custom class to all instances, or replace those classes completely. 39 | 40 | You can also replace any of the individual template components, up to and including the overall layout template, in the child theme as required. 41 | 42 | Note that the GDS Transport theme is only licensed for use on gov.uk domains, so if you're developing a theme for use elsewhere, you'll need to replace it with a suitable alternative. 43 | -------------------------------------------------------------------------------- /templates/partials/search-form.php: -------------------------------------------------------------------------------- 1 |
2 | 18 |
19 | -------------------------------------------------------------------------------- /app/Theme/Tables.php: -------------------------------------------------------------------------------- 1 | replaceMarkup($blockContent); 16 | } 17 | return $blockContent; 18 | } 19 | 20 | private function replaceMarkup($blockContent) 21 | { 22 | $elementReplacements = $this->getElementReplacements(); 23 | foreach ($elementReplacements as $element => $replacement) { 24 | $blockContent = str_replace($element, $replacement, $blockContent); 25 | } 26 | return $blockContent; 27 | } 28 | 29 | private function getElementReplacements() 30 | { 31 | return [ 32 | '' => '
', 33 | '' => '', 35 | '' => '', 36 | '' => '', 38 | '
' => '', 34 | '
' => '', 37 | '
' => '' 39 | ]; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /templates/theme.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 2, 3 | "settings": { 4 | "color": { 5 | "custom": false, 6 | "customDuotone": false, 7 | "customGradient": false, 8 | "defaultPalette": false, 9 | "gradients": {}, 10 | "link": false, 11 | "palette": [ 12 | { 13 | "name": "Black", 14 | "slug": "black", 15 | "color": "#000" 16 | }, 17 | { 18 | "name": "White", 19 | "slug": "white", 20 | "color": "#fff" 21 | }, 22 | { 23 | "name": "Light Grey", 24 | "slug": "light-grey", 25 | "color": "#b1b4b6" 26 | } 27 | ] 28 | }, 29 | "layout": { 30 | "contentSize": "960px", 31 | "wideSize": "1360px" 32 | }, 33 | "typography": { 34 | "customFontSize": false, 35 | "lineHeight": true, 36 | "dropCap": false, 37 | "letterSpacing": false, 38 | "fontWeight": false, 39 | "fontSizes": [ 40 | { 41 | "name": "Small", 42 | "slug": "normal", 43 | "size": "1rem" 44 | }, 45 | { 46 | "name": "Normal", 47 | "slug": "normal", 48 | "size": "1.1875rem" 49 | }, 50 | { 51 | "name": "Medium", 52 | "slug": "medium", 53 | "size": "1.5rem" 54 | }, 55 | { 56 | "name": "Large", 57 | "slug": "large", 58 | "size": "2rem" 59 | }, 60 | { 61 | "name": "Huge", 62 | "slug": "huge", 63 | "size": "3rem" 64 | } 65 | ] 66 | }, 67 | "blocks": { 68 | "core/button": { 69 | "border": { 70 | "radius": false 71 | } 72 | } 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /templates/search.php: -------------------------------------------------------------------------------- 1 | 2 |
3 |

w_template_title(); ?>

4 |
5 | 6 | 7 |
8 | 9 | 10 | 11 | found_posts ? $endCount : $wp_query->found_posts; 18 | ?> 19 | 20 | 21 |

Results to of found_posts ?>

22 | 23 | 24 |
    25 | 26 |
  • 27 | 28 | 29 |

    30 |

    31 |

    32 |
  • 33 | 34 |
35 | 36 | 37 |
38 | 39 |
40 | 41 | 42 |

No results found.

43 | 44 | 45 | 46 |
47 | -------------------------------------------------------------------------------- /static/lib/govuk-frontend/dist/govuk/assets/images/favicon.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /static/lib/govuk-frontend/dist/govuk/assets/rebrand/images/favicon.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /.github/workflows/theme.yml: -------------------------------------------------------------------------------- 1 | name: Theme 2 | 3 | on: push 4 | 5 | jobs: 6 | kahlan: 7 | runs-on: ubuntu-24.04 8 | strategy: 9 | matrix: 10 | php-versions: ['7.4'] 11 | steps: 12 | - uses: actions/checkout@v4.2.2 13 | - name: Setup PHP 14 | uses: shivammathur/setup-php@v2 15 | with: 16 | php-version: ${{ matrix.php-versions }} 17 | - name: Get Composer Cache Directory 18 | id: composer-cache 19 | run: | 20 | echo "::set-output name=dir::$(composer config cache-files-dir)" 21 | - uses: actions/cache@v5 22 | with: 23 | path: ${{ steps.composer-cache.outputs.dir }} 24 | key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} 25 | restore-keys: | 26 | ${{ runner.os }}-composer- 27 | - name: Install dependencies 28 | run: composer install --no-interaction 29 | - name: Run Kahlan tests 30 | run: vendor/bin/kahlan 31 | php-cs-fixer: 32 | runs-on: ubuntu-24.04 33 | strategy: 34 | matrix: 35 | php-versions: ['7.4'] 36 | steps: 37 | - uses: actions/checkout@v4.2.2 38 | - name: Setup PHP 39 | uses: shivammathur/setup-php@v2 40 | with: 41 | php-version: ${{ matrix.php-versions }} 42 | - name: Get Composer Cache Directory 43 | id: composer-cache 44 | run: | 45 | echo "::set-output name=dir::$(composer config cache-files-dir)" 46 | - uses: actions/cache@v5 47 | with: 48 | path: ${{ steps.composer-cache.outputs.dir }} 49 | key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} 50 | restore-keys: | 51 | ${{ runner.os }}-composer- 52 | - name: Install dependencies 53 | run: composer install --no-interaction 54 | - name: PHP CS fix 55 | run: vendor/bin/php-cs-fixer fix --dry-run -v --diff 56 | -------------------------------------------------------------------------------- /app/Theme/Scripts.php: -------------------------------------------------------------------------------- 1 | registerFunction('assetPath', [$this, 'assetPath']); 10 | $helpers->registerFunction('getAssetPath', [$this, 'getAssetPath']); 11 | } 12 | 13 | public function register() 14 | { 15 | add_action('wp_enqueue_scripts', [$this, 'wpEnqueueScripts']); 16 | add_action('enqueue_block_editor_assets', [$this, 'wpEnqueueEditorScripts']); 17 | add_theme_support('editor-styles'); 18 | add_editor_style('../static/editor.min.css'); 19 | } 20 | 21 | public function getAssetPath($path) 22 | { 23 | return dirname(get_template_directory_uri()).'/static/'.$path; 24 | } 25 | 26 | public function assetPath($path) 27 | { 28 | echo esc_url($this->getAssetPath($path)); 29 | } 30 | 31 | public function wpEnqueueScripts() 32 | { 33 | // 34 | // Do not add javascript to your theme here, unless you're sure you should. 35 | // 36 | // Normally, you should add Javascript to assets/js/main.js or make a file in assets/js/plugins. 37 | // 38 | // You can/should enqueue a script here only if it is a widely used library that is required by a plugin (or is likely to be later) 39 | // 40 | 41 | // Pretty much everything else should be compiled by Grunt. 42 | wp_enqueue_script('main', $this->getAssetPath('main.min.js'), ['jquery'], '', true); 43 | 44 | wp_enqueue_style('main', $this->getAssetPath('main.min.css')); 45 | } 46 | 47 | public function wpEnqueueEditorScripts() 48 | { 49 | wp_enqueue_script('theme-editor', $this->getAssetPath('editor.min.js'), ['wp-blocks', 'wp-dom'], filemtime(get_stylesheet_directory() . '/../assets/js/editor.js'), true); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## IMPORTANT ## 2 | # 3 | # Usually a pattern here also belongs in your `.dockerignore` file and vice 4 | # versa. 5 | # Note that Docker's ignore syntax is slightly different to Git's. The main 6 | # difference is that Git interprets patterns without a leading slash as applying 7 | # to any subdirectory, while Docker interprets them as relative to the project 8 | # root directory. To resolve that, a `.dockerignore` should prefix those 9 | # patterns with `**/`. This is also compatible with Git. 10 | ## How to use this file 11 | # Add patterns to the section they apply to, sorted by: 12 | # 1. absolute paths to or patterns for files (with a `/` prefix) 13 | # 2. absolute paths to or patterns for directories 14 | # 3. relative paths to or patterns for files (without a `/` prefix) 15 | # 4. relative paths to or patterns for directories 16 | # 5. pattern exceptions (sorted as above) 17 | # Sort them alphanumerically within each section. 18 | # If no section fits, create one. No path or pattern should exist without a 19 | # section or label. 20 | 21 | ## Sensitive files 22 | # To override these ignored files on a case-by-case basis, 23 | # instead of adding a rule to this file, force add them: 24 | # ``` 25 | # git add path/to/file --force 26 | # This reduces the risk of accidentally committing files that happen to match 27 | # the ignore pattern exception, or a file being removed and readded 28 | # unintentionally in the future. 29 | ### Databases 30 | *.db* 31 | *.dump* 32 | *.sql* 33 | *.sqlite3* 34 | ### Environment variables 35 | .env 36 | .env.* 37 | ### Logs 38 | *.log* 39 | ### Secrets and keys 40 | *.crt* 41 | *.key* 42 | *.pem* 43 | ### Spreadsheet data 44 | *.bks* 45 | *.csv* 46 | *.dex* 47 | *.numbers* 48 | *.ods* 49 | *.ots* 50 | *.tsv* 51 | *.xlr* 52 | *.xls* 53 | ### Terraform 54 | .terraformrc* 55 | terraform.rc* 56 | *.tfstate* 57 | *.tfvars* 58 | .terraform/ 59 | ### XML data 60 | *.xml* 61 | ## Dependencies 62 | node_modules/ 63 | vendor/ 64 | ## WordPress media 65 | /wp-content/uploads 66 | ## Temporary files 67 | tmp/ 68 | ## Build artifacts 69 | .php_cs.cache 70 | .sass-cache/ 71 | *.bak* 72 | -------------------------------------------------------------------------------- /spec/theme/wp_head.spec.php: -------------------------------------------------------------------------------- 1 | wpHead = new \Dxw\GovukTheme\Theme\WpHead(); 6 | }); 7 | 8 | afterEach(function () { 9 | }); 10 | 11 | it('is registrable', function () { 12 | expect($this->wpHead)->toBeAnInstanceOf(\Dxw\Iguana\Registerable::class); 13 | }); 14 | 15 | describe('->register()', function () { 16 | it('adds actions', function () { 17 | allow('add_action')->toBeCalled(); 18 | expect('add_action')->toBeCalled()->once()->with('init', [$this->wpHead, 'init']); 19 | $this->wpHead->register(); 20 | }); 21 | }); 22 | 23 | describe('->init()', function () { 24 | it('modifies the output of the WordPress head', function () { 25 | $actions = [ 26 | ['wp_head', 'print_emoji_detection_script', 7], 27 | ['wp_print_styles', 'print_emoji_styles'], 28 | ['admin_print_styles', 'print_emoji_styles'], 29 | ['admin_print_scripts', 'print_emoji_detection_script'], 30 | ['wp_head', 'rsd_link'], 31 | ['wp_head', 'wp_generator'], 32 | ['wp_head', 'wlwmanifest_link'], 33 | ['wp_head', 'feed_links_extra', 3], 34 | ['wp_head', 'start_post_rel_link', 10, 0], 35 | ['wp_head', 'parent_post_rel_link', 10, 0], 36 | ['wp_head', 'adjacent_posts_rel_link', 10, 0], 37 | ]; 38 | 39 | allow('remove_action')->toBeCalled(); 40 | 41 | foreach ($actions as $args) { 42 | if (count($args) == 2) { 43 | list($a, $b) = $args; 44 | expect('remove_action')->toBeCalled()->once()->with($a, $b); 45 | } 46 | if (count($args) == 3) { 47 | list($a, $b, $c) = $args; 48 | expect('remove_action')->toBeCalled()->once()->with($a, $b, $c); 49 | } 50 | if (count($args) == 4) { 51 | list($a, $b, $c, $d) = $args; 52 | expect('remove_action')->toBeCalled()->once()->with($a, $b, $c, $d); 53 | } 54 | } 55 | $this->wpHead->init(); 56 | }); 57 | }); 58 | }); 59 | -------------------------------------------------------------------------------- /spec/theme/tables.spec.php: -------------------------------------------------------------------------------- 1 | tables = new \Dxw\GovukTheme\Theme\Tables(); 6 | }); 7 | 8 | it('is registerable', function () { 9 | expect($this->tables)->toBeAnInstanceOf(\Dxw\Iguana\Registerable::class); 10 | }); 11 | 12 | describe('->register()', function () { 13 | it('registers the filter', function () { 14 | allow('add_filter')->toBeCalled(); 15 | expect('add_filter')->toBeCalled()->once()->with('render_block', [$this->tables, 'useGovukMarkup'], 10, 2); 16 | $this->tables->register(); 17 | }); 18 | }); 19 | 20 | describe('->useGovukMarkup()', function () { 21 | context('this is not a core table block', function () { 22 | it('returns the block content unchanged', function () { 23 | $block['blockName'] = 'core/paragraph'; 24 | $blockContent = '

This will not be changed

'; 25 | $result = $this->tables->useGovukMarkup($blockContent, $block); 26 | expect($result)->toEqual($blockContent); 27 | }); 28 | }); 29 | context('this is a core table block', function () { 30 | it('updates the markup to add the govuk classes', function () { 31 | $block['blockName'] = 'core/table'; 32 | allow('apply_filters')->toBeCalled()->andRun(function ($a, $b) { 33 | return '_' . $b . '_'; 34 | }); 35 | $blockContent = ''; 36 | $blockContent .= ''; 37 | $blockContent .= ''; 38 | $blockContent .= ''; 39 | $blockContent .= '
A caption
Column 1
Data 1
'; 40 | $result = $this->tables->useGovukMarkup($blockContent, $block); 41 | expect($result)->toEqual( 42 | '
A caption
Column 1
Data 1
' 43 | ); 44 | }); 45 | }); 46 | }); 47 | }); 48 | -------------------------------------------------------------------------------- /app/Lib/Whippet/TemplateTags.php: -------------------------------------------------------------------------------- 1 | registerFunction('w_template_title', [$this, 'w_template_title']); 10 | } 11 | 12 | public static function w_template_warning() 13 | { 14 | ?> 15 |

You're using a fallback template:

Did you really mean to? If you can, define a specific template and use it. Like single-post.php.

16 | name); 32 | } 33 | 34 | if (is_post_type_archive()) { 35 | return apply_filters('the_title', get_queried_object()->labels->name); 36 | } 37 | 38 | if (is_day()) { 39 | return sprintf(__('Daily Archives: %s', 'roots'), get_the_date()); 40 | } 41 | 42 | if (is_month()) { 43 | return sprintf(__('Monthly Archives: %s', 'roots'), get_the_date('F Y')); 44 | } 45 | 46 | if (is_year()) { 47 | return sprintf(__('Yearly Archives: %s', 'roots'), get_the_date('Y')); 48 | } 49 | 50 | if (is_author()) { 51 | $author = get_queried_object(); 52 | 53 | return sprintf(__('Author Archives: %s', 'roots'), apply_filters('the_author', is_object($author) ? $author->display_name : null)); 54 | } 55 | 56 | return single_cat_title('', false); 57 | } 58 | 59 | if (is_search()) { 60 | return sprintf(__('Search Results for %s', 'roots'), get_search_query()); 61 | } 62 | 63 | if (is_404()) { 64 | return __('Not Found', 'roots'); 65 | } 66 | 67 | return get_the_title(); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /assets/scss/editor.scss: -------------------------------------------------------------------------------- 1 | $govuk-assets-path: '/wp-content/themes/govuk-theme/static/lib/govuk-frontend/dist/govuk/assets/'; 2 | $govuk-new-typography-scale: true; 3 | 4 | /*-------------------------------------------------------------- 5 | # Settings 6 | 7 | Define our global preprocessor variables and CSS custom 8 | properties. 9 | --------------------------------------------------------------*/ 10 | @import 'settings/settings'; 11 | 12 | 13 | /*-------------------------------------------------------------- 14 | # Helpers 15 | 16 | Functions and mixins. 17 | --------------------------------------------------------------*/ 18 | @import 'helpers/aspect-ratio'; 19 | @import 'helpers/colour'; 20 | @import 'helpers/font-faces'; 21 | @import 'helpers/typography'; 22 | 23 | 24 | /*-------------------------------------------------------------- 25 | # GOV.UK Frontend 26 | 27 | Use the framework's starter styles and make helper mixins and 28 | functions available. 29 | --------------------------------------------------------------*/ 30 | @import "govuk-frontend/dist/govuk/index"; 31 | 32 | 33 | /*-------------------------------------------------------------- 34 | # Core 35 | 36 | Let's make use of the "C" in CSS; "Cascading" styles. With a 37 | relatively small amount of CSS we can reach a whole load of 38 | elements, no matter where they are situated. The markup need not 39 | be touched to give us a solid system from the outset. 40 | 41 | Unlike when using classes, element selectors can target the 42 | arbitrary, unattributed content produced by WYSIWYG editors. 43 | --------------------------------------------------------------*/ 44 | @import "core/forms"; 45 | @import "core/reset"; 46 | @import "core/typography"; 47 | 48 | 49 | /*-------------------------------------------------------------- 50 | # Layout objects 51 | 52 | These classes are all layout objects that don't impose any visual 53 | styles other than postioning and moving things around. 54 | --------------------------------------------------------------*/ 55 | @import "objects/grid"; 56 | 57 | 58 | /*-------------------------------------------------------------- 59 | # Components 60 | 61 | Class-based styles can be adhered to on any HTML element, 62 | anywhere in a document. They are more portable and composable 63 | than element styles, but require the author to affect the 64 | markup directly. 65 | --------------------------------------------------------------*/ 66 | 67 | 68 | /*-------------------------------------------------------------- 69 | # Overrides 70 | 71 | These classes are for final adjustments, and should not be 72 | overridden by anything that comes before them. 73 | --------------------------------------------------------------*/ 74 | @import "overrides/block-editor"; 75 | -------------------------------------------------------------------------------- /assets/js/editor.js: -------------------------------------------------------------------------------- 1 | /* globals wp */ 2 | wp.domReady(() => { 3 | /** 4 | * Manage block registration 5 | */ 6 | const restrictedBlocks = [ 7 | 'core/archives', 8 | 'core/audio', 9 | // 'core/button', 10 | // 'core/buttons', 11 | 'core/calendar', 12 | 'core/categories', 13 | // 'core/classic', 14 | 'core/code', 15 | // 'core/column', 16 | // 'core/columns', 17 | 'core/cover', 18 | // 'core/embed', 19 | 'core/file', 20 | 'core/freeform', 21 | 'core/gallery', 22 | // 'core/group', 23 | // 'core/heading', 24 | // 'core/html', 25 | // 'core/image', 26 | // 'core/legacy-widget', 27 | 'core/latest-comments', 28 | 'core/latest-posts', 29 | 'core/loginout', 30 | // 'core/list', 31 | // 'core/media-text', 32 | 'core/missing', 33 | 'core/more', 34 | // 'core/navigation', 35 | // 'core/navigation-link', 36 | 'core/nextpage', 37 | 'core/page-list', 38 | // 'core/paragraph', 39 | 'core/post-content', 40 | 'core/post-date', 41 | 'core/post-excerpt', 42 | 'core/post-featured-image', 43 | 'core/post-terms', 44 | 'core/post-title', 45 | 'core/preformatted', 46 | 'core/pullquote', 47 | 'core/query', 48 | 'core/query-title', 49 | // 'core/quote', 50 | 'core/rss', 51 | 'core/search', 52 | // 'core/separator', 53 | // 'core/shortcode', 54 | 'core/site-logo', 55 | 'core/site-tagline', 56 | 'core/site-title', 57 | 'core/social-link', 58 | 'core/social-links', 59 | // 'core/spacer', 60 | // 'core/subhead', 61 | 'core/table', 62 | 'core/tag-cloud', 63 | 'core/text-columns', 64 | 'core/verse' 65 | // 'core/video', 66 | // 'core/widget-area', 67 | ] 68 | 69 | // Remove blocks included in blacklist 70 | for (let i = 0, len = restrictedBlocks.length; i < len; i++) { 71 | wp.blocks.unregisterBlockType(restrictedBlocks[i]) 72 | }; 73 | 74 | /** 75 | * Manage embed variations 76 | */ 77 | const allowedEmbedBlocks = [ 78 | 'youtube', 79 | 'vimeo' 80 | ] 81 | 82 | // Unregister blocks not included in whitelist 83 | wp.blocks.getBlockVariations('core/embed').forEach(function (blockVariation) { 84 | if (allowedEmbedBlocks.indexOf(blockVariation.name) === -1) { 85 | wp.blocks.unregisterBlockVariation('core/embed', blockVariation.name) 86 | } 87 | }) 88 | 89 | /** 90 | * Manage block style variations 91 | */ 92 | wp.blocks.unregisterBlockStyle('core/image', ['rounded']) 93 | wp.blocks.unregisterBlockStyle('core/quote', ['large']) 94 | wp.blocks.unregisterBlockStyle('core/table', ['stripes']) 95 | }) -------------------------------------------------------------------------------- /static/lib/govuk-frontend/dist/govuk/assets/images/govuk-icon-mask.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/lib/govuk-frontend/dist/govuk/assets/rebrand/images/govuk-icon-mask.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/scss/main.scss: -------------------------------------------------------------------------------- 1 | $govuk-assets-path: '/wp-content/themes/govuk-theme/static/lib/govuk-frontend/dist/govuk/assets/'; 2 | $govuk-new-typography-scale: true; 3 | /*-------------------------------------------------------------- 4 | # Settings 5 | 6 | Define our global preprocessor variables and CSS custom 7 | properties. 8 | --------------------------------------------------------------*/ 9 | @import 'settings/settings'; 10 | 11 | 12 | /*-------------------------------------------------------------- 13 | # Helpers 14 | 15 | Functions and mixins. 16 | --------------------------------------------------------------*/ 17 | @import 'helpers/aspect-ratio'; 18 | @import 'helpers/colour'; 19 | @import 'helpers/font-faces'; 20 | @import 'helpers/typography'; 21 | 22 | 23 | /*-------------------------------------------------------------- 24 | # GOV.UK Frontend 25 | 26 | Use the framework's starter styles and make helper mixins and 27 | functions available. 28 | --------------------------------------------------------------*/ 29 | @import "govuk-frontend/dist/govuk/index"; 30 | 31 | 32 | /*-------------------------------------------------------------- 33 | # Core 34 | 35 | Let's make use of the "C" in CSS; "Cascading" styles. With a 36 | relatively small amount of CSS we can reach a whole load of 37 | elements, no matter where they are situated. The markup need not 38 | be touched to give us a solid system from the outset. 39 | 40 | Unlike when using classes, element selectors can target the 41 | arbitrary, unattributed content produced by WYSIWYG editors. 42 | --------------------------------------------------------------*/ 43 | @import "core/forms"; 44 | @import "core/reset"; 45 | @import "core/typography"; 46 | 47 | 48 | /*-------------------------------------------------------------- 49 | # Layout objects 50 | 51 | These classes are all layout objects that don't impose any visual 52 | styles other than postioning and moving things around. 53 | --------------------------------------------------------------*/ 54 | @import "objects/grid"; 55 | 56 | 57 | /*-------------------------------------------------------------- 58 | # Templates 59 | 60 | Define styles that apply to WordPress templates. The parent class 61 | will often be generated by WordPress in the element 62 | e.g. .page, .single, .archive. 63 | --------------------------------------------------------------*/ 64 | @import "templates/archive"; 65 | @import "templates/page"; 66 | @import "templates/search"; 67 | @import "templates/single"; 68 | 69 | 70 | /*-------------------------------------------------------------- 71 | # Components 72 | 73 | Class-based styles can be adhered to on any HTML element, 74 | anywhere in a document. They are more portable and composable 75 | than element styles, but require the author to affect the 76 | markup directly. 77 | --------------------------------------------------------------*/ 78 | @import "components/global-footer"; 79 | @import "components/global-footer-menu"; 80 | @import "components/global-header"; 81 | @import "components/navigation"; 82 | @import "components/pagination"; 83 | @import "components/search-form"; 84 | 85 | 86 | /*-------------------------------------------------------------- 87 | # Overrides 88 | 89 | These classes are for final adjustments, and should not be 90 | overridden by anything that comes before them. 91 | --------------------------------------------------------------*/ 92 | -------------------------------------------------------------------------------- /spec/theme/scripts.spec.php: -------------------------------------------------------------------------------- 1 | toBeCalled()->andRun(function ($a) { 6 | return '_'.$a.'_'; 7 | }); 8 | $this->helpers = new \Dxw\Iguana\Theme\Helpers(); 9 | $this->scripts = new \Dxw\GovukTheme\Theme\Scripts($this->helpers); 10 | }); 11 | 12 | afterEach(function () { 13 | }); 14 | 15 | it('is registrable', function () { 16 | expect($this->scripts)->toBeAnInstanceOf(\Dxw\Iguana\Registerable::class); 17 | }); 18 | 19 | describe('->register()', function () { 20 | it('registers nav scripts', function () { 21 | allow('add_action')->toBeCalled(); 22 | expect('add_action')->toBeCalled()->times(2); 23 | expect('add_action')->toBeCalled()->once()->with('wp_enqueue_scripts', [$this->scripts, 'wpEnqueueScripts']); 24 | expect('add_action')->toBeCalled()->once()->with('enqueue_block_editor_assets', [$this->scripts, 'wpEnqueueEditorScripts']); 25 | 26 | allow('add_theme_support')->toBeCalled(); 27 | expect('add_theme_support')->toBeCalled()->once()->with('editor-styles'); 28 | 29 | allow('add_editor_style')->toBeCalled(); 30 | expect('add_editor_style')->toBeCalled()->once()->with('../static/editor.min.css'); 31 | 32 | $this->scripts->register(); 33 | }); 34 | }); 35 | 36 | describe('->getAssetPath()', function () { 37 | it('gets the path of the assets', function () { 38 | allow('get_template_directory_uri')->toBeCalled()->andReturn('http://foo.bar.invalid/cat/dog'); 39 | expect($this->scripts->getAssetPath('meow'))->toEqual('http://foo.bar.invalid/cat/static/meow'); 40 | }); 41 | }); 42 | 43 | describe('->assetPath()', function () { 44 | it('echos the path of the assets', function () { 45 | allow('get_template_directory_uri')->toBeCalled()->andReturn('http://foo.bar.invalid/cat/dog'); 46 | ob_start(); 47 | $this->scripts->assetPath('meow'); 48 | $result = ob_get_contents(); 49 | ob_end_clean(); 50 | expect($result)->toEqual('_http://foo.bar.invalid/cat/static/meow_'); 51 | }); 52 | }); 53 | 54 | describe('->wpEnqueueScripts()', function () { 55 | it('enqueues some of the JavaScript files', function () { 56 | allow('get_template_directory_uri')->toBeCalled()->andReturn('http://a.invalid/zzz'); 57 | 58 | allow('wp_enqueue_script')->toBeCalled(); 59 | 60 | expect('wp_enqueue_script')->toBeCalled()->once()->with('main', 'http://a.invalid/static/main.min.js', ['jquery'], '', true); 61 | 62 | allow('wp_enqueue_style')->toBeCalled(); 63 | 64 | expect('wp_enqueue_style')->toBeCalled()->once()->with('main', 'http://a.invalid/static/main.min.css'); 65 | 66 | $this->scripts->wpEnqueueScripts(); 67 | }); 68 | 69 | describe('->wpEnqueueEditorScripts()', function () { 70 | it('enqueues assets for the editor', function () { 71 | allow('get_template_directory_uri')->toBeCalled()->with()->andReturn('http://a.invalid/zzz'); 72 | allow('get_stylesheet_directory')->toBeCalled()->with()->andReturn('http://a.invalid/zzz'); 73 | allow('filemtime')->toBeCalled()->andReturn('1615926129'); 74 | allow('wp_enqueue_script')->toBeCalled(); 75 | expect('wp_enqueue_script')->toBeCalled()->once(); 76 | expect('wp_enqueue_script')->toBeCalled()->with('theme-editor', 'http://a.invalid/static/editor.min.js', ['wp-blocks', 'wp-dom'], '1615926129', true); 77 | 78 | $this->scripts->wpEnqueueEditorScripts(); 79 | }); 80 | }); 81 | }); 82 | }); 83 | -------------------------------------------------------------------------------- /templates/partials/global-footer.php: -------------------------------------------------------------------------------- 1 |
2 |
3 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 49 |
50 |
51 | -------------------------------------------------------------------------------- /templates/partials/global-header.php: -------------------------------------------------------------------------------- 1 |
2 |
3 | 32 |
33 |
34 |
35 | 'header-search-form']) ?> 36 |
37 |
38 |
39 |
40 | 41 | 42 |
43 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | All notable changes to this project will be documented in this file. 3 | 4 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 5 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 6 | 7 | ## Unreleased 8 | 9 | ### Added 10 | - [Rebranded colour palette and assets](https://github.com/alphagov/govuk-frontend/blob/main/CHANGELOG.md#use-the-refreshed-govuk-brand-if-youre-not-using-nunjucks). 11 | - `data-module` to skip link, [to improve screen reader announcements](https://github.com/alphagov/govuk-frontend/blob/main/CHANGELOG.md#include-javascript-for-skip-link-to-improve-screen-reader-announcements). 12 | - Typography scale feature from govuk-frontend, as per [`govuk-frontend` recommendations](https://github.com/alphagov/govuk-frontend/blob/main/CHANGELOG.md#weve-adjusted-our-responsive-type-scale). 13 | 14 | ### Changed 15 | - Replace the header navigation with the new [service-navigation component](https://github.com/alphagov/govuk-frontend/blob/main/CHANGELOG.md#make-it-easier-to-navigate-complex-services-with-the-service-navigation-component). 16 | - Replace deprecated header class with `govuk-header__service-name`, [to reflect latest HTML markup](https://github.com/alphagov/govuk-frontend/blob/main/CHANGELOG.md#update-references-to-govuk-header__link--service-name-class-from-the-html-for-the-header-component). 17 | - Replace the deprecated `govuk/all` with `govuk/index` as [`govuk-frontend` will remove the `all` files in the next major release](https://github.com/alphagov/govuk-frontend/blob/main/CHANGELOG.md#importing-layers-using-all-files). 18 | - Improve Breadcrumb accessibility by updating it to [use nav and aria-label](https://github.com/alphagov/govuk-frontend/blob/main/CHANGELOG.md#update-breadcrumbs-to-use-nav-and-aria-label). 19 | - Update the `