Compare commits

...
Sign in to create a new pull request.

39 commits
tome ... main

Author SHA1 Message Date
6fa9b4fe21 Update menu links 2025-08-26 22:03:39 +01:00
604d54cae1 Publish blog page 2025-08-26 19:06:48 +01:00
3067d35497 Add pagination to the blog page 2025-08-26 19:06:48 +01:00
9d9795b64c Reorder packages 2025-08-25 20:20:54 +01:00
23cc6c99a0 Move custom packages 2025-08-25 18:59:53 +01:00
386c68813a Move publish script to Nix
Signed-off-by: Oliver Davies <oliver@oliverdavies.uk>
2025-08-25 18:20:11 +01:00
b4a233a20f Split flake.nix into separate flake-parts modules 2025-08-25 17:48:12 +01:00
c70e94ae27 Remove resources 2025-08-25 16:33:07 +01:00
4353453ede Add draft: Perpetually publishing
Signed-off-by: Oliver Davies <oliver@oliverdavies.uk>
2025-08-23 19:28:58 +01:00
76c8db7c52 Add draft: Using NixBook
Signed-off-by: Oliver Davies <oliver@oliverdavies.uk>
2025-08-23 18:10:38 +01:00
469049521d Add new-draft script 2025-08-22 21:16:03 +01:00
0f99141e8e Add draft: Nix for PHP Developers at PHP Thames Valley
Signed-off-by: Oliver Davies <oliver@oliverdavies.uk>
2025-08-22 20:53:20 +01:00
06689e3fae Allow for filtering drafts by directory
Allow for passing an argument to `drafts` which will be passed to
`grep`.

If no argument is passed, `source` will be used as the default value.
2025-08-22 12:25:04 +01:00
568ff7bc65 Remove new.md 2025-08-22 12:12:05 +01:00
a36f1b1dd8 Add drafts scripts 2025-08-22 00:42:54 +01:00
b438b27847 Copy daily emails from Tome 2025-08-21 23:34:05 +01:00
1b8441608f Move daily emails into the blog page 2025-08-21 00:28:11 +01:00
be69398931 Show post dates 2025-08-21 00:28:10 +01:00
763bbbcd3a Update post 2025-08-21 00:28:09 +01:00
a459d7d32f Fix old post 2025-08-20 23:20:08 +01:00
1fc4b6487e Move favicon.ico 2025-08-20 23:18:24 +01:00
5f1e2928d2 Remove cv.txt 2025-08-20 23:17:54 +01:00
0fe426be44 Remove daily email signup form from posts 2025-08-20 23:17:26 +01:00
3c818fb4fe Automatic Sculpin reloading with Browsersync 2025-08-20 23:17:13 +01:00
1c4506bd4b Re-add a temporary /blog page 2025-08-20 23:16:30 +01:00
a2132616d5 Add browser-sync 2025-08-20 23:15:08 +01:00
2ce6d04d2d Add PHP Thames Valley slides 2025-08-20 22:31:26 +01:00
116a65b38d Add /books to menu 2025-08-20 20:59:48 +01:00
a48cfb84c4 Add books page 2025-08-20 17:06:59 +01:00
92270ac7dd Automated commit
Signed-off-by: Oliver Davies <oliver@oliverdavies.uk>
2025-08-18 00:11:13 +01:00
c205ff34ae Automated commit
Signed-off-by: Oliver Davies <oliver@oliverdavies.uk>
2025-08-18 00:10:01 +01:00
2186aaf69c Fix deployment path 2025-08-18 00:07:27 +01:00
bedf08c833 Update heading
Signed-off-by: Oliver Davies <oliver@oliverdavies.uk>
2025-08-18 00:03:02 +01:00
3d877439d3 Add testimonial 2025-08-18 00:01:39 +01:00
8bc66e28b8 Add "Nix for PHP Developers" talk 2025-08-17 23:38:03 +01:00
7526638a3d Fix CSS 2025-08-17 23:21:42 +01:00
97ef8bde61 Remove deprecation notices 2025-08-17 15:42:05 +01:00
1dd6f82308 Add notes from zet.oliverdavies.uk 2025-08-04 01:09:00 +01:00
a59b05feb4 Add new podcast episodes 2025-08-04 00:57:53 +01:00
969 changed files with 3131 additions and 592 deletions

View file

@ -8,6 +8,10 @@ It contains pages about my products, services, public speaking and training, as
The styling is done using [Tailwind CSS].
## BrowserSync
I have [BrowserSync][] installed and use it to watch for changes to files and [automatically refresh my browser][0] instead of using Sculpin's built-in development server.
## Hosting
The website is hosted on a 1GB DigitalOcean droplet alongside other static websites.
@ -16,6 +20,8 @@ I'm using Apache as my web server so I can easily manage redirects using the `.h
As it's a static website, no PHP or database are needed.
[0]: https://www.oliverdavies.uk/blog/sculpin-browsersync
[browsersync]: https://browsersync.io
[sculpin]: https://sculpin.io
[tailwind css]: https://tailwindcss.com
[website]: https://www.oliverdavies.uk

View file

@ -1,7 +1,5 @@
---
sculpin_content_types:
daily_emails:
permalink: /daily/:year/:month/:day/:basename/
pages:
permalink: /:basename/
podcast_episodes:
@ -10,6 +8,8 @@ sculpin_content_types:
permalink: /blog/:basename/
presentations:
permalink: /presentations/:basename/
zets:
permalink: /zet/:basename-:title/
services:
App\Experience\TwigExtension\ExperienceTwigExtension:

View file

@ -35,7 +35,7 @@ drupalorg:
username: opdavies
features:
new_css: true
new_css: false
github:
url: https://github.com/%github.username%
@ -48,20 +48,16 @@ mastodon:
menu_links:
- title: Home
url: /
- title: Press Info
url: /press
- title: Services
url: /pricing
- title: Presentations
url: /presentations
- title: Blog
url: /blog
- title: Podcast
url: /podcast
attributes:
title: The Beyond Blocks Podcast
- title: Daily list
url: /daily
attributes:
title: The Daily Drupaler Email List
- title: Books
url: /books
- title: Sponsor me
url: /sponsor
- title: Contact
@ -74,6 +70,13 @@ meta:
Oliver is an Acquia-certified Triple Drupal expert, core contributor, Developer, Consultant and multiple-time DrupalCon speaker.
testimonials:
- text: |
Oliver devised a creative and original approach to Drupal theme switching based on Tailwind and provided us with the building blocks and basic theming.
He gave several helpful mentoring sessions with our front end developer to support us to build this approach into our site.
name: Technical Director, European knowledge platform
image: ~
tags: [front]
- text: |
This course is really great and I've recommended it to my coworkers here at Palantir.net.
name: Daniel Davis-Boxleitner

5
build Executable file
View file

@ -0,0 +1,5 @@
#!/usr/bin/env bash
set -uexo pipefail
vendor/bin/sculpin generate --watch --server "$@"

View file

@ -0,0 +1,29 @@
{ inputs, ... }:
{
imports = [ inputs.devshell.flakeModule ];
perSystem =
{ pkgs, self', ... }:
{
devshells.default = {
packages = with pkgs; [
nodePackages.browser-sync
(php83.buildEnv {
extraConfig = ''
error_reporting = E_ALL & ~E_DEPRECATED & ~E_USER_DEPRECATED
'';
})
php83Packages.composer
self'.packages.drafts
self'.packages.new-draft
self'.packages.publish
tailwindcss
];
};
};
}

16
flake-modules/drafts.nix Normal file
View file

@ -0,0 +1,16 @@
{
perSystem =
{ pkgs, ... }:
{
packages.drafts = pkgs.writeShellApplication {
name = "drafts";
runtimeInputs = with pkgs; [ gnugrep ];
text = ''
echo "oob"
grep -r 'draft: true' "''${1:-source}"
'';
};
};
}

View file

@ -0,0 +1,33 @@
{
perSystem =
{ pkgs, ... }:
{
packages.new-draft = pkgs.writeShellApplication {
name = "new-draft";
runtimeInputs = with pkgs; [
coreutils
git
];
text = ''
title="$1"
exclude_words="for|at|and"
filtered_title=$(echo "$title" | sed -E "s/\b($exclude_words)\b//g")
slug=$(echo "$filtered_title" | tr '[:upper:]' '[:lower:]' | sed -e 's/[^a-z0-9]/-/g' -e 's/-\+/-/g' -e 's/^-//g' -e 's/-$//g')
file="source/_posts/$slug.md"
echo -e "---\ntitle: $title\ndate: ~\ndraft: true\n---" > "$file"
echo "File created: $file"
git add "$file"
git commit -s -m "Add draft: $title"
'';
};
};
}

21
flake-modules/publish.nix Normal file
View file

@ -0,0 +1,21 @@
{
perSystem =
{ pkgs, ... }:
{
packages.publish = pkgs.writeShellApplication {
name = "publish";
runtimeInputs = with pkgs; [
rsync
php
];
text = ''
vendor/bin/sculpin generate --env prod
rsync -uvrP static/ output_prod "$@"
rsync -uvrP output_prod/ nixedo.oliverdavies.uk:/var/www/vhosts/website-sculpin "$@"
'';
};
};
}

View file

@ -0,0 +1,3 @@
{
systems = [ "x86_64-linux" ];
}

85
flake.lock generated
View file

@ -1,23 +1,94 @@
{
"nodes": {
"nixpkgs": {
"devshell": {
"inputs": {
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1742422364,
"narHash": "sha256-mNqIplmEohk5jRkqYqG19GA8MbQ/D4gQSK0Mu4LvfRQ=",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "a84ebe20c6bc2ecbcfb000a50776219f48d134cc",
"lastModified": 1741473158,
"narHash": "sha256-kWNaq6wQUbUMlPgw8Y+9/9wP0F8SHkjy24/mN3UAppg=",
"owner": "numtide",
"repo": "devshell",
"rev": "7c9e793ebe66bcba8292989a68c0419b737a22a0",
"type": "github"
},
"original": {
"owner": "nixos",
"owner": "numtide",
"repo": "devshell",
"type": "github"
}
},
"flake-parts": {
"inputs": {
"nixpkgs-lib": "nixpkgs-lib"
},
"locked": {
"lastModified": 1754487366,
"narHash": "sha256-pHYj8gUBapuUzKV/kN/tR3Zvqc7o6gdFB9XKXIp1SQ8=",
"owner": "hercules-ci",
"repo": "flake-parts",
"rev": "af66ad14b28a127c5c0f3bbb298218fc63528a18",
"type": "github"
},
"original": {
"owner": "hercules-ci",
"repo": "flake-parts",
"type": "github"
}
},
"import-tree": {
"locked": {
"lastModified": 1752730890,
"narHash": "sha256-GES8fapSLGz36MMPRVNkSUWXUTtqvGQNXHjRmRLfJUY=",
"owner": "vic",
"repo": "import-tree",
"rev": "6ebb8cb87987b20264c09296166543fd3761d274",
"type": "github"
},
"original": {
"owner": "vic",
"repo": "import-tree",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1755615617,
"narHash": "sha256-HMwfAJBdrr8wXAkbGhtcby1zGFvs+StOp19xNsbqdOg=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "20075955deac2583bb12f07151c2df830ef346b4",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs-lib": {
"locked": {
"lastModified": 1753579242,
"narHash": "sha256-zvaMGVn14/Zz8hnp4VWT9xVnhc8vuL3TStRqwk22biA=",
"owner": "nix-community",
"repo": "nixpkgs.lib",
"rev": "0f36c44e01a6129be94e3ade315a5883f0228a6e",
"type": "github"
},
"original": {
"owner": "nix-community",
"repo": "nixpkgs.lib",
"type": "github"
}
},
"root": {
"inputs": {
"devshell": "devshell",
"flake-parts": "flake-parts",
"import-tree": "import-tree",
"nixpkgs": "nixpkgs"
}
}

View file

@ -1,21 +1,20 @@
{
inputs.nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
inputs = {
devshell.inputs.nixpkgs.follows = "nixpkgs";
devshell.url = "github:numtide/devshell";
flake-parts.url = "github:hercules-ci/flake-parts";
import-tree.url = "github:vic/import-tree";
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
};
outputs =
{ nixpkgs, ... }:
let
system = "x86_64-linux";
pkgs = import nixpkgs { inherit system; };
in
{
devShells.${system}.default = pkgs.mkShell {
buildInputs = with pkgs; [
php83
php83Packages.composer
tailwindcss
];
};
formatter.${system} = pkgs.nixfmt-rfc-style;
inputs:
inputs.flake-parts.lib.mkFlake { inherit inputs; } {
imports = [
(inputs.import-tree ./flake-modules)
];
};
}

View file

@ -1,14 +0,0 @@
---
title: {{ title }}
date: {{ date }}
permalink: {{ permalink }}
tags:
- software-development
# - drupal
# - drupal-planet
# - php
# - podcast
cta: ~
snippet: |
TODO
---

View file

@ -102,7 +102,7 @@ function publish {
APP_ENV=prod generate
rsync --archive --verbose --compress --update --delete \
output_prod/ ssh.oliverdavies.uk:/var/www/vhosts/www.oliverdavies.uk
output_prod/ ssh.oliverdavies.uk:/var/www/vhosts/website-sculpin
git stash pop
}

View file

@ -1,20 +0,0 @@
{% extends 'page' %}
{% block meta_description %}{{ page.snippet|trim }}{% endblock %}
{% block content_wrapper %}
<time datetime="{{ page.date|date('Y-m-d') }}">{{ page.date|date('F jS, Y') }}</time>
{{ parent() }}
<p>- Oliver</p>
{% endblock %}
{% block content_bottom %}
{% include 'daily-email-form.html.twig' with {
intro: 'Sign up here and get more like this delivered straight to your inbox every day.',
title: 'Was this interesting?',
} %}
{% include 'about-me.html.twig' %}
{% endblock %}

View file

@ -7,10 +7,5 @@
{% endblock %}
{% block content_bottom %}
{% include 'daily-email-form.html.twig' with {
intro: 'Sign up here and get more like this delivered straight to your inbox every day.',
title: 'Was this interesting?',
} %}
{% include 'about-me.html.twig' %}
{% endblock %}

View file

@ -0,0 +1 @@
{% extends "page" %}

View file

@ -1,48 +0,0 @@
---
layout: page
title: The Daily Drupaler
meta:
title: The Daily Drupaler - Daily Software Development Thoughts and Tips | %site.name%
description: |-
Daily Software Development Thoughts and Tips by %site.name%.
generator: pagination
pagination:
max_per_page: 30
provider: data.daily_emails
use:
- daily_emails
---
{% block content %}
{% set daily_emails = data.daily_emails|filter((email) => email.date <= 'now'|date) %}
<p>This is an archive of the {{ daily_emails|length|number_format }} email messages I have sent to <a href="/daily">my daily mailing list</a> since the 12th of August, 2022. Enjoy!</p>
<div class="mt-6 space-y-16">
<div>
<ul>
{% for email in page.pagination.items %}
<li>
<a href="{{ email.url }}">
{{ email.date|date('jS F Y') }}:
{{ email.title }}
</a>
</li>
{% endfor %}
</ul>
</div>
{% if page.pagination.previous_page or page.pagination.next_page %}
<nav class="flex justify-center pt-10 space-x-6">
{% if page.pagination.previous_page %}<a href="{{ site.url }}{{ page.pagination.previous_page.url }}">&larr; Newer Posts{% endif %}<br />
{% if page.pagination.next_page %}<a href="{{ site.url }}{{ page.pagination.next_page.url }}">Older Posts &rarr;</a>{% endif %}<br />
</nav>
{% endif %}
</div>
{% endblock %}
{% block content_bottom %}
{% include 'daily-email-form.html.twig' %}
{% include 'about-me.html.twig' %}
{% endblock %}

View file

@ -0,0 +1,23 @@
---
title: Blog
generator: pagination
pagination:
max_per_page: 30
provider: data.posts
use: [posts]
---
<ul>
{% for post in page.pagination.items %}
<li>
<a href="{{ post.url|trim('/', 'right') }}">{{ post.title }}</a> - {{ post.date|date('jS F Y') }}
</li>
{% endfor %}
{% if page.pagination.previous_page or page.pagination.next_page %}
<nav class="flex justify-center pt-10 space-x-6">
{% if page.pagination.previous_page %}<a href="{{ site.url }}{{ page.pagination.previous_page.url }}">&larr; Newer Posts{% endif %}<br />
{% if page.pagination.next_page %}<a href="{{ site.url }}{{ page.pagination.next_page.url }}">Older Posts &rarr;</a>{% endif %}<br />
</nav>
{% endif %}
</ul>

View file

@ -1,260 +0,0 @@
Oliver Davies (opdavies)
oliver+cv@oliverdavies.uk
Software Developer and Technical Lead. Open source advocate, contributor and
maintainer. Public speaker and trainer.
Technical Skills
--------------------------------------------------------------------------------
- Languages: PHP, SQL, HTML, CSS, JavaScript, Bash, Nix, Terraform
- CMSes and Frameworks: Drupal (6+), Symfony (2+), Tailwind CSS, Vue.js,
TypeScript, Stimulus
- Tools: Git, PHPUnit, PHPStan, Behat, Jest, Docker, Ansible, Apache, Nginx,
Caddy, MySQL, GitHub Actions
- Platforms: Acquia, Platform.sh, Pantheon, Amazon AWS, DigitalOcean, Linode
Professional Experience
--------------------------------------------------------------------------------
Interim Web Development Manager 2023-Present
Transport for Wales
Drupal Development Consultant and Coach 2012-Present
Oliver Davies Ltd
- Developed applications using Drupal, Symfony and Silex.
- Migrated sites to newer versions of Drupal (6 to 7, and 7 to 8).
- Provisioned and maintained Linux servers for clients.
- Introduced version control systems, automation and deployment
processes to existing projects.
Lead Software Developer 2021-2023
Transport for Wales
- Co-developed the tfw.wales and trc.cymru websites, consolidating
legacy websites and transitioning from an outsourced team to
in-house Developers.
- Introduced automated testing and test-driven development and static
analysis into the development workflow.
- Created standardised environments using Docker and Docker Compose
for use across the team and within continuous integration (CI)
pipelines.
- Fixed accessibility issues to achieve WCAG 2.0 AA compliance.
- Technologies: PHP, Drupal, Vue.js, TypeScript, Docker, Git, Nix,
Amazon Web Services, Acquia
Acting Technical Team Lead 2019-2020
Inviqa
Senior Software Developer 2019-2021
Inviqa
- Worked on and led a development team responsible for many Drupal 7
and 8 projects.
- Augmented onto a client development team, co-developing an
application using Drupal, Angular and Typescript.
- Part of the out-of-hours critical application support team,
supporting applications including Drupal, Magento and Sylius.
- Certified Mental Health First Aider and part of the Wellbeing team.
Senior Drupal Developer 2017-2019
Microserve
- Developed and maintained various Drupal 7 and 8 projects including
custom modules and automated tests, such as integrating Drupal with
third-party services.
- Improved the accessibility of various projects by working on
front-end and theming-related tasks.
- Wrote custom migrations to import data from various sources into
Drupal 8.
Senior Drupal Developer 2016-2017
Appnovation
- Co-developed various Drupal 7 and 8 projects for UK, US and Canadian
clients, including custom modules and themes.
- Provided technical input to pre-sales opportunities, including the
companys first UK Drupal 8 project and first FTSE 100 client.
Senior Drupal Developer 2015-2016
CTI Digital
- Contributed to and helped support various existing Drupal 7 projects.
- Improved my Drupal 8 knowledge via self-guided learning, focussing on
custom module development and data migration.
- Developed a prototype of a command-line application to generate and
audit codebases, to reduce the onboarding time for Developers and
ensure consistency across projects.
Senior Drupal Developer 2015
Microserve
- Full-stack Drupal 7 development, focussing on custom module
development, REST server integration via restws module, and data
migration from Drupal 6.
- Updated and modernised a non-Drupal PHP platform to ensure its
compatibility with their new Drupal 7 website, adding Composer to
manage dependencies and Guzzle to perform HTTP requests to Drupal to
trigger actions via REST.
Drupal.org Developer 2014-2015
Drupal Association
- Worked on the Drupal.org website, its sub-sites and infrastructure,
developing new tools and features whilst fixing bugs and issues.
- Monitored and maintained the Drupal.org testbot infrastructure during
high traffic periods, ensuring that automated tests are able to run
for patches submitted to Drupal.org.
- Fixed any issues that made Drupal.org a Drupal 8 release blocker,
ensuring that there were no further delays in releasing Drupal 8.
Senior Drupal Developer 2013-2014
Precedent
- Led a development team consisting of colleagues in other offices as
well as an off-site client contractor. Completed an in-progress
Drupal 7 project, adding missing functionality and fixing bugs.
- Created and shared a Vagrant and Puppet-based development environment
to ensure consistency for Developers.
Application Developer 2012-2013
Nomensa
- Developed custom Drupal 7 modules including an integration with
CiviCRM.
- Completed front-end theme development work with a focus on
accessibility, ensuring that it was WCAG 2.0 compliant.
- Worked alongside and mentored front-end Developers in Drupal theming
on projects. Several of them would later become full-time Drupal
Developers and Themers.
- Provisioned servers with a Nginx, PHP-FPM and MySQL stack, and
deployed applications.
Freelance Web Developer 2007-2012
Freelance
Drupal/PHP Developer 2011-2012
Proctor + Stevenson
- Developed and co-developed new websites, including the agencys first
Drupal 7 client project. Provided ongoing support and maintenance of
websites for existing clients.
- Architected and developed a Drupal 6 and Ubertcart project for a
water services company, which processed residential and commercial
property transactions until September 2020.
- Performed Linux server provisioning and configuration tasks for
client websites.
Drupal Web Developer 2010-2011
Horse & Country TV
- Maintained and supported the companys Drupal 6 website as part of a
two-person team.
- Re-architected and re-developed the Events section, adding Ubercart
for paid events which added a new revenue stream for the company.
- Developed custom modules including the 'Now & Next' module which
displayed the current and subsequent programmes on the channel.
Additional Experience
--------------------------------------------------------------------------------
Bootcamp Mentor 2023-Present
School of Code
- Mentoring coding bootcamp students, working with one-on-one mentees
during the bootcamp as well as groups at in-person events such as hack
days.
- Presented a session to current students and graduates at the
TechConnect London event, organised by School of Code.
- Working with School of Code staff and other mentors to review and
select students for upcoming cohorts.
Individual contributor 2012-Present
https://github.com/opdavies
Maintaining and contributing to various open-source software projects.
Individual contributor 2008-Present
https://www.drupal.org/u/opdavies
- Contributed code to Drupal core.
- Maintained Drupal modules and themes, including the Override Node
Options module since 2012, which is used on around 40,000 active
Drupal websites (April 2024).
- Multiple-time DrupalCon speaker, contribution day mentor and track
committee member.
- Board member of the Drupal England & Wales Association.
- Former organiser of the Drupal Bristol user group and DrupalCamp
Bristol conference.
Bootcamp Mentor 2021
Drupal Career Online
Mentoring Drupal coding bootcamp students, organised by DrupalEasy.
Bootcamp Mentor 2018-2021
DevelopMe_
Mentoring coding bootcamp students, learning PHP and JavaScript.
Co-organiser/Organiser 2015-2023
PHP South West/PHP South Wales
- Co-organising PHP-related events in Bristol between 2015 and 2019.
- Organising PHP-related events in Cardiff between 2018 and 2023.
Certifications
--------------------------------------------------------------------------------
- Acquia certified Drupal Developer (2017)
- Acquia certified Drupal Front-End Specialist (2017)
- Acquia certified Drupal Back-End Specialist (2017)
- Acquia certified Drupal Cloud Pro (2018)
- Platform.sh partner certification (2021)
- Adult Mental Health First Aid - Training in Mind / St. John's Ambulance (2019)
Interests
--------------------------------------------------------------------------------
Open source software, Linux, self-hosting, running, martial arts.
Certifications
--------------------------------------------------------------------------------
References available upon request

View file

@ -1,34 +0,0 @@
---
layout: page
title: Sign up for the Daily Drupaler Email List
meta:
title: The Daily Drupaler - Daily Software Development Thoughts and Tips | %site.name%
description: |-
Daily software development thoughts and tips by %site.name%.
use: [daily_emails]
---
{% block content %}
Subscribe to my daily newsletter for software professionals on software development and delivery, Drupal, DevOps, community, and open-source.
{% include 'daily-email-form.html.twig' %}
<section>
<h2>Still not sure?</h2>
<p>These are the emails I sent this week:</p>
<ul>
{% for email in data.daily_emails[:7] %}
<li><a href="{{ email.url }}">{{ email.title }}</a></li>
{% endfor %}
</ul>
</section>
{% endblock %}
{% block content_bottom %}
{% include 'testimonials.html.twig' with {
tag: 'daily',
title: 'What subscribers have said',
} %}
{% endblock %}

View file

@ -84,7 +84,7 @@ urls:
{% include 'testimonials' with {
limit: 5,
tag: 'front',
title: 'Kind words from clients and colleagues',
title: 'Kind words from clients and customers',
} %}
<hr>

View file

@ -1,71 +0,0 @@
---
layout: page
title: Get Unlimited Drupal Consulting for a Fixed Monthly Price
meta:
title: Unlimited Drupal Consulting by Oliver Davies
draft: true
plans:
-
name: Standard
price: 5000
tagline: One concurrent request. Cancel anytime.
features:
- One request at a time.
url: https://buy.stripe.com/8wM14OgBc2jg8Vy3cn
-
name: Pro
price: 9000
tagline: Two concurrent requests. Cancel anytime.
features:
- Two requests at a time.
url: https://buy.stripe.com/9AQaFo0CeaPM3BecMY
features:
- Bug-free guarantee.
- Delivery in days, not weeks.
- Easy credit card or BACS payments.
- Cancel at any time.
---
{% block content %}
<div class="grid gap-8 md:grid-cols-2">
{% for plan in page.plans %}
<div>
<h2>{{ plan.name }} - £{{ plan.price|number_format }}</h2>
<div>
<p>{{ plan.tagline }}</p>
<ul>
{% for feature in page.features|merge(plan.features) %}
<li>{{ feature }}</li>
{% endfor %}
</ul>
<footer class="grid place-items-center">
{% include 'button.html.twig' with {
text: 'Register now<span class="sr-only"> for the ' ~ plan.name|lower ~ ' plan</span>',
url: plan.url,
withArrow: true,
} %}
</footer>
</div>
</div>
{% endfor %}
</div>
## What Does It Include?
## Looking for Something Else?
asdf
{% endblock %}
{% block content_bottom %}
<div class="space-y-12">
{% include 'testimonials' with {
limit: 5,
tag: 'subscription',
title: 'Kind words from clients',
} %}
</div>
{% endblock %}

View file

@ -14,6 +14,10 @@ use: [presentations]
</h2>
</div>
<p>{{ presentation.description }}</p>
{% if presentation.blocks.description %}
{{ presentation.blocks.description|raw }}
{% else %}
<p>{{ presentation.description }}</p>
{% endif %}
</article>
{% endfor %}

View file

@ -1,7 +1,6 @@
---
permalink: /sitemap.xml
use:
- daily_emails
- pages
- podcast_episodes
- posts

View file

@ -0,0 +1,27 @@
---
date: 2025-05-23
topic: Using AI tools for web coding
guests:
- Luke McCormick
transistor:
id: ~
links:
- - Luke on Drupal.org
- https://www.drupal.org/u/cellear
- - Web Coding for Non-Coders -- using AI, of course
- https://webcamp.stanford.edu/session/web-coding-for-non-coders-using-ai-of-course
- - Cursor - the AI text editor
- https://www.cursor.com
- - The Cache-Size-Block module
- https://github.com/cellear/Cache-Size-Block
- - Simplify Drupal
- https://simplifydrupal.com
quotes: []
chapters: []
episode_filename: 28-using-ai-web-coding.mp3
file_size: 28682900
duration: 00:56:04
use: [podcast_episodes]
---
In this episode, Oliver is joined again by Luke McCormick, this time to discuss using AI for web coding and how to simplify Drupal websites.

View file

@ -0,0 +1,25 @@
---
date: 2025-05-30
topic: Drupal CMS Recipes
guests:
- Gareth Alexander
transistor:
id: ~
links:
- - The Drupal recipes cookbook
- https://www.drupal.org/docs/extending-drupal/contributed-modules/contributed-module-documentation/distributions-and-recipes-initiative/recipes-cookbook
- - The Recipes Initiative project on Drupal.org
- https://www.drupal.org/project/distributions_recipes
- - The Bad Judgement module
- https://www.drupal.org/project/bad_judgement
- - Gareth on Drupal.org
- https://www.drupal.org/u/the_g_bomb
- - Gareth's presentation at DrupalCamp England
- https://www.youtube.com/watch?v=b7MDA-kKCCk
episode_filename: 29-drupal-cms-recipes.mp3
file_size: 30861164
duration: 00:59:29
use: [podcast_episodes]
---
In this episode, Oliver is joined by Gareth Alexander - Drupal CMS Accessibility Tools Track Lead and recent speaker at DrupalCamp England - to discuss Drupal CMS recipes.

View file

@ -0,0 +1,23 @@
---
date: 2025-06-11
topic: Growing Engineering Culture
guests:
- Ev Maslovskiy
links:
- - Ev on Drupal.org
- https://www.drupal.org/u/spleshka
- - SystemSeed
- https://systemseed.com
- - SystemSeed on Drupal.org
- https://www.drupal.org/systemseed
- - DrupalCamp England
- https://www.drupalcampengland.org
- - Video recording of Ev's talk
- https://www.youtube.com/watch?v=Q_9fWVCAUtU
episode_filename: 30-engineering-culture.mp3
file_size: 30861164
duration: 00:59:29
use: [podcast_episodes]
---
In this episode, Oliver is joined by Ev Maslovskiy - CTO at SystemSeed - to discuss engineering culture after his recent talk at DrupalCamp England.

View file

@ -0,0 +1,37 @@
---
date: 2025-06-27
topic: Modeler API
guests:
- Jürgen Haas
links:
- - Jürgen on Drupal.org
- https://www.drupal.org/u/jurgenhaas
- - The ECA module
- https://www.drupal.org/project/eca
- - The BPMN.iO module
- https://www.drupal.org/project/bpmn_io
- - Drupal Events, Conditions and Actions with Jürgen Haas
- /podcast/23-jurgen-haas-eca
- - Drupal Remote Dashboard
- https://www.drupal.org/project/drd
- - Drupal Recipes
- https://www.drupal.org/docs/extending-drupal/drupal-recipes
- - Discussing Drupal CMS Recipes with Gareth Alexander
- /daily/2025/06/03/discussing-drupal-cms-recipes-gareth-alexander
- - Drupal CMS
- https://www.drupal.org/project/cms
- - Discussing Drupalisms with Emma Horrell and Luke McCormick
- /podcast/27-discussing-drupalisms
- - Model Context Protocol
- https://modelcontextprotocol.io
- - The Model Context Protocol module
- https://www.drupal.org/project/mcp
- - Using AI tools for web coding with Luke McCormick
- /podcast/28-using-ai-tools-web-coding
episode_filename: 31-modeler-api.mp3
file_size: 21761540
duration: 00:46:05
use: [podcast_episodes]
---
In this episode, Oliver is re-joined by Jürgen Haas to discuss the new Modeler API module and progress made with the ECA module.

View file

@ -0,0 +1,39 @@
---
date: 2025-07-11
topic: Web Accessibility
guests:
- Mike Gifford
links:
- - Mike's website
- https://ox.ca
- - Mike on Drupal.org
- https://www.drupal.org/u/mgifford
- - My Web, My Way
- https://www.bbc.co.uk/programmes/p005khmk
- - simplA11yPDFCrawler
- https://github.com/accessibility-luxembourg/simplA11yPDFCrawler
- - Drupal.org's Accessibility page
- https://www.drupal.org/about/features/accessibility
- - WCAG 2 Overview
- https://www.w3.org/WAI/standards-guidelines/wcag
- - Drupal's core gates
- https://www.drupal.org/about/core/policies/core-change-policies/core-gates
- - Accessibility Roles and Responsibilities Mapping (ARRM) Community Group
- https://www.w3.org/community/arrm
- - Sustainable Web Interest Group
- https://www.w3.org/groups/ig/sustainableweb
- - Writing Accessibility tests in Nightwatch
- https://www.drupal.org/docs/develop/automated-testing/javascript-testing-using-nightwatch
- - The Sa11y module
- https://www.drupal.org/project/sa11y
- - Drupal's Accessibility Coding Standards
- https://www.drupal.org/docs/develop/standards/accessibility-coding-standards
- - Shift-left testing
- https://en.wikipedia.org/wiki/Shift-left_testing
episode_filename: 32-web-accessibility.mp3
file_size: 38235236
duration: 01:23:01
use: [podcast_episodes]
---
In this episode, Oliver is joined by Mike Gifford - Senior Strategist at CivicActions, W3C Invited Expert and Drupal Core Accessibility Maintainer - to discuss web accessibility.

View file

@ -66,10 +66,6 @@ return Collection::make($stationNodes)
->map(fn (StationInterface $station): string => $station->getStationCode())
->values();
```
<<<<<<< HEAD:website/source/_daily_emails/2022-10-03.md
=======
>>>>>>> b9cea6d (chore: replace Sculpin with Astro):website/src/pages/daily-emails/2022-10-03.md
I've added an additional `map` to convert the nodes to the value object, but the second map can now use the new typehint - ensuring better type safety and also giving us auto-completion in IDEs and text editors. If an incorrect node type is passed in, then the Exception will be thrown and a much clearer error message will be shown.
Finally, I can use the helper method to get the field value, encapsulating the logic within the value object and making it intention clearer and easier to read.

Some files were not shown because too many files have changed in this diff Show more