Compare commits
39 commits
Author | SHA1 | Date | |
---|---|---|---|
6fa9b4fe21 | |||
604d54cae1 | |||
3067d35497 | |||
9d9795b64c | |||
23cc6c99a0 | |||
386c68813a | |||
b4a233a20f | |||
c70e94ae27 | |||
4353453ede | |||
76c8db7c52 | |||
469049521d | |||
0f99141e8e | |||
06689e3fae | |||
568ff7bc65 | |||
a36f1b1dd8 | |||
b438b27847 | |||
1b8441608f | |||
be69398931 | |||
763bbbcd3a | |||
a459d7d32f | |||
1fc4b6487e | |||
5f1e2928d2 | |||
0fe426be44 | |||
3c818fb4fe | |||
1c4506bd4b | |||
a2132616d5 | |||
2ce6d04d2d | |||
116a65b38d | |||
a48cfb84c4 | |||
92270ac7dd | |||
c205ff34ae | |||
2186aaf69c | |||
bedf08c833 | |||
3d877439d3 | |||
8bc66e28b8 | |||
7526638a3d | |||
97ef8bde61 | |||
1dd6f82308 | |||
a59b05feb4 |
969 changed files with 3131 additions and 592 deletions
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
5
build
Executable file
|
@ -0,0 +1,5 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
set -uexo pipefail
|
||||
|
||||
vendor/bin/sculpin generate --watch --server "$@"
|
29
flake-modules/dev-shell.nix
Normal file
29
flake-modules/dev-shell.nix
Normal 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
16
flake-modules/drafts.nix
Normal 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}"
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
33
flake-modules/new-draft.nix
Normal file
33
flake-modules/new-draft.nix
Normal 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
21
flake-modules/publish.nix
Normal 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 "$@"
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
3
flake-modules/systems.nix
Normal file
3
flake-modules/systems.nix
Normal file
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
systems = [ "x86_64-linux" ];
|
||||
}
|
85
flake.lock
generated
85
flake.lock
generated
|
@ -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"
|
||||
}
|
||||
}
|
||||
|
|
31
flake.nix
31
flake.nix
|
@ -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)
|
||||
];
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,14 +0,0 @@
|
|||
---
|
||||
title: {{ title }}
|
||||
date: {{ date }}
|
||||
permalink: {{ permalink }}
|
||||
tags:
|
||||
- software-development
|
||||
# - drupal
|
||||
# - drupal-planet
|
||||
# - php
|
||||
# - podcast
|
||||
cta: ~
|
||||
snippet: |
|
||||
TODO
|
||||
---
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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 %}
|
|
@ -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 %}
|
||||
|
|
1
source/_layouts/zet.html.twig
Normal file
1
source/_layouts/zet.html.twig
Normal file
|
@ -0,0 +1 @@
|
|||
{% extends "page" %}
|
|
@ -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 }}">← Newer Posts{% endif %}<br />
|
||||
{% if page.pagination.next_page %}<a href="{{ site.url }}{{ page.pagination.next_page.url }}">Older Posts →</a>{% endif %}<br />
|
||||
</nav>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block content_bottom %}
|
||||
{% include 'daily-email-form.html.twig' %}
|
||||
|
||||
{% include 'about-me.html.twig' %}
|
||||
{% endblock %}
|
23
source/_pages/blog.html.twig
Normal file
23
source/_pages/blog.html.twig
Normal 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 }}">← Newer Posts{% endif %}<br />
|
||||
{% if page.pagination.next_page %}<a href="{{ site.url }}{{ page.pagination.next_page.url }}">Older Posts →</a>{% endif %}<br />
|
||||
</nav>
|
||||
{% endif %}
|
||||
</ul>
|
|
@ -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
|
||||
company’s 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 agency’s 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 company’s 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
|
||||
|
|
@ -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 %}
|
|
@ -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>
|
||||
|
|
|
@ -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 %}
|
|
@ -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 %}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
---
|
||||
permalink: /sitemap.xml
|
||||
use:
|
||||
- daily_emails
|
||||
- pages
|
||||
- podcast_episodes
|
||||
- posts
|
||||
|
|
27
source/_podcast_episodes/28-using-ai-tools-web-coding.md
Normal file
27
source/_podcast_episodes/28-using-ai-tools-web-coding.md
Normal 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.
|
25
source/_podcast_episodes/29-drupal-cms-recipes.md
Normal file
25
source/_podcast_episodes/29-drupal-cms-recipes.md
Normal 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.
|
23
source/_podcast_episodes/30-growing-engineering-culture.md
Normal file
23
source/_podcast_episodes/30-growing-engineering-culture.md
Normal 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.
|
37
source/_podcast_episodes/31-modeler-api.md
Normal file
37
source/_podcast_episodes/31-modeler-api.md
Normal 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.
|
39
source/_podcast_episodes/32-accessibility.md
Normal file
39
source/_podcast_episodes/32-accessibility.md
Normal 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.
|
|
@ -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
Loading…
Add table
Add a link
Reference in a new issue