-
- {% include 'talk/slides' %}
- {% include 'talk/video' %}
- {% include 'talk/tweets' %}
- {% include 'talk/events' with { events: get_events_for_talk(page, site.events) } only %}
-
-{% endblock %}
diff --git a/astro/sculpin-old/source/_pages/404.md b/astro/sculpin-old/source/_pages/404.md
deleted file mode 100644
index 1b989384..00000000
--- a/astro/sculpin-old/source/_pages/404.md
+++ /dev/null
@@ -1,7 +0,0 @@
----
-title: Page Not Found
-permalink: /404.html
-use: [posts]
----
-
-Please [contact me](/contact/) and let me know.
diff --git a/astro/sculpin-old/source/_pages/about.md b/astro/sculpin-old/source/_pages/about.md
deleted file mode 100644
index f0b2f974..00000000
--- a/astro/sculpin-old/source/_pages/about.md
+++ /dev/null
@@ -1,39 +0,0 @@
----
-layout: front
-title: About Me
-meta:
- og:
- title:
- 'Oliver Davies - Full Stack Developer, System Administrator, PHP and
- Drupal specialist'
- description:
- 'The personal website and blog of Oliver Davies, a Full Stack Developer
- and System Administrator from Wales, UK.'
- type: website
-permalink: /
----
-
-
-
-Hi, I'm Oliver Davies (aka [opdavies](https://www.google.com/#q=opdavies)). I’m
-a {{ site.work.role }} at
-[{{site.companies[site.work.company].name}}]({{site.companies[site.work.company].url}})
-and a part-time freelance Web Developer, based in Wales, UK.
-
-I’ve been a Developer since 2007 and specialise in using Drupal, Symfony and
-Vue.js, though I also use other technologies including Laravel and Sculpin. I
-use Ansible for server provisioning and application deployments.
-
-I’m an [Acquia certified](https://certification.acquia.com/user/1647756) Drupal
-8 Grand Master, and Webmaster and Documentation Maintainer on
-[Drupal.org](https://www.drupal.org). I was previously a Developer for the
-[{{site.companies.drupal_association.name}}]({{site.companies.drupal_association.url}}).
-
-I regularly [give talks](/talks) at user groups and conferences, and am an
-organiser of the
-[{{site.events.php_south_wales.name}}]({{site.events.php_south_wales.url}}) user
-group.
-
-I enjoy contributing to open source, and maintain a variety of different
-projects. You can see these on my [Drupal.org]({{site.drupalorg.url}}) and
-[GitHub]({{site.github.url}}) accounts.
diff --git a/astro/sculpin-old/source/_pages/accessibility.md b/astro/sculpin-old/source/_pages/accessibility.md
deleted file mode 100644
index fccc1bcd..00000000
--- a/astro/sculpin-old/source/_pages/accessibility.md
+++ /dev/null
@@ -1,11 +0,0 @@
----
-title: Accessibility
-use: [posts]
----
-
-# Accessibility
-
-I have made as much effort as possible to make this website accessible to all
-users.
-
-If you have any suggestions to improve the site, please [contact me](/contact/).
diff --git a/astro/sculpin-old/source/_pages/company-information.md b/astro/sculpin-old/source/_pages/company-information.md
deleted file mode 100644
index 047afed8..00000000
--- a/astro/sculpin-old/source/_pages/company-information.md
+++ /dev/null
@@ -1,14 +0,0 @@
----
-title: Company Information
-meta:
- description: 'Company information for Oliver Davies Ltd.'
-use: [posts]
----
-
-# Company Information
-
-Company name : Oliver Davies Ltd (previously Oliver Davies Web Development Ltd)
-
-Registered address : 3 Westfield Close, Caerleon, Newport, NP18 3ED
-
-Company number : 8017706
diff --git a/astro/sculpin-old/source/_pages/contact-thanks.md b/astro/sculpin-old/source/_pages/contact-thanks.md
deleted file mode 100644
index 2c340bb5..00000000
--- a/astro/sculpin-old/source/_pages/contact-thanks.md
+++ /dev/null
@@ -1,8 +0,0 @@
----
-title: Thanks!
-permalink: contact/thanks/
-use: [posts]
----
-
-Your email has been sent. You should receive a response within the next working
-day.
diff --git a/astro/sculpin-old/source/_pages/contact.html.twig b/astro/sculpin-old/source/_pages/contact.html.twig
deleted file mode 100644
index 8d759b82..00000000
--- a/astro/sculpin-old/source/_pages/contact.html.twig
+++ /dev/null
@@ -1,42 +0,0 @@
----
-title: Contact
-use: [posts]
-honeypot_field: Qr4W7oB25C
----
-{% block content %}
-
-
To send me an email, complete the form below.
-
-
-
-{% endblock %}
diff --git a/astro/sculpin-old/source/_pages/dev.md b/astro/sculpin-old/source/_pages/dev.md
deleted file mode 100644
index cb189d8b..00000000
--- a/astro/sculpin-old/source/_pages/dev.md
+++ /dev/null
@@ -1,28 +0,0 @@
----
-title: Developing this Website (WIP)
----
-
-This site is built with [Sculpin][], a static site generator written in PHP,
-that generates a static HTML website from Markdown files and Twig templates. You
-can see the [source code on GitHub].
-
-## Extending Sculpin
-
-- Custom Twig extensions
-- https://github.com/opdavies/sculpin-twig-markdown-bundle
-- https://github.com/opdavies/sculpin-gist-embed-bundle
-- https://github.com/opdavies/sculpin-content-generator-bundle
-
-## Front End
-
-On the front-end, I have used [PostCSS][] rather than Sass or Less, and
-[Tailwind CSS] for all of the styling, and some [Vue.js][] for the navbar and
-toggling the navigation menu on mobile. These are compiled with [Webpack
-Encore][] - a wrapper around Webpack, provided by Symfony.
-
-[postcss]: https://postcss.org
-[sculpin]: https://sculpin.io
-[source code on github]: https://github.com/opdavies/oliverdavies.uk
-[tailwind css]: https://tailwindcss.com
-[vue.js]: https://vuejs.org
-[webpack encore]: https://github.com/symfony/webpack-encore
diff --git a/astro/sculpin-old/source/_pages/opensource.html.twig b/astro/sculpin-old/source/_pages/opensource.html.twig
deleted file mode 100644
index 7afb71eb..00000000
--- a/astro/sculpin-old/source/_pages/opensource.html.twig
+++ /dev/null
@@ -1,168 +0,0 @@
----
-title: Open Source
-projects:
- drupal:
- - name: Accessibility (a11y) Checklist
- description: Similar to the SEO Checklist and QA Checklist modules, this module provides a checklist of accessibilty-related modules and tasks to perform on a Drupal site.
- url: https://www.drupal.org/project/a11y_checklist
- versions: [7]
-
- - name: Block ARIA Landmark Roles
- description: Inspired by Block Class, this module adds additional elements to the block configuration forms that allow users to assign a ARIA landmark role to a block.
- url: https://www.drupal.org/project/block_aria_landmark_roles
- versions: [7]
-
- - name: Breadcrumbs by Path
- description: A light-weight module which simply builds breadcrumb trails based on a URL alias.
- url: https://www.drupal.org/project/breadcrumbs_by_path
- versions: [7]
-
- - name: Collection class
- description: Integrates Laravel’s Collection class into Drupal 7.
- url: https://www.drupal.org/project/collection_class
- versions: [7]
-
- - name: Comment Hide Subject
- description: Hides the comment subject if the "Allow comment title" checkbox is unchecked for that node type.
- url: https://www.drupal.org/project/comment_hide_subject
- versions: [7]
-
- - name: Commerce Cart Empty Paths
- description: This module allows site administrators to define multiple paths, and when a user visits a non-declared page, their shopping cart is emptied.
- url: https://www.drupal.org/project/commerce_cart_empty_paths
- versions: [7]
-
- - name: Copyright Block
- description: Creates a block that allows you to configure a copyright message that automatically updates using the current year from the server that your site is hosted on.
- url: https://www.drupal.org/project/copyright_block
- versions: [7, 8]
-
- - name: Image Style Class
- description: Adds classes onto each rendered image showing the image style name.
- url: https://www.drupal.org/project/image_style_class
- versions: [7]
-
- - name: Mapify
- description: A module to make the implementation of mapify.js into Drupal 7 relatively simple.
- url: https://www.drupal.org/project/mapify
- versions: [7]
-
- - name: Node Comment Block
- description: This module moves the comments for a node into a moveable block.
- url: https://www.drupal.org/project/node_comment_block
- versions: [7]
-
- - name: Null User
- description: Adds a NullUser class for simpler code with less conditions.
- url: https://www.drupal.org/project/null_user
- versions: [8]
-
- - name: Override Node Options
- description: Allows permissions to be set to each field within the Authoring information and Publishing options field sets on the node form.
- url: https://www.drupal.org/project/override_node_options
- versions: [7, 8]
-
- - name: Pathauto Menu Link
- description: Forces an update of the Pathauto-generated path when a menu link item has been updated. Useful if you use parent menu links to generate paths.
- url: https://www.drupal.org/project/pathauto_menu_link
- versions: [7, 8]
-
- - name: Private Message Queue
- description: Adds the ability to queue private messages for sending.
- url: https://www.drupal.org/project/private_message_queue
- versions: [8]
-
- - name: 'Rules Block/Unblock User'
- description: Adds rules events, as well as some default rules, for when a user account is blocked or unblocked.
- url: https://www.drupal.org/project/rules_block_user
- versions: [7]
-
- - name: SpeakerDeck Field
- description: Adds a field for embedding content from SpeakerDeck.
- url: https://www.drupal.org/project/speakerdeck_field
- versions: [8]
-
- - name: System User
- description: Adds the ability to identify and retrieve system users.
- url: https://www.drupal.org/project/system_user
- versions: [7, 8]
-
- - name: Toggle Optional Fields
- description: Creates a simplified node form by allowing for the hiding and toggling of optional fields.
- url: https://www.drupal.org/project/toggle_optional_fields
- versions: [7]
-
- - name: Webform ARIA
- description: Adds ARIA support to forms created using the Webform module.
- url: https://www.drupal.org/project/webform_aria
- versions: [7]
-
- - name: WP Blog Migrate
- description: Convert your existing Drupal blog into the WP Blog module by re-assigning the content type for existing nodes and moving any existing tags into the WP Blog taxonomy vocabulary.
- url: https://www.drupal.org/project/wp_blog_migrate
- versions: [7]
-
- sculpin:
- - name: oliverdavies.uk
- description: The source code for this website, which is built with Sculpin.
- url: https://github.com/opdavies/oliverdavies.uk
-
- - name: Sculpin Content Generator Bundle
- description: Provides new Sculpin commands for generating new content.
- url: https://github.com/opdavies/sculpin-content-generator-bundle
-
- - name: Sculpin Gist Bundle
- description: Allows for embedding GitHub Gists into a Sculpin site.
- url: https://github.com/opdavies/sculpin-gist-embed-bundle
-
- - name: Sculpin Skeleton
- description: A skeleton project for the Sculpin static site generator.
- url: https://github.com/opdavies/sculpin-skeleton
-
- - name: Sculpin Twig Markdown Bundle
- description: Enables rendering content from markdown, using Sculpin’s core markdown parser.
- url: https://github.com/opdavies/sculpin-twig-markdown-bundle
-
- - name: Sculpin Twig Sort by Field Bundle
- description: Enables sorting an array by a certain field on each item.
- url: https://github.com/opdavies/sculpin-twig-sort-by-field-bundle
-
- php:
- - name: Drupal Meetups Twitterbot
- description: A Twitter bot that retweets posts about Drupal meetups.
- url: https://github.com/opdavies/drupal-meetups-twitterbot
-
- - name: Drupal VM CLI
- description: A command line tool for Drupal VM.
- url: https://github.com/opdavies/drupal-vm-cli
- active: false
-
- - name: Gmail Filter Builder
- description: Allows you to define Gmail filters in PHP using a fluent API, and then generate XML that you can import into Gmail's filter settings.
- url: https://github.com/opdavies/gmail-filter-builder
----
-
I have written, open-sourced, and maintain a number of Drupal modules, Sculpin bundles and PHP projects - as well as the source code for this website! Here is some information about each project and a link to it’s project page.
-
-
-
Drupal
-
- {% include 'opensource/projects' with {
- projects: page.projects.drupal
- } %}
-
-
-
-
Sculpin
-
- {% include 'opensource/projects' with {
- projects: page.projects.sculpin
- } %}
-
-
-
-
PHP
-
- {% include 'opensource/projects' with {
- projects: page.projects.php
- } %}
-
diff --git a/astro/sculpin-old/source/_pages/podcasts.html.twig b/astro/sculpin-old/source/_pages/podcasts.html.twig
deleted file mode 100644
index ae466ec0..00000000
--- a/astro/sculpin-old/source/_pages/podcasts.html.twig
+++ /dev/null
@@ -1,99 +0,0 @@
----
-title: Podcasts
-podcasts:
- howtocodewell:
- name: How to Code Well
- url: https://howtocodewell.fm
- talking_drupal:
- name: Talking Drupal
- url: http://talkingdrupal.com
- thatpodcast:
- name: That Podcast
- url: https://thatpodcast.io
-episodes:
- - title: 'Episode #175 - Automated Testing'
- description: I joined the Talking Drupal team to discuss automated testing.
- podcast: talking_drupal
- date: 2018-09-05
- url: http://talkingdrupal.com/175
- audio: true
-
- - title: 'Episode #204 - A Few Things'
- description: I joined the Talking Drupal team again, where we discussed Drupal updates, conferences and more.
- podcast: talking_drupal
- date: 2019-03-25
- url: http://talkingdrupal.com/204
- audio: true
-
- - title: What's new in Drupal 8+
- description: Talking about Drupal, open source, Drupal 7 vs Drupal 8, module development, testing and more.
- podcast: howtocodewell
- date: 2019-04-12
- url: https://howtocodewell.fm/episode/15-whats-new-in-drupal-8-plus-oliver-davies-interview
- audio: true
- video: true
-
- - title: 'Episode 60 - The One Where We Talk Twig, Drupal, and Sculpin'
- description: I joined Beau and Dave to talk about various topics including Drupal, the Sculpin static site generator, Twig, Tailwind CSS and Symfony.
- podcast: thatpodcast
- date: 2019-07-01
- url: https://thatpodcast.io/episodes/episode-60-the-one-where-we-talk-twig-drupal-and-sculpin-with-oliver-davies
- audio: true
-
- - title: Static Site Generators
- description: |
- Talking again with Peter Fisher, this time about static site generators. We talk about what they are, when you should and shouldn’t use them, and how to use them with a content management system like Drupal.
- podcast: howtocodewell
- date: 2019-07-19
- url: https://howtocodewell.fm/episode/29-what-are-static-site-generators-oliver-davies
- audio: true
- video: true
----
-{% macro episodeTitle(podcast, episode) -%}
- {{ podcast.name }}: {{ episode.title }}
-{%- endmacro %}
-
-{% import _self as helpers %}
-
-
-
As well as writing posts and giving talks, I also enjoy being on podcasts and speaking about interesting topics.
diff --git a/astro/sculpin-old/source/_pages/projects.html.twig b/astro/sculpin-old/source/_pages/projects.html.twig
deleted file mode 100644
index ede55774..00000000
--- a/astro/sculpin-old/source/_pages/projects.html.twig
+++ /dev/null
@@ -1,57 +0,0 @@
----
-title: Projects
-projects:
- - title: Rebuilding Acquia
- description: A clone of Acquia’s hosting dashboard, built with Vue.js and Tailwind CSS.
- url: https://github.com/opdavies/rebuilding-acquia
-
- - title: Rebuilding Bartik
- description: A clone of Bartik (Drupal’s default theme), built with Vue.js and Tailwind CSS.
- url: https://github.com/opdavies/rebuilding-bartik
-
- - title: Joind.in Winner Picker
- description: A Symfony 4 application that determines a randomly selected winner from a section of feedback left on Joind.in. Developed on behalf of the PHP South West (PHPSW) user group.
- url: https://github.com/opdavies/joindin-winner-picker-new
-
- - title: Drupal.org API library
- description: A PHP library for interacting with the Drupal.org API.
- url: https://github.com/opdavies/drupalorg-api-php
-
- - title: Drupal Meetups Twitterbot
- description: A Symfony 4 application for retweeting tweets about Drupal meetups.
- url: https://github.com/opdavies/sculpin-skeleton
-
- - title: Gmail Filter Builder
- description: A library for writing Gmail filters in PHP, then exporting them to importable XML.
- url: https://github.com/opdavies/gmail-filter-builder
-
- - title: Sculpin Skeleton
- description: A skeleton project for the Sculpin static site generator.
- url: https://github.com/opdavies/sculpin-skeleton
----
-
-
Here are some of the open source projects that I’ve written or currently maintain.
-# Speaker Info
-
-## Bio
-
-[Oliver Davies][website] ([@opdavies][twitter]) has been building websites since
-2007, and speaking at meetups and conferences since 2012. He is a Full Stack
-Developer and an Acquia certified Drupal Grand Master, who also has experience
-developing with Symfony, Laravel, Sculpin and Vue.js, as well as with DevOps and
-systems administration.
-
-He is a {{ site.work.role }} at
-[{{ site.companies[site.work.company].name }}][work], a Drupal core contributor
-and mentor, and an open source and contribution advocate.
-
-He regularly blogs and gives talks on various topics, maintains and contributes
-to various open source projects, and co-organises the PHP South Wales user
-group.
-
-[twitter]: {{site.twitter.url}}
-[website]: {{site.url}}
-
-[work]: {{site.companies[site.work.company].url}}
-
-## Photos
-
--
--
-
-## Some Events I’ve Spoken At
-
-- BlueConf 2019
-- DrupalCamp Brighton 2015
-- DrupalCamp Bristol 2016
-- DrupalCamp Dublin 2017
-- DrupalCamp London (2014, 2015, 2016, 2017, 2019)
-- DrupalCamp North 2015
-- DrupalCon Amsterdam 2019
-- Nomad PHP
-- PHP North West 2017 (10 year anniversary)
-- PHP South Coast 2016
-- PHP UK Conference 2018
-- WordCamp Bristol 2019
-
diff --git a/astro/sculpin-old/source/_pages/stream.md b/astro/sculpin-old/source/_pages/stream.md
deleted file mode 100644
index eba1f984..00000000
--- a/astro/sculpin-old/source/_pages/stream.md
+++ /dev/null
@@ -1,18 +0,0 @@
----
-title: Live Streaming
----
-
-I like try and do some live coding when I can, whether I’m working on a side
-project, my own website or some open source code. You can find my [stream link
-on YouTube][0], or view some previous streams below:
-
-## Stream Playlists
-
-- [Miscellaneous coding live streams][1] {# - [Building the PHP South Wales
- website][2] #} {# - [Using PHP to generate Gmail Filter XML with the Gmail
- Filter Builder][3] #}
-
-[0]: {{site.youtube.stream.url}}
-[1]: https://www.youtube.com/playlist?list=PLHn41Ay7w7kcWbjrYaiqXlfrqi_teTJE8
-[2]: https://www.youtube.com/playlist?list=PLHn41Ay7w7keUxBa-6TNn0_xz27ZfLD5f
-[3]: https://www.youtube.com/playlist?list=PLHn41Ay7w7keRp47rXEx9his-oA8kk4-v
diff --git a/astro/sculpin-old/source/_pages/talks.html.twig b/astro/sculpin-old/source/_pages/talks.html.twig
deleted file mode 100644
index f045b797..00000000
--- a/astro/sculpin-old/source/_pages/talks.html.twig
+++ /dev/null
@@ -1,47 +0,0 @@
----
-title: Talks
-meta:
- description: 'Information about previous and upcoming talks that Oliver has presented at conferences and user groups'
-use: [talks]
-talks:
- - title: 'Drupal and the LDAP module'
- description: A review and demonstration of some of the recent single sign-on work that I did using Drupal’s LDAP module.
- events:
- - event: swdug
- date: 2013-07-10
-
- - title: 'About the Drupal Association'
- description: An impromptu talk about what the Drupal Association is, and what work I’ve been doing since I joined the Association staff.
- events:
- - event: swdug
- date: 2014-08-19
-
- - title: 'Automated testing and Test Driven Development in Drupal 8'
- description: A workshop that I gave about automated testing and test driven development in Drupal 8.
- type: Workshop
- events:
- - event: drupal_bristol
- date: 2018-06-27
- - event: drupalcamp_london_20
- date: 2020-03-13
----
-{% block content %}
- {% set talks = page.talks|merge(data.talks) %}
-
-
-
- After giving my first talk in September 2012, I have now given {{ get_past_talk_count(talks) }} presentations at various conferences and meetups,
- on topics including PHP, Drupal, Git, CSS and systems administration.
-
-
-
-
- {% include 'talks/upcoming' with {
- talks: get_upcoming_talks(talks),
- } only %}
-
- {% include 'talks/past' with {
- talks: get_past_talks(talks),
- } only %}
-
-Having [given talks][1] and [workshops][workshop], been a guest on podcasts and [written articles][0] about automated testing in Drupal, I’m currently in the planning phase of a book and potentially some accompanying screencasts about it, focussing on Drupal 8.
-
-I’m still thinking about what use-cases to cover and examples to include, but
-here are some of the things I’m considering:
-
-- What things to test, and what not to test
-- The different types of available tests, and when to use each
-- How to write testable code
-- What happens when I run a test?
-- How to run tests in the Drupal UI
-- How to run tests with the `run-tests.sh` script
-- How to install, configure and run tests with PHPUnit in Drupal 8
-- Viewing HTML from run tests
-- How to write your first test
-- Debugging tests
-- How to organise your test files
-- Selecting the right base class and using test traits
-- Writing your own base test classes, traits and assertions
-- Managing dependencies for your tests (fields, configuration)
-- Creating users, checking access with roles and permissions
-- Creating pages and blocks with Views and testing the output
-- Creating pages with routes and controllers and testing the output
-- Testing custom plugins
-- Testing queuing items and processing queues
-- Testing sending emails
-- Testing custom Twig filters and functions
-
-
-- Running tests as part of your continuous integration pipeline
-
-I’ll most likely be publishing it via Leanpub, and will be sending free
-chapters, early-bird discounts and links to screencasts and blog posts as I
-write the book to subscribers of the mailing list.
-
-If you have questions or would like to suggest something for me to include in
-the book, please contact me.
-
-**Enter your email address to subscribe to the Test Driven Drupal mailing list
-and be notified of any updates.**
-
-
-
-{% include 'pages/book/signup-form' %}
-
-
-{% endblock %}
-
-[0]: /articles/tags/testing
-[1]: /talks/tdd-test-driven-drupal
-[2]: /contact
-[workshop]: https://web.archive.org/web/20200422110605/https://drupalcamp.london/training/Automated-Testing-and-Test-Driven-Development-in-Drupal-8
\ No newline at end of file
diff --git a/astro/sculpin-old/source/_pages/testimonials.html.twig b/astro/sculpin-old/source/_pages/testimonials.html.twig
deleted file mode 100644
index 1fbb553a..00000000
--- a/astro/sculpin-old/source/_pages/testimonials.html.twig
+++ /dev/null
@@ -1,100 +0,0 @@
----
-title: Testimonials
-use: [posts]
-testimonials:
- - name: Ed Welsby
- image: ed-welsby.png
- role: Senior Developer at Proctor & Stevenson
- text: |
- Oliver was great to work with, he has a solid knowledge of the various aspects of web development and never minded helping me out with Linux commands!
-
- - name: Brian Healy
- image: brian-healy.png
- role: Director of Business Development at Tincan.
- text: |
- Oliver was fantastic to work with - pro-active and highly responsive, he worked well remotely and as part of a project team. His understanding of the project requirement(s) and ability to translate it into working code was essential and he delivered.
-
- - name: Marlon Duncanson
- role: 'Brand & Web Specialist'
- text: |
- Oliver is a great guy and really easy to work with. He really goes the extra mile to make sure the project is done properly. I would recommend him and will not hesitate to use him again in future.
-
- - name: Brian Hartwell
- role: Interactive Creative Director
- text: |
- Oliver was great to work with. He has expert knowledge with Drupal and delivered exactly what we were looking for on time. He's understanding, friendly and easy to get along with. I would enjoy working with him again in the future.
-
- - name: Daniel Easterbrook
- role: Digital Strategy Consultant
- text: |
- Oliver is seasoned Drupal and all round highly skilled and experienced web developer. I have worked with Oliver on an important project where he was reliable, prompt and ensured strict client deadline delivery and confidentiality at all times.
-
- - name: James Chapman
- role: Director at Development Done Right
- image: james-chapman.png
- text: |
- We used Oliver on a number of occasions throughout 2012 and I have to say we've been delighted with his work. His skills working with Drupal are excellent particularly with custom module development and we wouldn’t hesitate to recommend him others.
-
- - name: Léonie Watson
- role: >
- Director of Accessibility at Nomensa
- image: leonie-watson.jpg
- text: |
- Oliver is a flexible and hardworking developer, with a terrific knowledge of Drupal. He promotes accessibility best practice within the Drupal community, and is always happy to share his knowledge with other people.
-
- - name: Holly Ross
- role: >
- Executive Director at the Drupal Association
- image: holly-ross.png
- text: |
- Oliver has been an outstanding contributor to the Drupal Association team. He is a talented developer who writes great code and applies his curiosity and love of learning to every project. He is also a fantastic team member, who gives to the team as much as he gets.
-
- Oliver is the embodiment of everything good about the Drupal community.
-
- - name: Josh Mitchell
- role: CTO at the Drupal Association
- image: josh-mitchell.png
- text: |
- Oliver is a skilled Drupal developer with a passion for the Drupal community. As his direct supervisor, I was able to watch Oliver grow with the Drupal Association and contribute an amazing amount of effort and integrity to all of his work.
-
- Everything we have thrown at Oliver, he has approached with an open and flexible mind that has allowed him to work on a wide range of projects and features for Drupal products.
-
- - name: Chris Jarvis
- image: chris-jarvis.jpg
- role: Developer at Microserve
- text: |
- Oliver is an amazing colleague, he's professional, full of knowledge and I could not recommend him more.
----
-{% block content %}
-
- {% for testimonial in page.testimonials|reverse %}
-
- {% if testimonial.image %}
-
- Oliver Davies is a Full Stack Web Developer and System Administrator based in the UK.
- He is a {{ site.work.role }} at {{ site.companies[site.work.company].name }} and a part-time freelancer specialising in Drupal, Symfony and Laravel development and Linux systems administration.
-
diff --git a/astro/sculpin-old/source/_posts/2014.md b/astro/sculpin-old/source/_posts/2014.md
deleted file mode 100644
index 2086ede9..00000000
--- a/astro/sculpin-old/source/_posts/2014.md
+++ /dev/null
@@ -1,84 +0,0 @@
----
-title: 2014
-date: 2015-03-20
-excerpt: A look back at 2014.
-tags:
- - drupal-association
- - drupalcamp-london
- - personal
-tweets: true
----
-
-A lot happened in 2014. Here are some of the main things that I'd like to
-highlight.
-
-## Joined the Drupal Association
-
-This was the main thing for me this year, in May I left
-[Precedent](http://precedent.com) and joined the
-[Drupal Association](https://assoc.drupal.org). I work on the Engineering team,
-focused mainly on [Drupal.org](https://www.drupal.org) but I've also done some
-theming work on the DrupalCon [Amsterdam](http://amsterdam2014.drupal.org) and
-[Latin America](http://latinamerica2015.drupal.org) websites, and some
-pre-launch work on [Drupal Jobs](https://jobs.drupal.org).
-
-Some of the tasks that I've worked on so far are:
-
-- Fixing remaining issues from the Drupal.org Drupal 7 upgrade.
-- Improving pages for
- [Supporting Partners](https://www.drupal.org/supporters/partners),
- [Technology Supporters](https://www.drupal.org/supporters/technology) and
- [Hosting Partners](https://www.drupal.org/supporters/hosting). These
- previously were manually updated pages using HTML tables, which are now
- dynamic pages built with [Views](https://www.drupal.org/project/views) using
- organisation nodes.
-- Configuring human-readable paths for user profiles using
- [Pathauto](https://www.drupal.org/project/pathauto). Only a small change, but
- made a big difference to end-users.
-- Migration of user data from profile values to fields, and various user profile
- improvements. This was great because now we can do things like reference
- mentors by their username and display their picture on your profile, as well
- as show lists of peope listing a user as their mentor. This, I think, adds a
- more personal element to Drupal.org because we can see the actual people and
- not just a list of names on a page.
-
-I've started keeping a list of tasks that I've been involved with on my
-[Work](/work/) page, and will be adding more things as I work on them.
-
-### Portland
-
-I was able to travel to Portland, Oregon twice last year to meet with the rest
-of the Association staff. Both times I met new people and it was great to spend
-some work and social time with everyone, and it was great to have everyone
-together as a team.
-
-## My First DrupalCamp
-
-In February, I attended [DrupalCamp London](http://2014.drupalcamplondon.co.uk).
-This was my first time attending a Camp, and I managed to attend some great
-sessions as well as meet people who I'd never previously met in person. I was
-also a volunteer and speaker, where I talked about
-[Git Flow](/blog/what-git-flow/) - a workflow for managing your Git projects.
-
-{% include 'tweet' with {
- content: '
— Greg Franklin (@gfranklin) March 2, 2014'
-} %}
-
-I was also able to do a little bit of sprinting whilst I was there, reviewing
-other people's modules and patches.
-
-Attending this and [DrupalCon Prague](https://prague2013.drupal.org) in 2013
-have really opened my eyes to the face-to-face side of the Drupal community, and
-I plan on attending a lot more Camps and Cons in the future.
-
-## DrupalCon Amsterdam
-
-I was also able to travel to Holland and attend
-[DrupalCon Amsterdam](https://amsterdam2014.drupal.org) along with other members
-of Association staff.
-
-## DrupalCamp Bristol
-
-In October, we started planning for
-[DrupalCamp Bristol](http://www.drupalcampbristol.co.uk). I'm one of the
-founding Committee members,
diff --git a/astro/sculpin-old/source/_posts/accessible-bristol-site.md b/astro/sculpin-old/source/_posts/accessible-bristol-site.md
deleted file mode 100644
index 1ec09c36..00000000
--- a/astro/sculpin-old/source/_posts/accessible-bristol-site.md
+++ /dev/null
@@ -1,30 +0,0 @@
----
-title: Accessible Bristol site launched
-date: 2012-11-15
-excerpt:
- I'm happy to report that the Accessible Bristol was launched this week, on
- Drupal 7.
-tags:
- - accessibility
- - accessible-bristol
- - nomensa
----
-
-I'm happy to announce that the
-[Accessible Bristol](http://www.accessiblebristol.org.uk) website was launched
-this week, on Drupal 7. The site has been developed over the past few months,
-and uses the [User Relationships](http://drupal.org/project/user_relationships)
-and [Privatemsg](http://drupal.org/project/privatemsg) modules to provide a
-community-based platform where people with an interest in accessibility can
-register and network with each other.
-
-The site has been developed over the past few months, and uses the
-[User Relationships](http://drupal.org/project/user_relationships) and
-[Privatemsg](http://drupal.org/project/privatemsg) modules to provide a
-community-based platform where people with an interest in accessibility can
-register and network with each other.
-
-The group is hosting a launch event on the 28th November at the Council House,
-College Green, Bristol. Interested? More information is available at
- or go to
- to register.
diff --git a/astro/sculpin-old/source/_posts/add-date-popup-calendar-custom-form.md b/astro/sculpin-old/source/_posts/add-date-popup-calendar-custom-form.md
deleted file mode 100644
index b8325c2c..00000000
--- a/astro/sculpin-old/source/_posts/add-date-popup-calendar-custom-form.md
+++ /dev/null
@@ -1,44 +0,0 @@
----
-title: How to add a date popup calendar onto a custom form
-date: 2012-05-23
-excerpt: How to use a date popup calendar within your custom module.
-tags:
- - forms
- - form-api
- - date
- - calendar
- - drupal-7
- - drupal-planet
- - drupal
----
-
-How to use a date popup calendar within your custom module.
-
-First, I need to download the
-[Date](http://drupal.org/project/date 'Date module on Drupal.org') module, and
-make my module dependent on date_popup by adding the following line into my
-module's .info file.
-
-```language-ini
-dependencies[] = date_popup
-```
-
-Within my form builder function:
-
-```language-php
-$form['date'] = array(
- '#title' => t('Arrival date'),
-
- // Provided by the date_popup module
- '#type' => 'date_popup',
-
- // Uses the PHP date() format - http://php.net/manual/en/function.date.php
- '#date_format' => 'j F Y',
-
- // Limits the year range to the next two upcoming years
- '#date_year_range' => '0:+2',
-
- // Default value must be in 'Y-m-d' format.
- '#default_value' => date('Y-m-d', time()),
-);
-```
diff --git a/astro/sculpin-old/source/_posts/add-taxonomy-term-multiple-nodes-using-sql.md b/astro/sculpin-old/source/_posts/add-taxonomy-term-multiple-nodes-using-sql.md
deleted file mode 100644
index 241e233c..00000000
--- a/astro/sculpin-old/source/_posts/add-taxonomy-term-multiple-nodes-using-sql.md
+++ /dev/null
@@ -1,79 +0,0 @@
----
-title: Add a Taxonomy Term to Multiple Nodes Using SQL
-date: 2010-07-07
-excerpt: How to add a new taxonomy term to multiple nodes in Drupal using SQL.
-tags:
- - taxonomy
- - drupal-planet
- - drupal-6
- - sql
- - sequal-pro
- - database
----
-
-In preparation for my Blog posts being added to
-[Drupal Planet](http://drupal.org/planet), I needed to create a new Taxonomy
-term (or, in this case, tag) called 'Drupal Planet', and assign it to new
-content to imported into their aggregator. After taking a quick look though my
-previous posts, I decided that 14 of my previous posts were relevant, and
-thought that it would be useful to also assign these the 'Drupal Planet' tag.
-
-I didn't want to manually open each post and add the new tag, so I decided to
-make the changes myself directly into the database using SQL, and as a follow-up
-to a previous post -
-[Quickly Change the Content Type of Multiple Nodes using SQL](/blog/change-content-type-multiple-nodes-using-sql/).
-
-**Again, before changing any values within the database, ensure that you have an
-up-to-date backup which you can restore if you encounter a problem!**
-
-The first thing I did was create the 'Drupal Planet' term in my Tags vocabulary.
-I decided to do this via the administration area of my site, and not via the
-database. Then, using [Sequel Pro](http://www.sequelpro.com), I ran the
-following SQL query to give me a list of Blog posts on my site - showing just
-their titles and nid values.
-
-```language-sql
-SELECT title, nid FROM node WHERE TYPE = 'blog' ORDER BY title ASC;
-```
-
-I made a note of the nid's of the returned nodes, and kept them for later. I
-then ran a similar query against the term_data table. This returned a list of
-Taxonomy terms - showing the term's name, and it's unique tid value.
-
-```language-sql
-SELECT NAME, tid FROM term_data ORDER BY NAME ASC;
-```
-
-The term that I was interested in, Drupal Planet, had the tid of 84. To confirm
-that no nodes were already assigned a taxonomy term with this tid, I ran another
-query against the database. I'm using aliases within this query to link the
-node, term_node and term_data tables. For more information on SQL aliases, take
-a look at .
-
-```language-sql
-SELECT * FROM node n, term_data td, term_node tn WHERE td.tid = 84 AND n.nid = tn.nid AND tn.tid = td.tid;
-```
-
-As expected, it returned no rows.
-
-The table that links node and term_data is called term_node, and is made up of
-the nid and vid columns from the node table, as well as the tid column from the
-term_data table. Is it is here that the additional rows would need to be
-entered.
-
-To confirm everything, I ran a simple query against an old post. I know that the
-only taxonomy term associated with this post is 'Personal', which has a tid
-value of 44.
-
-```language-sql
-SELECT nid, tid FROM term_node WHERE nid = 216;
-```
-
-Once the query had confirmed the correct tid value, I began to write the SQL
-Insert statement that would be needed to add the new term to the required nodes.
-The nid and vid values were the same on each node, and the value of my taxonomy
-term would need to be 84.
-
-Once this had completed with no errors, I returned to the administration area of
-my Drupal site to confirm whether or not the nodes had been assigned the new
-term.
diff --git a/astro/sculpin-old/source/_posts/adding-custom-theme-templates-drupal-7.md b/astro/sculpin-old/source/_posts/adding-custom-theme-templates-drupal-7.md
deleted file mode 100644
index 5404bc4c..00000000
--- a/astro/sculpin-old/source/_posts/adding-custom-theme-templates-drupal-7.md
+++ /dev/null
@@ -1,84 +0,0 @@
----
-title: Adding Custom Theme Templates in Drupal 7
-date: 2012-04-19
-excerpt: >
- Today, I had a situation where I was displaying a list of teasers for news
- article nodes. The article content type had several different fields assigned
- to it, including main and thumbnail images. In this case, I wanted to have
- different output and fields displayed when a teaser was displayed compared to
- when a complete node was displayed.
-tags:
- - drupal-planet
- - drupal
----
-
-Today, I had a situation where I was displaying a list of teasers for news
-article nodes. The article content type had several different fields assigned to
-it, including main and thumbnail images. In this case, I wanted to have
-different output and fields displayed when a teaser was displayed compared to
-when a complete node was displayed.
-
-I have previously seen it done this way by adding this into in a node.tpl.php
-file:
-
-```language-php
-if ($teaser) {
- // The teaser output.
-}
-else {
- // The whole node output.
-}
-```
-
-However, I decided to do something different and create a separate template file
-just for teasers. This is done using the hook_preprocess_HOOK function that I
-can add into my theme's template.php file.
-
-The function requires the node variables as an argument - one of which is
-theme_hook_suggestions. This is an array of suggested template files that Drupal
-looks for and attempts to use when displaying a node, and this is where I'll be
-adding a new suggestion for my teaser-specific template. Using the `debug()`
-function, I can easily see what's already there.
-
-```language-php
-array (
- 0 => 'node__article',
- 1 => 'node__343',
- 2 => 'node__view__latest_news',
- 3 => 'node__view__latest_news__page',
-)
-```
-
-So, within my theme's template.php file:
-
-```language-php
-/**
- * Implementation of hook_preprocess_HOOK().
- */
-function mytheme_preprocess_node(&$variables) {
- $node = $variables['node'];
-
- if ($variables['teaser']) {
- // Add a new item into the theme_hook_suggestions array.
- $variables['theme_hook_suggestions'][] = 'node__' . $node->type . '_teaser';
- }
-}
-```
-
-After adding the new suggestion:
-
-```language-php
-array (
- 0 => 'node__article',
- 1 => 'node__343',
- 2 => 'node__view__latest_news',
- 3 => 'node__view__latest_news__page',
- 4 => 'node__article_teaser',
-)
-```
-
-Now, within my theme I can create a new node--article-teaser.tpl.php template
-file and this will get called instead of the node--article.tpl.php when a teaser
-is loaded. As I'm not specifying the node type specifically and using the
-dynamic \$node->type value within my suggestion, this will also apply
-for all other content types on my site and not just news articles.
diff --git a/astro/sculpin-old/source/_posts/announcing-the-drupal-vm-generator.md b/astro/sculpin-old/source/_posts/announcing-the-drupal-vm-generator.md
deleted file mode 100644
index c90bb343..00000000
--- a/astro/sculpin-old/source/_posts/announcing-the-drupal-vm-generator.md
+++ /dev/null
@@ -1,108 +0,0 @@
----
-title: Announcing the Drupal VM Generator
-date: 2016-02-15
-excerpt:
- For the past few weeks, I’ve been working on a personal side project based on
- Drupal VM - the Drupal VM Generator.
-tags:
- - drupal
- - drupal-planet
- - drupal-vm
- - drupal-vm-generator
- - symfony
----
-
-For the past few weeks, I’ve been working on a personal side project based on
-Drupal VM. It’s called the [Drupal VM Generator][1], and over the weekend I’ve
-added the final features and fixed the remaining issues, and tagged the 1.0.0
-release.
-
-
-
-## What is Drupal VM?
-
-[Drupal VM][2] is a project created and maintained by [Jeff Geerling][3]. It’s a
-[Vagrant][4] virtual machine for Drupal development that is provisioned using
-[Ansible][5].
-
-What is different to a regular Vagrant VM is that uses a file called
-`config.yml` to configure the machine. Settings such as `vagrant_hostname`,
-`drupalvm_webserver` and `drupal_core_path` are stored as YAML and passed into
-the `Vagrantfile` and the `playbook.yml` file which is used when the Ansible
-provisioner runs.
-
-In addition to some essential Ansible roles for installing and configuring
-packages such as Git, MySQL, PHP and Drush, there are also some roles that are
-conditional and only installed based on the value of other settings. These
-include Apache, Nginx, Solr, Varnish and Drupal Console.
-
-## What does the Drupal VM Generator do?
-
-> The Drupal VM Generator is a Symfony application that allows you to quickly
-> create configuration files that are minimal and use-case specific.
-
-Drupal VM comes with an [example.config.yml file][6] that shows all of the
-default variables and their values. When I first started using it, I’d make a
-copy of `example.config.yml`, rename it to `config.yml` and edit it as needed,
-but a lot of the examples aren’t needed for every use case. If you’re using
-Nginx as your webserver, then you don’t need the Apache virtual hosts. If you
-are not using Solr on this project, then you don’t need the Solr variables.
-
-For a few months, I’ve kept and used boilerplace versions of `config.yml` - one
-for Apache and one for Nginx. These are minimal, so have most of the comments
-removed and only the variables that I regularly need, but these can still be
-quite time consuming to edit each time, and if there are additions or changes
-upstream, then I have two versions to maintain.
-
-The Drupal VM Generator is a Symfony application that allows you to quickly
-create configuration files that are minimal and use-case specific. It uses the
-[Console component][7] to collect input from the user, [Twig][8] to generate the
-file, the [Filesystem component][9] to write it.
-
-Based on the options passed to it and/or answers that you provide, it generates
-a custom, minimal `config.yml` file for your project.
-
-Here’s an example of it in action:
-
-
-
-You can also define options when calling the command and skip any or all
-questions. Running the following would bypass all of the questions and create a
-new file with no interaction or additional steps.
-
-{{ gist('24e569577ca4b72f049d', 'with-options.sh') }}
-
-## Where do I get it?
-
-The project is hosted on [GitHub][1], and there are installation instructions
-within the [README][10].
-
-
-
-The recommended method is via downloading the phar file (the same as Composer
-and Drupal Console). You can also clone the GitHub repository and run the
-command from there. I’m also wanting to upload it to Packagist so that it can be
-included if you manage your projects with Composer.
-
-Please log any bugs or feature requests in the [GitHub issue tracker][11], and
-I’m more than happy to receive pull requests.
-
-If you’re interested in contributing, please feel free to fork the repository
-and start doing so, or contact me with any questions.
-
-**Update 17/02/16:** The autoloading issue is now fixed if you require the
-package via Composer, and this has been tagged as the [1.0.1 release][12]
-
-[1]: https://github.com/opdavies/drupal-vm-generator
-[2]: http://www.drupalvm.com
-[3]: http://www.jeffgeerling.com
-[4]: http://www.vagrantup.com
-[5]: https://www.ansible.com
-[6]: https://github.com/geerlingguy/drupal-vm/blob/master/example.config.yml
-[7]: http://symfony.com/doc/current/components/console/introduction.html
-[8]: http://twig.sensiolabs.org
-[9]: http://symfony.com/doc/current/components/filesystem/introduction.html
-[10]:
- https://github.com/opdavies/drupal-vm-generator/blob/master/README.md#installation
-[11]: https://github.com/opdavies/drupal-vm-generator/issues
-[12]: https://github.com/opdavies/drupal-vm-generator/releases/tag/1.0.1
diff --git a/astro/sculpin-old/source/_posts/automating-sculpin-jenkins.md b/astro/sculpin-old/source/_posts/automating-sculpin-jenkins.md
deleted file mode 100644
index f6ac76cd..00000000
--- a/astro/sculpin-old/source/_posts/automating-sculpin-jenkins.md
+++ /dev/null
@@ -1,192 +0,0 @@
----
-title: Automating Sculpin Builds with Jenkins CI
-date: 2015-07-21
-excerpt: How to use Jenkins to automate building Sculpin websites.
-tags:
- - sculpin
- - jenkins
----
-
-As part of re-building this site with [Sculpin](http://sculpin.io), I wanted to
-automate the deployments, as in I wouldn't need to run a script like
-[publish.sh](https://raw.githubusercontent.com/sculpin/sculpin-blog-skeleton/master/publish.sh)
-locally and have that deploy my code onto my server. Not only did that mean that
-my local workflow was simpler (update, commit and push, rather than update,
-commit, push and deploy), but if I wanted to make a quick edit or hotfix, I
-could log into GitHub or Bitbucket (wherever I decided to host the source code)
-from any computer or my phone, make the change and have it deployed for me.
-
-I'd started using [Jenkins CI](http://jenkins-ci.org) during my time at the
-Drupal Association, and had since built my own Jenkins server to handle
-deployments of Drupal websites, so that was the logical choice to use.
-
-## Installing Jenkins and Sculpin
-
-If you don’t already have Jenkins installed and configured, I'd suggest using
-[Jeff Geerling](http://jeffgeerling.com/) (aka geerlingguy)'s
-[Ansible role for Jenkins CI](https://galaxy.ansible.com/list#/roles/440).
-
-I've also released an
-[Ansible role for Sculpin](https://galaxy.ansible.com/list#/roles/4063) that
-installs the executable so that the Jenkins server can run Sculpin commands.
-
-## Triggering a Build from a Git Commit
-
-I created a new Jenkins item for this task, and restricted where it could be run
-to `master` (i.e. the Jenkins server rather than any of the nodes).
-
-### Polling from Git
-
-I entered the url to the
-[GitHub repo](https://github.com/opdavies/oliverdavies.uk) into the **Source
-Code Management** section (the Git option _may_ have been added by the
-[Git plugin](https://wiki.jenkins-ci.org/display/JENKINS/Git+Plugin) that I have
-installed).
-
-As we don’t need any write access back to the repo, using the HTTP URL rather
-than the SSH one was fine, and I didn’t need to provide any additional
-credentials.
-
-Also, as I knew that I’d be working a lot with feature branches, I entered
-`*/master` as the only branch to build. This meant that pushing changes or
-making edits on any other branches would not trigger a build.
-
-
-
-I also checked the **Poll SCM** option so that Jenkins would be routinely
-checking for updated code. This essentially uses the same syntax as cron,
-specifying minutes, hours etc. I entered `* * * * *` so that Jenkins would poll
-each minute, knowing that I could make this less frequent if needed.
-
-This now that Jenkins would be checking for any updates to the repo each minute,
-and could execute tasks if needed.
-
-### Building and Deploying
-
-Within the **Builds** section of the item, I added an _Execute Shell_ step,
-where I could enter a command to execute. Here, I pasted a modified version of
-the original publish.sh script.
-
-```language-bash
-#!/bin/bash
-
-set -uex
-
-sculpin generate --env=prod --quiet
-if [ $? -ne 0 ]; then echo "Could not generate the site"; exit 1; fi
-
-rsync -avze 'ssh' --delete output_prod/ prodwww2:/var/www/html/oliverdavies.uk/htdocs
-if [ $? -ne 0 ]; then echo "Could not publish the site"; exit 1; fi
-```
-
-This essentially is the same as the original file, in that Sculpin generates the
-site, and uses rsync to deploy it somewhere else. In my case, `prodwww2` is a
-Jenkins node (this alias is configured in `/var/lib/jenkins/.ssh/config`), and
-`/var/www/html/oliverdavies.uk/htdocs` is the directory from where my site is
-served.
-
-## Building Periodically
-
-There is some dynamic content on my site, specifically on the Talks page. Each
-talk has a date assigned to it, and within the Twig template, the talk is
-positoned within upcoming or previous talks based on whether this date is less
-or greater than the time of the build.
-
-The YAML front matter:
-
-```language-yaml
----
-...
-talks:
- - title: Test Drive Twig with Sculpin
- location: DrupalCamp North
----
-```
-
-The Twig layout:
-
-```language-twig
-{% verbatim -%}
-{% for talk in talks|reverse if talk.date >= now %}
- {# Upcoming talks #}
-{% endfor %}
-
-{% for talk in talks if talk.date < now %}
- {# Previous talks #}
-{% endfor%}
-{%- endverbatim %}
-```
-
-I also didn’t want to have to push an empty commit or manually trigger a job in
-Jenkins after doing a talk in order for it to be positioned in the correct place
-on the page, so I also wanted Jenkins to schedule a regular build regardless of
-whether or not code had been pushed, so ensure that my talks page would be up to
-date.
-
-After originally thinking that I'd have to split the build steps into a separate
-item and trigger that from a scheduled item, and amend my git commit item
-accordingly, I found a **Build periodically** option that I could use within the
-same item, leaving it intact and not having to make amends.
-
-I set this to `@daily` (the same `H H * * *` - `H` is a Jenkins thing), so that
-the build would be triggered automatically each day without a commit, and deploy
-any updates to the site.
-
-
-
-## Next Steps
-
-This workflow works great for one site, but as I roll out more Sculpin sites,
-I'd like to reduce duplication. I see this mainly as I’ll end up creating a
-separate `sculpin_build` item that’s decoupled from the site that it’s building,
-and instead passing variables such as environment, server name and docroot path
-as parameters in a parameterized build.
-
-I'll probably also take the raw shell script out of Jenkins and save it in a
-text file that's stored locally on the server, and execute that via Jenkins.
-This means that I’d be able to store this file in a separate Git repository with
-my other Jenkins scripts and get the standard advantages of using version
-control.
-
-## Update
-
-Since publishing this post, I've added some more items to the original build
-script.
-
-### Updating Composer
-
-```language-bash
-if [ -f composer.json ]; then
- /usr/local/bin/composer install
-fi
-```
-
-Updates project dependencies via
-[Composer](https://getcomposer.org/doc/00-intro.md#introduction) if
-composer.json exists.
-
-### Updating Sculpin Dependencies
-
-```language-bash
-if [ -f sculpin.json ]; then
- sculpin install
-fi
-```
-
-Runs `sculpin install` on each build if the sculpin.json file exists, to ensure
-that the required custom bundles and dependencies are installed.
-
-### Managing Redirects
-
-```language-bash
-if [ -f scripts/redirects.php ]; then
- /usr/bin/php scripts/redirects.php
-fi
-```
-
-I've been working on a `redirects.php` script that generates redirects from a
-.csv file, after seeing similar things in the
-[Pantheon Documentation](https://github.com/pantheon-systems/documentation) and
-[That Podcast](https://github.com/thatpodcast/thatpodcast.io) repositories. This
-checks if that file exists, and if so, runs it and generates the source file
-containing each redirect.
diff --git a/astro/sculpin-old/source/_posts/back-to-the-future-git-diff-apply.md b/astro/sculpin-old/source/_posts/back-to-the-future-git-diff-apply.md
deleted file mode 100644
index aea0ac09..00000000
--- a/astro/sculpin-old/source/_posts/back-to-the-future-git-diff-apply.md
+++ /dev/null
@@ -1,73 +0,0 @@
----
-title: Back to the future with Git’s diff and apply commands
-date: 2018-04-23
-excerpt:
- How to revert files using Git, but as a new commit to prevent force pushing.
-tags:
- - git
----
-
-This is one of those “there’s probably already a better way to do this”
-situations, but it worked.
-
-I was having some issues this past weekend where, despite everything working
-fine locally, a server was showing a “500 Internal Server” after I pushed some
-changes to a site. In order to bring the site back online, I needed to revert
-the site files back to the previous version, but as part of a new commit.
-
-The `git reset` commands removed the interim commits which meant that I couldn’t
-push to the remote (force pushing, quite rightly, isn’t allowed for the
-production branch), and using `git revert` was resulting in merge conflicts in
-`composer.lock` that I’d rather have avoided if possible.
-
-This is what `git log --oneline -n 4` was outputting:
-
-```
-14e40bc Change webflo/drupal-core-require-dev version
-fc058bb Add services.yml
-60bcf33 Update composer.json and re-generate lock file
-722210c More styling
-```
-
-`722210c` is the commit SHA that I needed to go back to.
-
-## First Solution
-
-My first solution was to use `git diff` to create a single patch file of all of
-the changes from the current point back to the original commit. In this case,
-I’m using `head~3` (four commits before `head`) as the original reference, I
-could have alternatively used a commit ID, tag or branch name.
-
-```
-git diff head head~3 > temp.patch
-git apply -v temp.patch
-```
-
-With the files are back in the former state, I can remove the patch, add the
-files as a new commit and push them to the remote.
-
-```
-rm temp.patch
-
-git add .
-git commit -m 'Back to the future'
-git push
-```
-
-Although the files are back in their previous, working state, as this is a new
-commit with a new commit SHA reference, there is no issue with the remote
-rejecting the commit or needing to attempt to force push.
-
-## Second Solution
-
-The second solution is just a shorter, cleaner version of the first!
-
-Rather than creating a patch file and applying it, the output from `git diff`
-can be piped straight into `git apply`.
-
-```
-git diff head~3 head | git apply -v
-```
-
-This means that there’s only one command to run and no leftover patch file, and
-I can go ahead and add and commit the changes straight away.
diff --git a/astro/sculpin-old/source/_posts/building-gmail-filters-in-php.md b/astro/sculpin-old/source/_posts/building-gmail-filters-in-php.md
deleted file mode 100644
index e109a47f..00000000
--- a/astro/sculpin-old/source/_posts/building-gmail-filters-in-php.md
+++ /dev/null
@@ -1,102 +0,0 @@
----
-title: Building Gmail Filters with PHP
-date: 2016-07-15
-excerpt: How to use PHP to generate and export filters for Gmail.
-tags:
- - php
- - gmail
-promoted: true
----
-
-Earlier this week I wrote a small PHP library called [GmailFilterBuilder][0]
-that allows you to write Gmail filters in PHP and export them to XML.
-
-I was already aware of a Ruby library called [gmail-britta][1] that does the
-same thing, but a) I’m not that familiar with Ruby so the syntax wasn’t that
-natural to me - it’s been a while since I wrote any Puppet manifests, and b) it
-seemed like a interesting little project to work on one evening.
-
-The library contains two classes - `GmailFilter` which is used to create each
-filter, and `GmailFilterBuilder` that parses the filters and generates the XML
-using a [Twig][2] template.
-
-## Usage
-
-For example:
-
-```language-php
-# test.php
-
-require __DIR__ '/vendor/autoload.php';
-
-use Opdavies\GmailFilterBuilder\Builder;
-use Opdavies\GmailFilterBuilder\Filter;
-
-$filters = [];
-
-$filters[] = Filter::create()
- ->has('from:example@test.com')
- ->labelAndArchive('Test')
- ->neverSpam();
-
-new Builder($filters);
-```
-
-In this case, an email from `example@test.com` would be archived, never marked
-as spam, and have a label of "Test" added to it.
-
-With this code written, and the GmailFilterBuilder library installed via
-Composer, I can run `php test.php` and have the XML written to the screen.
-
-This can also be written to a file - `php test.php > filters.xml` - which can
-then be imported into Gmail.
-
-## Twig Extensions
-
-I also added a custom Twig extension that I moved into a separate
-[twig-extensions][5] library so that I and other people can re-use it in other
-projects.
-
-It’s a simple filter that accepts a boolean and returns `true` or `false` as a
-string, but meant that I could remove three ternary operators from the template
-and replace them with the `boolean_string` filter.
-
-Before:
-
-
-
-This can then be used to generate output like this, whereas having blank values
-would have resulted in errors when importing to Gmail.
-
-```language-xml
-
-```
-
-## Example
-
-For a working example, see my personal [gmail-filters][3] repository on GitHub.
-
-## Resources
-
-- [The GmailFilterBuilder library on Packagist][4]
-- [My Gmail filters on GitHub][3]
-- [My Twig Extensions on Packagist][5]
-
-[0]: https://github.com/opdavies/gmail-filter-builder
-[1]: https://github.com/antifuchs/gmail-britta
-[2]: http://twig.sensiolabs.org
-[3]: https://github.com/opdavies/gmail-filters
-[4]: https://packagist.org/packages/opdavies/gmail-filter-builder
-[5]: https://packagist.org/packages/opdavies/twig-extensions
diff --git a/astro/sculpin-old/source/_posts/building-the-new-phpsw-website.md b/astro/sculpin-old/source/_posts/building-the-new-phpsw-website.md
deleted file mode 100644
index 21595097..00000000
--- a/astro/sculpin-old/source/_posts/building-the-new-phpsw-website.md
+++ /dev/null
@@ -1,37 +0,0 @@
----
-title: Building the new PHPSW Website
-date: 2018-02-28
-excerpt:
- Earlier this week we had another hack night, working on the new PHPSW user
- group website.
-tags:
- - phpsw
- - symfony
- - tailwind-css
-has_tweets: true
----
-
-Earlier this week we had another hack night, working on the new [PHPSW user
-group][0] website.
-
-
-
-It’s built with Symfony so it’s naturally using Twig for templating. I’ve become
-a big fan of the utility based approach to CSS and [Tailwind CSS][1] in
-particular, so I’m using that for all of the styling, and using [Webpack
-Encore][2] to compile all of the assets.
-
-We have an integration with Meetup.com which we’re using to pull all of our
-previous event data and store them as JSON files for Symfony to parse and
-render, which it then uses to generate static HTML to upload onto the server.
-
-We’re in the process of populating all of the past data, but look out for a v1
-launch soon. In the meantime, feel free to take a peek at our [GitHub
-repository][3].
-
-[0]: https://phpsw.uk
-[1]: https://tailwindcss.com
-[2]: https://github.com/symfony/webpack-encore
-[3]: https://github.com/phpsw/phpsw-ng
diff --git a/astro/sculpin-old/source/_posts/change-content-type-multiple-nodes-using-sql.md b/astro/sculpin-old/source/_posts/change-content-type-multiple-nodes-using-sql.md
deleted file mode 100644
index 6557c5ac..00000000
--- a/astro/sculpin-old/source/_posts/change-content-type-multiple-nodes-using-sql.md
+++ /dev/null
@@ -1,43 +0,0 @@
----
-title: Change the Content Type of Multiple Nodes Using SQL
-date: 2010-07-01
-excerpt:
- In this post, I will be changing values within my Drupal 6 site's database to
- quickly change the content type of multiple nodes.
-tags:
- - drupal-planet
- - drupal-6
- - drupal
- - sql
- - sequel-pro
- - database
- - content-types
----
-
-In this post, I will be changing values within my Drupal 6 site's database to
-quickly change the content type of multiple nodes. I will be using a test
-development site with the core Blog module installed, and converting Blog posts
-to a custom content type called 'News article'.
-
-**Before changing any values within the database, ensure that you have an
-up-to-date backup which you can restore if you encounter a problem!**
-
-To begin with, I created the 'News article' content type, and then used the
-Devel Generate module to generate some Blog nodes.
-
-Using [Sequel Pro](http://www.sequelpro.com), I can query the database to view
-the Blog posts (you can also do this via the
-[Terminal](http://guides.macrumors.com/Terminal) in a Mac OS X/Linux,
-[Oracle SQL Developer](http://www.oracle.com/technology/software/products/sql/index.html)
-on Windows, or directly within
-[phpMyAdmin](http://www.phpmyadmin.net/home_page/index.php)):
-
-Using an SQL 'Update' command, I can change the type value from 'blog' to
-'article'. This will change every occurance of the value 'blog'. If I wanted to
-only change certain nodes, I could add a 'Where' clause to only affect nodes
-with a certain nid or title.
-
-Now, when I query the database, the type is shown as 'article'.
-
-Now, when I go back into the administration section of my site and view the
-content, the content type now shows at 'News article'.
diff --git a/astro/sculpin-old/source/_posts/checking-if-user-logged-drupal-right-way.md b/astro/sculpin-old/source/_posts/checking-if-user-logged-drupal-right-way.md
deleted file mode 100644
index 78682c39..00000000
--- a/astro/sculpin-old/source/_posts/checking-if-user-logged-drupal-right-way.md
+++ /dev/null
@@ -1,68 +0,0 @@
----
-title: Checking if a user is logged into Drupal (the right way)
-date: 2013-01-09
-excerpt: How to check if a user is logged in by using Drupal core API functions.
-tags:
- - drupal
- - drupal-6
- - drupal-7
- - drupal-planet
- - php
----
-
-I see this regularly when working on Drupal sites when someone wants to check
-whether the current user is logged in to Drupal (authenticated) or not
-(anonymous).
-
-```language-php
-global $user;
-if ($user->uid) {
- // The user is logged in.
-}
-```
-
-or
-
-```language-php
-global $user;
-if (!$user->uid) {
- // The user is not logged in.
-}
-```
-
-The better way to do this is to use the
-[user_is_logged_in()](http://api.drupal.org/api/drupal/modules!user!user.module/function/user_is_logged_in/7)
-function.
-
-```language-php
-if (user_is_logged_in()) {
- // Do something.
-}
-```
-
-This returns a boolean (TRUE or FALSE) depending or not the user is logged in.
-Essentially, it does the same thing as the first example, but there's no need to
-load the global variable.
-
-A great use case for this is within a `hook_menu()` implementation within a
-custom module.
-
-```language-php
-/**
- * Implements hook_menu().
- */
-function mymodule_menu() {
- $items['foo'] = array(
- 'title' => 'Foo',
- 'page callback' => 'mymodule_foo',
- 'access callback' => 'user_is_logged_in',
- );
-
- return $items;
-}
-```
-
-There is also a
-[user_is_anonymous()](http://api.drupal.org/api/drupal/modules!user!user.module/function/user_is_anonymous/7)
-function if you want the opposite result. Both of these functions are available
-in Drupal 6 and higher.
diff --git a/astro/sculpin-old/source/_posts/checkout-specific-revision-svn-command-line.md b/astro/sculpin-old/source/_posts/checkout-specific-revision-svn-command-line.md
deleted file mode 100644
index 38c042ee..00000000
--- a/astro/sculpin-old/source/_posts/checkout-specific-revision-svn-command-line.md
+++ /dev/null
@@ -1,22 +0,0 @@
----
-title: Checkout a specific revision from SVN from the command line
-date: 2012-05-23
-excerpt: How to checkout a specific revision from a SVN (Subversion) repository.
-tags:
- - svn
- - version-control
----
-
-How to checkout a specific revision from a SVN (Subversion) repository.
-
-If you're checking out the repository for the first time:
-
-```language-bash
-$ svn checkout -r 1234 url://repository/path
-```
-
-If you already have the repository checked out:
-
-```language-bash
-$ svn up -r 1234
-```
diff --git a/astro/sculpin-old/source/_posts/conditional-email-addresses-webform.md b/astro/sculpin-old/source/_posts/conditional-email-addresses-webform.md
deleted file mode 100644
index 050b9410..00000000
--- a/astro/sculpin-old/source/_posts/conditional-email-addresses-webform.md
+++ /dev/null
@@ -1,29 +0,0 @@
----
-title: Conditional Email Addresses in a Webform
-date: 2010-05-06
-excerpt:
- How to send webform emails to a different email address based on another
- field.
-tags:
- - drupal-planet
- - drupal-6
- - conditional-email
- - webform
----
-
-I created a new Webform to serve as a simple Contact form, but left the main
-configuration until after I created the form components. I added 'Name',
-'Email', 'Subject' and 'Message' fields, as well as a 'Category' select list.
-Below 'Options', I entered each of my desired options in the following format:
-
-```language-ini
-Email address|Visible name
-```
-
-I went back to the form configuration page and expanded 'Conditional Email
-Recipients', and selected my Category. Note that the standard 'Email To' field
-above it needs to be empty. Originally, I made the mistake of leaving addresses
-in that field which resulted in people being sent emails regardles of which
-category was selected. I then configured the rest of the form.
-
-Then, when I went to the finished form, the category selection was available.
diff --git a/astro/sculpin-old/source/_posts/configuring-the-reroute-email-module.md b/astro/sculpin-old/source/_posts/configuring-the-reroute-email-module.md
deleted file mode 100644
index 01f53bf5..00000000
--- a/astro/sculpin-old/source/_posts/configuring-the-reroute-email-module.md
+++ /dev/null
@@ -1,70 +0,0 @@
----
-title: Configuring the Reroute Email Module
-date: 2014-12-22
-excerpt:
- How to configure the Reroute Email module, to prevent sending emails to real
- users from your pre-production sites!
-tags:
- - drupal
- - drupal-6
- - drupal-7
- - drupal-planet
- - email
-draft: true
----
-
-[Reroute Email](https://www.drupal.org/project/reroute_email) module uses
-`hook_mail_alter()` to prevent emails from being sent to users from
-non-production sites. It allows you to enter one or more email addresses that
-will receive the emails instead of delivering them to the original user.
-
-> This is useful in case where you do not want email sent from a Drupal site to
-> reach the users. For example, if you copy a live site to a test site for the
-> purpose of development, and you do not want any email sent to real users of
-> the original site. Or you want to check the emails sent for uniform
-> formatting, footers, ...etc.
-
-As we don't need the module configured on production (we don't need to reroute
-any emails there), it's best to do this in code using settings.local.php (if you
-have one) or the standard settings.php file.
-
-The first thing that we need to do is to enable rerouting. Without doing this,
-nothing will happen.
-
-```language-php
-$conf['reroute_email_enable'] = TRUE;
-```
-
-The next option is to whether to show rerouting description in mail body. I
-usually have this enabled. Set this to TRUE or FALSE depending on your
-preference.
-
-```language-php
-$conf['reroute_email_enable_message'] = TRUE;
-```
-
-The last setting is the email address to use. If you're entering a single
-address, you can add it as a simple string.
-
-```language-php
-$conf['reroute_email_address'] = 'person1@example.com';
-```
-
-In this example, all emails from the site will be rerouted to
-person1@example.com.
-
-If you want to add multiple addresses, these should be added in a
-semicolon-delimited list. Whilst you could add these also as a string, I prefer
-to use an array of addresses and the `implode()` function.
-
-```language-php
-$conf['reroute_email_address'] = implode(';', array(
- 'person1@example.com',
- 'person2@example.com',
- 'person3@example.com',
-));
-```
-
-In this example, person2@example.com and person3@example.com would receive their
-emails from the site as normal. Any emails to addresses not in the array would
-continue to be redirected to person1@example.com.
diff --git a/astro/sculpin-old/source/_posts/create-and-apply-patches.md b/astro/sculpin-old/source/_posts/create-and-apply-patches.md
deleted file mode 100644
index 63c71773..00000000
--- a/astro/sculpin-old/source/_posts/create-and-apply-patches.md
+++ /dev/null
@@ -1,50 +0,0 @@
----
-title: How to Create and Apply Patches
-date: 2010-10-10
-excerpt: How to create and apply patches, ready for the Drupal.org issue queues.
-tags:
- - drupal-planet
- - drupal-6
- - modules
- - patches
----
-
-Earlier this year, I posted a solution to
-[an issue](http://drupal.org/node/753898) on the Drupal.org issue queue.
-Originally, I just posted the code back onto the issue, but have now created a
-patch that can easily be applied to any Drupal 6 installation. Here is a
-run-through of the process of creating and applying a patch. In this case, I
-made changes to the `user_pass_validate()` function that's found within
-`modules/user/user.pages.inc`.
-
-To begin with, a download a fresh copy of Drupal 6.19 and created a copy of the
-original user.pages.inc file. Within the duplicate file, I made the same changes
-to the function that I did in earlier code, and saved the changes. Now, within
-my Terminal, I can navigate to Drupal's root directory and create the patch.
-
-```language-bash
-diff -rup modules/user/user.pages.inc modules/user/user.pages2.inc > /Users/oliver/Desktop/different_messages_for_blocked_users.patch
-```
-
-This command compares the differences between the two files, and creates the
-specified patch file.
-
-To apply the patch to my Drupal installation, I go back to Terminal and run the
-following code:
-
-```language-bash
-patch -p0 < /Users/oliver/Desktop/different_messages_for_blocked_users.patch
-```
-
-If, for some reason, I need to reverse the patch, I can run this code:
-
-```language-bash
-patch -p0 -R < /Users/oliver/Desktop/different_messages_for_blocked_users.patch
-```
-
-And that's it!
-
-There is also a Git patch creation workflow, which is described at
-. Thanks to
-[Randy Fay](http://randyfay.com) for making me aware of this, and suggesting a
-slight change to my original patch creation command.
diff --git a/astro/sculpin-old/source/_posts/create-better-photo-gallery-drupal-part-1.md b/astro/sculpin-old/source/_posts/create-better-photo-gallery-drupal-part-1.md
deleted file mode 100644
index 9dc372c6..00000000
--- a/astro/sculpin-old/source/_posts/create-better-photo-gallery-drupal-part-1.md
+++ /dev/null
@@ -1,161 +0,0 @@
----
-title: Create a Better Photo Gallery in Drupal - Part 1
-date: 2010-08-11
-excerpt:
- How I started converting and migrating a Coppermine photo gallery into Drupal.
-tags:
- - drupal-planet
- - drupal-6
- - photo-gallery
- - sql
- - views
- - sequel-pro
- - cck
- - views-attach
- - drupal
----
-
-Recently, I converted a client's static HTML website, along with their
-Coppermine Photo Gallery, into a Drupal-powered website.
-
-Over the next few posts, I'll be replicating the process that I used during the
-conversion, and how I added some additional features to my Drupal gallery.
-
-To begin with, I created my photo gallery as described by
-[Jeff Eaton](http://www.lullabot.com/about/team/jeff-eaton) in
-[this screencast](http://www.lullabot.com/articles/photo-galleries-views-attach),
-downloaded all my client's previous photos via FTP, and quickly added them into
-the new gallery using the
-[Imagefield Import](http://drupal.org/project/imagefield_import) module (which I
-mentioned
-[previously](/blog/quickly-import-multiples-images-using-imagefieldimport-module/)).
-
-When I compare this to the previous gallery, I can see several differences which
-I'd like to include. The first of which is the number of photos in each gallery,
-and the date that the most recent photo was added.
-
-To do this, I'd need to query my website's database. To begin with, I wanted to
-have a list of all the galleries on my site which are published, and what
-they're unique node ID values are. To do this, I opened Sequel Pro and entered
-the following code:
-
-```language-sql
-SELECT title
-AS title, nid
-AS gallery_idFROM node
-WHERE type = 'gallery'
-AND status = 1;
-```
-
-As the nid value of each gallery corresponds with the 'field_gallery_nid' field
-within the content_type_photo field, I can now query the database and retrieve
-information about each specific gallery.
-
-For example, using [aliasing](http://www.w3schools.com/sql/sql_alias.asp) within
-my SQL statement, I can retrieve a list of all the published photos within the
-'British Squad 2008' gallery by using the following code:
-
-```language-sql
-SELECT n.title, n.nid, p.field_gallery_nid
-FROM node n, content_type_photo p
-WHERE p.field_gallery_nid = 105
-AND n.status = 1
-AND n.nid = p.nid;
-```
-
-I can easily change this to count the number of published nodes by changing the
-first line of the query to read SELECT COUNT(\*).
-
-```language-sql
-SELECT COUNT(*)
-FROM node n, content_type_photo p
-WHERE p.field_gallery_nid = 105
-AND n.status = 1
-AND n.nid = p.nid;
-```
-
-As I've used the [Views Attach](http://drupal.org/project/views_attach) module,
-and I'm embedding the photos directly into the Gallery nodes, I easily add this
-to each gallery by creating a custom node-gallery.tpl.php file within my theme.
-I can then use the following PHP code to retrieve the node ID for that specific
-gallery:
-
-```language-php
-
-```
-
-I can then use this variable as part of my next query to count the number of
-photos within that gallery, similar to what I did earlier.
-
-```language-php
-
-```
-
-Next, I wanted to display the date that the last photo was displayed within each
-album. This was done by using a similar query that also sorted the results in a
-descending order, and limited it to one result - effectively only returning the
-created date for the newest photo.
-
-```language-php
-
-```
-
-This was all then added into a 'print' statement which displayed it into the
-page.
-
-```language-php
-There are currently ' . $selected_gallery_total . ' photos in this gallery.';
- $output .= 'Last one added on ' . $latest_photo . '';
- print $output;
-}
-?>
-```
-
-OK, so let's take a look at the Gallery so far:
-
-You will notice that the returned date value for the latest photo added is
-displaying the UNIX timestamp instead of in a more readable format. This can be
-changed by altering the 'print' statement to include a PHP 'date' function:
-
-```language-php
-There are currently ' . $selected_gallery_total . ' photos in this gallery.';
- $output .= 'Last one added on ' . date("l, jS F, Y", $latest_photo) . '.';
- print $output;
-}
-?>
-```
-
-The values that I've entered are from
-[this page](http://php.net/manual/en/function.date.php) on PHP.net, and can be
-changed according on how you want the date to be displayed.
-
-As I've added all of these photos today, then the correct dates are being
-displayed. However, on the client's original website, the majority of these
-photos were pubished several months or years ago, and I'd like the new website
-to still reflect the original created dates. As opposed to modifying each
-individual photograph, I'll be doing this in bulk in my next post.
diff --git a/astro/sculpin-old/source/_posts/create-better-photo-gallery-drupal-part-2.md b/astro/sculpin-old/source/_posts/create-better-photo-gallery-drupal-part-2.md
deleted file mode 100644
index a36933b5..00000000
--- a/astro/sculpin-old/source/_posts/create-better-photo-gallery-drupal-part-2.md
+++ /dev/null
@@ -1,58 +0,0 @@
----
-title: Create a Better Photo Gallery in Drupal - Part 2
-date: 2010-08-17
-excerpt: Updating the galleries’ created and modified dates.
-tags:
- - drupal-planet
- - drupal-6
- - photo-gallery
- - sql
- - sequel-pro
----
-
-At the end of my last post, I'd finished creating the first part of the new
-photo gallery, but I wanted to change the dates of the published photos to
-reflect the ones on the client's original website.
-
-Firstly, I'll refer to the previous list of published galleries that I created
-before, and create something different that also displays the created and
-modified dates. Picking the node ID of the required gallery, I used the
-following SQL query to display a list of photos.
-
-```language-sql
-SELECT n.title, n.nid, n.created, n.changed, p.field_gallery_nid
-FROM node n, content_type_photo pWHERE n.type = 'photo'
-AND p.field_gallery_nid = 103AND n.nid = p.nid
-ORDER BY n.nid ASC;
-```
-
-When I look back at the old photo gallery, I can see that the previous 'last
-added' date was June 27, 2008. So, how do I update my new photos to reflect that
-date? Using , I can enter the
-required date in its readable format, and it will give me the equivilent UNIX
-timestamp. To keep things relatively simple, I'll set all photos within this
-gallery to the same time.
-
-The result that I'm given is '1217149200'. I can now use an UPDATE statement
-within another SQL query to update the created and modified dates.
-
-```language-sql
-UPDATE node
-INNER JOIN content_type_photo
-ON node.nid = content_type_photo.nid
-SET
- node.created = 1217149200,
- node.changed = 1217149200
-WHERE content_type_photo.field_gallery_nid = 103
-```
-
-Now when I query the database, both the created and modified dates have been
-updated, and when I return to the new photo gallery, the updated value is being
-displayed.
-
-Once the changes have been applied, it's a case of repeating the above process
-for each of the required galleries.
-
-In the next post, I'll explain how to add a count of published galleries and
-photos on the main photo gallery page, as well as how to install and configure
-the [Shadowbox](http://drupal.org/project/shadowbox) module.
diff --git a/astro/sculpin-old/source/_posts/create-better-photo-gallery-drupal-part-21.md b/astro/sculpin-old/source/_posts/create-better-photo-gallery-drupal-part-21.md
deleted file mode 100644
index 7b5571c4..00000000
--- a/astro/sculpin-old/source/_posts/create-better-photo-gallery-drupal-part-21.md
+++ /dev/null
@@ -1,64 +0,0 @@
----
-title: Create a Better Photo Gallery in Drupal - Part 2.1
-date: 2010-10-22
-excerpt: The missing code to get totals of galleries and photos.
-tags:
- - drupal
----
-
-Today, I realised that I hadn't published the code that I used to create the
-total figures of galleries and photos at the top of the gallery (I said at the
-end of
-[Part 2](/blog/create-better-photo-gallery-drupal-part-2/ 'Create a Better Photo Gallery in Drupal - Part 2')
-that I'd include it in
-[Part 3](/blog/create-better-photo-gallery-drupal-part-3/ 'Create a Better Photo Gallery in Drupal - Part 3'),
-but I forgot). So, here it is:
-
-```language-php
-
-```
-
-It was applied to the view as a header which had the input format set to PHP
-code.
diff --git a/astro/sculpin-old/source/_posts/create-better-photo-gallery-drupal-part-3.md b/astro/sculpin-old/source/_posts/create-better-photo-gallery-drupal-part-3.md
deleted file mode 100644
index df5d2881..00000000
--- a/astro/sculpin-old/source/_posts/create-better-photo-gallery-drupal-part-3.md
+++ /dev/null
@@ -1,49 +0,0 @@
----
-title: Create a Better Photo Gallery in Drupal - Part 3
-date: 2010-10-13
-excerpt: Grouping galleries by category.
-tags:
- - drupal
----
-
-The next part of the new gallery that I want to implement is to group the
-galleries by their respective categories. The first step is to edit my original
-photo_gallery view and add an additional display.
-
-I've called it 'Taxonomy', and it's similar to the original 'All Galleries'
-view. The differences are that I've added the taxonomy term as an argument,
-removed the header, and updated the path to be `gallery/%`. The other thing that
-I need to do is overwrite the output of the original 'All Galleries' View by
-creating a file called `views-view--photo-gallery--page-1.tpl.php` and placing
-it within my theme directory.
-
-Within that file, I can remove the standard content output. This still outputs
-the heading information from the original View. I can now use the function
-called 'views_embed_view' to embed my taxonomy display onto the display. The
-views_embed_view function is as follows:
-
-```language-php
-
-```
-
-So, to display the galleries that are assigned the taxonomy of 'tournaments', I
-can use the following:
-
-```language-php
-
-```
-
-To reduce the amount of code needed, I can use the following 'while' loop to
-generate the same code for each taxonomy term. It dynamically retrieves the
-relevant taxonomy terms from the database, and uses each name as the argument
-for the view.
-
-```language-php
-' . $term['name'] . '';
- print views_embed_view('gallery', 'page_2', $term['name']);
-}
-?>
-```
diff --git a/astro/sculpin-old/source/_posts/create-block-social-media-icons-using-cck-views-and-nodequeue.md b/astro/sculpin-old/source/_posts/create-block-social-media-icons-using-cck-views-and-nodequeue.md
deleted file mode 100644
index 9a4d189e..00000000
--- a/astro/sculpin-old/source/_posts/create-block-social-media-icons-using-cck-views-and-nodequeue.md
+++ /dev/null
@@ -1,44 +0,0 @@
----
-title: Create a Block of Social Media Icons using CCK, Views and Nodequeue
-date: 2010-06-23
-excerpt: How to create a block of social media icons in Drupal.
-tags:
- - drupal-planet
- - drupal-6
- - drupal
- - views
- - nodequeue
- - oliverdavies.co.uk
----
-
-I recently decided that I wanted to have a block displayed in a sidebar on my
-site containing icons and links to my social media profiles -
-[Twitter](http://twitter.com/opdavies), [Facebook](http://facebook.com/opdavies)
-etc. I tried the [Follow](http://drupal.org/project/follow) module, but it
-lacked the option to add extra networks such my
-[Drupal.org](http://drupal.org/user/381388) account, and my
-[RSS feed](http://oliverdavies.co.uk/rss.xml). I started to create my own
-version, and then found
-[this Blog post](http://www.hankpalan.com/blog/drupal-themes/add-your-social-connections-drupal-icons)
-by Hank Palan.
-
-I created a 'Social icon' content type with the body field removed, and with
-fields for a link and image - then downloaded the favicons from the appropriate
-websites to use.
-
-However, instead of using a custom template (node-custom.tpl.php) file, I used
-the Views module.
-
-I added fields for the node titles, and the link from the node's content. Both
-of these are excluded from being displayed on the site. I then re-wrote the
-output of the Icon field to create the link using the URL, and using the node's
-title as the image's alternative text and the link's title.
-
-I also used the [Nodequeue](http://drupal.org/project/nodequeue) module to
-create a nodequeue and arrange the icons in the order that I wanted them to be
-displayed. Once this was added as a relationship within my View, I was able to
-use node's position in the nodequeue as the sort criteria.
-
-To complete the process, I used the
-[CSS Injector](http://drupal.org/project/css_injector) module to add some
-additional CSS styling to position and space out the icons.
diff --git a/astro/sculpin-old/source/_posts/create-flickr-photo-gallery-using-feeds-cck-and-views.md b/astro/sculpin-old/source/_posts/create-flickr-photo-gallery-using-feeds-cck-and-views.md
deleted file mode 100644
index 97ae4765..00000000
--- a/astro/sculpin-old/source/_posts/create-flickr-photo-gallery-using-feeds-cck-and-views.md
+++ /dev/null
@@ -1,71 +0,0 @@
----
-title: Create a Flickr Photo Gallery Using Feeds, CCK and Views
-date: 2010-06-28
-excerpt:
- In this tutorial, I'll show you how to create a photo gallery which uses
- photos imported from Flickr.
-tags:
- - drupal-planet
- - drupal-6
- - photo-gallery
- - views
- - cck
- - imagecache
- - feeds
- - filefield
- - flickr
- - imagefield
----
-
-In this tutorial, I'll show you how to create a photo gallery which uses photos
-imported from [Flickr](http://www.flickr.com).
-
-The modules that I'll use to create the Gallery are:
-
-- [CCK](http://drupal.org/project/cck)
-- [Feeds](http://drupal.org/project/feeds)
-- [Feeds Image Grabber](http://drupal.org/project/feeds_imagegrabber)
-- [FileField](http://drupal.org/project/filefield)
-- [ImageAPI](http://drupal.org/project/imageapi)
-- [ImageCache](http://drupal.org/project/imagecache)
-- [ImageField](http://drupal.org/project/imagefield)
-- [Views](http://drupal.org/project/views)
-
-The first thing that I did was to create a content type to store my imported
-images. I named it 'Photo', removed the Body field, and added an Image field.
-
-Next, I installed and configured the Feeds and Image Grabber module. I used an
-overridden default Feed to import my photos from Flickr using the following
-settings:
-
-- **Basic settings:** I changed the Refresh time to 15 minutes.
-- **Processor settings:** I changed the content type to 'Photo', and the
- author's name from 'anonymous'.
-- **Processor mapping:** I added a new mapping from 'Item URL (link)' to 'Photo
- (FIG)'. The Photo FIG target is added by the Image Grabber module.
-
-Next, I needed to create the actual Feed, which I did by clicking 'Import'
-within the Navigation menu, and clicking 'Feed'. I gave it a title, entered the
-URL to my RSS feed from Flickr, and enabled the Image Grabber for this feed.
-
-Once the Feed is created, the latest 20 images from the RSS feed are imported
-and 20 new Photos nodes are created. In the example below, the image with the
-'Photo' label is the Image field mapped by the Image Grabber module. It is this
-image that I'll be displaying within my Gallery.
-
-With the new Photo nodes created, I then created the View to display them.
-
-The View selects the image within the Photo content type, and displays in it a
-grid using an ImageCache preset. The View is limited to 20 nodes per page, and
-uses a full pager if this is exceeded. The nodes are sorted by the descending
-post date, and filtered by whether or not they are published, and only to
-include Photo nodes.
-
-As an additional effect, I also included the 'Feeds Item - Item Link' field,
-which is basically the original link from the RSS feed. By checking the box the
-exclude the item from the display, it is not shown, but makes the link available
-to be used elsewhere. By checking the box 'Re-write the output for this field'
-on the 'Content: Photo' field, I was able to add the replacement token (in this
-case, [url]) as the path for a link around each image. This meant that when
-someone clicked a thumbnail of a photo, they were directed to the Flickr website
-instead of the node within my Drupal site.
diff --git a/astro/sculpin-old/source/_posts/create-multigroups-drupal-7-using-field-collections.md b/astro/sculpin-old/source/_posts/create-multigroups-drupal-7-using-field-collections.md
deleted file mode 100644
index 6bb37202..00000000
--- a/astro/sculpin-old/source/_posts/create-multigroups-drupal-7-using-field-collections.md
+++ /dev/null
@@ -1,59 +0,0 @@
----
-title: Create Multigroups in Drupal 7 using Field Collections
-date: 2011-08-28
-excerpt:
- How to replicate CCK’s multigroups in Drupal 7 using the Field Collections
- module.
-tags:
- - drupal-7
- - drupal-planet
- - cck
- - fields
- - field-collection
- - entity-api
- - multigroup
----
-
-One of my favourite things lately in Drupal 6 has been CCK 3, and more
-specifically, the Content Multigroups sub-module. Basically this allows you to
-create a fieldset of various CCK fields, and then repeat that multiple times.
-For example, I use it on this site whist creating invoices for clients. I have a
-fieldset called 'Line Item', containing 'Description', 'Quantity' and 'Price'
-fields. With a standard fieldset, I could only have one instance of each field -
-however, using a multigroup, I can create multiple groups of line items which I
-then use within the invoice.
-
-But at the time of writing this, there is no CCK 3 version for Drupal 7. So, I
-created the same thing using
-[Field Collection](http://drupal.org/project/field_collection) and
-[Entity](http://drupal.org/project/entity) modules.
-
-With the modules uploaded and enabled, go to admin/structure/field-collections
-and create a field collection.
-
-With the module enabled, you can go to your content type and add a Field
-Collection field. By default, the only available Widget type is 'Hidden'.
-
-Next, go to admin/structure/field-collections and add some fields to the field
-collection - the same way that you would for a content type. For this collection
-is going to contain two node reference fields - Image and Link.
-
-With the Field Collection created, I can now add it as a field within my content
-type.
-
-Whilst this works perfectly, the field collection is not editable from the node
-edit form. You need to load the node, and the collection is displayed here with
-add, edit, and delete buttons. This wasn't an ideal solution, and I wanted to be
-able to edit the fields within the collection from the node edit form - the same
-way as I can using multigroups in Drupal 6.
-
-After some searching I found
-[a link to a patch](http://drupal.org/node/977890#comment-4184524) which when
-applied adds a 'subform' widget type to the field collection field and allows
-for it to be embedded into, and editable from within the node form. Going back
-to the content type fields page, and clicking on 'Hidden' (the name of the
-current widget), I can change it to subform and save my changes.
-
-With this change applied, when I go back to add or edit a node within this
-content type, my field collection will be easily editable directly within the
-form.
diff --git a/astro/sculpin-old/source/_posts/create-omega-subtheme-less-css-preprocessor-using-omega-tools-and-drush.md b/astro/sculpin-old/source/_posts/create-omega-subtheme-less-css-preprocessor-using-omega-tools-and-drush.md
deleted file mode 100644
index afb7a25d..00000000
--- a/astro/sculpin-old/source/_posts/create-omega-subtheme-less-css-preprocessor-using-omega-tools-and-drush.md
+++ /dev/null
@@ -1,64 +0,0 @@
----
-title:
- Create an Omega Subtheme with LESS CSS Preprocessor using Omega Tools and
- Drush
-date: 2012-04-16
-excerpt: How to create an Omega subtheme on the command line using Drush.
-tags:
- - drupal-7
- - omega
- - theming
- - less
- - drupal-planet
- - drupal
----
-
-In this tutorial I'll be showing how to create an
-[Omega](http://drupal.org/project/omega) subtheme using the
-[Omega Tools](http://drupal.org/project/omega_tools) module, and have it working
-with the [LESS CSS preprocessor](http://lesscss.org).
-
-The first thing that I need to do is download the Omega theme and the Omega
-Tools and [LESS](http://drupal.org/project/less 'LESS module on drupal.org')
-modules, and then to enable both modules. I'm doing this using Drush, but you
-can of course do this via the admin interface at admin/modules.
-
-```language-bash
-$ drush dl less omega omega_tools;
-$ drush en -y less omega_tools
-```
-
-With the Omega Tools module enabled I get the drush omega-subtheme command that
-creates my Omega subtheme programatically. Using this command, I'm creating a
-new subtheme, enabling it and setting it as the default theme on my site.
-
-```language-bash
-$ drush omega-subtheme "Oliver Davies" --machine_name="oliverdavies" --enable --set-default
-```
-
-By default, four stylesheets are created within the subtheme's css directory.
-The first thing that I'm going to do is rename `global.css` to `global.less`.
-
-```language-bash
-$ mv css/global.css css/global.less
-```
-
-Now I need to find all references to global.css within my oliverdavies.info
-file. I did this using `$ nano oliverdavies.info`, pressing `Ctrl+W` to search,
-then `Ctrl+R` to replace, entering `global.css` as the search phrase, and then
-`global.less` as the replacement text. After making any changes to
-oliverdavies.info, I need to clear Drupal's caches for the changes to be
-applied.
-
-```language-bash
-$ drush cc all
-```
-
-I tested my changes by making some quick additions to my global.less file and
-reloading the page.
-
-If your changes aren't applied, then confirm that your global.less file is
-enabled within your theme's configuration. I did this by going to
-admin/appearance/settings/oliverdavies, clicking on the Toggle styles tab within
-_Layout configuration_ and finding global.less at the bottom of _Enable optional
-stylesheets_.
diff --git a/astro/sculpin-old/source/_posts/create-slideshow-multiple-images-using-fancy-slide.md b/astro/sculpin-old/source/_posts/create-slideshow-multiple-images-using-fancy-slide.md
deleted file mode 100644
index aa9935ff..00000000
--- a/astro/sculpin-old/source/_posts/create-slideshow-multiple-images-using-fancy-slide.md
+++ /dev/null
@@ -1,50 +0,0 @@
----
-title: Create a Slideshow of Multiple Images Using Fancy Slide
-date: 2010-05-25
-excerpt: How to create a slideshow of images using Drupal’s Fancy Slide module.
-tags:
- - drupal-planet
- - drupal
- - drupal-6
- - fancy-slide
- - slideshow
----
-
-Whilst updating my About page, I thought about creating a slideshow of several
-images instead of just the one static image. When I looking on Drupal.org, the
-only slideshow modules were to create slideshows of images that were attached to
-different nodes - not multiple images attached to one node. Then, I found the
-[Fancy Slide](http://drupal.org/project/fancy_slide) module. It's a jQuery
-Slideshow module with features that include integration with the
-[CCK](http://drupal.org/project/cck),
-[ImageCache](http://drupal.org/project/imagecache) and
-[Nodequeue](http://drupal.org/project/nodequeue) modules.
-
-I added an CCK Image field to my Page content type, and set the number of values
-to 3, then uploaded my images to the Page.
-
-Whilst updating my About page, I thought about creating a slideshow of several
-images instead of just the one static image. When I looking on Drupal.org, the
-only slideshow modules were to create slideshows of images that were attached to
-different nodes - not multiple images attached to one node. Then, I found the
-[Fancy Slide](http://drupal.org/project/fancy_slide) module. It's a jQuery
-Slideshow module with features that include integration with the
-[CCK](http://drupal.org/project/cck),
-[ImageCache](http://drupal.org/project/imagecache) and
-[Nodequeue](http://drupal.org/project/nodequeue) modules. Once the Images were
-added, I went to the Fancy Slide settings page and created the slideshow.
-
-I added the dimensions of my images, the type of animation, specified the node
-that contained the images, the slideshow field, delay between slides and
-transition speed. With the slideshow created, it now needed embedding into the
-page.
-
-I added the following code into my About page, as described in the Fancy Slide
-readme.txt file - the number representing the ID of the slideshow.
-
-```language-php
-
-```
-
-In my opinion, this adds a nice effect to the About page. I like it because it's
-easy to set up, and easy to add additional images later on if required.
diff --git a/astro/sculpin-old/source/_posts/create-virtual-hosts-mac-os-x-using-virtualhostx.md b/astro/sculpin-old/source/_posts/create-virtual-hosts-mac-os-x-using-virtualhostx.md
deleted file mode 100644
index 35636963..00000000
--- a/astro/sculpin-old/source/_posts/create-virtual-hosts-mac-os-x-using-virtualhostx.md
+++ /dev/null
@@ -1,50 +0,0 @@
----
-title: Create Virtual Hosts on Mac OS X Using VirtualHostX
-date: 2010-07-02
-excerpt:
- How to use the VirtualHostX application to manage virtual hosts on Mac OS X.
-tags:
- - drupal-planet
- - drupal-6
- - mamp
- - virtual-hosts
- - virtualhostx
----
-
-This isn't a Drupal related topic per se, but it is a walk-through of one of the
-applications that I use whilst doing Drupal development work. I assume, like
-most Mac OS X users, I use [MAMP](http://www.mamp.info/en/index.html) to run
-Apache, MySQL and PHP locally whilst developing. I also use virtual hosts in
-Apache to create local .dev domains which are as close as possible to the actual
-live domains. For example, if I was developing a site called mysite.com, my
-local development version would be mysite.dev.
-
-Normally, I would have to edit the hosts file and Apache's httpd.conf file to
-create a virtual host. The first to set the domain and it's associated IP
-address, and the other to configure the domain's directory, default index file
-etc. However, using [VirtualHostX](http://clickontyler.com/virtualhostx), I can
-quickly create a virtual host without having to edt any files. Enter the virtual
-domain name, the local path and the port, and apply the settings. VirtualHostX
-automatically restarts Apache, so the domain is ready to work straight away. You
-can also enter custom directives from within the GUI.
-
-There's also an option to share the host over the local network. Next, I intend
-on configuring a virtual Windows PC within VMware Fusion to view these domains
-so that I can do cross-browser testing before putting a site live.
-
-I ensured that my Apache configuration within MAMP was set to port 80, and that
-VirtualHostX was using Apache from MAMP instead of Apple's built-in Apache.
-
-**Note:** One problem that I had after setting this up, was that I was receving
-an error when attempting to open a Drupal website which said _'No such file or
-directory'._
-
-After some troubleshooting, I found out that Web Sharing on my Mac had become
-enabled (I don't know why, I've never enabled it), and that this was causing a
-conflict with Apache. Once I opened my System Preferences and disabled it,
-everything worked fine!
-
-This, along with [MAMP](http://www.mamp.info/en/index.html),
-[Coda](http://www.panic.com/coda), [Sequel Pro](http://www.sequelpro.com), and
-[Transmit](http://www.panic.com/transmit), has become an essential tool within
-my development environment.
diff --git a/astro/sculpin-old/source/_posts/create-zen-sub-theme-using-drush.md b/astro/sculpin-old/source/_posts/create-zen-sub-theme-using-drush.md
deleted file mode 100644
index 6faf7296..00000000
--- a/astro/sculpin-old/source/_posts/create-zen-sub-theme-using-drush.md
+++ /dev/null
@@ -1,40 +0,0 @@
----
-title: Create a Zen Sub-theme Using Drush
-date: 2013-09-06
-excerpt: How to quickly create a Zen sub-theme using Drush.
-tags:
- - drupal
- - drupal-planet
- - drush
- - zen
- - theming
----
-
-How to use [Drush](https://drupal.org/project/drush) to quickly build a new
-sub-theme of [Zen](https://drupal.org/project/zen).
-
-First, download the [Zen](https://drupal.org/project/zen 'The Zen theme') theme
-if you haven't already done so.
-
-```language-bash
-$ drush dl zen
-```
-
-This will now enable you to use the "drush zen" command.
-
-```language-bash
-$ drush zen "Oliver Davies" oliverdavies --description="A Zen sub-theme for oliverdavies.co.uk" --without-rtl
-```
-
-The parameters that I'm passing it are:
-
-1. The human-readable name of the theme.
-2. The machine-readable name of the theme.
-3. The description of the theme (optional).
-4. A flag telling Drush not to include any right-to-left elements within my
- sub-theme as these aren't needed (optional).
-
-This will create a new theme in sites/all/themes/oliverdavies.
-
-For further help, type `$ drush help zen` to see the Drush help page for the zen
-command.
diff --git a/astro/sculpin-old/source/_posts/creating-and-using-custom-tokens-drupal-7.md b/astro/sculpin-old/source/_posts/creating-and-using-custom-tokens-drupal-7.md
deleted file mode 100644
index caebc69c..00000000
--- a/astro/sculpin-old/source/_posts/creating-and-using-custom-tokens-drupal-7.md
+++ /dev/null
@@ -1,162 +0,0 @@
----
-title: Creating and using custom tokens in Drupal 7
-date: 2013-02-16
-excerpt:
- This post outlines the steps required to create your own custom tokens in
- Drupal.
-tags:
- - drupal
- - drupal-planet
- - drupal-7
- - tokens
----
-
-This post outlines the steps required to create your own custom tokens in
-Drupal.
-
-When writing the recent releases of the
-[Copyright Block](http://drupal.org/project/copyright_block) module, I used
-tokens to allow the user to edit and customise their copyright message and place
-the copyright_message:dates token in the desired position. When the block is
-rendered, the token is replaced by the necessary dates.
-
-We will be using the fictional _foo_ module to demonstrate this.
-
-## Requirements
-
-- [Token module](http://drupal.org/project/token)
-
-## Recommended
-
-- [Devel module](http://drupal.org/project/devel) - useful to run `dpm()` and
- `kpr()` functions
-- [Copyright Block module](http://drupal.org/project/copyright_block) - 7.x-2.x
- and 6.x-1.x use tokens, handy as a reference
-
-## Implementing hook_token_info()
-
-The first thing that we need to do is define the new token type and/or the token
-itself, along with it's descriptive text. To view the existing tokens and types,
-use `dpm(token_get_info());`, assuming that you have the
-[Devel module](http://drupal.org/project/devel) installed.
-
-```language-php
-/**
- * Implements hook_token_info().
- */
-function foo_token_info() {
- $info = array();
-
- // Add any new tokens.
- $info['tokens']['foo']['bar'] = t('This is my new bar token within the foo type.');
-
- // Return them.
- return $info;
-}
-```
-
-In this case, the token called _bar_ resides within the _foo_ group.
-
-If I needed to add a new token within an existing token type, such as 'node',
-the syntax would be `$info['tokens']['node']['bar']`.
-
-## Implementing hook_tokens()
-
-Now that the Token module is aware of our new token, we now need to determine
-what the token is replaced with. This is done using `hook_tokens()`. Here is the
-basic code needed for an implementation:
-
-```language-php
-/**
- * Implements hook_tokens().
- */
-function foo_tokens($type, $tokens, array $data = array(), array $options = array()) {
- $replacements = array();
-
- // Code goes here...
-
- // Return the replacements.
- return $replacements;
-}
-```
-
-The first thing to check for is the type of token using an `if()` function, as
-this could be an existing type like 'node', 'user' or 'site', or a custom token
-type like 'foo'. Once we're sure that we're looking at the right type(s), we can
-use `foreach ($tokens as $name => $original)` to loop through each of the
-available tokens using a `switch()`. For each token, you can perform some logic
-to work out the replacement text and then add it into the replacements array
-using `$replacements[$original] = $new;`.
-
-```language-php
-/**
- * Implements hook_tokens().
- */
-function foo_tokens($type, $tokens, array $data = array(), array $options = array()) {
- $replacements = array();
-
- // The first thing that we're going to check for is the type of token - node,
- // user etc...
- if ($type == 'foo') {
- // Loop through each of the available tokens.
- foreach ($tokens as $name => $original) {
- // Find the desired token by name
- switch ($name) {
- case 'bar':
- $new = '';
-
- // Work out the value of $new...
-
- // Add the new value into the replacements array.
- $replacements[$original] = $new;
- break;
- }
- }
- }
-
- // Return the replacements.
- return $replacements;
-}
-```
-
-## Example
-
-An example from Copyright Block module:
-
-```language-php
-/**
- * Implements hook_tokens().
- */
-function copyright_block_tokens($type, $tokens, array $data = array(), array $options = array()) {
- $replacements = array();
-
- if ($type == 'copyright_statement') {
- foreach ($tokens as $name => $original) {
- switch ($name) {
- case 'dates':
- $start_year = variable_get('copyright_block_start_year', date('Y'));
- $current_year = date('Y');
-
- $replacements[$original] = $start_year < $current_year ? $start_year . '-' . $current_year : $start_year;
- break;
- }
- }
- }
-
- return $replacements;
-}
-```
-
-## Using token_replace()
-
-With everything defined, all that we now need to do is pass some text through
-the `token_replace()` function to replace it with the values defined within
-`hook_token()`.
-
-```language-php
-$a = t('Something');
-// This would use any token type - node, user etc.
-$b = token_replace($a);
-// This would only use foo tokens.
-$c = token_replace($a, array('foo'));
-```
diff --git a/astro/sculpin-old/source/_posts/creating-custom-docksal-commands.md b/astro/sculpin-old/source/_posts/creating-custom-docksal-commands.md
deleted file mode 100644
index 4a7c963a..00000000
--- a/astro/sculpin-old/source/_posts/creating-custom-docksal-commands.md
+++ /dev/null
@@ -1,366 +0,0 @@
----
-title: Creating a Custom PHPUnit Command for Docksal
-date: 2018-05-06
-excerpt:
- How to write custom commands for Docksal, including one to easily run PHPUnit
- tests in Drupal 8.
-tags:
- - docksal
- - drupal
- - drupal-8
- - drupal-planet
- - phpunit
- - testing
----
-
-This week I’ve started writing some custom commands for my Drupal projects that
-use Docksal, including one to easily run PHPUnit tests in Drupal 8. This is the
-process of how I created this command.
-
-## What is Docksal?
-
-Docksal is a local Docker-based development environment for Drupal projects and
-other frameworks and CMSes. It is our standard tool for local environments for
-projects at [Microserve][0].
-
-There was a [great talk][1] recently at Drupaldelphia about Docksal.
-
-## Why write a custom command?
-
-One of the things that Docksal offers (and is covered in the talk) is the
-ability to add custom commands to the Docksal’s `fin` CLI, either globally or as
-part of your project.
-
-As an advocate of automated testing and TDD practitioner, I write a lot of tests
-and run PHPUnit numerous times a day. I’ve also given [talks][6] and have
-[written other posts][7] on this site relating to testing in Drupal.
-
-There are a couple of ways to run PHPUnit with Docksal. The first is to use
-`fin bash` to open a shell into the container, move into the docroot directory
-if needed, and run the `phpunit` command.
-
-```bash
-fin bash
-cd /var/www/docroot
-../vendor/bin/phpunit -c core modules/custom
-```
-
-Alternatively, it can be run from the host machine using `fin exec`.
-
-```
-cd docroot
-fin exec '../vendor/bin/phpunit -c core modules/custom'
-```
-
-Both of these options require multiple steps as we need to be in the `docroot`
-directory where the Drupal code is located before the command can be run, and
-both have quite long commands to run PHPUnit itself - some of which is repeated
-every time.
-
-By adding a custom command, I intend to:
-
-1. Make it easier to get set up to run PHPUnit tests - i.e. setting up a
- `phpunit.xml` file.
-1. Make it easier to run the tests that we’d written by shortening the command
- and making it so it can be run anywhere within our project.
-
-I also hoped to make it project agnostic so that I could add it onto any project
-and immediately run it.
-
-## Creating the command
-
-Each command is a file located within the `.docksal/commands` directory. The
-filename is the name of the command (e.g. `phpunit`) with no file extension.
-
-To create the file, run this from the same directory where your `.docksal`
-directory is:
-
-```bash
-mkdir -p .docksal/commands
-touch .docksal/commands/phpunit
-```
-
-This will create a new, empty `.docksal/commands/phpunit` file, and now the
-`phpunit` command is now listed under "Custom commands" when we run `fin`.
-
-
-
-You can write commands with any interpreter. I’m going to use bash, so I’ll add
-the shebang to the top of the file.
-
-```bash
-#!/usr/bin/env bash
-```
-
-With this in place, I can now run `fin phpunit`, though there is no output
-displayed or actions performed as the rest of the file is empty.
-
-## Adding a description and help text
-
-Currently the description for our command when we run `fin` is the default "No
-description" text. I’d like to add something more relevant, so I’ll start by
-adding a new description.
-
-fin interprets lines starting with `##` as documentation - the first of which it
-uses as the description.
-
-```bash
-#!/usr/bin/env bash
-
-## Run automated PHPUnit tests.
-```
-
-Now when I run it, I see the new description.
-
-
-
-Any additional lines are used as help text with running `fin help phpunit`. Here
-I’ll add an example command to demonstrate how to run it as well as some more
-in-depth text about what the command will do.
-
-```bash
-#!/usr/bin/env bash
-
-## Run automated PHPUnit tests.
-##
-## Usage: fin phpunit
-##
-## If a core/phpunit.xml file does not exist, copy one from elsewhere.
-## Then run the tests.
-```
-
-Now when I run `fin help phpunit`, I see the new help text.
-
-
-
-## Adding some content
-
-### Setting the target
-
-As I want the commands to be run within Docksal’s "cli" container, I can specify
-that with `exec_target`. If one isn’t specified, the commands are run locally on
-the host machine.
-
-```
-#: exec_target = cli
-```
-
-### Available variables
-
-These variables are provided by fin and are available to use within any custom
-commands:
-
-- `PROJECT_ROOT` - The absolute path to the nearest `.docksal` directory.
-- `DOCROOT` - name of the docroot folder.
-- `VIRTUAL_HOST` - the virtual host name for the project. Such as
- `myproject.docksal`.
-- `DOCKER_RUNNING` - (string) "true" or "false".
-
-
-**Note:** If the `DOCROOT` variable is not defined within the cli container, ensure that it’s added to the environment variables in `.docksal/docksal.yml`. For example:
-
-```
-version: "2.1"
-
-services:
- cli:
- environment:
- - DOCROOT
-```
-
-
-
-### Running phpunit
-
-When you run the `phpunit` command, there are number of options you can pass to
-it such as `--filter`, `--testsuite` and `--group`, as well as the path to the
-tests to execute, such as `modules/custom`.
-
-I wanted to still be able to do this by running `fin phpunit ` so the
-commands can be customised when executed. However, as the first half of the
-command (`../vendor/bin/phpunit -c core`) is consistent, I can wrap that within
-my custom command and not need to type it every time.
-
-By using `"$@"` I can capture any additional arguments, such as the test
-directory path, and append them to the command to execute.
-
-I’m using `$PROJECT_ROOT` to prefix the command with the absolute path to
-`phpunit` so that I don’t need to be in that directory when I run the custom
-command, and `$DOCROOT` to always enter the sub-directory where Drupal is
-located. In this case, it’s "docroot" though I also use "web" and I’ve seen
-various others used.
-
-```bash
-DOCROOT_PATH="${PROJECT_ROOT}/${DOCROOT}"
-DRUPAL_CORE_PATH="${DOCROOT_PATH}/core"
-
-# If there is no phpunit.xml file, copy one from elsewhere.
-
-# Otherwise run the tests.
-${PROJECT_ROOT}/vendor/bin/phpunit -c ${DRUPAL_CORE_PATH} "$@"
-```
-
-For example, `fin phpunit modules/custom` would execute
-`/var/www/vendor/bin/phpunit -c /var/www/docroot/core modules/custom` within the
-container.
-
-I can then wrap this within a condition so that the tests are only run when a
-`phpunit.xml` file exists, as it is required for them to run successfully.
-
-```bash
-if [ ! -e ${DRUPAL_CORE_PATH}/phpunit.xml ]; then
- # If there is no phpunit.xml file, copy one from elsewhere.
-else
- ${PROJECT_ROOT}/vendor/bin/phpunit -c ${DRUPAL_CORE_PATH} "$@"
-fi
-```
-
-### Creating phpunit.xml - step 1
-
-My first thought was that if a `phpunit.xml` file doesn’t exist was to duplicate
-core’s `phpunit.xml.dist` file. However this isn’t enough to run the tests, as
-values such as `SIMPLETEST_BASE_URL`, `SIMPLETEST_DB` and
-`BROWSERTEST_OUTPUT_DIRECTORY` need to be populated.
-
-As the tests wouldn't run at this point, I’ve exited early and displayed a
-message to the user to edit the new `phpunit.xml` file and run `fin phpunit`
-again.
-
-```bash
-if [ ! -e ${DRUPAL_CORE_PATH}/phpunit.xml ]; then
- echo "Copying ${DRUPAL_CORE_PATH}/phpunit.xml.dist to ${DRUPAL_CORE_PATH}/phpunit.xml."
- echo "Please edit it's values as needed and re-run 'fin phpunit'."
- cp ${DRUPAL_CORE_PATH}/phpunit.xml.dist ${DRUPAL_CORE_PATH}/phpunit.xml
- exit 1;
-else
- ${PROJECT_ROOT}/vendor/bin/phpunit -c ${DRUPAL_CORE_PATH} "$@"
-fi
-```
-
-However this isn’t as streamlined as I originally wanted as it still requires
-the user to perform an additional step before the tests can run.
-
-### Creating phpunit.xml - step 2
-
-My second idea was to keep a pre-configured file within the project repository,
-and to copy that into the expected location. That approach would mean that the
-project specific values would already be populated, as well as any
-customisations made to the default settings. I decided on
-`.docksal/drupal/core/phpunit.xml` to be the potential location.
-
-Also, if this file is copied then we can go ahead and run the tests straight
-away rather than needing to exit early.
-
-If a pre-configured file doesn’t exist, then we can default back to copying
-`phpunit.xml.dist`.
-
-To avoid duplication, I created a reusable `run_tests()` function so it could be
-executed in either scenario.
-
-```bash
-run_tests() {
- ${PROJECT_ROOT}/vendor/bin/phpunit -c ${DRUPAL_CORE_PATH} "$@"
-}
-
-if [ ! -e ${DRUPAL_CORE_PATH}/phpunit.xml ]; then
- if [ -e "${PROJECT_ROOT}/.docksal/drupal/core/phpunit.xml" ]; then
- echo "Copying ${PROJECT_ROOT}/.docksal/drupal/core/phpunit.xml to ${DRUPAL_CORE_PATH}/phpunit.xml"
- cp "${PROJECT_ROOT}/.docksal/drupal/core/phpunit.xml" ${DRUPAL_CORE_PATH}/phpunit.xml
- run_tests "$@"
- else
- echo "Copying ${DRUPAL_CORE_PATH}/phpunit.xml.dist to ${DRUPAL_CORE_PATH}/phpunit.xml."
- echo "Please edit it's values as needed and re-run 'fin phpunit'."
- cp ${DRUPAL_CORE_PATH}/phpunit.xml.dist ${DRUPAL_CORE_PATH}/phpunit.xml
- exit 1;
- fi
-else
- run_tests "$@"
-fi
-```
-
-This means that I can execute less steps and run a much shorter command compared
-to the original, and even if someone didn’t have a `phpunit.xml` file created
-they could have copied into place and have tests running with only one command.
-
-## The finished file
-
-```bash
-#!/usr/bin/env bash
-
-#: exec_target = cli
-
-## Run automated PHPUnit tests.
-##
-## Usage: fin phpunit
-##
-## If a core/phpunit.xml file does not exist, one is copied from
-## .docksal/core/phpunit.xml if that file exists, or copied from the default
-## core/phpunit.xml.dist file.
-
-DOCROOT_PATH="${PROJECT_ROOT}/${DOCROOT}"
-DRUPAL_CORE_PATH="${DOCROOT_PATH}/core"
-
-run_tests() {
- ${PROJECT_ROOT}/vendor/bin/phpunit -c ${DRUPAL_CORE_PATH} "$@"
-}
-
-if [ ! -e ${DRUPAL_CORE_PATH}/phpunit.xml ]; then
- if [ -e "${PROJECT_ROOT}/.docksal/drupal/core/phpunit.xml" ]; then
- echo "Copying ${PROJECT_ROOT}/.docksal/drupal/core/phpunit.xml to ${DRUPAL_CORE_PATH}/phpunit.xml"
- cp "${PROJECT_ROOT}/.docksal/drupal/core/phpunit.xml" ${DRUPAL_CORE_PATH}/phpunit.xml
- run_tests "$@"
- else
- echo "Copying phpunit.xml.dist to phpunit.xml"
- echo "Please edit it's values as needed and re-run 'fin phpunit'."
- cp ${DRUPAL_CORE_PATH}/phpunit.xml.dist ${DRUPAL_CORE_PATH}/phpunit.xml
- exit 0;
- fi
-else
- run_tests "$@"
-fi
-```
-
-It’s currently available as a [GitHub Gist][2], though I’m planning on moving it
-into a public GitHub repository either on my personal account or the [Microserve
-organisation][3], for people to either use as examples or to download and use
-directly.
-
-I’ve also started to add other commands to projects such as `config-export` to
-standardise the way to export configuration from Drupal 8, run Drupal 7 tests
-with SimpleTest, and compile front-end assets like CSS within custom themes.
-
-I think it’s a great way to shorten existing commands, or to group multiple
-commands into one like in this case, and I can see a lot of other potential uses
-for it during local development and continuous integration. Also being able to
-run one command like `fin init` and have it set up everything for your project
-is very convenient and a big time saver!
-
-
-Since writing this post, I’ve had a [pull request][8] accepted for this command to be added as a [Docksal add-on][9]. This means that the command can be added to any Docksal project by running `fin addon install phpunit`. It will be installed into the `.docksal/addons/phpunit` directory, and displayed under "Addons" rather than "Custom commands" when you run `fin`.
-
-
-## Resources
-
-- [PHPUnit](https://phpunit.de)
-- [PHPUnit in Drupal 8][4]
-- [Main Docksal website](https://docksal.io)
-- [Docksal documentation](https://docksal.readthedocs.io)
-- [Docksal: one tool to rule local and CI/CD environments][1] - Docksal talk
- from Drupaldelphia
-- [phpcs example custom command][5]
-- [phpunit command Gist][2]
-- [Docksal addons blog post][9]
-- [Docksal addons repository][10]
-
-[0]: {{site.companies.microserve.url}}
-[1]: https://youtu.be/1sjsvnx1P7g
-[2]: https://gist.github.com/opdavies/72611f198ffd2da13f363ea65264b2a5
-[3]: {{site.companies.microserve.github}}
-[4]: https://www.drupal.org/docs/8/phpunit
-[5]:
- https://github.com/docksal/docksal/blob/develop/examples/.docksal/commands/phpcs
-[6]: /talks/tdd-test-driven-drupal
-[7]: /articles/tags/testing
-[8]: https://github.com/docksal/addons/pull/15
-[9]: https://blog.docksal.io/installing-addons-in-a-docksal-project-172a6c2d8a5b
-[10]: https://github.com/docksal/addons
diff --git a/astro/sculpin-old/source/_posts/creating-local-and-staging-sites-drupals-domain-module-enabled.md b/astro/sculpin-old/source/_posts/creating-local-and-staging-sites-drupals-domain-module-enabled.md
deleted file mode 100644
index 7db84133..00000000
--- a/astro/sculpin-old/source/_posts/creating-local-and-staging-sites-drupals-domain-module-enabled.md
+++ /dev/null
@@ -1,52 +0,0 @@
----
-title: Creating Local and Staging sites with Drupal's Domain Module Enabled
-date: 2013-07-17
-excerpt: How to use aliases within Domain module for pre-production sites.
-tags:
- - drupal
- - drupal-planet
- - databases
- - domain
- - table-prefixing
----
-
-The
-[Domain Access project](https://drupal.org/project/domain 'The Domain Access project on Drupal.org')
-is a suite of modules that provide tools for running a group of affiliated sites
-from one Drupal installation and a single shared database. The issue is that the
-domains are stored within the database so these are copied across when the data
-is migrated between environments, whereas the domains are obviously going to
-change.
-
-Rather than changing the domain settings within the Domain module itself, the
-best solution I think is to use table prefixes and create a different domain
-table per environment. With a live, staging and local domains, the tables would
-be named as follows:
-
-```language-bash
-live_domain
-local_domain
-staging_domain
-```
-
-Within each site's settings.php file, define the prefix for the domain table
-within the databases array so that each site is looking at the correct table for
-its environment.
-
-```language-php
-$databases['default']['default'] = array(
- 'driver' => 'mysql',
- 'database' => 'foobar',
- 'username' => 'foo',
- 'password' => 'bar',
- 'host' => 'localhost',
- 'prefix' => array(
- 'default' => '',
- 'domain' => 'local_', // This will use the local_domain table.
- // Add any other prefixed tables here.
- ),
-);
-```
-
-Within each environment-specific domain table, update the subdomain column to
-contain the appropriate domain names.
diff --git a/astro/sculpin-old/source/_posts/croeso-php-south-wales.md b/astro/sculpin-old/source/_posts/croeso-php-south-wales.md
deleted file mode 100644
index 993b48f5..00000000
--- a/astro/sculpin-old/source/_posts/croeso-php-south-wales.md
+++ /dev/null
@@ -1,83 +0,0 @@
----
-title: Croeso PHP South Wales!
-date: 2018-08-01
-excerpt:
- Last night was the first meetup of Cardiff’s PHP South Wales user group.
-tags:
- - php
- - php-south-wales
- - meetups
-has_tweets: true
----
-
-Last night was the first meetup of Cardiff’s [PHP South Wales user group][0]! It
-was a great first event, and it was great to meet a lot of new people as well as
-catch up some familiars within the 36 (according to meetup.com) attendees -
-including some [PHP South West][9] regulars.
-
-Organised by Steve and Amy McDougall, it was held in Barclays’ [Eagle Lab][1]
-which was a great space, and it was cool to be back in Brunel House having
-worked in that building previously whilst at Appnovation.
-
-{% include 'tweet' with {
- class: 'my-6',
- data_cards: true,
- content: '
— Oliver Davies (@opdavies) July 31, 2018',
-} %}
-
-## Speakers
-
-[Rob Allen][2] was the main speaker, who gave an interesting talk and a brave
-live demo on serverless PHP and OpenWhisk. I always enjoy watching Rob speak,
-which I’ve done a number of times at different events, and it was great to be
-able to chat for a while after the meetup too.
-
-{% include 'tweet' with {
- class: 'my-6',
- data_cards: true,
- content: '
— Oliver Davies (@opdavies) July 31, 2018',
-} %}
-
-We also had a couple of lightning talks, starting with [Ismael Velasco][3]
-giving an introduction to progressive web applications (PWAs). I can see some
-potential uses for this on my current work project, and I look forward to seeing
-the full talk soon).
-
-I gave an updated version of my [Tailwind CSS lightning talk][4], and enjoyed
-being able to show some examples of new sites using Tailwind such as [Laravel
-Nova][5], [Spatie][6]’s new website and PHP South Wales itself!
-
-{% include 'tweet' with {
- class: 'my-6',
- data_cards: true,
- content: '
— PHP South Wales (@phpSouthWales) July 31, 2018',
-} %}
-
-## Conclusion
-
-It’s great to have a meetup in Cardiff again, and having thought about organsing
-something myself previously, I’m glad to see someone step forward to do so. This
-shows that there's still a strong PHP community in Cardiff and South Wales, and
-hopefully this will be the first meetup of many. I’ll look forward to seeing the
-local community grow!
-
-Thanks again to Steve and Amy for organising, Eagle Labs for hosting, the
-sponsors, and Rob and Ismael for speaking.
-
-It would be great to see even more people at the next one. If you’re interested,
-take a look at the [group’s website][0], [meetup.com group][7] and [Twitter
-profile][8]. Alternatively, get in touch with myself or one of the organisers
-for more information.
-
-**Croeso ac iechyd da PHP South Wales!**
-
-[0]: https://www.phpsouthwales.uk
-[1]: https://labs.uk.barclays/locations/cardiff-en
-[2]: https://twitter.com/akrabat
-[3]: https://twitter.com/IsmaelVelasco
-[4]: /talks/taking-flight-with-tailwind-css
-[5]: https://nova.laravel.com
-[6]: https://spatie.be
-[7]: https://www.meetup.com/PHP-South-Wales
-[8]: https://twitter.com/phpsouthwales
-[9]: https://phpsw.uk
diff --git a/astro/sculpin-old/source/_posts/debugging-drupal-commerce-promotions-illiminate-collections.md b/astro/sculpin-old/source/_posts/debugging-drupal-commerce-promotions-illiminate-collections.md
deleted file mode 100644
index a2094378..00000000
--- a/astro/sculpin-old/source/_posts/debugging-drupal-commerce-promotions-illiminate-collections.md
+++ /dev/null
@@ -1,144 +0,0 @@
----
-title:
- Debugging Drupal Commerce Promotions and Adjustments using Illuminate
- Collections (Drupal 8)
-date: 2018-10-24
-excerpt:
- Using Laravel’s Illuminate Collections to debug an issue with a Drupal
- Commerce promotion.
-tags:
- - drupal
- - drupal-8
- - drupal-commerce
- - drupal-planet
- - illuminate-collections
- - laravel-collections
- - php
-promoted: true
----
-
-Today I found another instance where I decided to use [Illuminate
-Collections][0] within my Drupal 8 code; whilst I was debugging an issue where a
-[Drupal Commerce][1] promotion was incorrectly being applied to an order.
-
-No adjustments were showing in the Drupal UI for that order, so after some
-initial investigation and finding that `$order->getAdjustments()` was empty, I
-determined that I would need to get the adjustments from each order item within
-the order.
-
-If the order were an array, this is how it would be structured in this
-situation:
-
-```php
-$order = [
- 'id' => 1,
- 'items' => [
- [
- 'id' => 1,
- 'adjustments' => [
- ['name' => 'Adjustment 1'],
- ['name' => 'Adjustment 2'],
- ['name' => 'Adjustment 3'],
- ]
- ],
- [
- 'id' => 2,
- 'adjustments' => [
- ['name' => 'Adjustment 4'],
- ]
- ],
- [
- 'id' => 3,
- 'adjustments' => [
- ['name' => 'Adjustment 5'],
- ['name' => 'Adjustment 6'],
- ]
- ],
- ],
-];
-```
-
-## Getting the order items
-
-I started by using `$order->getItems()` to load the order’s items, converted
-them into a Collection, and used the Collection’s `pipe()` method and the
-`dump()` function provided by the [Devel module][2] to output the order items.
-
-```php
-collect($order->getItems())
- ->pipe(function (Collection $collection) {
- dump($collection);
- });
-```
-
-## Get the order item adjustments
-
-Now we have a Collection of order items, for each item we need to get it’s
-adjustments. We can do this with `map()`, then call `getAdjustments()` on the
-order item.
-
-This would return a Collection of arrays, with each array containing it’s own
-adjustments, so we can use `flatten()` to collapse all the adjustments into one
-single-dimensional array.
-
-```php
-collect($order->getItems())
- ->map(function (OrderItem $order_item) {
- return $order_item->getAdjustments();
- })
- ->flatten(1);
-```
-
-There are a couple of refactors that we can do here though:
-
-- Use `flatMap()` to combine the `flatten()` and `map()` methods.
-- Use [higher order messages][3] to delegate straight to the `getAdjustments()`
- method on the order, rather than having to create a closure and call the
- method within it.
-
-```php
-collect($order->getItems())
- ->flatMap->getAdjustments();
-```
-
-## Filtering
-
-In this scenario, each order item had three adjustments - the correct promotion,
-the incorrect one and the standard VAT addition. I wasn’t concerned about the
-VAT adjustment for debugging, so I used `filter()` to remove it based on the
-result of the adjustment’s `getSourceId()` method.
-
-```php
-collect($order->getItems())
- ->flatMap->getAdjustments()
- ->filter(function (Adjustment $adjustment) {
- return $adjustment->getSourceId() != 'vat';
- });
-```
-
-## Conclusion
-
-Now I have just the relevant adjustments, I want to be able to load each one to
-load it and check it’s conditions. To do this, I need just the source IDs.
-
-Again, I can use a higher order message to directly call `getSourceId()` on the
-adjustment and return it’s value to `map()`.
-
-```php
-collect($order->getItems())
- ->flatMap->getAdjustments()
- ->filter(function (Adjustment $adjustment) {
- return $adjustment->getSourceId() != 'vat';
- })
- ->map->getSourceId();
-```
-
-This returns a Collection containing just the relevant promotion IDs being
-applied to the order that I can use for debugging.
-
-Now just to find out why the incorrect promotion was applying!
-
-[0]: https://laravel.com/docs/collections
-[1]: https://drupalcommerce.org
-[2]: https://www.drupal.org/project/devel
-[3]: https://laravel-news.com/higher-order-messaging
diff --git a/astro/sculpin-old/source/_posts/display-custom-menu-drupal-7-theme-template-file.md b/astro/sculpin-old/source/_posts/display-custom-menu-drupal-7-theme-template-file.md
deleted file mode 100644
index 69f290df..00000000
--- a/astro/sculpin-old/source/_posts/display-custom-menu-drupal-7-theme-template-file.md
+++ /dev/null
@@ -1,27 +0,0 @@
----
-title: Display a Custom Menu in a Drupal 7 Theme Template File
-date: 2012-08-18
-excerpt: The code needed to display a menu in a Drupal 7 template file.
-tags:
- - drupal
- - drupal-7
- - drupal-planet
- - php
- - aria
----
-
-For reference, this is the code needed to display a menu in a Drupal 7 template
-file, including the navigation ARIA role.
-
-```language-php
-$menu_name = 'menu-footer-menu';
-$menu_id = 'footer-menu';
-print theme('links', array(
- 'links' => menu_navigation_links($menu_name),
- 'attributes' => array(
- 'id' => $menu_id,
- 'role' => 'navigation',
- 'class'=> array('links', 'inline')
- )
-));
-```
diff --git a/astro/sculpin-old/source/_posts/display-git-branch-or-tag-names-your-bash-prompt.md b/astro/sculpin-old/source/_posts/display-git-branch-or-tag-names-your-bash-prompt.md
deleted file mode 100644
index db8d2eaf..00000000
--- a/astro/sculpin-old/source/_posts/display-git-branch-or-tag-names-your-bash-prompt.md
+++ /dev/null
@@ -1,70 +0,0 @@
----
-title: Display Git Branch or Tag Names in your Bash Prompt
-date: 2013-04-27
-excerpt:
- Whilst watching Drupalize.me's recent Introduction to Git series, I thought it
- was useful the way that the current Git branch or tag name was displayed in
- the bash prompt. Here's how to do it.
-tags:
- - drupal
- - drupal-planet
- - git
- - terminal
----
-
-Whilst watching [Drupalize.me](http://drupalize.me 'Drupalize.me')'s recent
-[Introduction to Git series](http://drupalize.me/series/introduction-git-series 'Introduction to Git on Drupalize.me'),
-I thought it was useful the way that the current Git branch or tag name was
-displayed in the bash prompt.
-
-Here's how to do it.
-
-For example (with some slight modifications):
-
-```language-bash
-oliver@oliver-mbp:~/Development/drupal(master) $
-oliver@oliver-mbp:~/Development/a11y_checklist(7.x-1.0) $
-```
-
-Here's how to do it.
-
-To begin with, create a new file to contain the functions,
-
-```language-bash
-vim ~/.bash/git-prompt
-```
-
-Paste the following code into the file, and save it.
-
-```language-bash
-parse_git_branch () {
- git branch 2> /dev/null | sed -e '/^[^*]/d' -e 's/* \(.*\)/ (\1)/'
-}
-
-parse_git_tag () {
- git describe --tags 2> /dev/null
-}
-
-parse_git_branch_or_tag() {
- local OUT="$(parse_git_branch)"
- if [ "$OUT" == " ((no branch))" ]; then
- OUT="($(parse_git_tag))";
- fi
- echo $OUT
-}
-```
-
-Edit your `.bashrc` or `.bash_profile` file to override the PS1 value.
-
-```language-bash
-vim ~/.bashrc
-```
-
-Add the following code at the bottom of the file, and save it.
-
-```language-bash
-source ~/.bash/git-prompt
-PS1="\u@\h:\w\$(parse_git_branch_or_tag) $ "
-```
-
-Restart your Terminal or type `source ~/.bashrc` to see your changes.
diff --git a/astro/sculpin-old/source/_posts/display-number-facebook-fans-php.md b/astro/sculpin-old/source/_posts/display-number-facebook-fans-php.md
deleted file mode 100644
index 56c3e49d..00000000
--- a/astro/sculpin-old/source/_posts/display-number-facebook-fans-php.md
+++ /dev/null
@@ -1,30 +0,0 @@
----
-title: Display the Number of Facebook fans in PHP
-date: 2011-03-15
-excerpt: How to use PHP to display the number of fans of a Facebook page.
-tags:
- - php
----
-
-Replace the \$page_id value with your Page ID number (unless you want to show
-the number of fans for this site).You can find your Page ID by logging into your
-Facebook account, going to 'Adverts and Pages', clicking 'Edit page', and
-looking at the URL.
-
-For example, mine is
-.
-
-I've also wrapped the output in a number_format() function so that it properly
-formatted with commas etc - like where I've used it within the
-[Gold Event listing](http://www.horseandcountry.tv/events/paid) on the Horse &
-Country TV website.
-
-```language-php
-$page_id = "143394365692197";
-$xml = @simplexml_load_file("http://api.facebook.com/restserver.php?method=facebook.fql.query&query=SELECT%20fan_count%20FROM%20page%20WHERE%20page_id=".$page_id."") or die ("a lot");
-$fans = $xml->page->fan_count;
-print number_format($fans);
-```
-
-This code was originally found at
-.
diff --git a/astro/sculpin-old/source/_posts/dividing-drupals-process-and-preprocess-functions-separate-files.md b/astro/sculpin-old/source/_posts/dividing-drupals-process-and-preprocess-functions-separate-files.md
deleted file mode 100644
index 1b507652..00000000
--- a/astro/sculpin-old/source/_posts/dividing-drupals-process-and-preprocess-functions-separate-files.md
+++ /dev/null
@@ -1,97 +0,0 @@
----
-title: Dividing Drupal's process and preprocess functions into separate files
-date: 2012-05-24
-excerpt:
- If you use a lot of process and preprocess functions within your Drupal theme,
- then your template.php can get very long and it can become difficult to find a
- certain piece of code. Following the example of the Omega theme, I've started
- separating my process and preprocess functions into their own files.
-tags:
- - drupal
- - code
- - theming
- - preprocessing
----
-
-If you use a lot of process and preprocess functions within your Drupal theme,
-then your template.php can get very long and it can become difficult to find a
-certain piece of code. Following the example of the
-[Omega theme](http://drupal.org/project/omega 'The Omega theme on Drupal.org'),
-I've started separating my process and preprocess functions into their own
-files. For example, mytheme_preprocess_node can be placed within a
-preprocess/node.inc file, and mytheme_process_page can be placed within
-process/page.inc.
-
-The first step is to use the default mytheme_process() and mytheme_preprocess()
-functions to utilise my custom function. So within my template.php file:
-
-```language-php
- This new version makes Media module available for all, improves migrations
-> significantly, stabilizes the Content Moderation and Settings Tray modules,
-> serves dynamic pages faster with BigPipe enabled by default, and introduces a
-> new experimental entity layout user interface. The release includes several
-> very important fixes for workflows of content translations and supports
-> running on PHP 7.2.
-
-I’ve been very impressed by the new release cycle Drupal 8 and the usage of
-semantic versioning. Though it adds a greater maintenance overhead for module,
-theme, installation profile and distribution developers to ensure that our
-projects are still working properly, having the ability to add new modules into
-Drupal core as well as new installation profiles like the [Unami demonstration
-profile][2] is pretty cool!
-
-For example, in addition to Unami, 8.5 alone adds media in core, two
-experimental modules have been marked as stable, an experimental new layout
-builder has been added and lots of PHP 7.2 improvements have been committed to
-make 8.5 fully PHP 7.2 compatible.
-
-I’m already looking forward to see what’s coming in 8.6 later this year!
-
-For more information on the 8.5 release, see the [blog post on Drupal.org][1].
-
-[0]: https://dri.es/drupal-8-5-0-released
-[1]: https://www.drupal.org/blog/drupal-8-5-0
-[2]:
- https://www.drupal.org/docs/8/umami-drupal-8-demonstration-installation-profile
diff --git a/astro/sculpin-old/source/_posts/drupal-8-commerce-fixing-error-on-user-checkout.md b/astro/sculpin-old/source/_posts/drupal-8-commerce-fixing-error-on-user-checkout.md
deleted file mode 100644
index 0292d85f..00000000
--- a/astro/sculpin-old/source/_posts/drupal-8-commerce-fixing-error-on-user-checkout.md
+++ /dev/null
@@ -1,96 +0,0 @@
----
-title: "Drupal 8 Commerce: Fixing 'No Such Customer' error on checkout"
-date: 2018-08-15
-excerpt:
- Fixing a Drupal Commerce error when a user tries to complete a checkout.
-tags:
- - drupal
- - drupal-8
- - drupal-commerce
- - stripe
----
-
-Recently I was experiencing an issue on the Drupal 8 website I’m working on,
-where a small number of users were not able to complete the checkout process and
-instead got a generic `The site has encountered an unexpected error` message.
-
-Looking at the log, I was able to see the error being thrown (the customer ID
-has been redacted):
-
-> Stripe\Error\InvalidRequest: No such customer: cus_xxxxxxxxxxxxxx in
-> Stripe\ApiRequestor::\_specificAPIError() (line 124 of
-> /var/www/vendor/stripe/stripe-php/lib/ApiRequestor.php).
-
-Logging in to the Stripe account, I was able to confirm that the specified
-customer ID did not exist. So where was it coming from, and why was Drupal
-trying to retrieve a non-existent customer?
-
-## Investigation
-
-After some investigation, I found a table in the database named
-`user__commerce_remote_id` which stores the remote customer ID for each payment
-method (again, the customer ID has been redacted).
-
-{.border.p-1}
-
-The `entity_id` and `revision_id` values in this case refer to the user that the
-Stripe customer has been associated with.
-
-As there was no customer in Stripe with this ID, I think that this must be a
-customer ID from the test environment (the data from which was deleted before
-the site went live).
-
-### Drupal code
-
-This I believe is the Drupal code where the error was being triggered:
-
-```language-php
-// modules/contrib/commerce_stripe/src/Plugin/Commerce/PaymentGateway/Stripe.php
-
-public function createPayment(PaymentInterface $payment, $capture = TRUE) {
- ...
-
- $owner = $payment_method->getOwner();
- if ($owner && $owner->isAuthenticated()) {
- $transaction_data['customer'] = $this->getRemoteCustomerId($owner);
- }
-
- try {
- $result = \Stripe\Charge::create($transaction_data);
- ErrorHelper::handleErrors($result);
- }
- catch (\Stripe\Error\Base $e) {
- ErrorHelper::handleException($e);
- }
-
- ...
-}
-```
-
-### Stripe code
-
-I can also see in the Stripe library where the original error is generated.
-
-```language-php
-private static function _specificAPIError($rbody, $rcode, $rheaders, $resp, $errorData)
-{
- $msg = isset($errorData['message']) ? $errorData['message'] : null;
- $param = isset($errorData['param']) ? $errorData['param'] : null;
- $code = isset($errorData['code']) ? $errorData['code'] : null;
-
- switch ($rcode) {
- ...
-
- case 404:
- return new Error\InvalidRequest($msg, $param, $rcode, $rbody, $resp, $rheaders);
-
- ...
- }
-}
-```
-
-## Solution
-
-After confirming that it was the correct user ID, simply removing that row from
-the database allowed the new Stripe customer to be created and for the user to
-check out successfully.
diff --git a/astro/sculpin-old/source/_posts/drupal-association.md b/astro/sculpin-old/source/_posts/drupal-association.md
deleted file mode 100644
index 495d1ecd..00000000
--- a/astro/sculpin-old/source/_posts/drupal-association.md
+++ /dev/null
@@ -1,37 +0,0 @@
----
-title: Drupal Association
-date: 2014-05-03
-excerpt: Next week, I'll be working for the Drupal Association.
-tags:
- - drupal
- - personal
----
-
-Today was my last day working at [Precedent](http://www.precedent.com). Next
-week, I'll be starting my
-[new job](https://assoc.drupal.org/node/18923 'Drupal.org Developer') at the
-[Drupal Association](http://assoc.drupal.org) working on Drupal's home -
-[Drupal.org](http://www.drupal.org).
-
-I was at Precedent for just over a year and had the opportunity to work on
-several Drupal projects from project leading to ad-hoc module and theme
-development, including my largest Drupal build to date.
-
-I was also lucky enough to go to
-[DrupalCon Prague](http://prague2013.drupal.org) as well as
-[DrupalCamp London](http://2014.drupalcamplondon.co.uk).
-
-I was able to [contribute some code](https://drupal.org/project/eventsforce)
-back into the community and encourage other team members to do the same.
-
-It was good to be able to introduce some new tools like
-[Vagrant](http://www.vagrantup.com), [Puppet](http://www.puppetlabs.com),
-[SASS](http://www.sass-lang.com) and [Compass](http://www.compass-style.org)
-into the team. I was pleased to introduce and champion the
-[Git Flow](http://danielkummer.github.io/git-flow-cheatsheet 'Git Flow Cheat Sheet')
-branching model, which them became the standard approach for all Drupal
-projects, and hopefully soon all development projects.
-
-Working for the Drupal Association and on Drupal.org was an opportunity that I
-couldn't refuse, and is certainly going to be a fun and interesting challenge. I
-can't wait to get started!
diff --git a/astro/sculpin-old/source/_posts/drupal-bristol-testing-workshop.md b/astro/sculpin-old/source/_posts/drupal-bristol-testing-workshop.md
deleted file mode 100644
index 918a1fe5..00000000
--- a/astro/sculpin-old/source/_posts/drupal-bristol-testing-workshop.md
+++ /dev/null
@@ -1,107 +0,0 @@
----
-title: Drupal Bristol Testing Workshop
-date: 2018-06-28
-excerpt:
- Yesterday evening, I did my first workshop, held at the Drupal Bristol user
- group.
-tags:
- [composer, docksal, drupal, drupal-8, drupal-bristol, php, phpunit, testing]
----
-
-Yesterday evening, I did [my first workshop][16] (and I believe, the first
-workshop) held at the [{{ site.events['drupal_bristol'].name }}][14] user group.
-The subject was automated testing with PHPUnit in Drupal 8, in preparation for
-my talk at [{{ site.events['drupal_dev_days_18'].name }}][12] next week and to
-help process some ideas for my [testing book][15].
-
-Here are some details about what we covered, and some of my thoughts in review.
-
-## Local Environment
-
-Before the meetup, I set up a [repository on GitHub][0] that contains a
-Composer-based Drupal 8 installation, based on the [Drupal 8 Composer
-template][4] along with the [Examples module][5] (which includes some PHPUnit
-tests) with a pre-configured [Docksal][2] environment to use locally - Docksal
-being our standard local development environment that we use at
-{{ site.companies['microserve'].name }} for all of our projects, so something
-that I’m familiar with using.
-
-In addition to the default stack, I added [the PHPUnit add-on that I wrote][6]
-so that it was easier to run tests, [configured settings.php using environment
-variables][7] and added a custom `fin init` command to install the Composer
-dependencies and install Drupal. This meant after that installing Docksal,
-everyone had a running Drupal 8 website after only running `git clone` and
-`fin init`, and could then run tests straight away using
-`fin phpunit web/modules/contrib/examples/phpunit_example`.
-
-## Exercises
-
-Once everyone was set up, we moved on to talk about why testing is important and
-the different options available to run them, before looking at the different
-types of tests available in Drupal 8. For each test type, I explained what it
-was used for and everyone completed an exercise on each - creating a test of
-that type, initially seeing it fail, and then doing the work to get it to pass.
-
-The completed code that I wrote beforehand for these is available in their own
-[GitHub repository][8], including all of the tests as well as the implementation
-code.
-
-Once these exercises were completed, we looked at creating a blog page using
-test driven development - the example that I use in the [TDD - Test Driven
-Drupal talk][9], to give a more real-word scenario. It would have been good to
-have gone through this as an exercise too, if we’d have had more time.
-
-## Wrap Up
-
-To finish, I demonstrated the PHPUnit integration within PHPStorm (which is
-working with Docksal) and showed some of the tests that I wrote for the [Private
-Message Queue][10] and [System User][11] modules, to see how things like adding
-items to queues and processing them, ensuring that emails are sent, to the right
-users and contain the right data, can be tested, as well as some of the tests
-that we’ve written on my work project over the last few months.
-
-## Slides
-
-I didn’t record this workshop, but I have exported the slides and embedded them
-below:
-
-{% include 'speakerdeck' with {
- data: {
- id: '2679401cb2ad421789d372cb8d38e368',
- ratio: '1.77777777777778',
- }
-} %}
-
-## Thoughts
-
-I was very happy with how my first workshop went, it was a great experience for
-me and it seemed that the attendees all learnt something and found it
-interesting.
-
-A couple of people mentioned about providing handouts to refer the code examples
-whilst working on the exercises, rather than relying on the slides and avoiding
-the need to sometimes switch back and forth between slides. I’ve found that I
-can export the slide deck as PNGs or JPGs from Deckset, so I’ll definitely do
-that next time.
-
-I’m giving the [Test Driven Drupal][9] talk at the [Drupal Dev Days
-conference][12] next week, and I’m hoping to give it again at other meetups and
-events in the UK. If you’d like me to do either at your meetup or event, [get in
-touch][13].
-
-[0]: https://github.com/opdavies/drupal-testing-workshop
-[1]: https://github.com/drupal-composer/drupal-project
-[2]: https://docksal.io
-
-[3]: {{site.companies['microserve'].url}} [4]:
-https://github.com/drupal-composer/drupal-project [5]:
-https://www.drupal.org/project/examples [6]:
-/articles/creating-a-custom-phpunit-command-for-docksal [7]:
-/articles/using-environment-variables-settings-docksal [8]:
-https://github.com/opdavies/drupal-testing-workshop-exercises [9]:
-/talks/tdd-test-driven-drupal [10]:
-https://www.drupal.org/project/private_message_queue [11]:
-https://www.drupal.org/project/system_user [12]:
-{{site.events.drupal_dev_days_18.url}} [13]: /contact [14]:
-{{site.events.drupal_bristol.url}} [15]: /test-driven-drupal [16]:
-https://groups.drupal.org/node/520891
diff --git a/astro/sculpin-old/source/_posts/drupal-vm-generator-updates.md b/astro/sculpin-old/source/_posts/drupal-vm-generator-updates.md
deleted file mode 100644
index 143d1c9e..00000000
--- a/astro/sculpin-old/source/_posts/drupal-vm-generator-updates.md
+++ /dev/null
@@ -1,33 +0,0 @@
----
-title: Drupal VM Generator 2.9.1 Released
-date: 2016-12-30
-excerpt: I’ve released some new versions of the Drupal VM Generator.
-tags: ['drupal-vm-generator', releases]
----
-
-The main updates are:
-
-- Fixed an `InvalidResponseException` that was thrown from within the
- `boolean_as_string` Twig filter from the opdavies/twig-extensions library when
- the `config:generate` command was run in non-interactive mode.
-- Adding a working test suite for the existing commands, using PhpUnit and
- Symfony’s Process component. This is now linked to [Travis CI][2], and the
- tests are run on each commit and pull request.
-- The version requirements have been changed to allow 2.7 versions of the used
- Symfony Components, as well as the 3.x versions. This was done to resolve a
- conflict when also installing Drush globally with Composer.
-
-## Next Steps
-
-Currently the project is based on Drupal VM 3.0.0 which is an outdated version
-([4.1.0][3] was released today). Adding updates and supporting the newer
-versions is a high priority, as well as keeping in sync with new releases. This
-will be easier with the test suite in place.
-
-My initial thoughts are that version 2.10.0 will support Drupal VM 4.0.0, and if
-needed, 2.11.0 will ship shortly afterwards and support Drupal VM 4.1.0.
-
-[0]: http://www.drupalvmgenerator.com
-[1]: https://github.com/opdavies/drupal-vm-generator/tree/master/tests/Command
-[2]: https://travis-ci.org/opdavies/drupal-vm-generator
-[3]: https://github.com/geerlingguy/drupal-vm/releases/tag/4.1.0
diff --git a/astro/sculpin-old/source/_posts/drupalcamp-bristol-2018.md b/astro/sculpin-old/source/_posts/drupalcamp-bristol-2018.md
deleted file mode 100644
index 2d86c0e1..00000000
--- a/astro/sculpin-old/source/_posts/drupalcamp-bristol-2018.md
+++ /dev/null
@@ -1,48 +0,0 @@
----
-title: DrupalCamp Bristol 2018 Statement
-date: 2018-01-30
-excerpt: Unfortunately, we won’t be running DrupalCamp Bristol this year.
-tags:
- - drupal-planet
- - drupalcamp-bristol
-use:
- - posts
-meta:
- image:
- url: /images/blog/drupalcamp-bristol-17-logo.jpg
- width: 228
- height: 448
- type: image/img
----
-
-It’s with heavy hearts that we are announcing there won’t be a DrupalCamp
-Bristol 2018. The committee have looked at the amount of work required to put
-the camp on and the capacity we all have and the two numbers are irreconcilable.
-
-Seeing Drupalists from all over the country and from overseas come to Bristol to
-share knowledge and ideas is something we take pride in. The past three camps
-have been fantastic, but as a trend we have left it later and later to organise.
-
-This year is the latest we have left to organise and we believe this is because
-we are all a bit fatigued right now, so it seems like a good place to stop and
-take stock.
-
-In our washup of last year’s camp we spoke a lot about what DrupalCamp is and
-who it is for. Traditionally we have tried to get a good mix of speakers from
-within the Drupal community and from the wider tech community. This does mean we
-dilute the ‘Drupal’ aspect of the camp, but the benefits it brings in terms of
-bringing together different views gives the camp greater value in our eyes.
-
-It’s because of this mix of talks and wider shifts in the community in ‘getting
-us off the island’ that we have been thinking about rebranding to reflect the
-mix of talks that the camp hosts. The fact is DrupalCamps don’t just cover
-Drupal anymore. There is Symfony, Composer, OOP principles, React, etc.
-
-We’ll take the gap this year to reevaluate who DrupalCamp Bristol is for and
-where it fits into the schedule of excellent tech events that take place in
-Bristol through the year, and we look forward to seeing you in 2019, refreshed
-and more enthusiastic than ever!
-
-The DrupalCamp Bristol organising committee
-
-Tom, Ollie, Emily, Sophie, Rob, Mark
diff --git a/astro/sculpin-old/source/_posts/drupalcamp-bristol-2019-speakers-sessions-announced.md b/astro/sculpin-old/source/_posts/drupalcamp-bristol-2019-speakers-sessions-announced.md
deleted file mode 100644
index 5ca81ca1..00000000
--- a/astro/sculpin-old/source/_posts/drupalcamp-bristol-2019-speakers-sessions-announced.md
+++ /dev/null
@@ -1,35 +0,0 @@
----
-title: Speakers and sessions announced for DrupalCamp Bristol 2019
-date: 2019-05-31
-excerpt:
- DrupalCamp Bristol is returning next month, and the accepted speakers and
- sessions have just been announced.
-tags: [drupalcamp, drupalcamp-bristol, dcbristol]
----
-
-
DrupalCamp Bristol is returning next month for a one-day, single-track conference, and we have just finished announcing the accepted sessions and speakers. It includes a mixture of new and returning speakers, presenting sessions including **Drupal in a microservice architecture**, **Automate to manage repetitive tasks with Ansible** and **Doing good with Drupal**.
-
-Find out more about all of our sessions and speakers on [the DrupalCamp Bristol
-website][website], as well as view the schedule for the day.
-
-Also, at the time of writing, [early bird tickets are still available][tickets]
-for a few more days!
-
-In the meantime, the videos from the 2017 Camp are on [our YouTube
-channel][youtube], including the opening keynote from [Emma Karayiannis][emma]:
-
-{% include 'video-embed' with {
- classes: 'video-full',
- video: {
- id: 'honnav4YlAA',
- attr: {
- height: '315',
- width: '560',
- }
- }
-} %}
-
-[emma]: https://twitter.com/embobmaria
-[tickets]: https://2019.drupalcampbristol.co.uk/tickets
-[website]: https://2019.drupalcampbristol.co.uk
-[youtube]: https://opdavi.es/dcbristol17-videos
diff --git a/astro/sculpin-old/source/_posts/drupalcamp-bristol-early-bird-tickets-sessions-sponsors.md b/astro/sculpin-old/source/_posts/drupalcamp-bristol-early-bird-tickets-sessions-sponsors.md
deleted file mode 100644
index bd204fbc..00000000
--- a/astro/sculpin-old/source/_posts/drupalcamp-bristol-early-bird-tickets-sessions-sponsors.md
+++ /dev/null
@@ -1,70 +0,0 @@
----
-title: DrupalCamp Bristol 2017 - Early Bird Tickets, Call for Sessions, Sponsors
-date: 2017-05-15
-excerpt:
- In less than two months time, DrupalCamp Bristol will be back for our third
- year.
-tags:
- - drupal
- - drupal-planet
- - drupalcamp
- - drupalcamp-bristol
-meta:
- image:
- url: /assets/image/blog/drupalcamp-bristol-17-logo.jpg
- height: 228
- width: 448
- type: image/jpg
----
-
-
-
-In less than two months time, [DrupalCamp Bristol][0] will be back for our third
-year! (July seems to come around quicker each year). This is this year’s
-schedule and venues:
-
-- 30th June - CXO (Business) day - [Watershed][1]
-- 1st July - Developer conference - [University of Bristol, School of
- Chemistry][2]
-- 2nd July - Contribution sprints - Venue TBC
-
-Today we announced [Emma Karayiannis][3] as our Saturday keynote speaker, and
-we’ll be announcing some of the other speakers later this week.
-
-Not submitted your session yet? The [session submissions][12] are open until May
-31st. We’re looking for talks not only on Drupal, but other related topics such
-as PHP, Symfony, server administration/DevOps, project management, case studies,
-being human etc. If you want to submit but want to ask something beforehand,
-please [send us an email][4] or ping us on [Twitter][5].
-
-Not spoken at a DrupalCamp before? No problem. We’re looking for both new and
-experienced speakers, and have both long (45 minutes) and short (20 minutes)
-talk slots available.
-
-Not bought your tickets yet? [Early bird tickets][10] for the CXO and conference
-days are still available! The sprint day tickets are free but limited, so do
-register for a ticket to claim your place.
-
-We still have [sponsorships opportunities][6] available (big thanks to
-[Microserve][7], [Deeson][8] and [Proctors][9]) who have already signed up), but
-be quick if you want to be included in our brochure so that we can get you added
-before our print deadline! Without our sponsors, putting on this event each year
-would not be possible.
-
-Any other questions? Take a look at [our website][0] or get in touch via
-[Twitter][5] or [email][11].
-
-[0]: https://2017.drupalcampbristol.co.uk
-[1]: http://www.watershed.co.uk
-[2]: http://www.bris.ac.uk/chemistry
-[3]: http://emmakarayiannis.com
-[4]: mailto:speakers@drupalcampbristol.co.uk
-[5]: https://twitter.com/DrupalCampBris
-[6]: https://2017.drupalcampbristol.co.uk/sponsorship
-[7]: https://microserve.io
-[8]: https://www.deeson.co.uk
-[9]: http://www.proctors.co.uk
-[10]:
- https://www.eventbrite.co.uk/e/drupalcamp-bristol-2017-tickets-33574193316#ticket
-[11]: mailto:info@drupalcampbristol.co.uk
-[12]: https://2017.drupalcampbristol.co.uk/#block-dcb2017-page-title
diff --git a/astro/sculpin-old/source/_posts/drupalcamp-london-2014.md b/astro/sculpin-old/source/_posts/drupalcamp-london-2014.md
deleted file mode 100644
index 95b4afcd..00000000
--- a/astro/sculpin-old/source/_posts/drupalcamp-london-2014.md
+++ /dev/null
@@ -1,24 +0,0 @@
----
-title: DrupalCamp London 2014
-date: 2014-02-09
-excerpt: It's all booked, I'm going to be attending DrupalCamp London.
-tags:
- - drupal
- - drupalcamp-london
- - git
- - git-flow
----
-
-It's all booked, I'm going to be attending
-[DrupalCamp London](http://2014.drupalcamplondon.co.uk) this year, my first
-DrupalCamp!
-
-I'm going as a volunteer, so I'm going to be helping with the registrations on
-the Saturday morning and for another couple hours elsewhere over the weekend.
-I've also offered to help organise and oversee some code sprints, although I'm
-definitely wanting to do some sprinting of my own and attend a few sessions.
-
-I'm looking forward to meeting some new people as well as catching up with some
-people that I met at [DrupalCon Prague](http://prague2013.drupal.org).
-
-If you're also coming, see you there!
diff --git a/astro/sculpin-old/source/_posts/drupalcamp-london-2019-tickets.md b/astro/sculpin-old/source/_posts/drupalcamp-london-2019-tickets.md
deleted file mode 100644
index 8ec1d9b5..00000000
--- a/astro/sculpin-old/source/_posts/drupalcamp-london-2019-tickets.md
+++ /dev/null
@@ -1,41 +0,0 @@
----
-title: DrupalCamp London 2019 - Tickets Available and Call for Sessions
-date: 2018-11-20
-excerpt:
- DrupalCamp London early-bird tickets are now available, and their call for
- sessions is open.
-tags:
- - conferences
- - drupal
- - drupalcamp
- - drupalcamp-london
-has_tweets: true
----
-
-It was announced this week that [early-bird tickets are now available][0] for
-[DrupalCamp London 2019][1], as well as their [call for sessions being open][2].
-
-{% include 'tweet' with {
- content: '
The time is finally here. You can now purchase your tickets. Early Bird finishes on 2nd January 2019 - https://t.co/aG6jstmWzv#Drupal
— DrupalCamp London (@DrupalCampLDN) November 19, 2018
-',
-} %}
-
-I’ve attended, given talks and volunteered previously, would definitely
-recommend others doing so, and I plan on attending and submitting again myself
-for 2019. If there’s something in particular that you’d like to see me give a
-talk on, let me know - I’d be happy to hear any suggestions. Alternatively, if
-you’d like to submit and would like some help writing an abstract or want some
-feedback on a talk idea, please get in touch.
-
-_Note: I am not an organiser of DrupalCamp London, nor am I involved with the
-session selection process._
-
-Hopefully there will be no [#uksnow][3] this year!
-
-DrupalCamp London is the 1-3 March 2019. Early bird tickets are available until
-2 January 2019, and the call for sessions is open until 21 January.
-
-[0]: https://twitter.com/DrupalCampLDN/status/1064584179113971712
-[1]: https://drupalcamp.london
-[2]: https://drupalcamp.london/get-involved/submit-a-session
-[3]: /articles/tweets-drupalcamp-london
diff --git a/astro/sculpin-old/source/_posts/drupalcamp-london-testing-workshop.md b/astro/sculpin-old/source/_posts/drupalcamp-london-testing-workshop.md
deleted file mode 100644
index 7f57df8e..00000000
--- a/astro/sculpin-old/source/_posts/drupalcamp-london-testing-workshop.md
+++ /dev/null
@@ -1,26 +0,0 @@
----
-title: Testing Workshop at DrupalCamp London 2020
-excerpt: This year, I’m teaching a workshop at DrupalCamp London.
-tags: [drupal, drupalcamp, testing]
-date: 2020-02-05
-lead_image:
- url: /images/blog/testing-workshop-drupalcamp-london/lead.jpg
----
-
-{.p-1 .border}
-
-
{{ page.excerpt }}
-
-The subject will be automated testing and test driven development in Drupal 8,
-and it will be on Friday 13th March 2020, between 1pm and 5pm.
-
-In the workshop, I’ll cover the methodology, approaches and terminology involved
-with automated testing, look at some examples and work through some exercises,
-and then take a test driven development approach to creating a new Drupal
-module.
-
-There are also other workshops on topics including Composer, Drupal Commerce,
-profiling, and chatbots.
-
-For more information and to register, go to the
-[DrupalCamp London website](https://opdavi.es/dclondon20 'Find out more and register on the DrupalCamp London website').
diff --git a/astro/sculpin-old/source/_posts/easier-git-repository-cloning-with-insteadof.md b/astro/sculpin-old/source/_posts/easier-git-repository-cloning-with-insteadof.md
deleted file mode 100644
index 5f782e74..00000000
--- a/astro/sculpin-old/source/_posts/easier-git-repository-cloning-with-insteadof.md
+++ /dev/null
@@ -1,83 +0,0 @@
----
-title: Easier Git Repository Cloning with insteadOf
-date: 2019-03-07
-excerpt:
- How to simplify 'git clone' commands by using the insteadOf configuration
- option within your .gitconfig file.
-tags: [git]
----
-
-When working on client or open source projects, I clone a lot of
-[Git](https://git-scm.com) repositories - either from GitHub, GitLab, Bitbucket
-or Drupal.org. The standard `git clone` commands though provided by these sites
-can be quite verbose with long repository URLs and use a mixture of different
-protocols, and I’d regularly need to go back to each website and look up the
-necessary command every time.
-
-For example, here is the command provided to clone Drupal’s
-[Override Node Options module](https://www.drupal.org/project/override_node_options):
-
-```plain
-git clone --branch 8.x-2.x https://git.drupal.org/project/override_node_options.git
-```
-
-We can though simplify the command to make it easier and quicker to type, using
-a Git configuration option called `insteadOf`.
-
-## What is insteadOf?
-
-From the
-[Git documentation](https://git-scm.com/docs/git-config#git-config-urlltbasegtinsteadOf):
-
-> **url.[base].insteadOf:**
->
-> Any URL that starts with this value will be rewritten to start, instead, with
-> [base]. In cases where some site serves a large number of repositories, and
-> serves them with multiple access methods, and some users need to use different
-> access methods, this feature allows people to specify any of the equivalent
-> URLs and have Git automatically rewrite the URL to the best alternative for
-> the particular user, even for a never-before-seen repository on the site. When
-> more than one insteadOf strings match a given URL, the longest match is used.
-
-Whilst examples are sparse,
-[it seems like](https://stackoverflow.com/questions/1722807/how-to-convert-git-urls-to-http-urls)
-insteadOf is used for resolving protocol issues with repository URLs. However,
-we can use it to simplify our clone commands, as mentioned above.
-
-## Example: cloning Drupal contrib projects
-
-When working on Drupal core, or on a module, theme or distribution, you need to
-have a cloned version of that repository to generate patch files from, and apply
-patches to.
-
-Again, here is the provided command to clone the Override Node Options module:
-
-```plain
-git clone --branch 8.x-2.x https://git.drupal.org/project/override_node_options.git
-```
-
-At the time of writing, the Git repository URL follow this same format -
-`https://git.drupal.org/project/{name}.git` (also the `.git` file extension is
-optional).
-
-To shorten and simplify this, I can add this snippet to my `~/.gitconfig` file:
-
-```
-[url "https://git.drupal.org/project/"]
- insteadOf = do:
- insteadOf = drupal:
-```
-
-With that added, I can now instead run `git clone drupal:{name}` or
-`git clone do:{name}` to clone the repository, specifying the project’s machine
-name.
-
-For example, to clone the Override Node Options module, I can now do this using
-just `git clone drupal:override_node_options`.
-
-This, I think, is definitely quicker and easier!
-
-## Resources
-
-You can view my entire `.gitconfig` file, as well as my other dotfiles, in
-[my dotfiles repository on GitHub](https://github.com/opdavies/dotfiles/blob/master/.gitconfig).
diff --git a/astro/sculpin-old/source/_posts/easier-sculpin-commands-with-composer-and-npm-scripts.md b/astro/sculpin-old/source/_posts/easier-sculpin-commands-with-composer-and-npm-scripts.md
deleted file mode 100644
index b813491d..00000000
--- a/astro/sculpin-old/source/_posts/easier-sculpin-commands-with-composer-and-npm-scripts.md
+++ /dev/null
@@ -1,77 +0,0 @@
----
-title: Easier Sculpin Commands with Composer and NPM Scripts
-date: 2017-01-07
-excerpt:
- In this video, I show you how I've simplied my Sculpin and Gulp workflow using
- custom Composer and NPM scripts.
-tags: [composer, gulp, sculpin]
----
-
-In this video, I show you how I've simplied my Sculpin and Gulp workflow using
-custom Composer and NPM scripts.
-
-My website includes several various command line tools - e.g. [Sculpin][4],
-[Gulp][5] and [Behat][6] - each needing different arguments and options,
-depending on the command being run. For example, for Sculpin, I normally include
-several additional options when viewing the site locally - the full command that
-I use is
-`./vendor/bin/sculpin generate --watch --server --clean --no-interaction`.
-Typing this repeatedly is time consuming and could be easily mis-typed,
-forgotten or confused with other commands.
-
-In this video, I show you how I've simplied my Sculpin and Gulp workflow using
-custom Composer and NPM scripts.
-
-
-
-
-
-## Scripts
-
-Here are the scripts that I’m using - they are slightly different from those in
-the video. I use the `--generate` and `--watch` options for Sculpin and the
-`gulp watch` command for NPM. I had to change these before the recording as I
-was using the [demo magic][0] script to run the commands, and existing from a
-watch session was also ending the script process.
-
-### composer.json
-
-```language-json
-"scripts": {
- "clean": "rm -rf output_*/",
- "dev": "sculpin generate --clean --no-interaction --server --watch",
- "production": "sculpin generate --clean --no-interaction --env='prod' --quiet"
-}
-```
-
-Run with `composer run `, e.g. `composer run dev`.
-
-### package.json
-
-```language-json
-"scripts": {
- "init": "yarn && bower install",
- "dev": "gulp watch",
- "production": "gulp --production"
-}
-```
-
-Run with `npm run `, e.g. `npm run production`.
-
-You can also take a look at the full [composer.json][1] and [package.json][2]
-files within my site repository on [GitHub][3].
-
-## Resources
-
-- [Composer scripts][7]
-- [oliverdavies.uk composer.json][1]
-- [oliverdavies.uk package.json][2]
-
-[0]: https://github.com/paxtonhare/demo-magic
-[1]: https://github.com/opdavies/oliverdavies.uk/blob/master/composer.json
-[2]: https://github.com/opdavies/oliverdavies.uk/blob/master/package.json
-[3]: https://github.com/opdavies/oliverdavies.uk
-[4]: https://sculpin.io
-[5]: http://gulpjs.com
-[6]: http://behat.org
-[7]: https://getcomposer.org/doc/04-schema.md#scripts
diff --git a/astro/sculpin-old/source/_posts/easily-embed-typekit-fonts-your-drupal-website.md b/astro/sculpin-old/source/_posts/easily-embed-typekit-fonts-your-drupal-website.md
deleted file mode 100644
index d65a655c..00000000
--- a/astro/sculpin-old/source/_posts/easily-embed-typekit-fonts-your-drupal-website.md
+++ /dev/null
@@ -1,34 +0,0 @@
----
-title: Easily Embed TypeKit Fonts into your Drupal Website
-date: 2011-02-14
-excerpt:
- How to use the @font-your-face module to embed TypeKit fonts into your Drupal
- website.
-tags:
- - drupal-planet
- - drupal-6
- - typekit
----
-
-To begin with, you will need to
-[register for a TypeKit account](https://typekit.com/plans) - there is a free
-version if you just want to try it out.
-
-Next, you'll need to create a kit that contains the fonts that you want to use
-on your website. I've used
-[FF Tisa Web Pro](http://typekit.com/fonts/ff-tisa-web-pro).
-
-Under 'Kit Settings', ensure that your website domain (e.g. mysite.com) is
-listed under 'Domains'.
-
-Download and install the
-[@font-your-face](http://drupal.org/project/fontyourface) module onto your
-Drupal site, and to go admin/settings/fontyourface to configure it. Enter
-[your TypeKit API key](https://typekit.com/account/tokens), and click 'Import
-Typekit' to import your kits and fonts.
-
-Go to admin/dist/themes/fontyourface, and click 'Browse fonts to enable'. Click
-on the name of the font that you want to enable, check 'Enabled', and click
-'Edit font' to save your changes.
-
-With the font enabled, you can now use it in your CSS.
diff --git a/astro/sculpin-old/source/_posts/entityform.md b/astro/sculpin-old/source/_posts/entityform.md
deleted file mode 100644
index 91c8b614..00000000
--- a/astro/sculpin-old/source/_posts/entityform.md
+++ /dev/null
@@ -1,63 +0,0 @@
----
-title: Programmatically Load an Entityform in Drupal 7
-date: 2015-12-22
-excerpt:
- How to programmatically load, render and embed an entityform in Drupal 7.
-tags:
- - drupal
- - drupal-7
- - drupal-planet
- - entityform
----
-
-I recently had my first experience using the
-[Entityform module](https://www.drupal.org/project/entityform) in a project. It
-was quite easy to configure with different form types, but then I needed to
-embed the form into an overlay. I was expecting to use the `drupal_get_form()`
-function and render it, but this didn’t work.
-
-Here are the steps that I took to be able to load, render and embed the form.
-
-## Loading the Form
-
-The first thing that I needed to do to render the form was to load an empty
-instance of the entityform using `entityform_empty_load()`. In this example,
-`newsletter` is the name of my form type.
-
-```language-php
-$form = entityform_empty_load('newsletter');
-```
-
-This returns an instance of a relevant `Entityform` object.
-
-## Rendering the Form
-
-The next step was to be able to render the form. I did this using the
-`entity_form_wrapper()` function.
-
-As this function is within the `entityform.admin.inc` file and not autoloaded by
-Drupal, I needed to include it using `module_load_include()` so that the
-function was available.
-
-```language-php
-module_load_include('inc', 'entityform', 'entityform.admin');
-
-$output = entityform_form_wrapper($form, 'submit', 'embedded'),
-```
-
-The first argument is the `Entityform` object that was created in the previous
-step (I’ve [submitted a patch](https://www.drupal.org/node/2639584) to type hint
-this within entityform so that it’s clearer what is expected), which is
-required.
-
-The other two arguments are optional. The second argument is the mode (`submit`
-is the default value), and the last is the form context. `page` is the default
-value, for use on the submit page, however I changed this to `embedded`.
-
-I could then pass this result into my theme function to render it successfully
-within the relevant template file.
-
-## Resources
-
-- [The entityform module](https://www.drupal.org/project/entityform)
-- [My issue and patch to add the type hint to the entityform_form_wrapper function](https://www.drupal.org/node/2639584)
diff --git a/astro/sculpin-old/source/_posts/examples-of-laravel-collections-in-drupal.md b/astro/sculpin-old/source/_posts/examples-of-laravel-collections-in-drupal.md
deleted file mode 100644
index aaa08eef..00000000
--- a/astro/sculpin-old/source/_posts/examples-of-laravel-collections-in-drupal.md
+++ /dev/null
@@ -1,73 +0,0 @@
----
-title: Examples of using Laravel Collections in Drupal
-date: 2018-08-23
-excerpt:
- Some examples of using Laravel’s Illuminate Collections within Drupal
- projects.
-tags:
- - drupal
- - drupal-7
- - drupal-8
- - drupal-planet
- - laravel
- - laravel-collections
- - php
-has_tweets: true
----
-
-Since starting to work with Laravel as well as Drupal and Symfony, watching Adam
-Wathan’s [Refactoring to Collections][0] course as well as [lessons on
-Laracasts][6], I’ve become a fan of [Laravel’s Illuminate Collections][1] and
-the object-orientated pipeline approach for interacting with PHP arrays.
-
-In fact I’ve given a talk on [using Collections outside Laravel][2] and have
-written a [Collection class module][3] for Drupal 7.
-
-I’ve also tweeted several examples of code that I’ve written within Drupal that
-use Collections, and I thought it would be good to collate them all here for
-reference.
-
-Thanks again to [Tighten][4] for releasing and maintaining the
-[tightenco/collect library][5] that makes it possible to pull in Collections via
-Composer.
-
-
- {% include 'tweet' with {
- class: 'block mb-4 lg:w-1/2 lg:px-2 lg:mb-0',
- data_cards: true,
- content: '
— Oliver Davies (@opdavies) February 14, 2018',
- } %}
-
- {% include 'tweet' with {
- class: 'block mb-4 lg:w-1/2 lg:px-2 lg:mb-0',
- data_cards: true,
- content: '
I knew that you could specify a property like 'price' in Twig and it would also look for methods like 'getPrice()', but I didn't know (or had maybe forgotten) that @laravelphp Collections does it too.
This means that these two Collections return the same result.
— Oliver Davies (@opdavies) August 10, 2018',
- } %}
-
- {% include 'tweet' with {
- class: 'block mb-4 lg:w-1/2 lg:px-2 lg:mb-0',
- data_cards: true,
- content: '
Some more #Drupal 8 fun with Laravel Collections. Loading the tags for a post and generating a formatted string of tweetable hashtags. pic.twitter.com/GbyiRPzIRo
-
-[0]: https://adamwathan.me/refactoring-to-collections
-[1]: https://laravel.com/docs/collections
-[2]: /talks/using-laravel-collections-outside-laravel
-[3]: https://www.drupal.org/project/collection_class
-[4]: https://tighten.co
-[5]: https://packagist.org/packages/tightenco/collect
-[6]: https://laracasts.com/series/how-do-i/episodes/18
diff --git a/astro/sculpin-old/source/_posts/experimenting-with-events-in-drupal-8.md b/astro/sculpin-old/source/_posts/experimenting-with-events-in-drupal-8.md
deleted file mode 100644
index abd6703d..00000000
--- a/astro/sculpin-old/source/_posts/experimenting-with-events-in-drupal-8.md
+++ /dev/null
@@ -1,83 +0,0 @@
----
-title: Experimenting with events in Drupal 8
-date: 2018-08-21
-excerpt:
- Trying a different way of structuring Drupal modules, using event subscribers
- and autowiring.
-tags:
- - drupal
- - drupal-8
- - drupal-planet
- - php
- - symfony
-promoted: true
----
-
-I’ve been experimenting with moving some code to Drupal 8, and I’m quite
-intrigued by a different way that I’ve tried to structure it - using event
-subscribers, building on some of the takeaways from Drupal Dev Days.
-
-Here is how this module is currently structured:
-
-{.border .p-1}
-
-Note that there is no `opdavies_blog.module` file, and rather than calling
-actions from within a hook like `opdavies_blog_entity_update()`, each action
-becomes it’s own event subscriber class.
-
-This means that there are no long `hook_entity_update` functions, and instead
-there are descriptive, readable event subscriber class names, simpler action
-code that is responsibile only for performing one task, and you’re able to
-inject and autowire dependencies into the event subscriber classes as services -
-making it easier and cleaner to use dependency injection, and simpler write
-tests to mock dependencies when needed.
-
-The additional events are provided by the
-[Hook Event Dispatcher module](https://www.drupal.org/project/hook_event_dispatcher).
-
-## Code
-
-`opdavies_blog.services.yml`:
-
-```yaml
-services:
- Drupal\opdavies_blog\EventSubscriber\PostToMedium:
- autowire: true
- tags:
- - { name: event_subscriber }
-
- Drupal\opdavies_blog\EventSubscriber\SendTweet:
- autowire: true
- tags:
- - { name: event_subscriber }
-```
-
-
-Adding `autowire: true` is not required for the event subscriber to work. I’m using it to automatically inject any dependencies into the class rather than specifying them separately as arguments.
-
-
-`src/EventSubscriber/SendTweet.php`:
-
-```php
-namespace Drupal\opdavies_blog\EventSubscriber;
-
-use Drupal\hook_event_dispatcher\Event\Entity\EntityUpdateEvent;
-use Drupal\hook_event_dispatcher\HookEventDispatcherInterface;
-use Symfony\Component\EventDispatcher\EventSubscriberInterface;
-
-class SendTweet implements EventSubscriberInterface {
-
- ...
-
- public static function getSubscribedEvents() {
- return [
- HookEventDispatcherInterface::ENTITY_UPDATE => 'sendTweet',
- ];
- }
-
- public function sendTweet(EntityUpdateEvent $event) {
- // Perform checks and send the tweet.
- }
-
-}
-```
diff --git a/astro/sculpin-old/source/_posts/finding-the-last-commit-that-a-patch-applies-to.md b/astro/sculpin-old/source/_posts/finding-the-last-commit-that-a-patch-applies-to.md
deleted file mode 100644
index 16b2b4ac..00000000
--- a/astro/sculpin-old/source/_posts/finding-the-last-commit-that-a-patch-applies-to.md
+++ /dev/null
@@ -1,47 +0,0 @@
----
-title: Finding the last commit that a patch applies to
-excerpt: How to find the last commit in a Git repository that a patch applies to.
-date: 2020-03-26
-tags: [bash, git]
-draft: true
----
-
-```bash
-#!/usr/bin/env bash
-
-# https://www.drupal.org/files/issues/2018-08-28/group-configurable-entities-as-group-content-2797793-58.patch
-
-patch_filename=group-configurable-entities-as-group-content-2797793-58.patch
-first_commit=6e8c22a
-last_commit=8.x-1.x
-
-find_commits_between() {
- first_commit=$1
- last_commit=$2
-
- git rev-list --reverse --ancestry-path $first_commit^...$last_commit
-}
-
-reset_repo() {
- git reset --hard $1 >& /dev/null
-}
-
-apply_patch() {
- git apply --check $patch_filename >& /dev/null
-}
-
-for sha1 in $(find_commits_between $first_commit $last_commit); do
- echo "Trying ${sha1}..."
-
- reset_repo $sha1
- apply_patch
-
- if [[ $? -eq 0 ]]; then
- echo "Patch applies"
- continue
- fi
-
- echo "Patch does not apply"
- exit 1
-done
-```
diff --git a/astro/sculpin-old/source/_posts/fix-vagrant-loading-wrong-virtual-machine.md b/astro/sculpin-old/source/_posts/fix-vagrant-loading-wrong-virtual-machine.md
deleted file mode 100644
index 3bfbe282..00000000
--- a/astro/sculpin-old/source/_posts/fix-vagrant-loading-wrong-virtual-machine.md
+++ /dev/null
@@ -1,28 +0,0 @@
----
-title: How to fix Vagrant Loading the Wrong Virtual Machine
-date: 2014-10-06
-excerpt:
- Here are the steps that I took to fix Vagrant and point it back at the correct
- VM.
-tags:
- - vagrant
- - virtualbox
----
-
-A few times recently, I've had instances where
-[Vagrant](https://www.vagrantup.com) seems to have forgotten which virtual
-machine it's supposed to load, probably due to renaming a project directory or
-the .vagrant directory being moved accidentally.
-
-Here are the steps that I took to fix this and point Vagrant back at the correct
-VM.
-
-1. Stop the machine from running using the `$ vagrant halt` command.
-1. Use the `$ VBoxManage list vms` command to view a list of the virtual
- machines on your system. Note the ID of the correct VM that should be
- loading. For example,
- `"foo_default_1405481857614_74478" {e492bfc3-cac2-4cde-a396-e81e37e421e2}`.
- The number within the curly brackets is the ID of the virtual machine.
-1. Within the .vagrant directory in your project (it is hidden by default),
- update the ID within the machines/default/virtualbox/id file.
-1. Start the new VM with `$ vagrant up`.
diff --git a/astro/sculpin-old/source/_posts/fixing-drupal-simpletest-docker.md b/astro/sculpin-old/source/_posts/fixing-drupal-simpletest-docker.md
deleted file mode 100644
index 3d25eba4..00000000
--- a/astro/sculpin-old/source/_posts/fixing-drupal-simpletest-docker.md
+++ /dev/null
@@ -1,132 +0,0 @@
----
-title: Fixing Drupal SimpleTest issues inside Docker Containers
-date: 2017-05-05
-excerpt:
- How I managed to get my Drupal SimpleTest tests to run and pass within Docker
- containers.
-tags:
- - docker
- - drupal
- - drupal-planet
- - simpletest
- - testing
----
-
-I’ve been a Drupal VM user for a long time, but lately I’ve been using a
-combination Drupal VM and Docker for my local development environment. There
-were a couple of issues preventing me from completely switching to Docker - one
-of which being that when I tried running of my Simpletest tests, a lot of them
-would fail where they would pass when run within Drupal VM.
-
-Here’s an excerpt from my `docker-compose.yml` file:
-
-**TL;DR** You need to include the name of your web server container as the
-`--url` option to `run-scripts.php`.
-
-I’ve been a [Drupal VM][1] user for a long time, but lately I’ve been using a
-combination Drupal VM and [Docker][0] for my local development environment.
-There were a couple of issues preventing me from completely switching to
-Docker - one of which being that when I tried running of my Simpletest tests, a
-lot of them would fail where they would pass when run within Drupal VM.
-
-Here’s an excerpt from my `docker-compose.yml` file:
-
-```language-yaml
-services:
- php:
- image: wodby/drupal-php:5.6
- volumes:
- - ./repo:/var/www/html
-
- nginx:
- image: wodby/drupal-nginx:7-1.10
- environment:
- NGINX_BACKEND_HOST: php
- NGINX_SERVER_ROOT: /var/www/html/web
- ports:
- - "80:80"
- volumes_from:
- - php
-...
-```
-
-Nginx and PHP-FPM are running in separate containers, the volumes are shared
-across both and the Nginx backend is set to use the `php` container.
-
-This is the command that I was using to run the tests:
-
-```language-bash
-$ docker-compose run --rm \
- -w /var/www/html/web \
- php \
- php scripts/run-tests.sh \
- --php /usr/local/bin/php \
- --class OverrideNodeOptionsTestCase
-```
-
-This creates a new instance of the `php` container, sets the working directory
-to my Drupal root and runs Drupal’s `run-tests.sh` script with some arguments.
-In this case, I'm running the `OverrideNodeOptionsTestCase` class for the
-override_node_options tests. Once complete, the container is deleted because of
-the `--rm` option.
-
-This resulted in 60 of the 112 tests failing, whereas they all passed when run
-within a Drupal VM instance.
-
-```language-markup
-Test summary
-------------
-
-Override node options 62 passes, 60 fails, 29 exceptions, and 17 debug messages
-
-Test run duration: 2 min 25 sec
-```
-
-Running the tests again with the`--verbose` option, I saw this message appear in
-the output below some of the failing tests:
-
-> simplexml_import_dom(): Invalid Nodetype to import
-
-\*\*Up After checking that I had all of the required PHP extensions installed, I
-ran `docker-compose exec php bash` to connect to the `php` container and ran
-`curl http://localhost` to check the output. Rather than seeing the HTML for the
-site, I got this error message:
-
-> curl: (7) Failed to connect to localhost port 80: Connection refused
-
-Whereas `curl http://nginx` returns the HTML for the page, so included it with
-the `--url` option to `run-tests.sh`, and this resulted in my tests all passing.
-
-```language-bash
-$ docker-compose run --rm \
- -w /var/www/html/web \
- php \
- php scripts/run-tests.sh \
- --php /usr/local/bin/php \
- --url http://nginx \
- --class OverrideNodeOptionsTestCase
-```
-
-```language-markup
-Test summary
-------------
-
-Override node options 121 passes, 0 fails, 0 exceptions, and 34 debug messages
-
-Test run duration: 2 min 31 sec
-```
-
-**Note:** In this example I have separate `nginx` and `php` containers, but I've
-tried and had the same issue when running Nginx and PHP-FPM in the same
-container - e.g. called `app` - and still needed to add `--url http://app` in
-order for the tests to run successfully.
-
-I don’t know if this issue is macOS specfic (I know that [Drupal CI][2] is based
-on Docker, and I don’t know if it’s an issue) but I’m going to test also on my
-Ubuntu Desktop environment and investigate further and also compare the test run
-times for Docker in macOS, Docker in Ubuntu and within Drupal VM. I’m also going
-to test this with PHPUnit tests with Drupal 8.
-
-[0]: https://www.docker.com
-[1]: https://www.drupalvm.com
-[2]: https://www.drupal.org/drupalorg/docs/drupal-ci
diff --git a/astro/sculpin-old/source/_posts/forward-one-domain-another-using-modrewrite-and-htaccess.md b/astro/sculpin-old/source/_posts/forward-one-domain-another-using-modrewrite-and-htaccess.md
deleted file mode 100644
index a0cb5d83..00000000
--- a/astro/sculpin-old/source/_posts/forward-one-domain-another-using-modrewrite-and-htaccess.md
+++ /dev/null
@@ -1,33 +0,0 @@
----
-title: Forward one domain to another using mod_rewrite and .htaccess
-date: 2012-05-23
-excerpt: How to use the .htaccess file to forward to a different domain.
-tags:
- - .htaccess
- - code
- - drupal
- - apache
- - mod_rewrite
----
-
-How to use the .htaccess file to forward to a different domain.
-
-Within the mod_rewrite section of your .htaccess file, add the following lines:
-
-```language-apacheconf
-RewriteCond %{HTTP_HOST} ^yoursite\.co\.uk$
-RewriteRule (.*) http://yoursite.com/$1 [R=301,L]
-```
-
-This automatically forwards any users from http://yoursite.co.uk to
-http://yoursite.com. This can also be used to forward multiple domains:
-
-```language-apacheconf
-RewriteCond %{HTTP_HOST} ^yoursite\.co\.uk$ [OR]
-RewriteCond %{HTTP_HOST} ^yoursite\.info$ [OR]
-RewriteCond %{HTTP_HOST} ^yoursite\.biz$ [OR]
-RewriteCond %{HTTP_HOST} ^yoursite\.eu$
-RewriteRule (.*) http://yoursite.com/$1 [R=301,L]
-```
-
-If any of the RewriteCond conditions apply, then the RewriteRule is executed.
diff --git a/astro/sculpin-old/source/_posts/git-format-patch.md b/astro/sculpin-old/source/_posts/git-format-patch.md
deleted file mode 100644
index 2f43e91f..00000000
--- a/astro/sculpin-old/source/_posts/git-format-patch.md
+++ /dev/null
@@ -1,138 +0,0 @@
----
-title: git format-patch is your Friend
-date: 2014-05-21
-excerpt:
- An explanation of the "git format-patch" command, and how it could be used in
- Drupal's Git workflow.
-tags:
- - patches
- - drupal
- - drupal-planet
- - git
----
-
-An explanation of the "git format-patch" command, and how it could be used in
-Drupal's Git workflow.
-
-## The Problem
-
-As an active contributor to the [Drupal](http://drupal.org) project, I spend a
-lot of time working with other peoples’ modules and themes, and occassionally
-have to fix a bug or add some new functionality.
-
-In the Drupal community, we use a patch based workflow where any changes that I
-make get exported to a file detailing the differences. The patch file (\*.patch)
-is attached to an item in an issue queue on Drupal.org, applied by the
-maintainer to their local copy of the code and reviewed, and hopefully
-committed.
-
-There is an option that the maintainer can add to the end of their commit
-message.
-
-For example:
-
-```language-bash
---author="opdavies "
-```
-
-This differs slightly different for each Drupal user, and the code can be found
-on their Drupal.org profile page.
-
-If this is added to the end of the commit message, the resulting commit will
-show that it was committed by the maintainer but authored by a different user.
-This will then display on Drupal.org that you’ve made a commit to that project.
-
-
-
-The problem is that some project maintainers either don’t know about this option
-or occasionally forget to add it. [Dreditor](http://dreditor.org) can suggest a
-commit message and assign an author, but it is optional and, of course, not all
-maintainers use Dreditor (although they probably should).
-
-The `git format-patch` command seems to be the answer, and will be my preferred
-method for generating patch files in the future rather than `git diff`.
-
-## What does it do Differently?
-
-From the [manual page](http://git-scm.com/docs/git-format-patch):
-
-> Prepare each commit with its patch in one file per commit, formatted to
-> resemble UNIX mailbox format. The output of this command is convenient for
-> e-mail submission or for use with git am.
-
-Here is a section of a patch that I created for the
-[Metatag module](http://drupal.org/project/metatag) using `git format-patch`:
-
-```language-bash
-From 80c8fa14de7f4a83c2e70367aab0aedcadf4f3b0 Mon Sep 17 00:00:00 2001
-From: Oliver Davies <oliver@oliverdavies.co.uk>
-Subject: [PATCH] Exclude comment entities when checking if this is the page,
- otherwise comment_fragment.module will break metatag
----
-```
-
-As mentioned above, the patch is structured in an email format. The commit
-message is used as the subject line, and the date that the commit was made
-locally is used for the date. What we’re interested in is the “From” value. This
-contains your name and email address from your `~/.gitconfig` file and is used
-to author the patch automatically.
-
-Everything below this is the same as a standard patch file, the same as if was
-generated with `git diff`.
-
-The full patch file can be found at
-.
-
-## The Process
-
-How did I create this patch? Here are the steps that I took:
-
-1. Clone the source repository using
- `$ git clone --branch 7.x-1.x http://git.drupal.org/project/metatag.git` and
- move into that directory.
-2. Create a branch for this patch using
- `$ git checkout -b 2265447-comment-fragment-conflict`.
-3. Add and commit any changes as normal.
-4. Generate the patch file using
- `$ git format-patch 7.x-1.x --stdout > metatag-comment-fragment-conflict-2265447-4.patch`.
-
-_Note:_ I am defining 7.x-1.x in the last step as the original branch to compare
-(i.e. the original branch that we forked to make our issue branch). This will
-change depending on the project that you are patching, and it’s version number.
-Also, commits should always be made against the development branch and not the
-stable release.
-
-By default, a separate patch file will be created for each commit that we’ve
-made. This is overridden by the `--stdout` option which combines all of the
-patches into a single file. This is the recommended approach when uploading to
-Drupal.org.
-
-The resulting patch file can be uploaded onto a Drupal.org issue queue, reviewed
-by the Testbot and applied by a module maintainer, and you automatically get the
-commit attributed. Problem solved.
-
-## Committing the Patch
-
-If you need to commit a patch that was created using `git format-patch`, the
-best command to do this with is the `git am` command.
-
-For example, within your repository, run:
-
-```language-bash
-$ git am /path/to/file
-$ git am ~/Code/metatag-comment-fragment-conflict-2265447-4.patch
-```
-
-You should end up with some output similar to the following:
-
-```language-bash
-Applying: #2272799 Added supporters section
-Applying: #2272799 Added navigation tabs
-Applying: #2272799 Fixed indentation
-Applying: #2272799 Replaced URL
-```
-
-Each line is the commit message associated with that patch.
-
-Assuming that there are no errors, you can go ahead and push your updated code
-into your remote repository.
diff --git a/astro/sculpin-old/source/_posts/going-drupalcon.md b/astro/sculpin-old/source/_posts/going-drupalcon.md
deleted file mode 100644
index 01bb0680..00000000
--- a/astro/sculpin-old/source/_posts/going-drupalcon.md
+++ /dev/null
@@ -1,18 +0,0 @@
----
-title: Going to DrupalCon
-date: 2013-07-26
-excerpt:
- Precedent are sending myself and two of our other Drupal Developers to
- Drupalcon Prague.
-tags:
- - drupalcon
- - precedent
----
-
-[Precedent](http://www.precedent.co.uk) are sending myself and two of our other
-Drupal Developers to [Drupalcon Prague](http://prague2013.drupal.org).
-
-Having wanted to attend the last few Drupalcons (London, especially) but not
-being able to, I'm definitely looking forward to this one.
-
-See you there!
diff --git a/astro/sculpin-old/source/_posts/imagefield-import-archive.md b/astro/sculpin-old/source/_posts/imagefield-import-archive.md
deleted file mode 100644
index 54bc336c..00000000
--- a/astro/sculpin-old/source/_posts/imagefield-import-archive.md
+++ /dev/null
@@ -1,35 +0,0 @@
----
-title: Imagefield Import Archive
-date: 2011-05-23
-excerpt: I've finally uploaded my first module onto Drupal.org!
-tags:
- - drupal-planet
- - imagefield-import
----
-
-I've finally uploaded my first module onto Drupal.org!
-
-I've written many custom modules, although the vast majority of them are either
-small tweaks for my own sites, or company/site-specific modules that wouldn't be
-good to anyone else, so there would be nothing achieved by contributing them
-back to the community. Previously, I've blogged about the
-[Imagefield Import](http://drupal.org/project/imagefield_import) module - a
-module that I use on a number of sites, both personal and for clients - and what
-I've looked for lately is for a way to speed up the process again. Gathering my
-images together and manually copying them into the import directory takes time -
-especially if I'm working somewhere with a slow Internet connection and I'm
-FTP-ing the images into the directory. Also, it's not always the easiest
-solution for site users - especially non-technical ones.
-
-So, I wrote the Imagefield Import Archive module. Including comments, the module
-contains 123 lines, and builds upon the existing functionality of the Imagefield
-Import module by adding the ability for the user to upload a .zip archive of
-images. The archive is then moved into the specified import directory and
-unzipped before being deleted, and the user is directed straight to the standard
-Imagefield Import page where their images are waiting to be imported, just as
-usual.
-
-The module is currently a
-[sandbox project](http://drupal.org/sandbox/opdavies/1165110) on Drupal.org,
-although I have applied for full project access so that I can be added as a
-fully-fledged downloadable module.
diff --git a/astro/sculpin-old/source/_posts/improve-jpg-quality-imagecache-and-imageapi.md b/astro/sculpin-old/source/_posts/improve-jpg-quality-imagecache-and-imageapi.md
deleted file mode 100644
index 424fd026..00000000
--- a/astro/sculpin-old/source/_posts/improve-jpg-quality-imagecache-and-imageapi.md
+++ /dev/null
@@ -1,25 +0,0 @@
----
-title: Improve JPG Quality in Imagecache and ImageAPI
-date: 2010-06-02
-excerpt: How to fix the quality of uploaded images in Drupal.
-tags:
- - drupal-planet
- - drupal-6
- - imagecache
----
-
-Whilst uploading images for my Projects and Testimonials sections, I noticed
-that the Imagecache-scaled images weren't as high a quality the originals on my
-Mac. I did some searching online and found out that, by default, Drupal
-resamples uploaded jpgs to 75% of their original quality.
-
-To increase the quality of your images, change the setting in the two following
-places:
-
-- admin/settings/imageapi/config
-- admin/settings/image-toolkit
-
-The first one is for ImageAPI. Primarily, this means Imagecache presets. The
-second one is for core's image.inc. This is used for resizing profile pictures
-in core, and some contrib modules. Once changed, I did have to flush each of the
-Imagecache presets (admin/dist/imagecache) for the changes to take effect.
diff --git a/astro/sculpin-old/source/_posts/include-css-fonts-using-sass-each-loop.md b/astro/sculpin-old/source/_posts/include-css-fonts-using-sass-each-loop.md
deleted file mode 100644
index 93bf22d9..00000000
--- a/astro/sculpin-old/source/_posts/include-css-fonts-using-sass-each-loop.md
+++ /dev/null
@@ -1,67 +0,0 @@
----
-title: Include CSS Fonts by Using a SASS each Loop
-date: 2014-11-18
-excerpt: How to use an SASS each loop to easily add multiple fonts to your CSS.
-tags:
- - compass
- - drupal-planet
- - fonts
- - sass
----
-
-How to use an @each loop in SASS to quickly include multiple font files within
-your stylesheet.
-
-Using a file structure similar to this, organise your font files into
-directories, using the the font name for both the directory name and for the
-file names.
-
-```language-bash
-.
-├── FuturaBold
-│ ├── FuturaBold.eot
-│ ├── FuturaBold.svg
-│ ├── FuturaBold.ttf
-│ └── FuturaBold.woff
-├── FuturaBoldItalic
-│ ├── FuturaBoldItalic.eot
-│ ├── FuturaBoldItalic.svg
-│ ├── FuturaBoldItalic.ttf
-│ └── FuturaBoldItalic.woff
-├── FuturaBook
-│ ├── FuturaBook.eot
-│ ├── FuturaBook.svg
-│ ├── FuturaBook.ttf
-│ └── FuturaBook.woff
-├── FuturaItalic
-│ ├── FuturaItalic.eot
-│ ├── FuturaItalic.svg
-│ ├── FuturaItalic.ttf
-│ └── FuturaItalic.woff
-```
-
-Within your SASS file, start an `@each` loop, listing the names of the fonts. In
-the same way as PHP's `foreach` loop, each font name will get looped through
-using the `$family` variable and then compiled into CSS.
-
-```language-scss
-@each $family in FuturaBook, FuturaBold, FuturaBoldItalic, FuturaItalic {
- @font-face {
- font-family: #{$family};
- src: url('../fonts/#{$family}/#{$family}.eot');
- src: url('../fonts/#{$family}/#{$family}.eot?#iefix') format('embedded-opentype'),
- url('../fonts/#{$family}/#{$family}.woff') format('woff'),
- url('../fonts/#{$family}/#{$family}.ttf') format('truetype'),
- url('../fonts/#{$family}/#{$family}.svg##{$family}') format('svg');
- font-weight: normal;
- font-style: normal;
- }
-}
-```
-
-When the CSS has been compiled, you can then use in your CSS in the standard
-way.
-
-```language-scss
-font-family: "FuturaBook";
-```
diff --git a/astro/sculpin-old/source/_posts/include-local-drupal-settings-file-environment-configuration-and-overrides.md b/astro/sculpin-old/source/_posts/include-local-drupal-settings-file-environment-configuration-and-overrides.md
deleted file mode 100644
index 4580790b..00000000
--- a/astro/sculpin-old/source/_posts/include-local-drupal-settings-file-environment-configuration-and-overrides.md
+++ /dev/null
@@ -1,66 +0,0 @@
----
-title:
- Include a Local Drupal Settings file for Environment Configuration and
- Overrides
-date: 2014-12-20
-excerpt:
- How to create and include a local settings file to define and override
- environment-specific variables.
-tags:
- - drupal
- - drupal-6
- - drupal-7
- - drupal-8
- - drupal-planet
- - settings.php
----
-
-How to create and include a local settings file to define and override
-environment-specific variables, and keep sensitive things like your database
-credentials and API keys safe.
-
-At the bottom of settings.php, add the following code:
-
-```language-php
-$local_settings = __DIR__ . '/settings.local.php';
-if (file_exists($local_settings)) {
- include $local_settings;
-}
-```
-
-This allows for you to create a new file called settings.local.php within a
-sites/\* directory (the same place as settings.php), and this will be included
-as an extension of settings.php. You can see the same technique being used
-within Drupal 8's
-[default.settings.php](http://cgit.drupalcode.org/drupal/tree/sites/default/default.settings.php#n621)
-file.
-
-Environment specific settings like `$databases` and `$base_url` can be placed
-within the local settings file. Other settings like
-`$conf['locale_custom_strings_en']` (string overrides) and
-`$conf['allow_authorize_operations']` that would apply to all environments can
-still be placed in settings.php.
-
-settings.php though is ignored by default by Git by a .gitignore file, so it
-won't show up as a file available to be committed. There are two ways to fix
-this. The first is to use the `--force` option when adding the file which
-overrides the ignore file:
-
-```language-bash
-git add --force sites/default/settings.php
-```
-
-The other option is to update the .gitignore file itself so that settings.php is
-no longer ignored. An updated .gitignore file could look like:
-
-```language-bash
-# Ignore configuration files that may contain sensitive information.
-sites/*/settings.local*.php
-
-# Ignore paths that contain user-generated content.
-sites/*/files
-sites/*/private
-```
-
-This will allow for settings.php to be added to Git and committed, but not
-settings.local.php.
diff --git a/astro/sculpin-old/source/_posts/install-and-configure-subversion-svn-server-ubuntu.md b/astro/sculpin-old/source/_posts/install-and-configure-subversion-svn-server-ubuntu.md
deleted file mode 100644
index fd401913..00000000
--- a/astro/sculpin-old/source/_posts/install-and-configure-subversion-svn-server-ubuntu.md
+++ /dev/null
@@ -1,178 +0,0 @@
----
-title: How to Install and Configure Subversion (SVN) Server on Ubuntu
-date: 2011-10-19
-excerpt: How to install and configure your own SVN server.
-tags:
- - svn
- - ubuntu
- - version-control
----
-
-Recently, I needed to set up a Subversion (SVN) server on a Ubuntu Linux server.
-This post is going to outline the steps taken, and the commands used, to install
-and configure the service.
-
-Note: As I was using Ubuntu, I was using the 'apt-get' command to download and
-install the software packages. If you're using a different distribution of
-Linux, then this command may be different. I'm also assuming that Apache is
-already installed.
-
-Firstly, I'm going to ensure that all of my installed packages are up to date,
-and install any available updates.
-
-```language-bash
-$ sudo apt-get update
-```
-
-Now, I need to download the subversion, subversion-tools and libapache2
-packages.
-
-```language-bash
-$ sudo apt-get install subversion subversion-tools libapache2-svn
-```
-
-These are all of the packages that are needed to run a Subversion server.
-
-## Create subversion directory
-
-Now, I need to create the directory where my repositories are going to sit. I've
-chosen this directory as I know that it's one that is accessible to my managed
-backup service.
-
-```language-bash
-$ sudo mkdir /home/svn
-```
-
-## Create a test repository
-
-First, I'll create a new folder in which I'll create my test project, and then
-I'll create a repository for it.
-
-```language-bash
-$ sudo mkdir ~/test
-$ sudo svnadmin create /home/svn/test -m 'initial project structure'
-```
-
-This will create a new repository containing the base file structure.
-
-## Adding files into the test project
-
-```language-bash
-$ cd ~/test
-$ mkdir trunk tags branches
-```
-
-I can now import these new directories into the test repository.
-
-```language-bash
-$ sudo svn import ~/test file:///home/svn/test -m 'Initial project directories'
-```
-
-This both adds and commits these new directories into the repository.
-
-In order for Apache to access the SVN repositories, the `/home/svn` directory
-needs to be owned by the same user and group that Apache runs as. In Ubuntu,
-this is usually www-data. To change the owner of a directory, use the chown
-command.
-
-```language-bash
-$ sudo chown -R www-data:www-data /home/svn
-```
-
-## Configuring Apache
-
-The first thing that I need to do is enable the dav_svn Apache module, using the
-a2enmod command.
-
-```language-bash
-$ sudo a2enmod dav_svn
-```
-
-With this enabled, now I need to modify the Apache configuration file.
-
-```language-bash
-$ cd /etc/apache2
-$ sudo nano apache2.conf
-```
-
-At the bottom of the file, add the following lines, and then save the file by
-pressing Ctrl+X.
-
-```language-apacheconf
-
- DAV svn
- SVNParentPath /home/svn
-
-```
-
-With this saved, restart the Apache service for the changes to be applied.
-
-```language-bash
-sudo service apache2 restart
-```
-
-I can now browse through my test repository by opening Firefox, and navigating
-to `http://127.0.0.1/svn/test`. Here, I can now see my three directories,
-although they are currently all empty.
-
-## Securing my SVN repositories
-
-Before I start committing any files to the test repository, I want to ensure
-that only authorised users can view it - currently anyone can view the
-repository and it's contents, as well as being able to checkout and commit
-files. To do this, I'm going to require the user to enter a username and a
-password before viewing or performing any actions with the repository.
-
-Re-open apache2.conf, and replace the SVN Location information with this:
-
-```language-apacheconf
-
- DAV svn
- SVNParentPath /home/svn
- AuthType Basic
- AuthName "My SVN Repositories"
- AuthUserFile /etc/svn-auth
- Require valid-user
-
-```
-
-Now I need to create the password file.
-
-```language-bash
-$ htpasswd -cm /etc/svn-auth oliver
-```
-
-I'm prompted to enter and confirm my password, and then my details are saved.
-The Apache service will need to be restarted again, and then the user will need
-to authenticate themselves before viewing the repositories.
-
-## Checking out the repository and commiting files
-
-For example, now want to checkout the files within my repository into a new
-directory called 'test2' within my home directory. Firstly, I need to create the
-new directory, and then I can issue the checkout command.
-
-```language-bash
-$ cd ~
-$ mkdir test2
-$ svn checkout http://127.0.0.1/svn/test/trunk test2
-```
-
-I'm passing the command two arguments - the first is the URL of the repository's
-trunk directory, and the second is the directory where the files are to be
-placed. As no files have been commited yet into the trunk, it appears to be
-empty - but if you perform an ls -la command, you'll see that there is a hidden
-.svn directory.
-
-Now you can start adding files into the directory. Once you've created your
-files, perform a svn add command, passing in individual filenames as further
-arguments.
-
-```language-bash
-$ svn add index.php
-$ svn add *
-```
-
-With all the required files added, they can be committed using
-`svn commit -m 'commit message'` command, and the server can be updated using
-the svn up command.
diff --git a/astro/sculpin-old/source/_posts/install-nomensa-media-player-drupal.md b/astro/sculpin-old/source/_posts/install-nomensa-media-player-drupal.md
deleted file mode 100644
index b033c3a3..00000000
--- a/astro/sculpin-old/source/_posts/install-nomensa-media-player-drupal.md
+++ /dev/null
@@ -1,88 +0,0 @@
----
-title: Install and Configure the Nomensa Accessible Media Player in Drupal
-date: 2012-07-14
-excerpt:
- This week I released the first version of the Nomensa Accessible Media Player
- module for Drupal 7. Here's some instructions of how to install and configure
- it.
-tags:
- - accessibility
- - drupal
- - drupal-planet
- - nomensa
----
-
-This week I released the first version of the Nomensa Accessible Media Player
-module for Drupal 7. Here's some instructions of how to install and configure
-it.
-
-_The official documentation for this module is now located at
-. This post was accurate at the time of
-writing, whereas the documentation page will be kept up to date with any future
-changes._
-
-## Initial configuration
-
-### Download the Library
-
-The library can be downloaded directly from GitHub, and should be placed within
-you _sites/all/libraries/nomensa_amp_ directory.
-
-```language-bash
-drush dl libraries nomensa_amp
-git clone https://github.com/nomensa/Accessible-Media-Player sites/all/libraries/nomensa_amp
-cd sites/all/libraries/nomensa_amp
-rm -rf Accessible-media-player_2.0_documentation.pdf example/ README.md
-drush en -y nomensa_amp
-```
-
-### Configure the Module
-
-Configure the module at admin/config/media/nomensa-amp and enable the
-players that you want to use.
-
-## Adding videos
-
-Within your content add links to your videos. For example:
-
-### YouTube
-
-```language-html
-Checking colour contrast
-```
-
-### Vimeo
-
-```language-html
-Screen readers are strange, when you're a stranger by Leonie Watson
-```
-
-## Adding captions
-
-The best way that I can suggest to do this is to use a File field to upload your
-captions file:
-
-1. Add a File field to your content type;
-1. On your page upload the captions file.
-1. Right-click the uploaded file, copy the link location, and use this for the
- path to your captions file.
-
-For example:
-
-```language-html
-Checking colour contrastCaptions for Checking Colour Contrast
-```
-
-## Screencast
-
-
-
-
diff --git a/astro/sculpin-old/source/_posts/installing-nagios-centos.md b/astro/sculpin-old/source/_posts/installing-nagios-centos.md
deleted file mode 100644
index 7eba1938..00000000
--- a/astro/sculpin-old/source/_posts/installing-nagios-centos.md
+++ /dev/null
@@ -1,15 +0,0 @@
----
-title: Installing Nagios on CentOS
-date: 2012-04-17
-excerpt: How to install Nagios on CentOS.
-tags:
- - nagios
- - centos
- - linux
----
-
-A great post details that details the steps needed to install
-[Nagios](http://nagios.org) - a popular open source system and network
-monitoring software application - on CentOS.
-
-
diff --git a/astro/sculpin-old/source/_posts/introducing-the-drupal-meetups-twitterbot.md b/astro/sculpin-old/source/_posts/introducing-the-drupal-meetups-twitterbot.md
deleted file mode 100644
index 2d1af814..00000000
--- a/astro/sculpin-old/source/_posts/introducing-the-drupal-meetups-twitterbot.md
+++ /dev/null
@@ -1,29 +0,0 @@
----
-title: Introducing the Drupal Meetups Twitterbot
-date: 2017-06-09
-excerpt: I’ve written a twitterbot for promoting Drupal meetups.
-tags:
- - twitter
- - php
----
-
-

-
-The [Drupal Meetups Twitterbot][0] is a small project that I worked on a few
-months ago, but hadn't got around to promoting yet. It’s intention is to provide
-[one Twitter account][1] where people can get the up to date news from various
-Drupal meetups.
-
-It works by having a whitelist of [Twitter accounts and hashtags][2] to search
-for, uses [Codebird][3] to query the Twitter API and retweets any matching
-tweets on a scheduled basis.
-
-If you would like your meetup group to be added to the list of searched
-accounts, please [open an issue][4] on the GitHub repo.
-
-[0]: https://github.com/opdavies/drupal-meetups-twitterbot
-[1]: https://twitter.com/drupal_meetups
-[2]:
- https://github.com/opdavies/drupal-meetups-twitterbot/blob/master/bootstrap/config.php
-[3]: https://www.jublo.net/projects/codebird/php
-[4]: https://github.com/opdavies/drupal-meetups-twitterbot/issues/new
diff --git a/astro/sculpin-old/source/_posts/leaving-nomensa-joining-precedent.md b/astro/sculpin-old/source/_posts/leaving-nomensa-joining-precedent.md
deleted file mode 100644
index 49ccb1b2..00000000
--- a/astro/sculpin-old/source/_posts/leaving-nomensa-joining-precedent.md
+++ /dev/null
@@ -1,34 +0,0 @@
----
-title: Leaving Nomensa, Joining Precedent
-date: 2013-04-20
-excerpt:
- Yesterday was my last day working at Nomensa. Next week, I'll be starting as a
- Senior Developer at Precedent.
-tags:
- - nomensa
- - precedent
- - personal
----
-
-Yesterday was my last day working at
-[Nomensa](http://www.nomensa.com 'Nomensa'). Next week, I'll be starting as a
-Senior Developer at [Precedent](http://www.precedent.co.uk 'Precedent').
-
-The last 14 months that I've been working at Nomensa have been absolutely
-fantastic, and had allowed me to work on some great projects for great clients -
-mainly [unionlearn](http://www.unionlearn.org 'unionlearn') and
-[Digital Theatre Plus](http://www.digitaltheatreplus.com 'Digital Theatre Plus').
-I've learned so much about accessibility and web standards, and have pretty much
-changed my whole approach to front-end development to accommodate best
-practices. I've also been involved with the Drupal Accessibility group since
-starting at Nomensa, and have written several accessibility-focused Drupal
-modules, including the
-[Nomensa Accessible Media Player](http://drupal.org/project/nomensa_amp 'The Nomensa Accessible Media Player Drupal module')
-module and the
-[Accessibility Checklist](http://drupal.org/project/a11y_checklist 'The accessibility checklist for Drupal').
-I'll definitely be continuing my interest in accessibility, championing best
-practices, and incorporating it into my future work wherever possible.
-
-With that all said, I'm really looking forward to starting my new role at
-Precedent, tackling some new challenges, and I'm sure that it'll be as great a
-place to work as Nomensa was.
diff --git a/astro/sculpin-old/source/_posts/live-blogging-symfonylive-london.md b/astro/sculpin-old/source/_posts/live-blogging-symfonylive-london.md
deleted file mode 100644
index e37a7d86..00000000
--- a/astro/sculpin-old/source/_posts/live-blogging-symfonylive-london.md
+++ /dev/null
@@ -1,713 +0,0 @@
----
-title: Live Blogging From SymfonyLive London 2019
-date: 2019-09-13
-tags:
- - conference
- - symfony
- - symfonylive
- - php
----
-
-Inspired by [Matt Stauffer](https://twitter.com/stauffermatt)'s
-[live blogging of the keynote](https://mattstauffer.com/blog/introducing-laravel-vapor)
-at Laracon US, I’m going to do the same for the sessions that I’m attending at
-[SymfonyLive London 2019](https://london2019.live.symfony.com)...
-
-## Keynote (Back to the basics)
-
-**Embrace the Linux philosophy**
-
-- How we grow the Symfony ecosystem. Built abstracts.
-- HttpFoundation, HttpKernel
-- Moved to infrastructure
-- A few abstractions on top of PHP. Improved versions of PHP functions (`dump`
- and `var_dump`)
-- Started a add higher level abstractions (e.g. Mailer), built on the lower
- ones.
-- Recently worked on PHPUnit assertions. Mailer in Symony 4.4. Can test if an
- email is sent or queued
-
-**Building flexible high-level abstractions on top of low-level ones**
-
-### What's next?
-
-- Mailer announced in London last year. New component.
-- System emails? e.g. new customer, new invoice.
-- Symfony Mailer = Built-in responsive, flexible, and generic system emails
- - Twig with TwigExtraBundle
- - Twig `inky-extra` package (Twig 1.12+)
- - Zurb Foundation for Emails CSS stylesheet
- - Twig `cssinliner-extra` package (Twig 1.12+)
- - Optimised Twig layouts
-- `SystemEmail` class extends templated email
-- Can set importance,
-- Customisable
-- Always trying to keep flexible, so things can be overidden and customised
-
-### Sending SMS messages
-
-- new `Texter` and `SmsMessage` class for sending SMS messages
-- Same abstraction as emails, but for SMS messages
-- Based on HttpClient + Symfony Messenger and third-party providers (Twilio and
- Nexmo) `twilio://` and `nemxo://`
-- Can set via transport `$sms->setTransport('nexmo')`
-- Extend the `SystemEmail` and do what you want
-- Failover
-
-### Sending Messages
-
-- Create `ChatMessage`
-- Telegram and Slack
-- `$message->setTransport('telegram')`, `$bus->dispatch($message)`
-- Send to Slack **and** Telegram
-- `SlackOptions` and `TelegramOptions` for adding emojis etc
-- Common transport layer `TransportInterface`, `MessageInterface`
-- Failover - e.g. if Twilio is down, send to Telegram
-
-### New component - SymfonyNotifier
-
-- Channels - email, SMS, chat
-- Transport, slack, telegram, twilio
-- Create a notification, arguments are message and transports (array)
-- Receiver
-- Customise notifications, `InvoiceNotification` extends `Notification`.
- `getChannels`
- - Override default rendering
- - `ChatNotificationInterface` - `asChatMessage()`
-- Semantic configuration
- - `composer req twilio-notifier telegram-notifier`
-- Channels
- - Mailer
- - Chatter
- - Texter
- - Browser
- - Pusher (iOS, Android, Desktop native notifications)
- - Database (web notification centre)
- - **A unified way to notify Users via a unified Transport layer**
-- Each integration is only 40 lines of code
-
-### What about a SystemNotification?
-
-- Autoconfigured channels
-- `new SystemNotification`, `Notifier::getSystemReceivers`
-- Importance, automatically configures channels
-- Different channels based on importance
-- `ExceptionNotification` - get email with stack trace attached
-
-Notifier
-
-- send messages via a unified api
-- send to one or many receivers
-- Default configu or custom one
-
-### How can we leverage this new infrastructure?
-
-- `Monolog NotifierHandler` - triggered on `Error` level logs
-- Uses notified channel configuration
-- Converts Error level logs to importance levels
-- Configurablelike other Notifications
-- 40 lines of code
-- Failed Messages Listener - 10 lines of glue code
-
-- **Experimental component in 5.0**
-- Can't in in 4.4 as it's a LTS version
-- First time an experimental component is added
-- Stable in 5.1
-
-## Queues, busses and the Messenger component (Tobias Nyholm)
-
-- Stack is top and buttom - Last-in, first-out
-- Queue is back and front - last in, first out
-
-### 2013
-
-- Using Symfony, used 40 or 50 bundles in a project - too much information!
-- Used to copy and paste, duplicate a lot of code
-- Testing your controllers - controllers as services?
-- Controllers are 'comfortable'
-- Tried adding `CurrentUserProvider` service to core, should be passed as an
- argument. Cannot test.
-- 'Having Symfony all over the place wasn't the best thing' - when to framework
- (Matthias Noback)
- - Hexagonal architecture
- - Keep your kernel away from infrastructure. Let the framework handle the
- infrastructure.
-- Controller -> Command -> Command Bus -> `CommandHandler`
-
-#### What did we win?
-
-- Can leverage Middleware with a command bus
-- Queues as a service (RabbitMQ)
-- Work queue - one producer, multiple consumers
-- Queues should be durable - messages are also stored on disk, consumers should
- acknowledge a message once a message is handled
-- Publish/subscribe
- - Producer -> Fanout/direct with routing (multiple queues) -> multiple
- consumers
-- Topics - wildcards
-
-### 2016
-
-- New intern. Understand everything, 'just PHP'. Plain PHP application, not
- 'scary Symfony'
-
-### Symfony Messenger
-
-- `composer req symfony/messager` - best MessageBus implementation
-- Message -> Message bus -> Message handler
-- Message is a plain PHP class
-- Handler is a normal PHP class which is invokable
-- `messenger:message_hander` tag in config
-- Autowire with `MessageHandlerInterface`
-- What if it takes 20 seconds to send a message? Use asynchronous.
-- Transports as middleware (needs sender, receiver, configurable with DSN,
- encode/decode). `MESSENGER_DSN` added to `.env`
-- Start consumer with `bin/console messager:consume-messages`. Time limit with
- `--time-limit 300`
-- PHP Enqueue - production ready, battle-tested messaging solution for PHP
-
-### Issues
-
-- Transformers, takes an object and transforms into an array -
- `FooTransformer implements TransformerInterface`.
-- Don't break other apps by changing the payload.
-
-#### Multiple buses
-
-- Command bus, query bus, event bus
-- Separate actions from reactions
-
-#### Envelope
-
-- Stamps for metadata - has the item been on the queue already?
-
-#### Failures
-
-- Requeue, different queue or same queue after a period of time
-- Failed queue 1 every minute, failed queue 2 every hour - temporary glitches or
- a bug?
-
-#### Creating entities
-
-- What if two users registered at the same tiem? Use uuids rather than IDs.
-- Symfony validation - can be used on messages, not just forms.
-
-- Cache everything
-
- - Option 1: HTTP request -> Thin app (gets responses from Redis) -> POST to
- queue. Every GET request would warm cache
- - Option 2: HTTP request -> Thin app -> return 200 response -> pass to workers
-
-- Tip: put Command and CommandHandlers in the same directory
-
-## HttpClient (Nicolas Grekas)
-
-- new symfony component, released in may
-- Httpclient contracts, separate package that contains interfaces
- - Symfony
- - PHP-FIG
- - Httplug
-- `HttpClient::create()`. `$client->get()`
-- JSON decoded with error handling
-- Used on symfony.com website (#1391). Replaces Guzzle `Client` for
- `HttpClientInterface`
-- Object is stateless, Guzzle is not. Doesn't handle cookies, cookies are state
-- Remove boilerplate - use `toArray()`
-- Options as third argument - array of headers, similar to Guzzle
-
-### What can we do with the Response?
-
-- `getStatusCode(): int`
-- `getHeaders(): array`
-- `getContent(): string`
-- `toArray(): array`
-- `cancel(): void`
-- `getInfo(): array` - metadata
-- Everything is lazy!
-- 80% of use-cases covered
-
-### What about PSR-18?
-
-- Decorator/adapter to change to PSR compatible
-- Same for Httplug
-
-### What about the remaining 20%?
-
-- Options are part of the abstraction, not the implementation
-
-#### Some of the options
-
-- `timeout` - control inactivity periods
-- `proxy` - get through a http proxy
-- `on_progress` - display a progress bar / build a scoped client
-- `base_url` - resolve relative URLS / build a scoped client
-- `resolve` - protect webhooks against calls to internal endpoints
-- `max_redirects` - disable or limit redirects
-
-- Robust and failsafe by default
-
-- Streamable uploads - `$mimeParts->toIterable()`.
-- donwload a file
-
- ```php
- foreach ($client->stream($response) as $chunk) {
- // ...
- }
- ```
-
-* Responses are lazy, requests are concurrent
-* Asychronus requests. Reading in network order
-
-```
-foreach ($client->stream($responses) as $response => $chunk) {
- if ($chunk->isLast()) {
- // a $response completed
- } else {
- // a $response's got network activity or timeout
- }
-}
-```
-
-- 379 request completed in 0.4s!
-- `Stream` has second argument, max number of seconds to wait before yielding a
- timeout chunk
-- `ResponseInterface::getInfo()` - get response headers, redirect count and URL,
- start time, HTTP method and code, user data and URL
- - `getInfo('debug')` - displays debug information
-
-### The components
-
-- `NativeHttpClient` and `CurlHttpClient`
- - both provide
- - 100% contracts
- - secure directs
- - extended (time) info
- - transparent HTTP compression and (de)chunking
- - automatic HTTP proxy configuration via env vars
-
-#### `NativeHttpClient`
-
-- is most portable, works for everyone
-- based on HTTP stream wrapper with fixed redirect logic
-- blocking until response headers arrive
-
-#### `CurlHttpClient`
-
-- Requires ext-curl with fixed redirection logic
-- Multiplexing response headers and bodies
-- Leverages HTTP/2 and PUSH when available
-- Keeps connections open also between synchronous requests, no DNS resolution so
- things are faster
-
-#### Decorators
-
-- ScopingHttpClient - auto-configure options based on request URL
-- MockHttpClient - for testing, doesn't make actual HTTP requests
-- CachingHttpClient - adds caching on a HTTP request
-- Psr18Client
-- HttplugClient
-- TraceableHttpClient
-
-### Combining
-
-#### FrameworkBundle/Autowiring
-
-```yml
-framework:
- http_client:
- max_host_connections: 4
- deault_options:
- # ....
- scoped_client:
- # ...
-```
-
-#### HttpBrowser
-
-- HttpClient + DomCrawler + CssSelector + HttpKernel + BrowserKit
-- RIP Goutte!
-
-### Coming in 4.4...
-
-- `max_duration`
-- `buffer` based on a callable
-- `$chunk->isInformational()`
-- `$response->toStream()`
-- Async-compatible extensibility, when decoration is not enough
-
-`composer req symfony/http-client`
-
-## Symfony Checker is coming (Valentine Boineau)
-
-- Static analysis tool for Symfony
- - Does a method exist?
- - Is it deprecated?
-- insight.symfony.com
-- @symfonyinsight
-- Released soon
-
-### Differences
-
-- Specialise in Symfony - can see more relevant things
-- Different interface to other services
-
-## Feeling unfulfilled by SPA promises? Go back to Twig (Dan Blows)
-
-A way on the front-end JS, CSS, images at the beginning of the request, sends a
-HTTP request (XHR/AJAX) to the back-end
-
-### Why SPAs?
-
-- A way on the front-end JS, CSS, images at the beginning of the request, sends
- a HTTP request (XHR/AJAX) to the back-end
-- no full page refresh
-- Supposed to be much quicker
-- 'Right tool for the job' - JS on the front-end, PHP on the back-end
-- Division of responsibility == faster development
-- Reusable API - Api -> Mobile App and SPA - easy to add another consumer
-- Easier to debug?
-
-### Why not SPAs?
-
-- Lots of HTTP requests (400 to load the initial page on one project) == slow
- front end
-- Blurred responsibilities == tightly coupled teams
-- harder to debug, bugs fall between systems and teams. Huge gap between
- front-end and back-end, passing responsibilites.
-- You can fix these problems in SPAs, but is it worth it?
- - Examples of good SPAs - Trello, Flickr
-
-### Using Twig as an alternative to an SPA?
-
-#### Faster UI - Try and figure out where the problem is.
-
-If you're trying to speed things up, find out where the problem is.
-
-- Browser tools
-- Web Debug Toolbar
-- Blackfire
-- Optimise and monitor
-
-#### Speed up Twig
-
-- Speeding up Symfony
-- ext/twig (PHP5 only, not PHP 7)
-- Store compiled templates in Opcache, make sure it's enabled
-- Render assets though the webserver (assetic not running all the time)
-
-#### Edge side includes
-
-- Component cached differently to the rest of the page
-- Varnish/Nginx
-- `render_esi`
-- News block that caches frequently, rest of the page
-
-#### HTTP/2 with Weblink
-
-- slow finding CSS files to load - 'push' over CSS files, doesn't need to wait
-- `preload()` - https://symfony.com/doc/current/web_link.html
-
-#### Live updating pages
-
-- Instantly update when sports results are updated, news articles are added
-- Mercure - https://github.com/symfony/mercure
-- LiveTwig - whole block or whole section, and live update `render_live`
-- Turbolinks - replace whole body, keeps CSS and JS in memory. Merges new stuff
- in. `helthe/turbolinks`
-- ReactPHP - shares kernel between requests
-
-### Writing better code with Twig
-
-- Keep templates simple. Avoid spaghetti code, only about UI. HTML or small
- amounts of Twig.
-- Avoid delimeter chains
- - Bad:`blog_post.authors.first.user_account.email_address`
- - Good `{{ blog_post.authors_email_address }}`
- - Less brittle, slow
-
-* Filters
- - Use filters to be precise
- - Custom filters
- - Avoid chains. Can cause odd results. Create a new filter in PHP
-* Functions
- - Write your own functions
- - Simpler templates
- - Get data, can use boolean statements
-* Components
- - Break a page into components rather than one large page
- - `include()`
- - Use `only` to only pass that data. less tightenly coupled.
- * `render` calls the whole of Symfony, boots Kernel, can be expensive and slow
- * Loosely couple templates and controllers
- - Keep responses simple
- - What makes sense
- - if you need extra data in the template, get it in the template
- * View models
- - Mixed results
- - `BlogPostViewModel`
- - Can result in boilerplate code
- - Can be useful if the view model is different to the Entity
- * DRY
- - "Don't repeat yourself"
-
-- Faster development
- - Separate UI tests from back-end tests. Different layers for different teams.
- People don't need to run everything if they are only changing certain
- things.
-
-* Help your front end
- - Webpack - Encore
- - Type hinting in functions and filters, easier to debug
- - Logging
- - Friendly exceptions - help front-end devs by returning meaningful, readbale
- errors
- - Web Debug Toolbar and Profiler, provide training for toolbar and profilers
- - Twig-friendly development environment - Twig support in IDEs and text
- editors
-
-SPAs are sometimes teh right solution. Why do they want to use it, can the same
-benefits be added with Twig?
-
-3 most important points:
-
-- Profile, identidy, optimise, monitor
-- Loosely couple templates to your app code
-- Help your front ends - put your front end developers first
-- You don't need to use a SPA for single pages, use JavaScript for that one
- page. It doesn't need to be all or nothing.
-
-## BDD Your Symfony Application (Kamil Kokot)
-
-- Applying BDD to Sylius
-- 2 years since release of Sylius (Symfony 2 alpha)
-- The business part is more important than the code part
-
-### What is BDD?
-
-- Behaviour driven development. Combines TDD and DDD, into an agile methodology
-- Encourages communication and creates shared understanding
-- Living, executable documentation that non-programmers understand. Always
- correct.
-- Feature file
- - Feature
- - Scenario - example of the behaviour for this feature. Simple, atomic. (e.g.
- I need a product in order to add it to a cart)
- - In order to...
- - Who gets the benefit?
-
-### BDD in practice
-
-- Feature: booking flight tickets
-- Scenario: booking flight ticket for one person
- - Given there are the following flights...
- - When I visit '/flight/LTN-WAW'
- - Then I should be on '/flight/LTN-WAW'
- - Add I should see "Your flight has been booked." in "#result"
-- In the BDD way - what is the business logic? What is the value for this
- scenario? What is the reason 'why', and who benefits from this?
- - We just need to know that there are 5 seats left on a flight
- - Talk and communicate about how the feature is going to work - not just
- developers
- - BDD aids communication
-- Questions we can ask
- - Can we get a different outcome when the context changes?
- - When there was only one seat available
- - When there were no available seats
- - Can we get the same outcome when the event changes? Can we change 'When' and
- 'Then stays the same'
- - When it is booked for an adult and a child
- - When it is booked for an adult
- - Does anything else happen that is not mentioned?
- - Generate an invoice if a seat is booked
- - a pilot would like to get a notification that a seat was booked.
- * Figuring out the rules
- - Adults are 15+ years old
- - Children are 2-14 years old
- - Infants and children can only travel with an adult
- - We don't allow for overbooking
- - Translating rules into examples
- - Add a new scenario for each rule - e.g. don't allow over booking
- - "And the flight should be no longer available..."
-
-### Behat
-
-- Used to automate and execute BDD tests, also SpecDDD
-- maps steps to PHP code
-- Given a context, when an event, then an outcome
-- Domain Context, API context
-- class implements `Context`, annotations for `@Given`, `@When`, `@Then`. allows
- for arguments and regular expressions
-- Suites: change what code is executed, and what scenarios are executed. context
- and tags
-- FriendsOfBehat SymfonyExtension - integrates Behat with Symfony
- - Contexts registered as Symfony services - inject dependencies, service as a
- context in Behat. Need to be 'public' for it to work
- - Reduces boilerplate code. Supports autowiring.
- - Zero configuration
-
-### Domain context
-
-- `Given` verb matches `@Given` annotation. Same for `When` and `Then`.
-- Transformers, type hint name string, return Client instance
-
-### API context
-
-- inject `FlightBookingService` and `KernelBrowser`
-- Use `$this->kernelBrowser->request()`
-- Use `assert()` function wuthin `@Then`
-
-### Back to reality - how it's done with Sylius
-
-- Business part applies to all context. Start talking about what needs to be
- done, start communicating
-- Implement contexts for UI and API
-- 12716 steps, 1175 scenarios, 8 min 8 sec, 2.4 scenarios /sec
-- 12x faster than JS (17 min 48 sec, 0.19 scenario / sec)
-- Treat test CI environment like production
-
- - Turn off debug settings, add caching
- - Enable OPcache
-
-- Write features in a natural way
-- Too many setup steps - merge steps. less visual debt. e.g. Create currency,
- zone and locale when creating a store
-- Avoid scenarios that are too detailed. You should specify only what's
- important to this scenario.
-
-## Migrating to Symfony one route at a time (Steve Winter)
-
-- New client with an old application, built in an old version of another
- framework with unusual dependency management, no tests, no version control and
- deploying via FTP. Done over a ~3 month period.
-
-- Subscription based index of suppliers
-- New requirements to implement by the client
-- Our requirements: Needed a deployment process, make it testable, fix the build
- chain
-- Solution attempt 1: Migrate to a new version of the current framework
- - Minor template and design changes were fine
- - Modifiy features, add new dependencies.
-- Solution attempt 2: Upgrade to the latest version - same outcome due to
- multiple BC breaks (no semver), lots of manual steps
-- Solution attempt 3: Symfony!
- - Semver! Backwards compatibility promise
- - Symfony app to run in parallel, Apache proxy rules and minor changes to the
- legacy app, added data transfer mechanisms
- - Anything new done in Symfony
- - Installed on the same server with it's own vhost but not publicly accessible
- - Deployed independently of legacy app
-
-### Apache proxy rules
-
-Proxy `/public` to symfony app
-
-### Legacy app
-
-- Shared cookie for single login between apps - user account details (name etc),
- session details (login time)
-
-### Added functionality
-
-- Built in Symfony
-- new proxy rules for new routes
-- Add menu links to legacy app menu
-- How do we show how many reminders are active?
- - Symfony based API called from the front-end
-
-### Migrating routes
-
-- Rebuilt or extend in Symfony app
-- Test and deploy, then update the apache config to add new proxy rules
-
-### A gotcha
-
-- Legacy app uses CSRF
-- Needed to track the token, added to shared cookie and pass through to the
- Symfony side
-
-### Storing data
-
-- Both apps using the same data with different credentials
-- Some shared tables, some tables are specific to each app
-
-### Remaining challenges
-
-- User session management, still handled by legacy app
-- Templating/CSS - two versions of everything
- - Next step: move all CSS to Symfony
-
-### Summary
-
-- Add Symfony app, Apache proxy rules for routes
-- User transfer mechanisms
-- New functionality added in Symfony
-
-### Is this right for you?
-
-It depends. Fine for a 'modest' size. Use a real proxy for larger scale apps,
-use different servers with database replication.
-
-## Closing Keynote: The fabulous World of Emojis and other Unicode symbols (Nicolas Grekas)
-
-- ASCII. Still used today. Map between the first 128 numbers to characters. OK
- for UK and US.
-- 256 numbers in Windows-1252 (character sets). Each country had their own set.
-- It's legacy. 0.2% for Windows-1252. 88.8% for UTF-8 (Feb 2017)
-- Unicode: 130k characters, 135 scripts (alphabets)
-- Validation errors using native alphabet - e.g. invalid last name when
- submitting a form
-- 17 plans, each square is 255 code points
-- Emojis are characters, not images
-- Gliph is a visual representation of a character
-- From code points to bytes
- - UTF-8: 1,2,3 or 4 bytes
- - UTF16: 2 or 4 bytes
- - UTF-32: 4 bytes
-- UTF-8 is compatible with ASCII
-- Case sensitivity - 1k characters are concerned. One uppercase letter, two
- lower case variants. Turkish exception (similar looking letters that are
- different letters with different meanings). Full case folding.
-- Collations - ordering is depends on the language. 'ch' in Spanish is a single
- character.
-- Single number in unicode to represent accents. Combining characters.
-- Composed (NFC) and decomposed (NFD) forms - normalisation for comparison
-- Grapheme clusters - multiple characters, but one letter as you write it
- (separate characters for letters and accent)
-- Emjois - combining characters. e.g. Combine face with colour. Different codes
- and character names. Also applies to ligatures. A way to combine several
- images together into one single visual representation.
-
-### unicode fundamentals
-
-- uppercase, lowercase, folding
-- compositions, ligatures
-- comparistions - normalisations and collations
-- segmentation: characters, words, sentences and hyphens
-- locales: cultural conventions, translitterations
-- identifiers & security, confusables
-- display: direction, width
-
-### unicode in practice
-
-- MySQL - `utf*_*`. `SET NAMES utf8mb4` for security and storing emojis. Cannot
- store emojis with `utf8`
-
-### in php
-
-- `mb_*()`
-- `iconv_*()`
-- `preg_*()`
-- `grapheme_*()` `normalizer_*()`
-- `symfony/polyfill-*` - pure PHP implementation
-- Made a component - **symfony/string** -
- https://github.com/symfony/symfony/pull/33553
-- Object orientated api for strings. Immutable value objects
-- `AbstractString`
- - `GraphemeString`
- - `Utf8String`
- - `BinaryString`
-
-* AbstractString - Methods to serialize, get length, to binary or grapheme or
- utf8
- - Methods for starts with, ends with, is empty, join, prepend, split, trim,
- title etc
diff --git a/astro/sculpin-old/source/_posts/looking-forward-to-drupalcamp-london.md b/astro/sculpin-old/source/_posts/looking-forward-to-drupalcamp-london.md
deleted file mode 100644
index f6d4703a..00000000
--- a/astro/sculpin-old/source/_posts/looking-forward-to-drupalcamp-london.md
+++ /dev/null
@@ -1,68 +0,0 @@
----
-title: Looking forward to DrupalCamp London
-date: 2018-02-27
-excerpt:
- This weekend is DrupalCamp London 2018. I’ll be there along with a number of
- my Microserve colleagues.
-tags:
- - drupal
- - drupalcamp
- - drupalcamp-london
- - speaking
----
-
-This weekend is [DrupalCamp London 2018][1]. I’ll be there along with a number
-of my [Microserve][2] colleagues.
-
-I look forward to DrupalCamp London every year, partly because it was the first
-DrupalCamp that I attended back in 2014. It was also the first DrupalCamp that I
-[gave a talk][3] at, when I presented a session about Git Flow having given only
-one user group talk before.
-
-I’ve presented sessions at every DrupalCamp London since (including two last
-year), and I’m lucky enough to be [speaking again this year][4] due to one of
-the originally announced speakers no longer being able to make it to the event.
-
-Here are some other sessions that I’m hoping to see (in no particular order):
-
-- Keynote by [Ryan Szrama][5] from [Commerce Guys][6]
-- [Drupal 8 Services And Dependency Injection](https://drupalcamp.london/session/drupal-8-services-and-dependency-injection)
- by Phil Norton
-- [Growing developers with Drupal](https://drupalcamp.london/session/growing-developers-drupal)
- by Fran Garcia-Linares (fjgarlin)
-- [How to make it easier for newcomers to get involved in Drupal](https://drupalcamp.london/session/how-make-it-easier-newcomers-get-involved-drupal)
- by heather
-- [Let’s take the best route - Exploring Drupal 8 Routing System](https://drupalcamp.london/session/lets-take-best-route-exploring-drupal-8-routing-system)
- by surbhi
-- [New recipe of Decoupling: Drupal 8, Symfony and Slim Framework](https://drupalcamp.london/session/new-recipe-decoupling-drupal-8-symfony-and-slim-framework)
- by Jyoti Singh
-- [Plugin API by examples](https://drupalcamp.london/session/plugin-api-examples)
- by Gabriele (gambry)
-- [Value of mentorship in the community](https://drupalcamp.london/session/value-mentorship-community)
- by Hussain Abbas (hussainweb)
-- [Warden - Helping Drupal Agencies Sleep at Night](https://drupalcamp.london/session/warden-helping-drupal-agencies-sleep-night)
- by Mike Davis
-
-Unfortunately there are some time slots where I’d like to see more than one of
-the talks (including when I’m going to be speaking). This regularly happens at
-conferences, but I’ll look forward to watching those on [YouTube][7] after the
-event.
-
-I’m also looking forward to catching up with former colleagues, spending some
-time in the "hallway track" and hopefully doing some sprinting too!
-
-## Finally
-
-For nostalgia, [here’s the blog post][0] that I wrote before I attended my first
-DrupalCamp London.
-
-See everyone this weekend!
-
-[0]: {{site.url}}/blog/2014/02/09/drupalcamp-london-2014
-[1]: https://drupalcamp.london
-[2]: {{site.companies.microserve.url}}
-[3]: {{site.url}}/talks/git-flow
-[4]: {{site.url}}/talks/deploying-drupal-fabric
-[5]: http://ryanszrama.com
-[6]: https://commerceguys.com
-[7]: https://www.youtube.com/channel/UCsaB96zszIP4Y3czs-ndiIA
diff --git a/astro/sculpin-old/source/_posts/mediacurrent-contrib-half-hour-is-back.md b/astro/sculpin-old/source/_posts/mediacurrent-contrib-half-hour-is-back.md
deleted file mode 100644
index 8851118f..00000000
--- a/astro/sculpin-old/source/_posts/mediacurrent-contrib-half-hour-is-back.md
+++ /dev/null
@@ -1,67 +0,0 @@
----
-title: Yay, the Mediacurrent Contrib Half Hour is Back!
-date: 2018-03-02
-excerpt: Mediacurrent’s "contrib half hour sessions" are back.
-tags:
- - contribution
- - drupal
- - open-source
-has_tweets: true
----
-
-Back in November, [Mediacurrent introduced][1] the contrib half hour - a weekly
-online meeting to provide guidance and assistance on contributing to Drupal and
-Drupal projects. A range of topics were covered in the first few sessions,
-including finding and testing bug fixes, Composer, Drush, and how to re-roll
-patches.
-
-From Damien's [introductory blog post][2]:
-
-> Not sure what this whole "patch" thing is? Have a core change that you can't
-> quite finish? Running into a problem with a contrib module, or a theme, or a
-> 3rd party library, and not sure how to fix it? New to maintaining a module and
-> unsure of what to do next? Wondering how to get your module through the
-> security opt-in process? Is your project's issue queue getting you down? Join
-> us every Thursday at noon EST for the Mediacurrent Contrib Half Hour where
-> we'll be available to help solve contrib challenges.
->
-> Each week we'll host a live meeting to give step-by-step guidance on some best
-> practices for contributing to Drupal, and provide Q and A assistance for our
-> favorite open source (OSS) content management system (CMS). The meetings will
-> be lead by yours truly, Damien McKenna, a prolific contributor to the Drupal
-> community, and my coworkers here at Mediacurrent.
-
-There is also an [updates blog post][3] that continues to show the latest
-information, and the video recordings are [uploaded to YouTube][0] after the
-session. Here is the first one from November:
-
-
-
-I enjoyed watching the first few videos, as I’m always interested in
-contribution to Drupal and open-source and how to encourage it, but then no new
-videos were uploaded for a while and I hoped that it hadn’t faded away.
-
-I’m glad to see today that it’s back and that all of the previous videos have
-been uploaded and added to the [YouTube playlist][0], and that [on the update
-post][3] there are scheduled topics for the rest of this month including
-documentation and automated testing.
-
-
-
-I do enjoy watching these, and I like both the presentation and Q&A format that
-they alternate between. I’ll look forward to catching up over the next few days,
-and to hopefully seeing them continue to be uploaded after future meetings.
-
-Thanks Damien and Mediacurrent!
-
-[0]: https://www.youtube.com/playlist?list=PLu-MxhbnjI9rHroPvZO5LEUhr58Yl0j_F
-[1]:
- https://www.mediacurrent.com/blog/introducing-mediacurrent-contrib-half-hour
-[2]:
- https://www.mediacurrent.com/blog/introducing-mediacurrent-contrib-half-hour
-[3]:
- https://www.mediacurrent.com/blog/updates-mediacurrent-contrib-half-hour-weekly-meeting
diff --git a/astro/sculpin-old/source/_posts/minimum-core-version.md b/astro/sculpin-old/source/_posts/minimum-core-version.md
deleted file mode 100644
index b536f022..00000000
--- a/astro/sculpin-old/source/_posts/minimum-core-version.md
+++ /dev/null
@@ -1,97 +0,0 @@
----
-title: How to Define a Minimum Drupal Core Version
-date: 2015-04-03
-excerpt: How to define a minimum Drupal core version for your module or theme.
-tags:
- - drupal
- - drupal-7
- - drupal-planet
-meta:
- og:
- title: 'How to Define a Minimum Drupal Core Version'
- excerpt:
- 'How to define a minimum Drupal core version for your module or theme.'
- type: article
----
-
-This week, my first code patch was
-[committed to Drupal core](https://www.drupal.org/node/2394517#comment-9773143).
-The patch adds the `user_has_role()` function to the user module, to simplify
-the way to check whether a user in Drupal has been assigned a specific role.
-This is something that I normally write a custom function for each project, but
-it's now available in Drupal core as of
-[7.36](https://www.drupal.org/drupal-7.36-release-notes).
-
-But what if someone is using a core version less than 7.36 and tries using the
-function? The site would return an error because that function wouldn't exist.
-
-If you're building a new Drupal site, then I'd assume that you're using a latest
-version of core, or you have the opportunity to update it when needed. But what
-if you're writing a contrib module? How can you be sure that the correct minimum
-version of core?
-
-## Setting Dependencies
-
-What I'm going to be doing for my contrib projects is defining a minimum version
-of Drupal core that the module is compatible with. If this dependency isn't met,
-the module won't be able to be enabled. This is done within your module's .info
-file.
-
-### Adding a Simple Dependency
-
-You can define a simple dependency for your module by adding a line this this to
-your project's .info file:
-
-```language-bash
-dependencies[] = views
-```
-
-This would make your module dependant on having the
-[Views](https://www.drupal.org/project/views) module present and enabled, which
-you'd need if you were including views as part of your module, for example.
-
-### Adding a Complex Dependency
-
-In the previous example, our module would enable if _any_ version of Views was
-enabled, but we need to specify a specific version. We can do this by including
-version numbers within the dependencies field in the following format:
-
-```language-bash
-dependencies[] = modulename (major.minor)
-```
-
-This can be a for a specific module release or a branch name:
-
-```language-bash
-dependencies[] = modulename (1.0)
-dependencies[] = modulename (1.x)
-```
-
-We can also use the following as part of the field for extra granularity:
-
-- = or == equals (this is the default)
-- > greater than
-- < lesser than
-- > = greater than or equal to
-- <= lesser than or equal to
-- != not equal to
-
-In the original scenario, we want to specify that the module can only be enabled
-on Drupal core 7.36 or later. To do this, we can use the "greater than or equal
-to" option.
-
-```language-ini
-dependencies[] = system (>=7.36)
-```
-
-Because we need to check for Drupal's core version, we're using the system
-module as the dependency and specifying that it needs to be either equal to or
-greater than 7.36. If this dependency is not met, e.g. Drupal 7.35 is being
-used, then the module cannot be enabled rather than showing a function not found
-error for `user_has_role()` when it is called.
-
-
-
-## External Links
-
-- [Writing module .info files (Drupal 7.x)](https://www.drupal.org/node/542202#dependencies)
diff --git a/astro/sculpin-old/source/_posts/my-first-blog-post-published-for-inviqa.md b/astro/sculpin-old/source/_posts/my-first-blog-post-published-for-inviqa.md
deleted file mode 100644
index d1f9da1e..00000000
--- a/astro/sculpin-old/source/_posts/my-first-blog-post-published-for-inviqa.md
+++ /dev/null
@@ -1,10 +0,0 @@
----
-title: My first blog post published for Inviqa
-excerpt: My first blog post has been published on the inviqa.com website.
-date: 2020-04-29
-tags: [drupal, testing]
----
-
-My first blog post was published on the Inviqa website last week. Is an introduction to automated testing in Drupal, which also includes a recap of the workshop that I recently gave at DrupalCamp London.
-
-The blog post can be found at , and there's more information about the workshop specifically at .
diff --git a/astro/sculpin-old/source/_posts/my-new-drupal-modules.md b/astro/sculpin-old/source/_posts/my-new-drupal-modules.md
deleted file mode 100644
index 27488233..00000000
--- a/astro/sculpin-old/source/_posts/my-new-drupal-modules.md
+++ /dev/null
@@ -1,24 +0,0 @@
----
-title: My new Drupal modules
-date: 2012-07-12
-excerpt: After a busy few days, I've released two new contrib Drupal modules.
-tags:
- - drupal
- - drupal-modules
- - drupal-6
- - drupal-7
- - drupal-planet
- - accessibility
----
-
-After a busy few days, I've released two new contrib Drupal modules.
-
-- [Block Aria Landmark Roles](http://drupal.org/project/block_aria_landmark_roles) -
- Inspired by [Block Class](http://drupal.org/project/block_class), this module
- adds additional elements to the block configuration forms that allow users to
- assign a ARIA landmark role to a block.
-- [Nomensa Accessible Media Player](http://drupal.org/project/nomensa_amp) -
- Provides integration with Nomensa's
- [Accessible Media Player](https://github.com/nomensa/Accessible-Media-Player).
-
-Documentation for both to follow shortly on Drupal.org.
diff --git a/astro/sculpin-old/source/_posts/my-sublime-text-2-settings.md b/astro/sculpin-old/source/_posts/my-sublime-text-2-settings.md
deleted file mode 100644
index ad9be3e9..00000000
--- a/astro/sculpin-old/source/_posts/my-sublime-text-2-settings.md
+++ /dev/null
@@ -1,111 +0,0 @@
----
-title: My Sublime Text 2 settings
-date: 2012-10-25
-excerpt:
- Sublime Text
- 2 has been my text editor of choice for the past few months, and I use it
- at home, in work, and on any virtual machines that I run. So rather than
- having to manually re-enter my settings each time, I thought that I'd document
- them here for future reference.
-tags:
- - sublime-text
----
-
-[Sublime Text 2](http://www.sublimetext.com/2) has been my text editor of choice
-for the past few months, and I use it at home, in work, and on any virtual
-machines that I run. So rather than having to manually re-enter my settings each
-time, I thought that I'd document them here for future reference.
-
-These preferences ensure that the code is compliant with
-[Drupal coding standards](http://drupal.org/coding-standards 'Drupal coding standards on Drupal.org') -
-using two spaces instead of a tab, no trailing whitespace, blank line at the end
-of a file etc.
-
-## Preferences
-
-These can be changed by going to Preferences > Settings - User.
-
-```language-json
-{
- "color_scheme": "Packages/Theme - Aqua/Color Schemes/Tomorrow Night Aqua.tmTheme",
- "default_line_ending": "unix",
- "ensure_newline_at_eof_on_save": true,
- "fallback_encoding": "UTF-8",
- "file_exclude_patterns":
- [
- "*.pyc",
- "*.pyo",
- "*.exe",
- "*.dll",
- "*.obj",
- "*.o",
- "*.a",
- "*.lib",
- "*.so",
- "*.dylib",
- "*.ncb",
- "*.sdf",
- "*.suo",
- "*.pdb",
- "*.idb",
- ".DS_Store",
- "*.class",
- "*.psd",
- "*.db",
- "*.sublime*"
- ],
- "folder_exclude_patterns":
- [
- ".svn",
- ".git",
- ".hg",
- "CVS",
- "FirePHPCore"
- ],
- "font_options":
- [
- "no_bold",
- "no_italic"
- ],
- "font_size": 16.0,
- "highlight_line": true,
- "ignored_packages":
- [
- ],
- "line_padding_bottom": 1,
- "rulers":
- [
- 80
- ],
- "save_on_focus_lost": true,
- "shift_tab_unindent": true,
- "tab_size": 2,
- "theme": "Soda Light.sublime-theme",
- "translate_tabs_to_spaces": true,
- "trim_automatic_white_space": true,
- "trim_trailing_white_space_on_save": true,
- "word_wrap": false
-}
-```
-
-## Key bindings
-
-These can be changed by going to Preferences > Key Bindings - User.
-
-```language-json
-[
- { "keys": ["alt+s"], "command": "toggle_side_bar" },
- { "keys": ["alt+r"], "command": "reindent" }
-]
-```
-
-## Packages
-
-These are the packages that I currently have installed.
-
-- [DocBlockr](https://github.com/spadgos/sublime-jsdocs 'DocBlockr on GitHub')
-- [Drupal API](https://github.com/BrianGilbert/Sublime-Text-2-Goto-Drupal-API)
-- [LESS](https://github.com/danro/LESS-sublime)
-- [Package Control](http://wbond.net/sublime_packages/package_control)
-- [Sublime CodeIntel](http://github.com/Kronuz/SublimeCodeIntel)
-- [Theme - Soda](https://github.com/buymeasoda/soda-theme)
diff --git a/astro/sculpin-old/source/_posts/nginx-redirects-with-query-string-arguments.md b/astro/sculpin-old/source/_posts/nginx-redirects-with-query-string-arguments.md
deleted file mode 100644
index 46ba0205..00000000
--- a/astro/sculpin-old/source/_posts/nginx-redirects-with-query-string-arguments.md
+++ /dev/null
@@ -1,58 +0,0 @@
----
-title: Nginx Redirects With Query String Arguments
-date: 2017-01-31
-excerpt:
- How to redirect from an old domain to a new one, and also to redirect from the
- root example.com domain to the canonical www subdomain.
-tags: [nginx]
----
-
-This is an example of how my Nginx configuration looked to redirect from an old
-domain to a new one, and also to redirect from the root `example.com` domain to
-the canonical `www` subdomain.
-
-```language-nginx
-server {
- listen 80;
-
- server_name example.com;
- server_name my-old-domain.com;
- server_name www.my-old-domain.com;
-
- return 301 https://www.example.com$uri;
-}
-```
-
-It also redirects the URI value, e.g. from `http://example.com/test` to
-`http://example.com/test`, but I noticed recently though that any the query
-string would be lost - e.g. `http://example.com/?test` would redirect to
-`http://www.example.com` and the `?test` would be dropped. The application that
-I built references images based on the query string, so I wanted these to be
-included within the redirect.
-
-This was fixed by making a small change to my `return` statement.
-
-Before:
-
-```language-nginx
-return 301 https://www.example.com$uri;
-```
-
-After:
-
-```language-nginx
-return 301 https://www.example.com$uri$is_args$args;
-```
-
-`$is_args` is an empty string if there are no arguments, or a `?` to signify the
-start of the query string. `$args` then adds the arguments (`$query_string`
-could also be used with the same result).
-
-Here is an demo of it working on this website:
-
-
-
-## Resources
-
-- [Query string](https://en.wikipedia.org/wiki/Query_string)
-- [Nginx ngx_http_core_module](http://nginx.org/en/docs/http/ngx_http_core_module.html)
diff --git a/astro/sculpin-old/source/_posts/null-users-and-system-users-in-drupal.md b/astro/sculpin-old/source/_posts/null-users-and-system-users-in-drupal.md
deleted file mode 100644
index a81e615a..00000000
--- a/astro/sculpin-old/source/_posts/null-users-and-system-users-in-drupal.md
+++ /dev/null
@@ -1,155 +0,0 @@
----
-title: Null Users and System Users in Drupal
-date: 2018-08-16
-excerpt: Announcing the Null User and System User modules.
-tags:
- - drupal
- - drupal-7
- - drupal-8
- - drupal-modules
- - drupal-planet
- - php
----
-
-Have you ever needed to have a 'special user' to perform tasks on your Drupal
-site, such as performing actions based on an API request, or for sending an
-internal site message?
-
-If you just create a new user, how do you identify that user going forward? Do
-you hard-code the 'magic' user ID in your custom code? What if the user has a
-different ID on different environments of your site? You could declare it in
-each environment’s settings file and retrieve it from there, but what then if
-you need to do the same on another site? That would mean some duplication of
-code - and something that could have been abstracted and re-used.
-
-I had to do this recently, and rather than just duplicate the code I decided to
-make it into it’s own module - which then became two modules.
-
-## System users
-
-The [System User module][1] provides a re-usable, generic way to denote users as
-'system users', which is not specific to a certain site or environment as this
-is value is stored against each individual user in the database.
-
-'System user' is a term used in Linux, which I thought also applies well to this
-scenario.
-
-From :
-
-> A system account is a user account that is created by an operating system
-> during installation and that is used for operating system defined purposes.
-> System accounts often have predefiend user ids. Examples of system accounts
-> include the root account in Linux.
-
-A system user isn’t an account that we’d expect a person to log in with and
-perform routine tasks like updating content, but rather for the system (site) to
-use to perform tasks like the earlier examples.
-
-### Declaring a user as a system user
-
-System User module adds a base field to Drupal’s User entity, which determines
-whether or not each user is a system user - i.e. if this field is `TRUE`, that
-user is a system user. This means that users can easily be queried to identify
-which are system users, without having to rely on magic, environment and site
-specific user IDs. This also means that we can have multiple system users, if
-needed.
-
-{.border
-.p-1}
-
-In the Drupal 8 version of the module, a `SystemUser` is a custom entity, that
-contains it’s own `create` method for creating new system users. This is a
-essentially a wrapper around `User::create()` that automatically sets the value
-of the system user field as part of the creation.
-
-The original intention is that system users would always be created manually in
-an custom install or update hook, however since releasing the module, I’ve also
-added an install hook to the module to automatically create a new system user
-when the module is installed, basing the username on the site name.
-
-There is also an open issue to add a Drush command to create a new system user,
-and I’d imagine I’ll also add a Drupal Console command too.
-
-### Retrieving system users
-
-Whilst you could easily write your own query that retrieves users based on the
-value of the system user field, but the module contains a `SystemUserManager`
-service that contains methods to do so. It also provides a static helper class
-that determines if a specified user is a system user by checking the value of
-the system user field.
-
-```
-// Retrieve the first system user.
-$system_user = $this->systemUserManager->getFirst();
-
-// Is the specified user a system user?
-$is_system_user = SystemUserManager::isSystemUser($user);
-```
-
-But what do we return if there are no system users? You could return `NULL` or
-`FALSE`, but I decided to take a different approach, which became the second
-module.
-
-## Null users
-
-The [Null User module][2] is an implementation of the [null object pattern][3]
-for users in Drupal 8. In this case, a [NullUser][4] is an extension of Drupal’s
-`AnonymousUserSession`, which means that it inherits sensible defaults to return
-for a non-existent User. Though, through inheritance, the `id`, `getRoles` and
-`hasPermission` methods are overridden to return relevant values.
-
-```language-php
-use Drupal\Core\Session\AnonymousUserSession;
-
-class NullUser extends AnonymousUserSession {
- ...
-}
-```
-
-Null User module is a dependency of System User in Drupal 8, so When no system
-user is found from the `getFirst()` method, a `NullUser` is returned. Whilst I
-could alternatively have returned `NULL` or `FALSE`, we then would need to check
-if the returned value was an object or not before calling methods on it.
-
-```language-php
-$system_user = $this->systemUserManager->getFirst(); // Returns NULL or FALSE.
-
-// Need to check if a user was returned or not.
-if (!$system_user) {
- return;
-}
-
-if ($system_user->isActive()) {
- ...
-}
-```
-
-Because instead we’re returning a `NullUser`, which through class inheritance
-has the same methods and properties as a regular user, there is no need to do
-the additional check as you will always receive a relevant object, and the
-expected methods will always be present.
-
-```language-php
-$system_user = $this->systemUserManager->getFirst(); // Returns a NullUser.
-
-if ($system_user->isActive()) {
- ...
-}
-```
-
-This means we have less code, which also is simpler and more readable.
-
-System User module is the only one that I’m aware of that makes use of Null
-User, but I’ve added a list to the [project page][2] so let me know if you can
-think of any others.
-
-## Resources
-
-- [Null object pattern][3]
-- [Null User module][2]
-- [System User module][1]
-
-[1]: https://www.drupal.org/project/system_user
-[2]: https://www.drupal.org/project/null_user
-[3]: https://en.wikipedia.org/wiki/Null_object_pattern
-[4]: http://cgit.drupalcode.org/null_user/tree/src/NullUser.php?h=8.x-1.x
diff --git a/astro/sculpin-old/source/_posts/open-sublime-text-2-mac-os-x-command-line.md b/astro/sculpin-old/source/_posts/open-sublime-text-2-mac-os-x-command-line.md
deleted file mode 100644
index 69c40e82..00000000
--- a/astro/sculpin-old/source/_posts/open-sublime-text-2-mac-os-x-command-line.md
+++ /dev/null
@@ -1,23 +0,0 @@
----
-title: Open Sublime Text 2 from the Mac OS X Command Line
-date: 2012-11-17
-excerpt: How to open Sublime Text from the command line.
-tags:
- - sublime-text
- - mac-os-x
- - terminal
----
-
-How to open Sublime Text from the command line.
-
-Paste the following code into the Mac OS X Terminal, assuming that you've
-installed Sublime Text 2 into the /Applications folder.
-
-```language-bash
-$ ln -s "/Applications/Sublime Text 2.app/Contents/SharedSupport/bin/subl" ~/bin/sublime
-```
-
-Now you can type `sublime ` open a file or directory in Sublime Text,
-or `sublime .` to open the current directory.
-
-You can also type `sublime --help` to see a list of the available commands.
diff --git a/astro/sculpin-old/source/_posts/pantheon-settings-files.md b/astro/sculpin-old/source/_posts/pantheon-settings-files.md
deleted file mode 100644
index 9b86c3d2..00000000
--- a/astro/sculpin-old/source/_posts/pantheon-settings-files.md
+++ /dev/null
@@ -1,100 +0,0 @@
----
-title: Include environment-specific settings files on Pantheon
-date: 2014-11-27
-excerpt: How to load a different settings file per environment on Pantheon.
-tags:
- - drupal
- - drupal-planet
- - pantheon
- - settings.php
----
-
-I was recently doing some work on a site hosted on
-[Pantheon](http://getpantheon.com) and came across an issue, for which part of
-the suggested fix was to ensure that the `$base_url` variable was explicitly
-defined within settings.php (this is also best practice on all Drupal sites).
-
-The way that was recommended was by using a `switch()` function based on
-Pantheon's environment variable. For example:
-
-```language-php
-switch ($_SERVER['PANTHEON_ENVIRONMENT']) {
- case 'dev':
- // Development environment.
- $base_url = 'dev-my-site.gotpantheon.com';
- break;
-
-
- case 'test':
- // Testing environment.
- $base_url = 'test-my-site.gotpantheon.com';
- break;
-
-
- case 'live':
- // Production environment.
- $base_url = 'live-my-site.gotpantheon.com';
- break;
-}
-```
-
-Whilst this works, it doesn't conform to the DRY (don't repeat yourself)
-principle and means that you also might get a rather long and complicated
-settings file, especially when you start using multiple switches and checking
-for the value of the environment multiple times.
-
-My alternative solution to this is to include an environment-specific settings
-file.
-
-To do this, add the following code to the bottom of settings.php:
-
-```language-php
-if (isset($_SERVER['PANTHEON_ENVIRONMENT'])) {
- if ($_SERVER['PANTHEON_ENVIRONMENT'] != 'live') {
- // You can still add things here, for example to apply to all sites apart
- // from production. Mail reroutes, caching settings etc.
- }
-
- // Include an environment-specific settings file, for example
- // settings.dev.php, if one exists.
- $environment_settings = __DIR__ . '/settings.' . $_SERVER['PANTHEON_ENVIRONMENT'] . '.php';
- if (file_exists($environment_settings)) {
- include $environment_settings;
- }
-}
-```
-
-This means that rather than having one long file, each environment has it's own
-dedicated settings file that contains it's own additional configuration. This is
-much easier to read and make changes to, and also means that less code is loaded
-and parsed by PHP. Settings that apply to all environments are still added to
-settings.php.
-
-Below this, I also include a
-[similar piece of code](/blog/include-local-drupal-settings-file-environment-configuration-and-overrides/)
-to include a settings.local.php file. The settings.php file then gets committed
-into the [Git](http://git-scm.com) repository.
-
-Within the sites/default directory, I also include an example file
-(example.settings.env.php) for reference. This is duplicated, renamed and
-populated accordingly.
-
-```language-php
- In this video, we work through how to put your PHP application in a
-> subdirectory of another site.
->
-> For example, we may have an application running at example.org but need a
-> second application running at example.org/blog.
->
-> This feels like it should be simple, but it turns out to be more complex and
-> fraught with confusing Nginx configurations! To make matter worse (or,
-> perhaps, to illustrate this point), a quick Google search reveals a TON of
-> confusing, non-working examples.
-
-
-
-[0]: https://twitter.com/fideloper
-[1]: https://serversforhackers.com
diff --git a/astro/sculpin-old/source/_posts/presenting-on-tailwind-css-and-ansible-at-cms-philly.md b/astro/sculpin-old/source/_posts/presenting-on-tailwind-css-and-ansible-at-cms-philly.md
deleted file mode 100644
index 7edf5179..00000000
--- a/astro/sculpin-old/source/_posts/presenting-on-tailwind-css-and-ansible-at-cms-philly.md
+++ /dev/null
@@ -1,16 +0,0 @@
----
-title: Presenting on Tailwind CSS and Ansible at CMS Philly
-excerpt: I'll be presenting on Tailwind CSS and deployments with Ansible at CMS Philly on May 1st.
-date: 2020-04-24
-tags: [conference, speaking, tailwind-css, ansible, ansistrano, drupal, drupal-planet]
----
-
-{.mx-auto}
-
-I'm happy to be presenting two talks remotely at this year's [CMS Philly](https://cmsphilly.org) conference (formerly [Drupaldelphia](https://www.drupaldelphia.org)).
-
-The first talk is [Deploying PHP applications with Ansible, Ansible Vault and Ansistrano](/talks/deploying-php-ansible-ansistrano) at 1pm (6pm UK time) where I'll be doing an introduction to Ansible and show how to use Ansistrano to do deploy a Drupal 8 application.
-
-The second talk is [Taking Flight with Tailwind CSS](/talks/taking-flight-with-tailwind-css) at 2pm (7pm UK time) where I'll show how to configure and use Tailwind CSS.
-
-CMS Philly is happening virtually on Friday, May 1st via GoToWebinar.
diff --git a/astro/sculpin-old/source/_posts/prevent-apache-displaying-text-files-within-web-browser.md b/astro/sculpin-old/source/_posts/prevent-apache-displaying-text-files-within-web-browser.md
deleted file mode 100644
index 7f1dc6e9..00000000
--- a/astro/sculpin-old/source/_posts/prevent-apache-displaying-text-files-within-web-browser.md
+++ /dev/null
@@ -1,30 +0,0 @@
----
-title: Prevent Apache from displaying text files within a web browser
-date: 2012-05-23
-excerpt:
- How to prevent Apache from displaying the contents of files like
- CHANGELOG.txt.
-tags:
- - apache
- - code
- - drupal
----
-
-When you download [Drupal](http://drupal.org/project/drupal), there are several
-text files that are placed in the root of your installation. You don't want or
-need these to be visible to anyone attempting to view them in a browser -
-especially CHANGELOG.txt as that includes the exact version of Drupal you are
-running and could therefore have security implications.
-
-Rather than delete these files or change the file permissions manually for each
-file, I can add the following lines into my VirtualHost configuration.
-
-```language-apacheconf
-
- Order deny,allow
- Deny from all
-
-```
-
-This prevents any files with a .txt extension from being accessed and rendered
-in a web browser.
diff --git a/astro/sculpin-old/source/_posts/proctor-stevenson.md b/astro/sculpin-old/source/_posts/proctor-stevenson.md
deleted file mode 100644
index c61f3b90..00000000
--- a/astro/sculpin-old/source/_posts/proctor-stevenson.md
+++ /dev/null
@@ -1,20 +0,0 @@
----
-title: Proctor & Stevenson
-date: 2011-03-31
-excerpt: I’m moving jobs.
-tags:
- - personal
----
-
-2 weeks ago, I handed in my notice of resignation to
-[Horse & Country TV](http://horseandcountry.tv)because I've been offered a new
-role at [Proctor & Stevenson](http://proctors.co.uk) - a Marketing Design and
-Communications agency in Bristol.
-
-Proctors have an [extensive client list](http://www.proctors.co.uk/clients) -
-including [BMW](http://www.proctors.co.uk/clients/bmw-financial-services),
-[Panasonic](http://www.proctors.co.uk/clients/panasonic), the
-[Open University](http://www.proctors.co.uk/clients/open-university) and
-[VOSA](http://www.proctors.co.uk/clients/vosa), and it's going to be a fantastic
-opportunity for me to continue expanding my skillset whilst gaining vital
-experience.
diff --git a/astro/sculpin-old/source/_posts/proctors-hosting-next-drupal-meetup.md b/astro/sculpin-old/source/_posts/proctors-hosting-next-drupal-meetup.md
deleted file mode 100644
index 2b734e9f..00000000
--- a/astro/sculpin-old/source/_posts/proctors-hosting-next-drupal-meetup.md
+++ /dev/null
@@ -1,17 +0,0 @@
----
-title: Proctors Hosting the next Drupal Meetup
-date: 2011-05-20
-excerpt:
- Proctor & Stevenson are going to be hosting the next Bristol & South West
- Drupal meetup.
-tags:
- - meetups
- - drupal-bristol
----
-
-My employer, [Proctor & Stevenson](http://www.proctors.co.uk), are going to be
-hosting the next Bristol & South West Drupal meetup on the 25th May at our
-offices.
-
-You can [view more details](http://groups.drupal.org/node/147324), or register
-[on our website](http://www.proctors.co.uk/Drupal-SWUG-Meetup).
diff --git a/astro/sculpin-old/source/_posts/psr4-autoloading-test-cases-drupal-7.md b/astro/sculpin-old/source/_posts/psr4-autoloading-test-cases-drupal-7.md
deleted file mode 100644
index 609f19d1..00000000
--- a/astro/sculpin-old/source/_posts/psr4-autoloading-test-cases-drupal-7.md
+++ /dev/null
@@ -1,137 +0,0 @@
----
-title: Using PSR-4 Autoloading for your Drupal 7 Test Cases
-excerpt:
- How to use the PSR-4 autoloading standard for Drupal 7 Simpletest test cases.
-tags: [drupal, drupal-planet, drupal-7, testing, simpletest, php, psr]
-date: 2020-02-04
----
-
-
{{ page.excerpt }}
-
-## The Traditional Way
-
-The typical way of including test cases in Drupal 7 is to add one or more
-classes within a `.test` file - e.g. `opdavies.test`. This would typically
-include all of the different test cases for that module, and would be placed in
-the root of the module’s directory alongside the `.info` and `.module` files.
-
-In order to load the files, each file would need to be declared within the
-`.info` file for the module.
-
-There is a convention that if you have multiple tests for your project, these
-can be split into different files and grouped within a `tests` directory.
-
-```ini
-; Load a test file at the root of the module
-files[] = opdavies.test
-
-; Load a test file from within a subdirectory
-files[] = tests/foo.test
-files[] = tests/bar.test
-```
-
-## Using the xautoload Module
-
-Whilst splitting tests into separate files makes things more organised, each
-file needs to be loaded separately. This can be made simpler by using the
-[Xautoload module][], which supports wildcards when declaring files.
-
-[xautoload module]: https://www.drupal.org/project/xautoload
-
-```ini
-files[] = tests/**/*.test
-```
-
-This would load all of the `.test` files within the tests directory.
-
-## Using PSR-4 Autoloading
-
-Another option is to use PSR-4 (or PSR-0) autoloading.
-
-This should be a lot more familiar to those who have worked with Drupal 8,
-Symfony etc, and means that each test case is in its own file which is cleaner,
-files have the `.php` extension which is more standard, and the name of the file
-matches the name of the test class for consistency.
-
-To do this, create a `src/Tests` (PSR-4) or `lib/Drupal/{module_name}/Tests`
-(PSR-0) directory within your module, and then add or move your test cases
-there. Add the appropriate namespace for your module, and ensure that
-`DrupalWebTestCase` or `DrupalUnitTestCase` is also namespaced.
-
-```php
-// src/Tests/Functional/OliverDaviesTest.php
-
-namespace Drupal\opdavies\Tests\Functional;
-
-class OliverDaviesTest extends \DrupalWebTestCase {
- // ...
-}
-```
-
-This also supports subdirectories, so you can group classes within `Functional`
-and `Unit` directories if you like.
-
-If you want to see an real-world example, see the Drupal 7 branch of the
-[Override Node Options module][override_node_options].
-
-[override_node_options]:
- https://git.drupalcode.org/project/override_node_options/tree/7.x-1.x
-
-### Digging into the simpletest_test_get_all function
-
-This is the code within `simpletest.module` that makes this work:
-
-```php
-// simpletest_test_get_all()
-
-// ...
-
-$module_dir = DRUPAL_ROOT . '/' . dirname($filename);
-
-// Search both the 'lib/Drupal/mymodule' directory (for PSR-0 classes)
-// and the 'src' directory (for PSR-4 classes).
-foreach (array(
- 'lib/Drupal/' . $name,
- 'src',
-) as $subdir) {
-
- // Build directory in which the test files would reside.
- $tests_dir = $module_dir . '/' . $subdir . '/Tests';
-
- // Scan it for test files if it exists.
- if (is_dir($tests_dir)) {
- $files = file_scan_directory($tests_dir, '/.*\\.php/');
- if (!empty($files)) {
- foreach ($files as $file) {
-
- // Convert the file name into the namespaced class name.
- $replacements = array(
- '/' => '\\',
- $module_dir . '/' => '',
- 'lib/' => '',
- 'src/' => 'Drupal\\' . $name . '\\',
- '.php' => '',
- );
- $classes[] = strtr($file->uri, $replacements);
- }
- }
- }
-}
-```
-
-It looks for a the tests directory (`src/Tests` or
-`lib/Drupal/{module_name}/Tests`) within the module, and then finds any `.php`
-files within it. It then converts the file name into the fully qualified
-(namespaced) class name and loads it automatically.
-
-### Running the Tests
-
-You can still run the tests from within the Simpletest UI, or from the command
-line using `run-tests.sh`.
-
-If you want to run a specific test case using the `--class` option, you will now
-need to include the fully qualified name.
-
-```
-php scripts/run-tests.sh --class Drupal\\opdavies\\Tests\\Functional\\OliverDaviesTest
-```
diff --git a/astro/sculpin-old/source/_posts/published-my-first-npm-package.md b/astro/sculpin-old/source/_posts/published-my-first-npm-package.md
deleted file mode 100644
index dfb70af7..00000000
--- a/astro/sculpin-old/source/_posts/published-my-first-npm-package.md
+++ /dev/null
@@ -1,119 +0,0 @@
----
-title: Published my first NPM package
-date: 2018-12-16
-excerpt:
- Yesterday I published my first module onto NPM, and it’s a plugin for Tailwind
- CSS to be used alongside Vue.js.
-tags:
- - npm
- - tailwind-css
- - vuejs
----
-
-Yesterday I published my first module onto NPM, and it’s a plugin for [Tailwind
-CSS][tailwind] to be used alongside [Vue.js](https://vuejs.org).
-
-The plugin adds classes for showing and hiding elements in different display
-variations in combination with Vue's
-[v-cloak directive](https://vuejs.org/v2/api/#v-cloak), which I originally saw
-in [the first 'Building Kitetail' video](https://youtu.be/XUXpcbYQ_iQ?t=2360).
-These are useful for when you want an element to be visible whilst Vue is
-compiling, and hidden afterwards.
-
-Here is the compiled CSS that is added by the plugin:
-
-```css
-[v-cloak] .v-cloak-block {
- display: block;
-}
-
-[v-cloak] .v-cloak-flex {
- display: flex;
-}
-
-[v-cloak] .v-cloak-hidden {
- display: none;
-}
-
-[v-cloak] .v-cloak-inline {
- display: inline;
-}
-
-[v-cloak] .v-cloak-inline-block {
- display: inline-block;
-}
-
-[v-cloak] .v-cloak-inline-flex {
- display: inline-flex;
-}
-
-[v-cloak] .v-cloak-invisible {
- visibility: hidden;
-}
-
-.v-cloak-block,
-.v-cloak-flex,
-.v-cloak-inline,
-.v-cloak-inline-block,
-.v-cloak-inline-flex {
- display: none;
-}
-```
-
-The `v-cloak` directive exists on an element until Vue finishes compiling, after
-which it is removed. Therefore adding a `v-cloak-block` class to an element will
-make it `display: block` whilst Vue is compiling and the element is cloaked, and
-`display: none` afterwards when the Vue markup is compiled and rendered.
-
-In my `base.html.twig` template, I’ve added `v-cloak` to the wrapper div within
-the `body`.
-
-{% verbatim %}
-
-```twig
-
-
- {# ... #}
-
-
-```
-
-
{% endverbatim %}
-
-Within my `navbar.html.twig` partial, I have a placeholder div that also
-contains the site name, which is instantly visible but has the `v-cloak-block`
-class so it’s hidden once Vue has compiled and the `Navbar` Vue component is
-visible instead.
-
-{% verbatim %}
-
-```twig
-
-
-
- {{ site.title }}
-
-
-
-
-
-```
-
-
{% endverbatim %}
-
-I was originally surprised that these classes weren’t included as part of
-Tailwind or as part of an existing plugin, but as I’ve already used these styles
-on several projects that include Vue.js with Symfony or Sculpin, it made sense
-to extract it into a plugin and make it available as a npm package which I can
-easily add to any project - as well as making it easier to maintain if I need to
-add additional variations at a later point.
-
-**You can view [the package on npmjs.com][npm], and [the code repository on
-GitHub][github].**
-
-[github]: https://github.com/opdavies/tailwindcss-vuejs
-[npm]: https://www.npmjs.com/package/tailwindcss-vuejs
-[tailwind]: https://tailwindcss.com
diff --git a/astro/sculpin-old/source/_posts/publishing-sculpin-sites-with-github-pages.md b/astro/sculpin-old/source/_posts/publishing-sculpin-sites-with-github-pages.md
deleted file mode 100644
index 00bb822e..00000000
--- a/astro/sculpin-old/source/_posts/publishing-sculpin-sites-with-github-pages.md
+++ /dev/null
@@ -1,110 +0,0 @@
----
-title: Publishing Sculpin Sites with GitHub Pages
-date: 2017-07-13
-excerpt: How I moved my website to GitHub pages.
-tags: [sculpin, php, github]
-meta:
- image:
- url: '/images/blog/jackson-octocat.png'
- type: 'image/png'
- height: 200
- width: 451
----
-
-

-
-Earlier this week I moved this site from my personal Linode server to [GitHub
-Pages][0].
-
-This made sense as I already kept the source code in [on GitHub][1], the issue
-was that GitHub Pages doesn’t know how to dynamically parse and generate a
-Sculpin site like it does with some other static site generators. It can though
-parse and serve HTML files, which is what Sculpin generates. It’s just a case of
-how those files are added to GitHub.
-
-I’ve seen different implementations of this, mostly where the Sculpin code is on
-one branch, and the generated HTML code is on a separate `gh-pages` or `master`
-branch (depending on your repository name). I’m not fond of this approach as it
-means automatically checking out and merging branches which can get messy, and
-also it’s weird to look at a repo’s branches page and see one branch maybe tens
-or hundreds of commits both ahead and behind the default branch.
-
-This has been made simpler and tidier now that we can use a `docs` directory
-within the repository to serve content.
-
-
-
-This means that I can simply re-generate the site after making changes and add
-it as an additional commit to my main branch with no need to switch branches or
-perform a merge.
-
-To simplify this, I’ve added a new [publish.sh script][3] into my repository to
-automate the sites. This is how it currently looks:
-
-```language-bash
-#!/usr/bin/env bash
-
-SITE_ENV="prod"
-
-# Remove the existing docs directory, build the site and create the new
-# docs directory.
-rm -rf ./docs
-vendor/bin/sculpin generate --no-interaction --clean --env=${SITE_ENV}
-touch output_${SITE_ENV}/.nojekyll
-mv output_${SITE_ENV} docs
-
-# Ensure the correct Git variables are used.
-git config --local user.name 'Oliver Davies'
-git config --local user.email oliver@oliverdavies.uk
-
-# Add, commit and push the changes.
-git add --all docs
-git commit -m 'Build.'
-git push origin HEAD
-```
-
-This begins by removing the deleting the existing `docs` directory and
-re-generating the site with the specified environment. Then I add a `.nojekyll`
-file and rename the output directory to replace `docs`.
-
-Now the changes can be added, committed and pushed. Once pushed, the new code is
-automatically served by GitHub Pages.
-
-## HTTPS
-
-GitHub Pages unfortunately does [not support HTTPS for custom domains][7].
-
-As the site was previously using HTTPS, I didn’t want to have to go back to
-HTTP, break any incoming links and lose any potential traffic. To continue using
-HTTPS, I decided to [use Cloudflare][6] to serve the site via their CDN which
-does allow for HTTPS traffic.
-
-## Next Steps
-
-- Enable automatically running `publish.sh` when new changes are pushed to
- GitHub rather than running it manually. I was previously [using Jenkins][4]
- and Fabric for this, though I’m also going to look into using Travis to
- accomplish this.
-- Add the pre-build steps such as running `composer install` and `yarn` to
- install dependencies, and `gulp` to create the front-end assets. This was
- previously done by Jenkins in my previous setup.
-
-## Resources
-
-- [Publishing your GitHub Pages site from a /docs folder on your master
- branch][2]
-- [Bypassing Jekyll on GitHub Pages][5]
-- [Secure and fast GitHub Pages with CloudFlare][6]
-
-[0]: https://pages.github.com
-[1]: https://github.com/opdavies/oliverdavies.uk
-[2]:
- https://help.github.com/articles/configuring-a-publishing-source-for-github-pages/#publishing-your-github-pages-site-from-a-docs-folder-on-your-master-branch
-[3]: https://github.com/opdavies/oliverdavies.uk/blob/master/publish.sh
-[4]: /articles/2015/07/21/automating-sculpin-jenkins
-[5]: https://github.com/blog/572-bypassing-jekyll-on-github-pages
-[6]: https://blog.cloudflare.com/secure-and-fast-github-pages-with-cloudflare
-[7]: https://github.com/blog/2186-https-for-github-pages
diff --git a/astro/sculpin-old/source/_posts/queuing-private-messages-in-drupal-8.md b/astro/sculpin-old/source/_posts/queuing-private-messages-in-drupal-8.md
deleted file mode 100644
index 180b79a1..00000000
--- a/astro/sculpin-old/source/_posts/queuing-private-messages-in-drupal-8.md
+++ /dev/null
@@ -1,84 +0,0 @@
----
-title: Queuing Private Messages in Drupal 8
-date: 2018-02-27
-excerpt: Introducing the Private Message Queue module for Drupal 8.
-tags:
- - drupal
- - drupal-8
- - drupal-modules
- - drupal-planet
- - open-source
----
-
-My current project at [Microserve][0] is a Drupal 8 website that uses the
-[Private Message][1] module for users to send messages to each other.
-
-In some cases though, the threads could contain hundreds of recipients so I
-decided that it would be good to queue the message requests so that they can be
-processed as part of a background process for better performance. The Private
-Message module does not include this, so I've written and released a separate
-[Private Message Queue][2] module.
-
-## Queuing a Message
-
-The module provices a `PrivateMessageQueuer` service
-(`private_message_queue.queuer`) which queues the items via the `queue()`
-method.
-
-The method accepts an array of `User` objects as the messsage recipients, the
-message body text and another user as the message owner. (I’m currently
-considering [whether to make the owner optional][4], and default to the current
-user if one is not specified)
-
-Here is an example:
-
-```php
-$recipients = $this->getRecipients(); // An array of User objects.
-$message = 'Some message text';
-$owner = \Drupal::currentUser();
-
-$queuer = \Drupal::service('private_message_queue.queuer');
-$queuer->queue($recipients, $message, $owner);
-```
-
-These three pieces of data are then saved as part of the queued item. You can
-see these by checking the "queue" table in the database or by running
-`drush queue-list`.
-
-
-
-```
-$ drush queue-list
-Queue Items Class
-private_message_queue 19 Drupal\Core\Queue\DatabaseQueue
-```
-
-## Processing the Queue
-
-The module also provides a `PrivateMessageQueue` queue worker, which processes
-the queued items. For each item, it creates a new private message setting the
-owner and the message body.
-
-It uses the `PrivateMessageThread` class from the Private Message module to find
-for an existing thread for the specified recipients, or creates a new thread if
-one isn't found. The new message is then added to the thread.
-
-The queue is processed on each cron run, so I recommend adding a module like
-[Ultimate Cron][3] so that you can process the queued items frequently (e.g.
-every 15 minutes) and run the heavier tasks like checking for updates etc less
-frequently (e.g. once a day).
-
-You can also process the queue manually with Drush using the
-`drush queue-run ` command - e.g.
-`drush queue-run private_message_queue`.
-
-```
-$ drush queue-run private_message_queue
-Processed 19 items from the private_message_queue queue in 3.34 sec.
-```
-
-[0]: {{site.companies.microserve.url}}
-[1]: https://www.drupal.org/project/private_message
-[2]: https://www.drupal.org/project/private_message_queue
-[3]: https://www.drupal.org/project/ultimate_cron
-[4]: https://www.drupal.org/project/private_message_queue/issues/2948233
diff --git a/astro/sculpin-old/source/_posts/quick-project-switching-in-phpstorm.md b/astro/sculpin-old/source/_posts/quick-project-switching-in-phpstorm.md
deleted file mode 100644
index 75e4d36f..00000000
--- a/astro/sculpin-old/source/_posts/quick-project-switching-in-phpstorm.md
+++ /dev/null
@@ -1,67 +0,0 @@
----
-title: Quick Project Switching in PhpStorm
-date: 2018-09-04
-excerpt: How to quickly switch between projects in PhpStorm.
-tags:
- - phpstorm
-has_tweets: true
----
-
-Following a recent conversation on Twitter with
-[socketwench](https://twitter.com/socketwench) about project switching in
-PhpStorm, I thought I’d document my workflow here.
-
-Here is the original tweet and my initial response. I also have a lot of
-PhpStorm projects, and as I’m always working on multiple projects I regularly
-need to switch between them.
-
-{% include 'tweet' with {
- content: '
I think you can start typing and it will filter?
— Oliver Davies (@opdavies) August 28, 2018',
-} %}
-
-On the PhpStorm welcome screen that displays when you first open it, your recent
-projects are displayed on the left-hand side of the screen, and are filterable.
-That means that I can start typing a project name, e.g. `oli`, and I will only
-see projects that start with that input.
-
-{.with-border
-.with-padding}
-
-That’s great when opening a project from scratch, but what about when we’re
-already within a project and just want to be able to switch to another?
-
-{% include 'tweet' with {
- content: '
You can also use 'Open recent' within the actions list, and then filter the list of projects. pic.twitter.com/k8G9iIQNP0
— Oliver Davies (@opdavies) August 28, 2018',
-} %}
-
-There’s also a way to access this list once PhpStorm is open, by clicking 'Open
-Recent' within the File menu. The issue here though is that this list is not
-filterable.
-
-You can also access this list using the keyboard, though the 'Search everywhere'
-or 'Find action' panes, and these are filterable.
-
-{.with-border
-.with-padding}
-
-Once the 'Open Recent' option is selected, you see the same project list as on
-the welcome screen, which is filtered in the same way by starting to type
-potential project names.
-
-{.with-border
-.with-padding}
-
-## Adding a Keyboard Shortcut
-
-We can make this easier by adding a new keyboard shortcut. Within the Keymap
-preferences, you can search for 'Open Recent' and right-click it to add a new
-keyboard shortcut and define the key combination.
-
-{.with-border
-.with-padding}
-
-{.with-border
-.with-padding}
-
-This this shortcut added, you can now use it to instantly bring up your recent
-projects list, filter it and switch project.
diff --git a/astro/sculpin-old/source/_posts/quickest-way-install-sublime-text-2-ubuntu.md b/astro/sculpin-old/source/_posts/quickest-way-install-sublime-text-2-ubuntu.md
deleted file mode 100644
index 2095a7c5..00000000
--- a/astro/sculpin-old/source/_posts/quickest-way-install-sublime-text-2-ubuntu.md
+++ /dev/null
@@ -1,27 +0,0 @@
----
-title: The Quickest way to Install Sublime Text 2 in Ubuntu
-date: 2013-03-02
-excerpt:
- After reading numerous blog posts about how to install Sublime Text 2 in
- Ubuntu, this is definitely the quickest way!
-tags:
- - linux
- - sublime-text
- - ubuntu
----
-
-After reading numerous blog posts about how to install
-[Sublime Text 2](http://www.sublimetext.com/2 'Sublime Text 2') in
-[Ubuntu](http://www.ubuntu.com/2 'Ubuntu'), this is definitely the quickest way!
-
-Just paste the following lines into your Terminal:
-
-```language-bash
-$ sudo add-apt-repository ppa:webupd8team/sublime-text-2
-$ sudo apt-get update
-$ sudo apt-get install sublime-text
-```
-
-After running this, Sublime Text 2 has been installed within the
-_/usr/lib/sublime-text-2_ directory and can be launched from the Dashboard, or
-by typing `subl`, `sublime-text` or `sublime-text-2` into a Terminal window.
diff --git a/astro/sculpin-old/source/_posts/quickly-apply-patches-using-git-and-curl-or-wget.md b/astro/sculpin-old/source/_posts/quickly-apply-patches-using-git-and-curl-or-wget.md
deleted file mode 100644
index 27bab751..00000000
--- a/astro/sculpin-old/source/_posts/quickly-apply-patches-using-git-and-curl-or-wget.md
+++ /dev/null
@@ -1,31 +0,0 @@
----
-title: Quickly Apply Patches Using Git and curl or wget
-date: 2013-12-24
-excerpt:
- How to quickly download a patch file and apply it to a Git repository in one
- line
-tags:
- - git
- - drupal-planet
----
-
-Testing a patch file is usually a two-step process. First you download the patch
-file from the source, and then you run a separate command to apply it.
-
-You can save time and typing by running the two commands on one line:
-
-```language-bash
-$ curl http://drupal.org/files/[patch-name].patch | git apply -v
-```
-
-Or, if you don't have curl installed, you can use wget:
-
-```language-bash
-$ wget -q -O - http://drupal.org/files/[patch-name].patch | git apply -v
-```
-
-These commands need to be run within the root of your Git repository (i.e. where
-the .git directory is).
-
-These snippets were taken from
-[Applying Patches with Git](https://drupal.org/node/1399218) on Drupal.org.
diff --git a/astro/sculpin-old/source/_posts/quickly-import-multiples-images-using-imagefieldimport-module.md b/astro/sculpin-old/source/_posts/quickly-import-multiples-images-using-imagefieldimport-module.md
deleted file mode 100644
index a5269667..00000000
--- a/astro/sculpin-old/source/_posts/quickly-import-multiples-images-using-imagefieldimport-module.md
+++ /dev/null
@@ -1,44 +0,0 @@
----
-title: Quickly Import Multiples Images Using the Imagefield_Import Module
-date: 2010-05-29
-excerpt: How to use the Imagefield Import module.
-tags:
- - drupal-planet
- - imagefield-import
- - drupal
- - drupal-6
- - photo-gallery
- - cck
- - imagefield
----
-
-**Thanks to Bob at [Mustardseed Media](http://mustardseedmedia.com) for
-[tweeting](http://twitter.com/mustardseedinc/status/14713096905) about this
-module. It's undoubtedly saved me hours of work today alone!**
-
-I've recently started a personal project converting a website to Drupal. It's
-currently a static HTML/CSS site which also uses the
-[Coppermine Photo Gallery](http://coppermine-gallery.net). As part of building
-the new website, I wanted to move all the photos from the existing site onto the
-new one. However, with 1260 photos in 17 albums, this could have been a lengthy
-process!
-
-I created a new Drupal-powered Gallery as described in
-[this screencast](http://lullabot.com/articles/photo-galleries-views-attach) by
-[Jeff Eaton](http://twitter.com/eaton) - using the CCK and Imagefield modules,
-and re-created each of my existing Gallery nodes. Using the
-[Imagefield_Import](http://drupal.org/project/imagefield_import) module, I was
-then able to quickly import the photos into the new Galleries.
-
-I downloaded all the photos from the previous Gallery via FTP, and installed and
-configured the Imagefield_Import module.
-
-I created an 'Import' folder, selected the target field and mode. In this case,
-I want each image to be imported into its own Photo node. I moved the photos for
-the first album into the Import folder, and loaded the 'Import Images' screen
-(admin/content/imagefield_import).
-
-After clicking 'Import', a node is created for each photo, the image is
-uploaded, and added to the selected Gallery.
-
-Just another 1248 photos to go...
diff --git a/astro/sculpin-old/source/_posts/rebuilding-acquia-dashboard-with-vuejs-tailwind-css.md b/astro/sculpin-old/source/_posts/rebuilding-acquia-dashboard-with-vuejs-tailwind-css.md
deleted file mode 100644
index 376c2dd3..00000000
--- a/astro/sculpin-old/source/_posts/rebuilding-acquia-dashboard-with-vuejs-tailwind-css.md
+++ /dev/null
@@ -1,162 +0,0 @@
----
-title: Rebuilding Acquia’s Dashboard with Vue.js and Tailwind CSS
-excerpt: How I rebuilt Acquia’s dashboard using Vue.js and Tailwind CSS.
-tags:
- - drupal
- - tailwind-css
- - tweet
- - vuejs
-draft: true
-promoted: true
----
-
-After
-[rebuilding Drupal’s Bartik theme](/blog/rebuilding-bartik-with-vuejs-tailwind-css),
-I’ve now used [Vue.js][vue] and [Tailwind CSS][tailwind] to rebuild another
-Drupal related UI - this time it’s [Acquia’s](https://www.acquia.com) web
-hosting dashboard. Again, you can [view the site on Netlify][netlify] and [the
-code on GitHub][github].
-
-## Why?
-
-The same as the Bartik rebuild, this was a good opportunity for me to gain more
-experience with new technologies - Vue in particular - and to provide another
-demonstration of how Tailwind CSS can be used.
-
-Like the Bartik clone, this was originally going to be another single page
-rebuild, however after completing the first page I decided to expand it to
-include three pages which also gave me the opportunity to use
-[Vue Router](https://router.vuejs.org) - something that I had not used
-previously - and to organise a multi-page Vue application.
-
-## Configuring Vue Router
-
-`src/router/index.js`:
-
-```js
-import Vue from 'vue';
-import Router from 'vue-router';
-import Applications from '@/views/Applications';
-import Environment from '@/views/Environment';
-import Environments from '@/views/Environments';
-
-Vue.use(Router);
-
-export default new Router({
- routes: [
- {
- path: '/',
- name: 'applications',
- component: Applications,
- },
- {
- path: '/:id/environments',
- name: 'environments',
- component: Environments,
- props: true,
- },
- {
- path: '/:id/environments/:environmentName',
- name: 'environment',
- component: Environment,
- props: true,
- },
- ],
-});
-```
-
-## Passing in data
-
-`src/data.json`
-
-```json
-{
- "applications": {
- "1": {
- "id": 1,
- "name": "Rebuilding Acquia",
- "machineName": "rebuildingacquia",
- "type": "Drupal",
- "level": "Enterprise",
- "environments": {
- "dev": {
- "name": "Dev",
- "url": "dev.rebuilding-acquia.com",
- "label": "develop"
- },
- "stage": {
- "name": "Stage",
- "url": "stg.rebuilding-acquia.com",
- "label": "master"
- },
- "prod": {
- "name": "Prod",
- "url": "rebuilding-acquia.com",
- "label": "tags/2018-12-21"
- }
- },
- "tasks": [
- {
- "text": "Commit: fdac923 Merge branch 'update-password-policy' refs/heads/master",
- "user": "system",
- "times": {
- "display": "Dec 19, 2018 3:48:29 PM UTC +0000",
- "started": "Dec 19, 2018 3:48:29 PM UTC +0000",
- "completed": "Dec 19, 2018 3:48:29 PM UTC +0000"
- },
- "loading": false,
- "success": true
- }
- ]
- }
- }
-}
-```
-
-## The Environments page
-
-This was the first page that I rebuilt - the Environments page for an
-application that shows the information of the different configured environments.
-
-Vue Router is configured to show the
-
-{% include 'figure' with {
- image: {
- src: '/images/blog/rebuilding-acquia-vue-tailwind/3-environments.png',
- alt: 'A screenshot of the rebuilt Environments page.',
- },
- caption: 'The rebuilt Environments page for an application.',
-} %}
-
-## The applications page
-
-{% include 'figure' with {
- image: {
- src: '/images/blog/rebuilding-acquia-vue-tailwind/1-applications-grid.png',
- alt: 'The rebuild Applications page, with applications displayed in a grid.',
- },
- caption: 'The rebuilt Applications page - grid view',
-} %}
-
-{% include 'figure' with {
- image: {
- src: '/images/blog/rebuilding-acquia-vue-tailwind/2-applications-list.png',
- alt: 'The rebuild Applications page, with applications displayed as a list.',
- },
- caption: 'The rebuilt Applications page - list view',
-} %}
-
-## An environment page
-
-{% include 'figure' with {
- image: {
- src: '/images/blog/rebuilding-acquia-vue-tailwind/4-environment.png',
- alt: 'A screenshot of the rebuilt Environment page.',
- },
- caption: 'The rebuilt page for an environment within an application.',
-} %}
-
-[github]: https://github.com/opdavies/rebuilding-acquia
-[netlify]: https://rebuilding-acquia.oliverdavies.uk
-[tailwind]: https://tailwindcss.com
-[vue]: https://vuejs.org
diff --git a/astro/sculpin-old/source/_posts/rebuilding-bartik-with-vuejs-tailwind-css-part-2.md b/astro/sculpin-old/source/_posts/rebuilding-bartik-with-vuejs-tailwind-css-part-2.md
deleted file mode 100644
index 7ec5c37a..00000000
--- a/astro/sculpin-old/source/_posts/rebuilding-bartik-with-vuejs-tailwind-css-part-2.md
+++ /dev/null
@@ -1,316 +0,0 @@
----
-title:
- Rebuilding Bartik (Drupal’s Default Theme) with Vue.js and Tailwind CSS - part
- 2
-date: 2018-12-27
-excerpt:
- A follow-up to my original post on rebuilding Bartik with Tailwind and Vue.js.
-tags:
- - drupal
- - tailwind-css
- - tweet
- - vuejs
-has_tweets: true
----
-
-In [the original post](/blog/rebuilding-bartik-with-vuejs-tailwind-css) I
-detailed how I built [a clone of Drupal’s Bartik theme][netlify] with
-[Vue.js][vuejs] and [Tailwind CSS][tailwind]. This follow-up post details some
-updates that I’ve made to it since then.
-
-## Customising Tailwind’s colours
-
-During the first version of the page, my thoughts were to not edit the Tailwind
-configuration, however I changed my mind on this whilst working on the
-subsequent updates and did make some changes and customisations to the
-`tailwind.js` file.
-
-By default, Tailwind includes a full colour palette including colours such as
-yellows, oranges, reds that weren’t being used in this page so they were
-removed. This makes the file more readable as well as reduces the number of
-classes that Tailwind generates.
-
-Whist I was changing the colours, I also took the opportunity to tweak the
-values of the remaining colours to more closely match Bartik’s original colours.
-
-I also added a `black-60` class which uses
-[RGBA](https://css-tricks.com/the-power-of-rgba) to provide a semi-transparent
-background. I used this when adding the
-[skip to main content link](#adding-the-skip-to-main-content-link).
-
-```js
-let colors = {
- transparent: 'transparent',
-
- black: '#22292f',
- 'grey-darkest': '#3d4852',
- 'grey-dark': '#8795a1',
- grey: '#b8c2cc',
- 'grey-light': '#dae1e7',
- 'grey-lighter': '#f0f0f0',
- 'grey-lightest': '#F6F6F2',
- white: '#ffffff',
-
- 'black-60': 'rgba(0, 0, 0, .6)',
-
- 'blue-dark': '#2779bd',
- blue: '#3490dc',
- 'blue-light': '#bcdefa',
-
- 'green-dark': '#325E1C',
- green: '#77B159',
- 'green-light': '#CDE2C2',
- 'green-lighter': '#F3FAEE',
-};
-```
-
-## Adding default styling for links
-
-In the first version, every link was individually styled which resulted in a lot
-of duplicate classes and a potential maintenance issue.
-
-I added a `style` section within `Welcome.vue`, and added some default styling
-for links based on their location on the page -
-[extracting some Tailwind components](https://tailwindcss.com/docs/extracting-components).
-
-
{% verbatim %}
-```vuejs
-
- ...
-
-
-
-```
-
-Within the `style` section, I’m able to use Tailwind’s custom `@apply` directive
-to inject it’s rules into more traditional CSS, rather than needing to add them
-onto every link.
-
-```vuejs
-
-```
-
-{% endverbatim %}
-
-## Extracting a Vue component for Drupal blocks
-
-As well as being able to extract re-usable components within Tailwind, the same
-can be done within Vue. As the page could potentially have multiple sidebar
-blocks, I extracted a `SidebarBlock` component which would act as a wrapper
-around the block’s contents.
-
-```vuejs
-// src/components/Sidebar.vue
-
-
-
-
-
-
-```
-
-The component provides the wrapping div and the appropriate classes in a single
-easy-to-maintain location, and
-[uses a slot](https://vuejs.org/v2/guide/components-slots.html) as a placeholder
-for the main content.
-
-That means that within `Welcome.vue`, the markup within the `sidebar-block` tags
-will be used as the block contents.
-
-```html
-
-
My block contents.
-
-```
-
-## Adding the Skip to Main Content Link
-
-One thing
-[that was missing](https://github.com/opdavies/rebuilding-bartik/issues/1) was
-the 'Skip to main content link'. This an accessibility feature that allows for
-users who are navigating the page using only a keyboard to bypass the navigation
-links and skip straight to the main content if they wish by clicking a link that
-is hidden and only visible whilst it’s focussed on.
-
-Here is the markup that I used, which is placed directly after the opening
-`` tag.
-
-```html
-
- Skip to main content
-
-```
-
-I initially tried to implement the same feature on this website using
-[Tailwind’s visually hidden plugin](https://www.npmjs.com/package/tailwindcss-visuallyhidden)
-which also contains a `focussable` class, though I wasn’t able to style it the
-way that I needed. I created my own
-[Tailwind skip link plugin](https://www.npmjs.com/package/tailwindcss-skip-link)
-and moved the re-usable styling there.
-
-To enable the plugin, I needed to add it within the `plugins` section of my
-`tailwind.js` file:
-
-```js
-plugins: [
- require('tailwindcss/plugins/container')(),
- require('tailwindcss-skip-link')(),
-],
-```
-
-I added only the page-specific styling classes to the link (as well as the
-`skip-link` class that the plugin requires) as well as my own focus state to the
-skip link that I did within the `style` section of `App.vue`.
-
-```vuejs
-
-```
-
-{.border}
-
-## Adding the DrupalMessage component
-
-I also added a version of Drupal’s status message as another Vue component. This
-also uses a slot to include the message contents and accepts a
-[prop](https://vuejs.org/v2/guide/components-props.html) for the message type.
-
-```html
-
-
-
-
-
-
-
-
-```
-
-The value of the `type` prop is then used within some computed properties to
-determine the type specific classes to add (e.g. green for success, and red for
-warning), as well as whether or not to include the checkmark SVG image.
-
-```js
-
-```
-
-I did need to make one change to the `tailwind.js` file in order to change the
-border on links when they are hovered over - within `modules` I needed to enable
-the `borderStyle` module for hover and focus states in order for Tailwind to
-generate the additional classes.
-
-```js
-modules: {
- // ...
- borderStyle: ['responsive', 'hover', 'focus'],
- // ...
-}
-```
-
-The message is included within the Welcome component by including the
-`` element, though rather than importing it there, it’s
-registed as a global component so it would be available to any other components
-that could be added in the future.
-
-This is done within `main.js`:
-
-```js
-// ...
-
-Vue.component('drupal-message', require('@/components/DrupalMessage').default);
-
-new Vue({
- render: h => h(App),
-}).$mount('#app');
-```
-
-{.border}
-
-**The updated version is [live on Netlify][netlify], and the [latest source code
-is available on GitHub][github].**
-
-[github]: https://github.com/opdavies/rebuilding-bartik
-[netlify]: https://rebuilding-bartik.oliverdavies.uk
-[tailwind]: https://tailwindcss.com
-[vuejs]: https://vuejs.org
diff --git a/astro/sculpin-old/source/_posts/rebuilding-bartik-with-vuejs-tailwind-css.md b/astro/sculpin-old/source/_posts/rebuilding-bartik-with-vuejs-tailwind-css.md
deleted file mode 100644
index abd229bb..00000000
--- a/astro/sculpin-old/source/_posts/rebuilding-bartik-with-vuejs-tailwind-css.md
+++ /dev/null
@@ -1,345 +0,0 @@
----
-title: Rebuilding Bartik (Drupal’s Default Theme) with Vue.js and Tailwind CSS
-date: 2018-11-20
-excerpt: How I rebuilt Drupal’s Bartik theme using Vue.js and Tailwind CSS.
-tags:
- - drupal
- - tailwind-css
- - tweet
- - vuejs
-has_tweets: true
----
-
-Earlier this week, I built a clone of [Drupal][0]’s default theme, Bartik, with
-[Vue.js][1] and [Tailwind CSS][2]. You can [view the code on GitHub][3] and the
-[site itself on Netlify][4].
-
-{% include 'tweet' with {
- content: '
— Oliver Davies (@opdavies) November 20, 2018',
- data_cards: true,
-} %}
-
-## Why build a Bartik clone?
-
-I’m a big fan of utility based styling and Tailwind CSS in particular, I was and
-originally thinking of a way to more easily integrate Tailwind within Drupal -
-something like I’ve since done with the [Tailwind CSS starter kit theme][5].
-Whilst thinking about that, I wondered about doing the opposite - rebuilding
-Drupal (or Bartik) with Tailwind.
-
-Others including [Adam Wathan](https://adamwathan.me) (one of the creators of
-Tailwind CSS) have rebuilt existing UIs like Netlify, YouTube, Twitter, Coinbase
-and Transistor.fm with Tailwind as an opportunity for learning and also to
-demonstrate using Tailwind - this was my opportunity to do the same.
-
-Whilst
-[Drupal itself has adoped React](https://dri.es/drupal-looking-to-adopt-react),
-I’ve personally been looking into Vue.js and have used it for some small
-personal projects, including some elements of the site. So I decided to use Vue
-for the interactive parts of my Bartik clone to create a fully functional clone
-rather than focussing only on the CSS.
-
-## Building a static template with Tailwind
-
-The first stage was to build the desktop version, which was done as a simple
-HTML file with Tailwind CSS pulled in from it’s CDN. This stage took just over
-an hour to complete.
-
-As Tailwind was added via a CDN, there was no opportunity to customise it’s
-configuration, so I needed to use to Tailwind’s default configuration for
-colours, padding, spacing, fonts, breakpoints etc. The page is built entirely
-with classes provided by Tailwind and uses no custom CSS, except for one inline
-style that is used to add the background colour for the Search block, as there
-wasn’t a suitable Tailwind option.
-
-When I decided that I was going to later add some interactivity onto the mobile
-navigation menu, the existing code was ported into a new Vue.js application
-generated by the Vue CLI, with the majority of the markup within a `Welcome`
-component. This meant that Tailwind was also added as a dependency with it’s own
-configuration file, though although I had the opportunity to customise it I
-decided not to and made no changes to it and continued with the default values.
-
-`src/App.vue`:
-
-```
-
-
-
-
-
-
-````
-{% endverbatim %}
-
-## Making it responsive
-
-The second stage began with making the existing desktop version responsive - particularly making the navigation menu behave and appear differently on mobile and tablet screens, and stacking the main content area and the sidebar on mobile screens. This was all achieved using Tailwind’s responsive variants.
-
-```html
-
- ...
-
-````
-
-In this example, the `pb-4` class adds 1rem of bottom padding to the element by
-default, then increases it to 3rem at large screen sizes due to the `lg:pb-12`
-class.
-
-## Adding interactivity
-
-This is how the main navigation menu works on mobile:
-
-
-
-The show and hide text appears next to a hamburger menu, and clicking it toggles
-the visiblity of the menu links which are stacked below, as well as the wording
-of the text itself.
-
-The code for this was moved into a separate `MainMenu` component, which means
-that it was easier to have dedicated data properties for whether the menu was
-open or not, as well as computed properties for building the show/hide text. The
-`open` value can then be used to apply the appropriate classes to the main menu
-to toggle it.
-
-I also moved the links into `data` too - each link is it’s own object with it's
-`title` and `href` values. This means that I can use a `v-for` directive to loop
-over the data items and inject dynamic values, removing the duplication of
-markup which makes the component easier to read and maintain.
-
-`src/components/MainMenu.vue`:
-
-{% verbatim %}
-
-```vuejs
-
-
-
-
-
-
-
-
-
-
-
-
-
-```
-
-
{% endverbatim %}
-
-## The result
-
-The whole task only took around two hours to complete, and although some of the
-colours and spacings are slightly different due to the decision to stick with
-the default Tailwind configuration values, I’m happy with the result.
-
-### The original version
-
-
-
-### The Vue.js and Tailwind CSS version
-
-
-
-
-I’ve also made some additional changes since this version, which are described in [this follow-up post](/blog/rebuilding-bartik-with-vuejs-tailwind-css-part-2).
-
-
-[0]: https://www.drupal.org
-[1]: https://vuejs.org
-[2]: https://tailwindcss.com
-[3]: https://github.com/opdavies/rebuilding-bartik
-[4]: https://rebuilding-bartik.oliverdavies.uk
-[5]: https://www.drupal.org/project/tailwindcss
diff --git a/astro/sculpin-old/source/_posts/reflections-speaking-unifieddiff.md b/astro/sculpin-old/source/_posts/reflections-speaking-unifieddiff.md
deleted file mode 100644
index aef82a21..00000000
--- a/astro/sculpin-old/source/_posts/reflections-speaking-unifieddiff.md
+++ /dev/null
@@ -1,41 +0,0 @@
----
-title: Reflections on speaking at UnifiedDiff
-date: 2012-09-06
-excerpt:
- Yesterday evening I went along and spoke at the UnifiedDiff meetup in Cardiff.
-tags:
- - talks
----
-
-Yesterday evening I went along and spoke at the
-[UnifiedDiff meetup](http://www.unifieddiff.co.uk) in Cardiff, having offered
-previously to do a presentation providing an introduction to Drupal.
-
-I'm an experienced Drupal Developer, but not an experienced public speaker
-(although I have done several user training sessions and Drupal demonstrations
-for clients previously), and I think that some of the nerves that I had
-beforehand were apparent during the presentation, and being the first speaker
-for the evening probably didn't help, although I did get a
-[nice tweet](https://twitter.com/craigmarvelley/status/243418608720543745)
-mid-way through.
-
-Initially, after aiming for a 20-minute presentation plus Q&A, I think I wrapped
-up the presentation in around 14 minutes, although I did about 6 minutes of
-answering questions afterwards including the apparently mandatory "Why use
-Drupal compared to WordPress or Joomla?" question, some Drupal 8 and Symfony
-questions, as well as an interesting question about the White House development
-project after I'd listed it within a list of example sites. Next time, I think
-that some more detailed presenter notes are needed. Typically, as soon as it sat
-back in my seat, the majority of things that I'd managed to remember beforehand
-all came flooding back to me and I thought "I should have said that whilst I was
-up speaking".
-
-Overall, considering my inexperience at speaking to this type of audience, I was
-fairly happy with my presentation, although I'm sure that I'll change my mind
-once I've watched the video of it on the UnifiedDiff website. Regardless, I
-think that it was a great experience and I enjoyed doing it, and I'd like to
-thank the organisers of UnifiedDiff for having me speak at their meetup. It was
-great to have a more relaxed conversation with some people after the other
-speakers had been up, and having introduced Drupal I would be more than happy to
-come back and do a more in-depth presentation if there is an interest for me to
-do so.
diff --git a/astro/sculpin-old/source/_posts/restructuring-my-tailwindjs-config-files.md b/astro/sculpin-old/source/_posts/restructuring-my-tailwindjs-config-files.md
deleted file mode 100644
index 3be4af80..00000000
--- a/astro/sculpin-old/source/_posts/restructuring-my-tailwindjs-config-files.md
+++ /dev/null
@@ -1,238 +0,0 @@
----
-title: Restructuring my tailwind.js configuration files
-date: 2019-03-08
-excerpt:
- How I’ve started structuring my tailwind.js configuration files in preparation
- for Tailwind 1.0.
-tags:
- - laravel-mix
- - tailwind-css
----
-
-After watching Adam Wathan’s recent
-["Working on Tailwind 1.0" YouTube video](https://www.youtube.com/watch?v=SkTKN38wSEM)
-and seeing some of the proposed changes to the `tailwind.js` configuration file,
-I’ve started to structure my current config files a little differently in
-preparation for 1.0.
-
-## The current tailwind.js file format
-
-Currently when you run `tailwind init` to create a new config file, it includes
-all of Tailwind’s default values, and then you can add, edit and remove values
-as needed.
-
-Some values like colours, font families, plugins and modules you are likely to
-change for each project, whilst others like shadows, leading, z-index and
-opacity, you’re less likely to need to change.
-
-It’s 952 lines including comments, which is quite long and could potentially be
-daunting for new Tailwind users.
-
-The contents of the full file can be found in the
-[Tailwind CSS documentation](https://tailwindcss.com/docs/configuration#default-configuration),
-or it can be found in
-[various GitHub repositories](https://github.com/tailwindcss/plugin-examples/blob/master/tailwind.js).
-
-## A preview of the new tailwind.js file format
-
-In Adam’s [Laracon Online](https://laracon.net) talk, Tailwind CSS by Example,
-he showed the new configuration file format. Here is a snippet:
-
-```js
-module.exports {
- theme: {
- extend: {
- spacing: {
- 7: '1.75rem',
- },
- },
- colors: {
- white: {
- default: '#fff',
- 20: 'rgba(255,255,255,.2)',
- 40: 'rgba(255,255,255,.4)',
- 60: 'rgba(255,255,255,.6)',
- 80: 'rgba(255,255,255,.8)',
- },
- ...
- }
- ...
- }
-}
-```
-
-You’ll notice that the structure of the file is quite different, and that all of
-the default values have been removed and are now maintained by Tailwind itself.
-
-This means that the configuration file contains only your custom changes, where
-you've either overridden a default value (e.g. colours) or added your own using
-`extend` (e.g. adding another spacing value, as in this example).
-
-I think that's a great improvement and makes the file so much cleaner, and
-easier to read and understand.
-
-## An interim approach
-
-If you don’t want to wait until 1.0, or potentially 0.8, you can get some of
-this functionality now by restructuring your Tailwind configuration file.
-
-Here is the complete `tailwind.js` file for the
-[DrupalCamp Bristol 2019 static landing page](https://dcb-2019-static.netlify.com),
-which uses Tailwind in addition to the existing traditional CSS:
-
-```js
-let defaultConfig = require('tailwindcss/defaultConfig')();
-
-var colors = {
- ...defaultConfig.colors,
- black: '#000',
-};
-
-module.exports = {
- ...defaultConfig,
- colors: colors,
- textColors: colors,
- backgroundColors: colors,
- borderColors: Object.assign({ default: colors['grey-light'] }, colors),
- plugins: [
- require('tailwindcss-interaction-variants')(),
- require('tailwindcss-spaced-items'),
- ],
- modules: {
- ...defaultConfig.modules,
- textStyle: [...defaultConfig.modules.textStyle, 'hocus'],
- },
- options: {
- ...defaultConfig.options,
- prefix: 'tw-',
- important: true,
- },
-};
-```
-
-Here are the steps that I took to create this file:
-
-
-
-
**Get the default configuration**. This is done using `require('tailwindcss/defaultConfig')()`. Essentially this has the same contents as the current `tailwind.js` file, though now it’s owned and maintained within Tailwind itself, and not by the user.
-
Also any new or updated values within the default configuration will be automatically available.
-
This line is present but commented out in the current generated `tailwind.js` file.
-
-
-
-
**Create the colors object.** This will by default override Tailwind’s default colours, however you can add `...defaultConfig.colors` to include them and then add or edit values as needed.
-
In this example, I’m overridding the value used for the `black` colour classes to match the existing colour in the other CSS.
-
-
-
-
**Return the main configuration object.** For sites with no overrides, this could just be `module.exports = defaultConfig` for a minimal configuration.
-
To extend the defaults, add `...defaultConfig` at the beginning.
-
-
-
-
**Assign our colours.** Use them for `colors`, `textColors`, `backgroundColors` and `borderColours`.
-
-
-
-
**Add any plugins**. I use plugins on most projects, in this case I’m using [tailwindcss-interaction-variants](https://www.npmjs.com/package/tailwindcss-interaction-variants) and [tailwindcss-spaced-items](https://www.npmjs.com/package/tailwindcss-spaced-items). Usually the default `container` plugin would be here too.
-
-
-
-
**Add or override modules.** Here I’m adding the `hocus` (hover and focus) variant provided by the interaction variants plugin to the text style classes.
-
-
-
-
**Add or override options.** As this markup was originally from a Drupal website, I needed to override some of the options values. I’ve added the `tw-` prefix to avoid Tailwind classes from clashing with Drupal’s default markup, and set all Tailwind classes to use `!important` so that they override any existing styles.
-
-
-
-This file is only 27 lines long, so considerably shorter than the default file,
-and I think that it’s much easier to see what your additional and overridden
-values are, as well able to quickly recognise whether a class is generated from
-a custom value or from a Tailwind default value.
-
-To move this file to the new format I think would be much easier as there’s no
-default configuration to filter out, and you can move across only what is
-needed.
-
-## Other changes
-
-### Consistent spacing for padding and margin
-
-Similar to defining colours, you could also set some standard spacing values,
-and using those for padding, margin and negative margin to ensure that they are
-all consistent.
-
-In this case, we can use `defaultConfig.margin` to get the default, add or
-override any values, and then assign it to the relevant sections of the main
-object.
-
-```js
-const spacing = {
- ...defaultConfig.margin,
- '2px': '2px',
-};
-
-module.exports = {
- ...defaultConfig,
- // ...
- padding: spacing,
- margin: spacing,
- negativeMargin: spacing,
- // ...
-};
-```
-
-### Picking values with lodash
-
-In the opposite to extending, if we wanted to limit the number of values within
-a part of the configuration, we can do that too. I’d suggest using the
-[pick method](https://lodash.com/docs/4.17.11#pick) provided by
-[Lodash](https://lodash.com).
-
-From the documentation:
-
-> Creates an object composed of the picked object properties.
-
-For example, if we only wanted normal, medium and bold font weights:
-
-```js
-module.exports = {
- ...defaultConfig,
- // ...
- fontWeights: _.pick(defaultConfig.fontWeights, ['normal', 'medium', 'bold']),
- // ...
-};
-```
-
-### Renaming the file
-
-Also in Tailwind 1.0, it seems that the configuration file name is changing from
-`tailwind.js` to `tailwind.config.js`.
-
-If you use [Laravel Mix](https://laravel-mix.com) and the
-[Laravel Mix Tailwind plugin](https://github.com/JeffreyWay/laravel-mix-tailwind)
-like I do on this site (even though it’s a Sculpin site), it will look for a
-`tailwind.js` file by default or you can specify whatever filename you need.
-
-Here is an excerpt of the Tailwind configuration file for this site, using
-`tailwind.config.js`:
-
-```js
-mix
- .postCss('assets/css/app.css', 'source/dist/css')
- .tailwind('tailwind.config.js');
-```
-
-## Looking foward to Tailwind CSS 1.0!
-
-Adam has said that Tailwind 1.0 should be released within a few weeks of the
-time of writing this, I assume once
-[the 1.0 To-Do list](https://github.com/tailwindcss/tailwindcss/issues/692) is
-completed.
-
-I really like some of the improvements that are coming in 1.0, including the new
-configuration file format and the ability to easily add and extend values, as
-well as the file itself now being completely optional.
-
-I can’t wait for it to land!
diff --git a/astro/sculpin-old/source/_posts/review-adminhover-module.md b/astro/sculpin-old/source/_posts/review-adminhover-module.md
deleted file mode 100644
index e1ac9af9..00000000
--- a/astro/sculpin-old/source/_posts/review-adminhover-module.md
+++ /dev/null
@@ -1,58 +0,0 @@
----
-title: Review of the Admin:hover Module
-date: 2010-08-10
-excerpt: My review of Drupal’s admin:hover module.
-tags:
- - drupal-planet
- - drupal-6
- - drupal-modules
- - admin:hover
- - administration
----
-
-Sorry for the lack of Blog posts lately, but
-[my new job](http://horseandcountry.tv) that I started a few weeks ago has
-certainly been keeping me busy! I've got a few more posts that I'm preparing
-content for, and I'll hopefully be back into my weekly-post routine before too
-long!
-
-Today, I'd like to just give a quick overview of the
-[Admin:hover](http://drupal.org/project/admin_hover) module. It basically adds
-an administrative menu that pops up when you hover over a node or block within
-your Drupal website - the kind of functionality that was present within previous
-versions of the [Admin module](http://drupal.org/project/admin). It also
-integrates well with the [Devel](http://drupal.org/project/devel) and
-[Clone](http://drupal.org/project/node_clone) modules.
-
-I've found this to be extremely useful whilst working on photo galleries etc.
-where multiple nodes are displayed in a grid format and I quickly need to
-publish or unpublish something for testing purposes. No longer do I need to open
-each node, or go into the administration area to perform the required actions.
-
-It is also possible to customise which links are available from within the
-adminstration area. The possible selections that I currently have on this site
-are as follows:
-
-**Node links:**
-
-- Edit
-- Publish
-- Unpublish
-- Promote
-- Unpromote
-- Make sticky
-- Make unsticky
-- Delete
-- Clone
-- Dev load
-- View author
-- Edit author
-- Add
-
-**Block links:**
-
-- Configure block
-- Add block
-
-Although, as I have additional contributed modules installed, some of these may
-not neccassaily be available out of the box.
diff --git a/astro/sculpin-old/source/_posts/review-image-caption-module.md b/astro/sculpin-old/source/_posts/review-image-caption-module.md
deleted file mode 100644
index 2ec2aa57..00000000
--- a/astro/sculpin-old/source/_posts/review-image-caption-module.md
+++ /dev/null
@@ -1,40 +0,0 @@
----
-title: Review of the Image Caption Module
-date: 2010-08-20
-excerpt: My review of Drupal’s Image Caption module.
-tags:
- - drupal-planet
- - drupal
- - drupal-6
- - imagefield
- - image-caption
----
-
-Up until as recent as last week, whenever I added an image into one of my Blog
-posts, I was manually adding the caption below each image and styling it
-accordingly. That was until I installed the
-[Image Caption](http://drupal.org/project/image_caption) module.
-
-The Image Caption module uses jQuery to dynamically add captions to images. Here
-is a walkthrough of the process that I followed to install and configure the
-module. As always, I used Drush to download and enable the module, then visited
-the Image Caption Settings page (admin/settings/image_caption). Here, I select
-which node types should be included in image captioning. In my case, I only
-wanted this to apply to Blog posts.
-
-As I use the [FileField](http://drupal.org/project/filefield),
-[ImageField](http://drupal.org/project/imagefield) and
-[Insert](http://drupal.org/project/insert) modules to add images to my posts, as
-opposed to via a WYSIWYG editor, I'm able to add the CSS class of 'caption' to
-my images.
-
-Now, all images inserted this way will have the CSS class of 'caption'.
-
-As the Image Caption module uses the image's title tag to create the displayed
-caption, I enabled the custom title text for my Image field so that when I
-upload an image, I'm prompted to enter text for the caption.
-
-This results in a span called `image-caption-container` around the inserted
-image, and a caption below it called `image-caption` containing the text.
-
-All that's left is to style these classes within your CSS stylesheet.
diff --git a/astro/sculpin-old/source/_posts/review-teleport-module.md b/astro/sculpin-old/source/_posts/review-teleport-module.md
deleted file mode 100644
index 5129c9a7..00000000
--- a/astro/sculpin-old/source/_posts/review-teleport-module.md
+++ /dev/null
@@ -1,39 +0,0 @@
----
-title: Review of the Teleport Module
-date: 2010-07-12
-excerpt: My review of Drupal’s Teleport module.
-tags:
- - drupal-planet
- - drupal-6
- - drupal-modules
- - teleport
----
-
-As a heavily-reliant
-[Quicksilver](http://en.wikipedia.org/wiki/Quicksilver_%28software%29) user on
-my MacBook Pro, I was glad when I found the
-[Teleport](http://drupal.org/project/teleport) module for
-[Drupal](http://drupal.org) _(due to Elliott Rothman's
-[tweet](http://twitter.com/elliotttt/status/18044234238))_.
-
-When you press a configurable hot-key, a jQuery dialog box appears where you can
-search for nodes by title or path, or directly enter the path that you want to
-navigate to. This will greatly reduce the number of clicks that I need to
-perform to get to my desired page - even compared to the
-[Admin](http://drupal.org/project/admin) and
-[Administration Menu](http://drupal.org/project/admin_menu) modules.
-
-Although it's not a new module (the first commits were 2 years ago), I hope that
-they are still planning on achieving the list of future directions listed on
-their Drupal.org project page:
-
-- Make interface act more like Quicksilver (i.e. you should only have to press
- Enter once to launch)
-- 'Actions' like Quicksilver: if you select a node, a second input should appear
- with options to go to the View page, Edit page, (un)publish, etc. Same with
- users.
-- Hook into more non-node content, like taxonomy terms and functions in the API
- module.
-
-Personally, this will make navigation around both the front-end and
-administration area of my Drupal sites so much easier.
diff --git a/astro/sculpin-old/source/_posts/running-drupal-with-symfony-local-server.md b/astro/sculpin-old/source/_posts/running-drupal-with-symfony-local-server.md
deleted file mode 100644
index 97bcd980..00000000
--- a/astro/sculpin-old/source/_posts/running-drupal-with-symfony-local-server.md
+++ /dev/null
@@ -1,323 +0,0 @@
----
-title: Running Drupal 8.8 with the Symfony Local Server
-excerpt: How to use Symfony's local web server to run a Drupal 8.8 website.
-date: 2020-03-09
-tags:
- - drupal
- - drupal-8
- - symfony
----
-
-
-
-
-
-## Installation
-
-
-
-The Symfony server is bundled as part of the `symfony` binary that is available
-to download from .
-
-To install it, run this command:
-
-```bash
-curl -sS https://get.symfony.com/cli/installer | bash
-```
-
-Even though it’s by Symfony, the local webserver works with any type of
-project - including Drupal 8 (and 9) and Drupal 7.
-
-## Getting started
-
-Here are the basic commands to start and stop the server:
-
-```bash
-# Alias for server:start, starts the server
-symfony serve
-
-# Run the server in daemon mode (in the background)
-symfony serve -d
-
-# Display the status of the server
-symfony server:status
-
-# Stop the server
-symfony server:stop
-```
-
-If your Drupal files are within a `web` or `docroot` directory, it will
-automatically be used as the document root for the server, so files are served
-from there if you run the serve command.
-
-If you use a different subdirectory name - one that isn't loaded automatically -
-you can use the `--document-root` option:
-
-```bash
-symfony serve --document-root www
-```
-
-## Different PHP Versions
-
-One of the most useful features of the Symfony server is that it
-[supports multiple versions of PHP](https://symfony.com/doc/current/setup/symfony_server.html#different-php-settings-per-project)
-if you have them installed, and a different version can be selected per
-directory.
-
-This is done by adding a `.php-version` file to the root of the project that
-contains the PHP version to use. For example:
-
-```bash
-echo "7.3" > .php-version
-```
-
-Next time the server is started, this file will be read and the correct version
-of PHP will be used.
-
-If you’re using macOS and want to install another version of PHP, you can do it
-using Homebrew:
-
-```bash
-# Install PHP 7.3
-brew install php@7.3
-```
-
-[Further PHP customisations can be made per project](https://symfony.com/doc/current/setup/symfony_server.html#overriding-php-config-options-per-project)
-by adding a `php.ini` file.
-
-## Securing Sites Locally
-
-The Symfony server allows for serving sites via HTTPS locally by installing its
-own local certificate authority.
-
-If it’s not installed automatically, run this command to install it:
-
-```
-symfony server:ca:install
-```
-
-Now any site will be served via HTTPS by default, and any HTTP requests will be
-automatically redirected.
-
-If you need to run a site with just HTTP, add the `--no-tls` option to the
-`serve` command.
-
-## Adding Databases (and other services) with Docker
-
-The Symfony server has an integration with Docker for providing extra services -
-such as databases that we’ll need to install Drupal.
-
-This is my `docker-compose.yaml` file which defines a `database` service for
-MySQL:
-
-```yaml
-version: '2.1'
-
-services:
- database:
- image: mysql:5.7
- ports: [3306]
- environment:
- MYSQL_ROOT_PASSWORD: secret
- volumes:
- - mysql-data:/var/lib/mysql
-
-volumes:
- mysql-data:
-```
-
-Because port 3306 is exposed, the server recognises it as a database service and
-automatically creates environment variables prefixed with `DATABASE_`.
-
-A list of all the environment variables can be seen by running
-`symfony var:export` (add `| tr " " "\n"` if you want to view each one on a new
-line, and `| sort` if you want to list them alphabetically):
-
-```dotenv
-DATABASE_DATABASE=main
-DATABASE_DRIVER=mysql
-DATABASE_HOST=127.0.0.1
-DATABASE_NAME=main
-DATABASE_PASSWORD=secret
-DATABASE_PORT=32776
-DATABASE_SERVER=mysql://127.0.0.1:32776
-DATABASE_URL=mysql://root:secret@127.0.0.1:32776/main?sslmode=disable&charset=utf8mb4
-DATABASE_USER=root
-DATABASE_USERNAME=root
-SYMFONY_DOCKER_ENV=1
-SYMFONY_TUNNEL=
-SYMFONY_TUNNEL_ENV=
-```
-
-Now these environment variables can be used within `settings.php` file to allow
-configure Drupal’s database connection settings:
-
-```php
-// web/sites/default/settings.php
-
-if ($_SERVER['SYMFONY_DEFAULT_ROUTE_URL']) {
- $databases['default']['default'] = [
- 'driver' => $_SERVER['DATABASE_DRIVER'],
- 'host' => $_SERVER['DATABASE_HOST'],
- 'database' => $_SERVER['DATABASE_NAME'],
- 'username' => $_SERVER['DATABASE_USER'],
- 'password' => $_SERVER['DATABASE_PASSWORD'],
- 'port' => $_SERVER['DATABASE_PORT'],
- 'prefix' => '',
- 'namespace' => 'Drupal\\Core\\Database\\Driver\\mysql',
- 'collation' => 'utf8mb4_general_ci',
- ];
-}
-```
-
-To keep things organised, I usually like to split these settings into their own
-file and include it:
-
-```php
-if ($_SERVER['SYMFONY_DEFAULT_ROUTE_URL'] && file_exists(__DIR__ . '/settings.symfony.php')) {
- require_once __DIR__ . '/settings.symfony.php';
-}
-```
-
-## Installing Drupal
-
-Now that Drupal can connect to the (empty) database, we can install the site. I
-usually do this using Drush, which is added as a dependency via Composer.
-
-The command that I’d usually run is:
-
-```bash
-cd web
-
-../vendor/bin/drush site-install
-```
-
-However, this will cause an error like this because Drupal cannot connect to the
-database when Drush is run in this way.
-
-> Error: Class 'Drush\Sql\Sql' not found in Drush\Sql\SqlBase::getInstance()
-
-To fix this, ensure that the command is prefixed with `symfony php`. This will
-ensure that the correct PHP version and configuration is used, and that the
-appropriate environment variables are available.
-
-```bash
-symfony php ../vendor/bin/drush site-install
-```
-
-This also applies to all other Drush commands.
-
-## Custom Domain Names
-
-Currently we can only access the site via the localhost URL with a specific
-port. The port is determined automatically when the server is started so it can
-change if you have multiple projects running.
-
-Symfony server also allows for
-[adding local domain names through a proxy](https://symfony.com/doc/current/setup/symfony_server.html#local-domain-names).
-This is useful if you always want to access the site from the same URL, or if
-the site relies on using a specific URL such as a multisite setup (multiple
-domains served from the same codebase).
-
-{% include 'figure' with {
- image: {
- src: '/images/blog/running-drupal-with-symfony-local-server/proxy.png',
- alt: 'A screenshot of the proxy overview screen, showing three local projects with their local domains, ports and directories.',
- },
- caption: 'The proxy overview screen'
-} only %}
-
-### Setting up a multisite
-
-Here’s an example of how I would use local domains to configure a multisite
-Drupal installation (taken from
-).
-
-The first thing is to add the subdomain to the proxy. In this example, I’m going
-to set up a version of the Umami demo installation profile at
-`https://umami.wip`.
-
-```bash
-# Add umami.wip to the proxy and attach it to this directory
-symfony proxy:domain:attach umami
-```
-
-Now we can add it to Drupal’s `sites.php` file to route requests to the correct
-site directory:
-
-```php
-// web/sites/sites.php
-
-// This maps https://umami.wip to the sites/umami directory
-$sites['umami.wip'] = 'umami';
-```
-
-To create the directory, we can duplicate the `default` site directory and its
-contents.
-
-```
-cp -R web/sites/default web/sites/umami
-```
-
-To create a separate database, we add a new service to the `docker-compose.yaml`
-file and a new MySQL volume to store the data. We can use labels to generate
-site specific environment variables.
-
-```diff
- version: '2.1'
-
- services:
- database:
- image: mysql:5.7
- ports: [3306]
- environment:
- MYSQL_ROOT_PASSWORD: secret
- volumes:
- - mysql-data:/var/lib/mysql
-
-+ database_umami:
-+ image: mysql:5.7
-+ ports: [3306]
-+ environment:
-+ MYSQL_ROOT_PASSWORD: secret
-+ volumes:
-+ - mysql-data-umami:/var/lib/mysql
-+ labels:
-+ com.symfony.server.service-prefix: 'UMAMI_DATABASE'
-
- volumes:
- mysql-data:
-+ mysql-data-umami:
-```
-
-These can then be added to `sites/umami/settings.php`:
-
-```php
-$databases['default']['default'] = [
- 'driver' => $_SERVER['UMAMI_DATABASE_DRIVER'],
- 'host' => $_SERVER['UMAMI_DATABASE_HOST'],
- 'database' => $_SERVER['UMAMI_DATABASE_NAME'],
- 'username' => $_SERVER['UMAMI_DATABASE_USER'],
- 'password' => $_SERVER['UMAMI_DATABASE_PASSWORD'],
- 'port' => $_SERVER['UMAMI_DATABASE_PORT'],
- 'prefix' => '',
- 'namespace' => 'Drupal\\Core\\Database\\Driver\\mysql',
- 'collation' => 'utf8mb4_general_ci',
-];
-```
-
-Now that the Umami site is able to connect to its own database, we can install
-Drupal - specifying the installation profile to use and also the site directory
-to target.
-
-```bash
-symfony php ../vendor/bin/drush site-install \
- demo_umami \
- -l umami \
- --no-interaction
-```
diff --git a/astro/sculpin-old/source/_posts/running-phpunit-tests-docksal-phpstorm.md b/astro/sculpin-old/source/_posts/running-phpunit-tests-docksal-phpstorm.md
deleted file mode 100644
index 56d22433..00000000
--- a/astro/sculpin-old/source/_posts/running-phpunit-tests-docksal-phpstorm.md
+++ /dev/null
@@ -1,217 +0,0 @@
----
-title: How to run Drupal 8 PHPUnit Tests within Docksal from PhpStorm
-date: 2018-07-19
-excerpt: How to configure PhpStorm to run automated tests within Docksal.
-tags:
- - docksal
- - drupal
- - drupal-8
- - phpstorm
- - phpunit
- - testing
-promoted: true
----
-
-I’ve recently re-watched [A Clean PHPUnit Workflow in PHPStorm][0] on
-[Laracasts][1], where Jeffrey configures PhpStorm to run tests from within the
-IDE. With Drupal 8 using PHPUnit too, I decided to try and do the same with a
-local D8 site.
-
-Though because I’m using [Docksal][4] for my local development environment
-which, at least on a Mac, runs Docker containers within a virtual machine, there
-were some additional steps needed to achieve this and to have the tests run
-within the Docksal virtual machine and using the correct containers.
-
-In this post, I’ll be using my [Drupal Testing Workshop codebase][2] as an
-example, which is based on the [Drupal Composer project][3] with some
-pre-configured Docksal configuration.
-
-This post is separated into a few different sections:
-
-- [Allow PhpStorm to connect to the CLI container](#allow-phpstorm-to-connect-to-the-cli-container)
-- [Add a new deployment server](#add-a-new-deployment-server)
-- [Configure PHP interpreter](#configuring-the-php-interpreter)
-- [Set up PHPUnit in PhpStorm](#set-up-phpunit-in-phpstorm)
-- [Running tests](#running-tests)
-
-## Allow PhpStorm to connect to the CLI container
-
-The first thing to do is to allow PhpStorm to connect to Docksal’s CLI container
-to allow it to run the tests. We can do this by exposing the container’s SSH
-port so that it’s available to the host machine and PhpStorm.
-
-As this is going to be unique to my environment, I’m going to add this to
-`.docksal/docksal-local.yml` which I have in `.gitignore`, rather than
-committing it into the repository and enforcing the same port number for
-everyone else and potentially causing conflicts.
-
-In this case I’ll expose port 22 in the container to port 2225 locally.
-
-```
-version: '2.1'
-
-services:
- cli:
- ports:
- - '2225:22'
-```
-
-Once added, run `fin start` to rebuild the project’s containers.
-
-You can verify the change by running `fin ps` and you should see something like
-`0.0.0.0:2225->22/tcp` under Ports for the CLI container.
-
-## Add a new Deployment server
-
-Now PhpStorm can connect to Docksal, I can configure it to do so by adding a new
-deployment server.
-
-- Open PhpStorm’s preferences, and go to 'Build, Execution, Deployment' and
- 'Deployment'.
-- Click 'Add' to configure a new deployment server.
-- Enter a name like 'Docksal', and select SFTP as the server type.
-
-{.with-border
-.sm:max-w-sm}
-
-### Connection settings
-
-On the Connection tab:
-
-- Enter your domain name - e.g. `drupaltest.docksal` as the SFTP host. This will
- resolve to the correct local IP address.
-- Enter the exposed port for the CLI container that was entered in the previous
- step.
-- Enter "docker" as both the username and password.
-
-You should now be able to click "Test SFTP connection" and get a successfully
-connected confirmation message.
-
-
-
-### Mapping settings
-
-On the Mappings tab, add `/var/www` as the deployment path so that PhpStorm is
-looking in the correct place for the project code.
-
-{.with-border}
-
-## Configuring the PHP Interpreter
-
-In Preferences, search for 'PHP' within 'Languages & Frameworks', and add a new
-CLI interpreter.
-
-{.with-border}
-
-In this case I’ve called it 'Docksal PHP 7.1', used the Docksal deployment
-configuration, and set the path to the PHP executable to `/usr/local/bin/php`
-(the same path that we would get if we ran `fin run which php`). You should see
-both the deployment host URL displayed as well as the remote PHP version and
-configuration filenames.
-
-{.with-border}
-
-This can now be selected as the CLI interpreter for this project.
-
-{.with-border}
-
-## Set up PHPUnit in PhpStorm
-
-In Preferences, search for 'Test Frameworks' and add a new framework.
-
-{.with-border}
-
-Select 'PHPUnit by Remote Interpreter' and then the 'Docksal PHP 7.1' that we
-created in the last step.
-
-Select 'Use Composer autoloader' for the PHPUnit library setting so that
-PhpStorm uses the version required by Drupal core, and set the path to
-`/var/www/vendor/autoload.php`.
-
-Also specify the path to the default (phpunit.xml) configuration file. This will
-depend on how your project is structured, in this case it’s at
-`/var/www/web/core/phpunit.xml`.
-
-{.with-border}
-
-## Running tests
-
-With PHPUnit configured, next to each test class and method, you can see a green
-circle (or a red one if the test failed the last run). You can click the circle
-and select to run that test class or method. You can also right-click
-directories in the project sidebar to run all of the tests within that
-directory.
-
-{.with-border}
-
-When the tests start running, a new tool window will open that shows you all of
-the selected tests, how long each test took to run and whether it passed or
-failed. You can also see the CLI output from PHPUnit itself next to it.
-
-{.with-border}
-
-From here, you also have the ability to re-run all of the tests, as well as a
-single test method or a specific test class.
-
-Any test failures are shown here too, and for some failures like differences
-between two arrays you can use PhpStorm’s internal comparison tools to view the
-difference rather than needing to do so on the command line.
-
-{.with-border}
-
-{.with-border
-.sm:max-w-md}
-
-### Keyboard shortcuts
-
-As per the video, I’ve also added some keyboard shortcuts to my keymap, so I can
-press ⌘T to run the current test method or class that I’m in, and ⇧⌘T to re-run
-the last test.
-
-{.with-border}
-
-{.with-border}
-
-### Database issues
-
-When running functional tests that require a database, I was getting a database
-error like the one below:
-
-> Drupal\Core\Installer\Exception\InstallerException : Resolve all issues below
-> to continue the installation. For help configuring your database server, see
-> the installation
-> handbook, or contact your hosting provider.
-
-In `settings.php`, I check for the presence of `/.dockerenv` to ensure that
-we’re inside a Docker container, as well as the presence of a
-`docksal.settings.yml` file. The latter contains the database credentials for
-Drupal to connect to the MySQL database.
-
-```php
-if (file_exists('/.dockerenv') && file_exists(__DIR__ . '/docksal.settings.php')) {
- include __DIR__ . '/docksal.settings.php';
-}
-```
-
-In order to get the tests to run, I had to prevent this file from being loaded
-during the tests. I can do this by checking that `SIMPLETEST_DB`, an environment
-variable set in phpunit.xml is not present.
-
-```php
-// settings.php
-
-if (file_exists('/.dockerenv') && file_exists(__DIR__ . '/docksal.settings.php') && !getenv('SIMPLETEST_DB')) {
- include __DIR__ . '/docksal.settings.php';
-}
-```
-
-With this extra condition, the database credentials are loaded correctly and the
-functional tests run properly.
-
-Happy testing!
-
-[0]: https://laracasts.com/series/php-bits/episodes/2
-[1]: https://laracasts.com
-[2]: https://github.com/opdavies/drupal-testing-workshop
-[3]: https://github.com/drupal-composer/drupal-project
-[4]: https://docksal.io
diff --git a/astro/sculpin-old/source/_posts/sculpin-twig-resources.md b/astro/sculpin-old/source/_posts/sculpin-twig-resources.md
deleted file mode 100644
index b06557cb..00000000
--- a/astro/sculpin-old/source/_posts/sculpin-twig-resources.md
+++ /dev/null
@@ -1,53 +0,0 @@
----
-title: Sculpin and Twig Resources
-date: 2015-07-19
-excerpt:
- A list of resources that I compiled whilst preparing for my Sculpin and Twig
- talk at DrupalCamp North.
-tags:
- - sculpin
- - drupalcamp
- - drupalcamp-north
- - twig
----
-
-Here’s a list of resources that I compiled whilst preparing for my
-[Sculpin and Twig talk](http://drupalcampnorth.org/session/test-drive-twig-sculpin)
-at [DrupalCamp North](http://drupalcampnorth.org).
-
-## General Information
-
--
--
-
-## Where to Get Sculpin
-
--
--
--
--
-
-## Source Code Examples
-
--
-- - the source repository for this
- site.
--
--
--
--
--
--
-- Google for "`sculpin_site.yml site:github.com`" for more examples.
-
-## Videos
-
-- - a YouTube playlist of Sculpin videos.
-
-## Twig
-
--
-- - variables, filters,
- functions, template inheritance, expressions etc.
-- Go to http://twig.sensiolabs.org/{foo} to search for a tag, filter, test or
- function.
diff --git a/astro/sculpin-old/source/_posts/simplifying-drupal-migrations-with-xautoload.md b/astro/sculpin-old/source/_posts/simplifying-drupal-migrations-with-xautoload.md
deleted file mode 100644
index a464de4d..00000000
--- a/astro/sculpin-old/source/_posts/simplifying-drupal-migrations-with-xautoload.md
+++ /dev/null
@@ -1,137 +0,0 @@
----
-title: Simplifying Drupal Migrations with xautoload
-date: 2016-05-03
-excerpt:
- How to use the xautoload module to autoload migration classes within your
- Drupal 7 migration modules.
-tags:
- - autoloading
- - drupal
- - drupal-planet
- - drupal-7
- - php
----
-
-How to use the [xautoload][1] module to autoload migration classes within your
-Drupal 7 migration modules.
-
-## What is xautoload?
-
-[xautoload][1] is a Drupal module that enables the autoloading of PHP classes,
-in the same way that you would do so in a [Composer][2] based project such as
-Drupal 8 or Symfony.
-
-It supports both the [PSR-0][3] and [PSR-4][4] standards, as well as providing a
-wildcard syntax for Drupal’s `file[]` syntax in .info files.
-
-To use it, download and enable it from Drupal.org as you would for any other
-module, and then add it as a dependency within your module. The xautoload
-project page suggests including a minimum version in this format:
-
-```language-ini
-dependencies[] = xautoload (>= 7.x-5.0)
-```
-
-This will ensure that the version of xautoload is 7.x-5.0 or newer.
-
-## How to use it
-
-### Wildcard syntax for .info files
-
-Here is an example .info file for a migrate module.
-
-```language-ini
-; foo_migrate.info
-
-name = Foo Migration
-core = 7.x
-package = Foo
-
-files[] = includes/user.inc
-files[] = includes/nodes/article.inc
-files[] = includes/nodes/page.inc
-```
-
-In this example, each custom migration class is stored in it’s own file within
-the `includes` directory, and each class needs to be loaded separately using the
-`files[] = filename` syntax.
-
-One thing that the xautoload module does to enable for the use of wildcards
-within this syntax. By using wildcards, the module file can be simplified as
-follows:
-
-```language-ini
-files[] = includes/**/*.inc
-```
-
-This will load any .inc files within the `includes` directory as well as any
-sub-directories, like 'node' in the original example.
-
-This means that any new migration classes that are added will be automatically
-loaded, so you don’t need to declare each include separately within
-foo_migrate.info again. The great thing about this approach is that it works
-with the existing directory and file structure.
-
-### Use the PSR-4 structure
-
-If you want to use the [PSR-4][4] approach, you can do that too.
-
-In order to do so, you’ll need to complete the following steps:
-
-1. Rename the `includes` directory to `src`.
-2. Ensure that there is one PHP class per file, and that the file extension is
- `.php` rather than `.inc`.
-3. Ensure that the name of the file matches the name of the class -
- `FooArticleNodeMigration` would be in a file called
- `FooArticleNodeMigration.php`.
-4. Add a namespace to each PHP file. This uses the same format as Drupal 8,
- including the machine name of the module. For example, `Drupal\foo_migrate`.
- - If the class is within a sub-directory, then this will also need to be
- included within the namespace - e.g. `Drupal\foo_migrate\Node`.
- - You’ll also need to import any class names that you are referencing,
- including class names that are you extending, by adding `use` statements at
- the top of the file. You may be able to prefix it with `\` instead (e.g.
- `\DrupalNode6Migration`), but I prefer to use imports.
-
-Now your class may look something like this:
-
-```language-php
- 'Drupal\foo_migrate\Node\FooArticleNodeMigration',
- 'source_type' => 'story',
- 'destination_type' => 'article',
-);
-```
-
-## Resources
-
-- [xautoload module][1]
-- [migrate module][5]
-- [migrate_d2d module][6]
-- [PSR-0][3]
-- [PSR-4][4]
-
-[1]: https://www.drupal.org/project/xautoload
-[2]: http://getcomposer.org
-[3]: http://www.php-fig.org/psr/psr-0/
-[4]: http://www.php-fig.org/psr/psr-4/
-[5]: https://www.drupal.org/project/migrate
-[6]: https://www.drupal.org/project/migrate_d2d
diff --git a/astro/sculpin-old/source/_posts/site-upgraded-drupal-7.md b/astro/sculpin-old/source/_posts/site-upgraded-drupal-7.md
deleted file mode 100644
index bd1e1627..00000000
--- a/astro/sculpin-old/source/_posts/site-upgraded-drupal-7.md
+++ /dev/null
@@ -1,23 +0,0 @@
----
-title: Site Upgraded to Drupal 7
-date: 2012-01-04
-excerpt:
- As the vast majority of the Drupal websites that I currently work on are built
- on Drupal 7, I thought that it was time that I upgraded this site.
-tags: [drupal]
----
-
-As the vast majority of the Drupal websites that I currently work on are built
-on Drupal 7, I thought that it was time that I upgraded this site. Following the
-[core upgrade process](http://drupal.org/node/570162) and the
-[CCK migration process](http://drupal.org/node/1144136), everything was upgraded
-smoothly without any issues.
-
-I've upgraded a handful of essential contrib modules to the latest stable
-version, [Administration Menu](http://drupal.org/project/admin_menu),
-[Views](http://drupal.org/project/views) etc., and will continue upgrading the
-other modules on the site as time allows.
-
-I also prefer [Bartik](http://drupal.org/project/bartik) to
-[Garland](http://drupal.org/project/garland) - but I will be creating a new
-custom theme when I get a chance.
diff --git a/astro/sculpin-old/source/_posts/some-useful-git-aliases.md b/astro/sculpin-old/source/_posts/some-useful-git-aliases.md
deleted file mode 100644
index 6f5f1a30..00000000
--- a/astro/sculpin-old/source/_posts/some-useful-git-aliases.md
+++ /dev/null
@@ -1,36 +0,0 @@
----
-title: Some Useful Git Aliases
-date: 2014-01-15
-excerpt:
- Here are some bash aliases that I use and find helpful for quickly writing Git
- and Git Flow commands.
-tags:
- - git
----
-
-Here are some bash aliases that I use and find helpful for quickly writing Git
-and Git Flow commands.
-
-These should be placed within your `~/.bashrc` or `~/.bash_profile` file:
-
-```language-bash
-alias gi="git init"
-alias gcl="git clone"
-alias gco="git checkout"
-alias gs="git status"
-alias ga="git add"
-alias gaa="git add --all"
-alias gc="git commit"
-alias gcm="git commit -m"
-alias gca="git commit -am"
-alias gm="git merge"
-alias gr="git rebase"
-alias gps="git push"
-alias gpl="git pull"
-alias gd="git diff"
-alias gl="git log"
-alias gfi="git flow init"
-alias gff="git flow feature"
-alias gfr="git flow release"
-alias gfh="git flow hotfix"
-```
diff --git a/astro/sculpin-old/source/_posts/some-useful-links-using-simpletest-drupal.md b/astro/sculpin-old/source/_posts/some-useful-links-using-simpletest-drupal.md
deleted file mode 100644
index 14ef9c8a..00000000
--- a/astro/sculpin-old/source/_posts/some-useful-links-using-simpletest-drupal.md
+++ /dev/null
@@ -1,21 +0,0 @@
----
-title: Some useful links for using SimpleTest in Drupal
-date: 2013-06-13
-excerpt:
- Here are some useful links that I've found when researching about unit testing
- in Drupal using SimpleTest.
-tags:
- - simpletest
- - tdd
- - test-driven-development
- - drupal-planet
- - drupal
- - testing
----
-
-- [An Introduction to Unit Testing in Drupal](http://www.lullabot.com/blog/articles/introduction-unit-testing-drupal 'An Introduction to Unit Testing in Drupal')
-- [Module Developer's Guide to SimpleTest](http://www.lullabot.com/blog/articles/drupal-module-developers-guide-simpletest "Module Developer's Guide to SimpleTest")
-- [SimpleTest Tutorial (Drupal 6)](https://drupal.org/simpletest-tutorial 'SimpleTest Tutorial (Drupal 6)')
-- [SimpleTest Tutorial (Drupal 7)](https://drupal.org/simpletest-tutorial-drupal7 'SimpleTest Tutorial (Drupal 7)')
-- [SimpleTest Reference](https://drupal.org/node/278126 'SimpleTest Reference')
-- [Testing with SimpleTest](https://drupal.org/node/1128366 'Testing with SimpleTest')
diff --git a/astro/sculpin-old/source/_posts/south-wales-drupal-user-group.md b/astro/sculpin-old/source/_posts/south-wales-drupal-user-group.md
deleted file mode 100644
index 541014ff..00000000
--- a/astro/sculpin-old/source/_posts/south-wales-drupal-user-group.md
+++ /dev/null
@@ -1,22 +0,0 @@
----
-title: The Inaugural Meetup for the South Wales Drupal User Group
-date: 2010-09-26
-excerpt:
- If you do Drupal and you're in the area, come and join us for the first SWDUG
- meetup!
-tags:
- - drupal
- - drupal-planet
- - swdug
- - meetups
----
-
-If you do Drupal and you're in the area, come and join us for the first SWDUG
-meetup!
-
-We'll be meeting in the communal area just outside of the
-[SubHub](http://www.subhub.com) HQ, at:
-
-4, The Studios 3 Burt Street Cardiff CF10 5FZ
-
-For more information and to signup, visit .
diff --git a/astro/sculpin-old/source/_posts/speaking-drupalcon-amsterdam.md b/astro/sculpin-old/source/_posts/speaking-drupalcon-amsterdam.md
deleted file mode 100644
index 5368c173..00000000
--- a/astro/sculpin-old/source/_posts/speaking-drupalcon-amsterdam.md
+++ /dev/null
@@ -1,38 +0,0 @@
----
-title: Speaking at DrupalCon Amsterdam
-date: 2019-07-25
-excerpt:
- I’m going to be attending DrupalCon Europe again this year, but for the first
- time as a speaker.
-tags: [speaking, drupalcon, personal]
-has_tweets: true
----
-
-
I’ve attended numerous DrupalCons since my first in Prague in 2013, as a delegate, as a [{{site.companies.drupal_association.name}}]({{site.companies.drupal_association.url}}) staff member, and also as a contribution sprint mentor. I’m excited to be attending DrupalCon Amsterdam again this year - but as my first time as a DrupalCon speaker.
— Oliver Davies (@opdavies) July 16, 2019'
-} %}
-
-The session that I’m going to be presenting is a twenty minute version of my
-[Deploying PHP applications with Ansible, Ansible Vault and Ansistrano](/talks/deploying-php-ansible-ansistrano)
-talk.
-
-{% include 'figure' with {
- image: {
- src: '/images/blog/speaking-drupalcon-amsterdam/drupalcon-schedule.jpg',
- alt: 'My session on the DrupalCon Amsterdam schedule.',
- },
- caption: 'My session on the DrupalCon Amsterdam schedule.',
-} %}
-
-I’ve been working with Drupal since 2007 (or maybe 2008), and it was the subject
-of my [first meetup talk](/talks/so-what-is-this-drupal-thing) in 2012. Since
-then I’ve given 48 more talks
-(including one workshop) at various user groups and conferences on a range of
-development and systems administration topics. So it’s a nice conincedence that
-this will be my fiftieth (50th) talk.
-
-Thanks also to my employer,
-[{{site.companies.inviqa.name}}]({{site.companies.inviqa.url}}), who are giving
-me the time and covering my costs to attend the conference.
diff --git a/astro/sculpin-old/source/_posts/splitting-new-drupal-project-from-repo.md b/astro/sculpin-old/source/_posts/splitting-new-drupal-project-from-repo.md
deleted file mode 100644
index afa76553..00000000
--- a/astro/sculpin-old/source/_posts/splitting-new-drupal-project-from-repo.md
+++ /dev/null
@@ -1,165 +0,0 @@
----
-title: How to split a new Drupal contrib project from within another repository
-date: 2018-03-10
-excerpt:
- How to use Git to split a directory from within an existing repository into
- it’s own.
-tags:
- - drupal
- - drupal-7
- - drupal-8
- - drupal-planet
- - git
- - open-source
----
-
-Yay! You’ve written a new Drupal module, theme or installation profile as part
-of your site, and now you’ve decided to open source it and upload it to
-Drupal.org as a new contrib project. But how do you split it from the main site
-repository into it’s own?
-
-Well, there are a couple of options.
-
-## Does it need to be part of the site repository?
-
-An interesting thing to consider is, does it _need_ to be a part of the site
-repository in the first place?
-
-If from the beginning you intend to contribute the module, theme or distribution
-and it’s written as generic and re-usable from the start, then it _could_ be
-created as a separate project on Drupal.org or as a private repository on your
-Git server from the beginning, and added as a dependency of the main project
-rather than part of it. It could already have the correct branch name and adhere
-to the Drupal.org release conventions and be managed as a separate project, then
-there is no later need to "clean it up" or split it from the main repo at all.
-
-This is how I worked at the [Drupal Association][2] - with all of the modules
-needed for Drupal.org hosted on Drupal.org itself, and managed as a dependency
-of the site repository with Drush Make.
-
-Whether this is a viable option or not will depend on your processes. For
-example, if your code needs to go through a peer review process before releasing
-it, then pushing it straight to Drupal.org would either complicate that process
-or bypass it completely. Pushing it to a separate private repository may depend
-on your team's level of familiarity with [Composer][3], for example.
-
-It does though avoid the “we’ll clean it up and contribute it later” scenario
-which probably happens less than people intend.
-
-## Create a new, empty repository
-
-If the project is already in the site repo, this is probably the most common
-method - to create a new, empty repository for the new project, add everything
-to it and push it.
-
-For example:
-
-```language-bash
-cd web/modules/custom/my_new_module
-
-# Create a new Git repository.
-git init
-
-# Add everything and make a new commit.
-git add -A .
-git commit -m 'Initial commit'
-
-# Rename the branch.
-git branch -m 8.x-1.x
-
-# Add the new remote and push everything.
-git remote add origin username@git.drupal.org:project/my_new_module.git
-git push origin 8.x-1.x
-```
-
-There is a huge issue with this approach though - **you now have only one single
-commit, and you’ve lost the commmit history!**
-
-This means that you lose the story and context of how the project was developed,
-and what decisions and changes were made during the lifetime of the project so
-far. Also, if multiple people developed it, now there is only one person being
-attributed - the one who made the single new commit.
-
-Also, if I’m considering adding your module to my project, personally I’m less
-likely to do so if I only see one "initial commit". I’d like to see the activity
-from the days, weeks or months prior to it being released.
-
-What this does allow though is to easily remove references to client names etc
-before pushing the code.
-
-## Use a subtree split
-
-An alternative method is to use [git-subtree][0], a Git command that "merges
-subtrees together and split repository into subtrees". In this scenario, we can
-use `split` to take a directory from within the site repo and split it into it’s
-own separate repository, keeping the commit history intact.
-
-Here is the description for the `split` command from the Git project itself:
-
-> Extract a new, synthetic project history from the history of the
-> subtree. The new history includes only the commits (including merges) that
-> affected , and each of those commits now has the contents of
-> at the root of the project instead of in a subdirectory. Thus, the newly
-> created history is suitable for export as a separate git repository.
-
-
-__Note__: This command needs to be run at the top level of the repository. Otherwise you will see an error like "You need to run this command from the toplevel of the working tree.".
-
-To find the path to the top level, run `git rev-parse --show-toplevel`.
-
-
-
-In order to do this, you need specify the prefix for the subtree (i.e. the
-directory that contains the project you’re splitting) as well as a name of a new
-branch that you want to split onto.
-
-```
-git subtree split --prefix web/modules/custom/my_new_module -b split_my_new_module
-```
-
-When complete, you should see a confirmation message showing the branch name and
-the commit SHA of the branch.
-
-```
-Created branch 'split_my_new_module'
-7edcb4b1f4dc34fc3b636b498f4284c7d98c8e4a
-```
-
-If you run `git branch`, you should now be able to see the new branch, and if
-you run `git log --oneline split_my_new_module`, you should only see commits for
-that module.
-
-If you do need to tidy up a particular commit to remove client references etc,
-change a commit message or squash some commits together, then you can do that by
-checking out the new branch, running an interactive rebase and making the
-required amends.
-
-```
-git checkout split_my_new_module
-git rebase -i --root
-```
-
-Once everything is in the desired state, you can use `git push` to push to the
-remote repo - specifying the repo URL, the local branch name and the remote
-branch name:
-
-```
-git push username@git.drupal.org:project/my_new_module.git split_my_new_module:8.x-1.x
-```
-
-In this case, the new branch will be `8.x-1.x`.
-
-Here is a screenshot of example module that I’ve split and pushed to GitLab.
-Notice that there are multiple commits in the history, and each still attributed
-to it’s original author.
-
-
-
-Also, as this is standard Git functionality, you can follow the same process to
-extract PHP libraries, Symfony bundles, WordPress plugins or anything else.
-
-[0]: https://github.com/git/git/blob/master/contrib/subtree/git-subtree.txt
-[1]:
- https://github.com/git/git/blob/master/contrib/subtree/git-subtree.txt#L101-L108
-[2]: {{site.companies.drupal_association.url}}
-[3]: https://getcomposer.org
diff --git a/astro/sculpin-old/source/_posts/style-drupal-6s-taxonomy-lists-php-css-and-jquery.md b/astro/sculpin-old/source/_posts/style-drupal-6s-taxonomy-lists-php-css-and-jquery.md
deleted file mode 100644
index 5564950b..00000000
--- a/astro/sculpin-old/source/_posts/style-drupal-6s-taxonomy-lists-php-css-and-jquery.md
+++ /dev/null
@@ -1,75 +0,0 @@
----
-title: Style Drupal 6's Taxonomy Lists with PHP, CSS and jQuery
-date: 2010-04-05
-excerpt: Getting started with Drupal theming by styling Drupal’s taxonomy lists.
-tags:
- - drupal-6
- - drupal-planet
- - drupal-theming
- - taxonomy
----
-
-Whilst developing this, and other Drupal websites for clients, I decided that I
-wanted to categorise content using the taxonomy system. However, I wasn't happy
-with the way that Drupal displayed the terms lists by default, and I started
-comparing this to other websites that I look at.
-
-To start with, I wanted to have something that described what the list was
-displaying - like in the second example above. I wanted to have the words
-'Posted in' displayed before the list of terms. To do this, I had to edit the
-node template file that exists within my theme folder (sites/all/themes). As I
-only wanted this change to affect my Blog posts, the file that I needed to
-change is **node-blog.tpl.php**
-
-I scrolled down until I found the piece of code that displayed the terms list:
-
-```language-php
-
-
-
-
-
-```
-
-Adding `print t(' Posted in ')` will print the words 'Posted in' before
-outputing the terms.
-
-I then added some CSS to re-size the spacing between the items, and then add the
-commas between them to seperate them:
-
-```language-css
-.terms ul.links li {
- margin-right: 1px;
- padding: 0;
-}
-
-.terms ul.links li:after {
- content: ",";
-}
-
-.terms ul.links li.last:after {
- content: ".";
-}
-```
-
-I created a file named **script.js** in my theme folder with the following code
-in it. After clearing Drupal's caches, this file is automatically recognised by
-Drupal 6.
-
-```language-js
-if (Drupal.jsEnabled) {
- $(document).ready(function() {
- $('.terms ul.links li.last').prev().addClass('test');
- })
-}
-```
-
-This code finds the last item in the list, uses **.prev** to select the one
-before it, and then uses **.addClass** to assign it the HTML class of "test". We
-can then use this class to target it with specific CSS.
-
-```language-css
-.terms ul.links li.test:after {
- content: " and";
-}
-```
diff --git a/astro/sculpin-old/source/_posts/test-driven-ansible-role-development-molecule.md b/astro/sculpin-old/source/_posts/test-driven-ansible-role-development-molecule.md
deleted file mode 100644
index 37bf2ff3..00000000
--- a/astro/sculpin-old/source/_posts/test-driven-ansible-role-development-molecule.md
+++ /dev/null
@@ -1,46 +0,0 @@
----
-title: Test Driven Ansible Role Development with Molecule
-date: 2019-06-02
-excerpt:
- Some resources that I found for testing Ansible roles with a tool called
- Molecule.
-tags: [ansible, molecule, testing, video]
----
-
-I used to maintain a number of [Ansible roles][roles], and I recently wrote one
-for automatically generating `settings.php` files for Drupal projects that I use
-for some client projects as part of the [Ansible and Ansistrano deployment
-process][talk], as it can populate these files with credentials stored in
-Ansible Vault.
-
-I uploaded an initial version of the role [onto GitHub][github], but haven’t yet
-released it onto Ansible Galaxy.
-
-I’d seen in other people’s roles and read elsewhere about writing automated
-tests for Ansible roles using a tool called [Molecule][molecule], and wanted to
-write some tests for this role before publishing it onto Galaxy.
-
-I looked around for resources about Molecule, and found a [blog post by Jeff
-Geerling][jeff-post], but also this YouTube video that I found very helpful.
-
-I’ve since been re-writing the role from scratch based on Molecule, and plan to
-release an official version of it soon.
-
-{% include 'video-embed' with {
- classes: 'video-full',
- video: {
- id: 'DAnMyBZ8-Qs',
- attr: {
- height: '315',
- width: '560',
- }
- }
-} %}
-
-[github]: https://github.com/opdavies/ansible-role-drupal-settings
-[jeff-post]:
- https://www.jeffgeerling.com/blog/2018/testing-your-ansible-roles-molecule
-[molecule]: https://molecule.readthedocs.io
-[roles]:
- https://docs.ansible.com/ansible/latest/user_guide/playbooks_reuse_roles.html
-[talk]: /talks/deploying-php-ansible-ansistrano
diff --git a/astro/sculpin-old/source/_posts/test-driven-drupal-on-gitstore-leanpub.md b/astro/sculpin-old/source/_posts/test-driven-drupal-on-gitstore-leanpub.md
deleted file mode 100644
index fe3abd84..00000000
--- a/astro/sculpin-old/source/_posts/test-driven-drupal-on-gitstore-leanpub.md
+++ /dev/null
@@ -1,30 +0,0 @@
----
-title: Test Driven Drupal on Gitstore and Leanpub
-excerpt: The work-in-progress codebase for the example application is now on Gitstore.
-date: 2020-04-22
-tags: [drupal, drupal-8, drupal-association, drupal-planet, drupalcares, testing, test-driven-drupal]
-has_tweets: true
----
-
-Some time ago, I announced that I was planning on writing a book on automated testing and test driven development with Drupal. I [created a landing page][landing page] and set up a mailing list, but I wasn't sure at that point what I was going to cover or create as part of the book.
-
-
-{% include 'tweet' with {
- class: 'my-6',
- data_cards: true,
- content: '
I'm going to write a book on automated testing in Drupal. Join the mailing list for updates, and I'm happy to take suggestions on what to cover. https://t.co/YXNpe6f8Ft#drupal
— Oliver Davies (@opdavies) May 15, 2018',
-} %}
-
-Being a meetup and DrupalCamp conference organiser, after some thought I decided to build a website for an example conference, and that some of this code would then be included in the book as example content. This seemed to cover most of what I originally wanted, through features like a call for papers for potential speakers to propose sessions, allowing organisers to administer and moderate those proposals, automatically sending notification emails to submitters and displaying the accepted sessions.
-
-I've started building it with Drupal 8.8 and it is [now available on GitStore][gitstore] to purchase access to, including all future updates as I continue building the application - adding new features and upgrading to Drupal 9 once it is released. There are some other interesting things there too, such as using feature flags to enable or disable functionality, and using GitHub Actions to run the tests automatically.
-
-The book itself I've [added a page for on Leanpub][leanpub], and I'll be continuing to add content to it in parallel to building the example codebase. Once there is enough content, I will release the first draft for purchase.
-
-Any purchases that are made via Gitstore or Leanpub, an amount will be donated to the [Drupal Association][] and the [#DrupalCares campaign][drupalcares] to help sustain the Association during COVID-19.
-
-[drupal association]: https://www.drupal.org/association
-[drupalcares]: https://www.drupal.org/association/drupal-cares-challenge
-[gitstore]: https://enjoy.gitstore.app/repositories/opdavies/test-driven-drupal-conference-app
-[landing page]: /test-driven-drupal
-[leanpub]: https://leanpub.com/test-driven-drupal
diff --git a/astro/sculpin-old/source/_posts/testing-tailwindcss-plugins-with-jest.md b/astro/sculpin-old/source/_posts/testing-tailwindcss-plugins-with-jest.md
deleted file mode 100644
index 23c39a1d..00000000
--- a/astro/sculpin-old/source/_posts/testing-tailwindcss-plugins-with-jest.md
+++ /dev/null
@@ -1,284 +0,0 @@
----
-title: Testing Tailwind CSS plugins with Jest
-date: 2019-04-29
-excerpt: How to write tests for Tailwind CSS plugins using Jest.
-tags:
- - javascript
- - jest
- - tailwind-css
- - testing
-promoted: true
----
-
-
-**Note:** The content of this post is based on tests seen in Adam Wathan’s ["Working on Tailwind 1.0" video][working-on-tailwind-video], the Jest documentation website, and existing tests for other Tailwind plugins that I’ve used such as [Tailwind CSS Interaction Variants][tailwindcss-interaction-variants].
-
-
-## Preface
-
-In Tailwind 0.x, there was a `list-reset` utility that reset the list style and
-padding on a HTML list, though it was removed prior to 1.0 and moved into
-Tailwind’s base styles and applied by default.
-
-However, on a few projects I use Tailwind in addition to either existing custom
-styling or another CSS framework, and don’t use `@tailwind base` (formerly
-`@tailwind preflight`) so don’t get the base styles.
-
-Whilst I could re-create this by replacing it with two other classes
-(`list-none` and `p-0`), I decided to write [my own Tailwind CSS plugin][repo]
-to re-add the `list-reset` class. This way I could keep backwards compatibility
-in my projects and only need to add one class in other future instances.
-
-In this post, I’ll use this as an example to show how to write tests for
-Tailwind CSS plugins with a JavaScript testing framework called [Jest][jest].
-
-More information about plugins for Tailwind CSS themselves can be found on the
-[Tailwind website][tailwind-docs-plugins].
-
-## Add dependencies
-
-To start, we need to include `jest` as a dependency of the plugin, as well as
-`jest-matcher-css` to perform assertions against the CSS that the plugin
-generates.
-
-We also need to add `tailwindcss` and `postcss` so that we can use them within
-the tests.
-
-```plain
-yarn add -D jest jest-matcher-css postcss tailwindcss@next
-```
-
-This could be done with `yarn add` or `npm install`.
-
-## Writing the first test
-
-In this plugin, the tests are going to be added into a new file called
-`test.js`. This file is automatically loaded by Jest based on it’s [testRegex
-setting][jest-testregex-setting].
-
-This is the format for writing test methods:
-
-```js
-test('a description of the test', () => {
- // Perform tasks and write assertions
-});
-```
-
-The first test is to ensure that the correct CSS is generated from the plugin
-using no options.
-
-We do this by generating the plugin’s CSS, and asserting that it matches the
-expected CSS within the test.
-
-```js
-test('it generates the list reset class', () => {
- generatePluginCss().then(css => {
- expect(css).toMatchCss(`
- .list-reset {
- list-style: none;
- padding: 0
- }
- `);
- });
-});
-```
-
-However, there are some additional steps needed to get this working.
-
-### Generating the plugin’s CSS
-
-Firstly, we need to import the plugin’s main `index.js` file, as well as PostCSS
-and Tailwind. This is done at the beginning of the `test.js` file.
-
-```js
-const plugin = require('./index.js');
-const postcss = require('postcss');
-const tailwindcss = require('tailwindcss');
-```
-
-Now we need a way to generate the CSS so assertions can be written against it.
-
-In this case, I’ve created a function called `generatePluginCss` that accepts
-some optional options, processes PostCSS and Tailwind, and returns the CSS.
-
-```js
-const generatePluginCss = (options = {}) => {
- return postcss(tailwindcss())
- .process('@tailwind utilities;', {
- from: undefined,
- })
- .then(result => result.css);
-};
-```
-
-Alternatively, to test the output of a component, `@tailwind utilities;` would
-be replaced with `@tailwind components`.
-
-```js
-.process('@tailwind components;', {
- from: undefined
-})
-```
-
-Whilst `from: undefined` isn’t required, if it’s not included you will get this
-message:
-
-> Without `from` option PostCSS could generate wrong source map and will not
-> find Browserslist config. Set it to CSS file path or to `undefined` to prevent
-> this warning.
-
-### Configuring Tailwind
-
-In order for the plugin to generate CSS, it needs to be enabled within the test,
-and Tailwind’s core plugins need to be disabled so that we can assert against
-just the output from the plugin.
-
-As of Tailwind 1.0.0-beta5, this can be done as follows:
-
-```
-tailwindcss({
- corePlugins: false,
- plugins: [plugin(options)]
-})
-```
-
-In prior versions, each plugin in `corePlugins` needed to be set to `false`
-separately.
-
-I did that using a `disableCorePlugins()` function and [lodash][lodash], using
-the keys from `variants`:
-
-```
-const _ = require('lodash')
-
-// ...
-
-const disableCorePlugins = () => {
- return _.mapValues(defaultConfig.variants, () => false)
-}
-```
-
-### Enabling CSS matching
-
-In order to compare the generated and expected CSS, [the CSS matcher for
-Jest][jest-css-matcher] needs to be required and added using
-[expect.extend][jest-expect-extend].
-
-```js
-const cssMatcher = require('jest-matcher-css')
-
-...
-
-expect.extend({
- toMatchCss: cssMatcher
-})
-```
-
-Without it, you’ll get an error message like _"TypeError: expect(...).toMatchCss
-is not a function"_ when running the tests.
-
-## The next test: testing variants
-
-To test variants we can specify the required variant names within as options to
-`generatePluginCss`.
-
-For example, this is how to enable `hover` and `focus` variants.
-
-```js
-generatePluginCss({ variants: ['hover', 'focus'] });
-```
-
-Now we can add another test that generates the variant classes too, to ensure
-that also works as expected.
-
-```js
-test('it generates the list reset class with variants', () => {
- generatePluginCss({ variants: ['hover', 'focus'] }).then(css => {
- expect(css).toMatchCss(`
- .list-reset {
- list-style: none;
- padding: 0
- }
-
- .hover\\:list-reset:hover {
- list-style: none;
- padding: 0
- }
-
- .focus\\:list-reset:focus {
- list-style: none;
- padding: 0
- }
- `);
- });
-});
-```
-
-## Running tests locally
-
-Now that we have tests, we need to be able to run them.
-
-With Jest included as a dependency, we can update the `test` script within
-`package.json` to execute it rather than returning a stub message.
-
-```diff
-- "test": "echo \"Error: no test specified\" && exit 1"
-+ "test": "jest"
-```
-
-This means that as well as running the `jest` command directly to run the tests,
-we can also run `npm test` or `yarn test`.
-
-After running the tests, Jest will display a summary of the results:
-
-
-
-## Running tests automatically with Travis CI
-
-As well as running the tests locally, they can also be run automatically via
-services like [Travis CI][travis] when a new pull request is submitted or each
-time new commits are pushed.
-
-This is done by adding a `.travis-ci.yml` file to the repository, like this one
-which is based on the [JavaScript and Node.js example][travis-nodejs-example]:
-
-```yml
-language: node_js
-
-node_js:
- - '8'
-
-cache:
- directories:
- - node_modules
-
-before_install:
- - npm update
-
-install:
- - npm install
-
-script:
- - npm test
-```
-
-With this in place, the project can now be enabled on the Travis website, and
-the tests will be run automatically.
-
-For this plugin, you can see the results at
-.
-
-[jest-css-matcher]: https://www.npmjs.com/package/jest-matcher-css
-[jest-expect-extend]: https://jestjs.io/docs/en/expect#expectextendmatchers
-[jest-testregex-setting]:
- https://jestjs.io/docs/en/configuration#testregex-string-array-string
-[jest]: https://jestjs.io
-[lodash]: https://lodash.com
-[repo]: https://github.com/opdavies/tailwindcss-list-reset
-[tailwind-docs-plugins]: https://tailwindcss.com/docs/plugins
-[tailwindcss-interaction-variants]:
- https://www.npmjs.com/package/tailwindcss-interaction-variants
-[travis-nodejs-example]:
- https://docs.travis-ci.com/user/languages/javascript-with-nodejs
-[travis]: https://travis-ci.org
-[working-on-tailwind-video]: https://www.youtube.com/watch?v=SkTKN38wSEM
diff --git a/astro/sculpin-old/source/_posts/thanks.md b/astro/sculpin-old/source/_posts/thanks.md
deleted file mode 100644
index 79bafbcb..00000000
--- a/astro/sculpin-old/source/_posts/thanks.md
+++ /dev/null
@@ -1,15 +0,0 @@
----
-title: Thanks
-date: 2014-05-06
-excerpt:
- Thanks everyone for their comments about my move to the Drupal Association.
-tags:
- - drupal
- - drupal-association
- - personal
----
-
-This is just a quick post to thank everyone for their comments and
-congratulations after my previous post about
-[joining the Drupal Association](/blog/drupal-association/). I’m looking forward
-to my first day in the job tomorrow.
diff --git a/astro/sculpin-old/source/_posts/turning-drupal-module-into-feature.md b/astro/sculpin-old/source/_posts/turning-drupal-module-into-feature.md
deleted file mode 100644
index 43c37706..00000000
--- a/astro/sculpin-old/source/_posts/turning-drupal-module-into-feature.md
+++ /dev/null
@@ -1,35 +0,0 @@
----
-title: Turning Your Custom Drupal Module into a Feature
-date: 2017-05-20
-excerpt: How to turn a custom Drupal module into a Feature.
-tags:
- - drupal
- - drupal-7
- - drupal-planet
- - features
----
-
-Yesterday I was fixing a bug in an inherited Drupal 7 custom module, and I
-decided that I was going to add some tests to ensure that the bug was fixed and
-doesn’t get accidentially re-introduced in the future. The test though required
-me to have a particular content type and fields which are specific to this site,
-so weren’t present within the standard installation profile used to run tests.
-
-I decided to convert the custom module into a [Feature][0] so that the content
-type and it’s fields could be added to it, and therefore present on the testing
-site once the module is installed.
-
-To do this, I needed to expose the module to the Features API.
-
-All that’s needed is to add this line to the `mymodule.info` file:
-
-```language-ini
-features[features_api][] = api:2
-```
-
-After clearing the cache, the module is now visible in the Features list - and
-ready to have the appropriate configuration added to it.
-
-
-
-[0]: https://www.drupal.org/project/features
diff --git a/astro/sculpin-old/source/_posts/tweets-drupalcamp-london.md b/astro/sculpin-old/source/_posts/tweets-drupalcamp-london.md
deleted file mode 100644
index 7508e2ad..00000000
--- a/astro/sculpin-old/source/_posts/tweets-drupalcamp-london.md
+++ /dev/null
@@ -1,71 +0,0 @@
----
-title: Tweets from DrupalCamp London
-date: 2018-03-04
-excerpt:
- I wasn’t able to make it to DrupalCamp London, but here are some of the tweets
- that I saw.
-tags:
- - drupal
- - drupalcamp
- - drupalcamp-london
-has_tweets: true
----
-
-In the end, I wasn’t able to make it to DrupalCamp London because of the heavy
-snow that’s hit the UK over the last few days. I did though keep a close eye on
-Twitter and still had good conversations with some of the attendees, so it did
-feel that in some ways I was still part of the conference.
-
-Thanks to [@ChandeepKhosa](https://twitter.com/ChandeepKhosa),
-[@OrangePunchUK](https://twitter.com/OrangePunchUK),
-[@hussainweb](https://twitter.com/hussainweb),
-[@littlepixiez](https://twitter.com/littlepixiez),
-[@cferthorney](https://twitter.com/cferthorney) and others for taking the time
-to tweet whilst enjoying the event.
-
-Here are some of my favourites that I saw, and no snow next year, please!
-
-
This weekend at @DrupalCampLDN will be 5 years since my 1st #Drupal conference. It was life-changing, leading to travel across Europe learning, being inspired & speaking at 25 others. Thanks everyone who helped shape my journey, see you soon! #DCLondonpic.twitter.com/BeulE0XqET
A great weekend. Thanks to the organisers for putting on a great show. Thanks to @ReasonDigital for sending me. Lots of new stuff to try out on Monday! https://t.co/Xxvl7ZYcqj
A huge huge huge thank you to all our sponsors, speakers, volunteers, attendees and everyone else involved in that Camp. It was a fantastic weekend! Look out for the post Camp Survey and more! #DCLondon
diff --git a/astro/sculpin-old/source/_posts/updating-features-and-adding-components-using-drush.md b/astro/sculpin-old/source/_posts/updating-features-and-adding-components-using-drush.md
deleted file mode 100644
index 8c5c4dcd..00000000
--- a/astro/sculpin-old/source/_posts/updating-features-and-adding-components-using-drush.md
+++ /dev/null
@@ -1,74 +0,0 @@
----
-title: Updating Features and Adding Components Using Drush
-date: 2014-10-21
-excerpt: How to update features on the command line using Drush.
-tags:
- - drupal
- - drupal-planet
- - drush
- - features
----
-
-If you use the [Features module](http://drupal.org/project/features) to manage
-your Drupal configuration, it can be time consuming to update features through
-the UI, especially if you are working on a remote server and need to keep
-downloading and uploading files.
-
-If you re-create a feature through the UI, you'll be prompted to download a new
-archive of the feature in its entirety onto your local computer. You could
-either commit this into a local repository and then pull it remotely, or use a
-tool such as SCP to upload the archive onto the server and commit it from there.
-You can simplify this process by using [Drush](http://drush.org).
-
-## Finding Components
-
-To search for a component, use the `drush features-components` command. This
-will display a list of all components on the site. As we're only interested in
-components that haven't been exported yet, add the `--not-exported` option to
-filter the results.
-
-To filter further, you can also use the `grep` command to filter the results.
-For example, `drush features-components --not-exported field_base | grep foo`,
-would only return non-exported field bases containing the word "foo".
-
-The result is a source and a component, separated by a colon. For example,
-`field_base:field_foo`.
-
-## Exporting the Feature
-
-Once you have a list of the components that you need to add, you can export the
-feature. This is done using the `drush features-export` command, along with the
-feature name and the component names.
-
-For example:
-
-```language-bash
-$ drush features-export -y myfeature field_base:field_foo field_instance:user-field_foo
-```
-
-In this example, the base for field_boo and it's instance on the user object is
-being added to the "myfeature" feature.
-
-If you are updating an existing feature, you'll get a message informing you that
-the module already exists and asking if you want to continue. This is fine, and
-is automatically accepted by including `-y` within the command. If a feature
-with the specified name doesn't exist, it will be created.
-
-If you're creating a new feature, you can define where the feature will be
-created using the `--destination` option.
-
-Once complete, you will see a confirmation message.
-
-> Created module: my feature in sites/default/modules/custom/features/myfeature
-
-## The Result
-
-Once finished, the feature is updated in it's original location, so there's no
-download of the feature and then needing to re-upload it. You can add and commit
-your changes into Git or continue with your standard workflow straight away.
-
-## Useful Links
-
-- [The Features project page on Drupal.org](http://www.drupal.org/project/features)
-- [The "drush features-components" command](http://www.drushcommands.com/drush-6x/features/features-components)
-- [The "drush features-export" command](http://www.drushcommands.com/drush-6x/features/features-export)
diff --git a/astro/sculpin-old/source/_posts/updating-forked-github-repos.md b/astro/sculpin-old/source/_posts/updating-forked-github-repos.md
deleted file mode 100644
index 31cabd25..00000000
--- a/astro/sculpin-old/source/_posts/updating-forked-github-repos.md
+++ /dev/null
@@ -1,123 +0,0 @@
----
-title: Updating Forked Repositories on GitHub
-date: 2015-06-18
-excerpt:
- I just had to update a repo that I forked on GitHub. This is how I did it. Did
- I do it the correct way?
-tags:
- - git
- - github
- - phpstorm
- - sculpin
----
-
-I just had to update a repo that I forked on GitHub. This is how I did it. Did I
-do it the correct way?
-
-## Sculpin
-
-People may or may not know, but this site runs on
-[Sculpin](https://sculpin.io/), a PHP based static site generator (this may be
-the first time that I've mentioned it on this site). The source code is hosted
-on [GitHub](https://github.com/opdavies/oliverdavies.uk), and I've listed the
-site on the [Community page](https://sculpin.io/community/) on the Sculpin
-website.
-
-To get it there, I forked the
-[main sculpin.io repository](https://github.com/sculpin/sculpin.io) so that I
-had [my own copy](https://github.com/opdavies/sculpin.io), created a branch,
-made my additions and submitted a pull request. Easy enough!
-
-## New Domain
-
-In the last week or so, I've changed this site URL from .co.uk to just .uk, and
-also updated the GitHub repo URL to match, so I wanted to update the Community
-page to use the correct URL.
-
-There had been commits to the main repo since my pull request was merged, I
-didn't want to delete my repo and fork again, and making any changes against and
-old codebase isn't best practice, so I wanted to merge the latest changes into
-my forked repo before I did anything else - just to check that I didn't break
-anything!
-
-## Updating my Local Repo
-
-I had a quick look for a _Update my fork_ button or something, but couldn't see
-one to I added the main repository as an additional remote called `upstream` and
-fetched the changes.
-
-```language-bash
-$ git remote add upstream https://github.com/sculpin/sculpin.io.git
-
-$ git fetch upstream
-remote: Counting objects: 33, done.
-remote: Total 33 (delta 6), reused 6 (delta 6), pack-reused 27
-Unpacking objects: 100% (33/33), done.
-From https://github.com/sculpin/sculpin.io
-* [new branch] master -> upstream/master
-* [new branch] pr/4 -> upstream/pr/4
-```
-
-Now my local site knows about the upstream repo, and I could rebase the changes
-(`git pull upstream master` should have worked too) and push them back to
-origin.
-
-```language-bash
-$ git rebase upstream/master
-First, rewinding head to replay your work on top of it...
-...
-Fast-forwarded master to upstream/master.
-
-$ git push origin master
-```
-
-This seems to have worked OK - the commits are still authored by the correct
-people and at the correct date and time - and I went ahead and created a new
-feature branch and pull request based on that master branch.
-
-{% include 'figure' with {
- image: {
- src: '/images/blog/forked-github-repo-commits.png',
- alt: 'The commits on my master branch after rebasing',
- },
- caption: 'The commits on my forked master branch after rebasing and pushing. All good!',
-} %}
-
-{% include 'figure' with {
- image: {
- src: '/images/blog/my-commit-to-the-rebased-branch.png',
- alt: 'The new feature branch with my additional commit',
- },
- caption: 'The new feature branch with the new commit.',
-} %}
-
-## Is There a Better Way?
-
-Did I miss something? Is there a recommended and/or better way to update your
-forked repos, maybe through the UI? Please
-send
-me a tweet with any comments.
-
-## Up
-
-**December 2015:** I’ve found that PhpStorm has an option available to rebase a
-fork from within the IDE. This is within the _VCS_ > _Git_ menu.
-
-I believe that it will use an existing "upstream" remote if it exists, otherwise
-it will add one automatically for you, linking to the repository that you forked
-from.
-
-Once you’ve completed the rebase, you can then push your updated branch either
-from the terminal, or using the _Push_ command from the same menu.
-
-
-
-It would be great to see something similar added to
-[hub](https://hub.github.com) too (I’ve created
-[an issue](https://github.com/github/hub/issues/1047))!
-
-## Resources
-
-- [PhpStorm - Advanced GitHub Integration: Rebase My GitHub Fork (blog post)](http://blog.jetbrains.com/idea/2011/02/advanced-github-integration-rebase-my-github-fork/)
-- [Rebasing a GitHub fork inside PhpStorm (video)](https://www.youtube.com/watch?v=Twy-dhVgN4k)
-- [hub](https://hub.github.com) - makes Git better with GitHub
diff --git a/astro/sculpin-old/source/_posts/updating-override-node-options-tests.md b/astro/sculpin-old/source/_posts/updating-override-node-options-tests.md
deleted file mode 100644
index 81d8b81d..00000000
--- a/astro/sculpin-old/source/_posts/updating-override-node-options-tests.md
+++ /dev/null
@@ -1,239 +0,0 @@
----
-title: Updating Override Node Options Tests
-date: 2017-05-05
-excerpt: ~
-tags:
- - drupal
- - drupal-modules
- - drupal-planet
- - testing
-draft: true
----
-
-Recently, I reviewed [a patch][1] in the [Override Node Options][2] module issue
-queue. For those not familiar with it, the module adds extra permissions for
-node options like "authored by" and "published on" which are normally only
-available to users with the `administer nodes` permission. What the patch does
-is to optionally add another set of permissions that enable options for all
-content types - e.g. "override published option for all node types", in addition
-to or instead of the content type specific ones.
-
-It was quite an old issue and the latest patch needed to be re-rolled due to
-merge conflicts, but the existing tests still passed. Though as no new tests
-were added for the new functionality, these needed to be added before I
-committed it.
-
-## Reviewing the Existing Tests
-
-The first thing to do was to run the existing tests and check that they still
-passed. I do this on the command line by typing
-`php scripts/run-tests.sh --class OverrideNodeOptionsTestCase`.
-
-```language-markup
-Drupal test run
----------------
-
-Tests to be run:
- - Override node options (OverrideNodeOptionsTestCase)
-
-Test run started:
- Saturday, April 29, 2017 - 14:44
-
-Test summary
-------------
-
-Override node options 142 passes, 0 fails, 0 exceptions, and 38 debug messages
-
-Test run duration: 32 sec
-```
-
-After confirming that the existing tests still passed, I reviewed them to see
-what could be re-used.
-
-This is one of the original tests:
-
-```language-php
-/**
- * Test the 'Authoring information' fieldset.
- */
-protected function testNodeOptions() {
- $this->adminUser = $this->drupalCreateUser(array(
- 'create page content',
- 'edit any page content',
- 'override page published option',
- 'override page promote to front page option',
- 'override page sticky option',
- 'override page comment setting option',
- ));
- $this->drupalLogin($this->adminUser);
-
- $fields = array(
- 'status' => (bool) !$this->node->status,
- 'promote' => (bool) !$this->node->promote,
- 'sticky' => (bool) !$this->node->sticky,
- 'comment' => COMMENT_NODE_OPEN,
- );
- $this->drupalPost('node/' . $this->node->nid . '/edit', $fields, t('Save'));
- $this->assertNodeFieldsUpdated($this->node, $fields);
-
- $this->drupalLogin($this->normalUser);
- $this->assertNodeFieldsNoAccess($this->node, array_keys($fields));
-}
-```
-
-The first part of the test is creating and logging in a user with some content
-type specific override permissions (`$this->adminUser`), and then testing that
-the fields were updated when the node is saved. The second part is testing that
-the fields are not visible for a normal user without the extra permissions
-(`$this->normalUser`), which is created in the `setUp()` class' method.
-
-To test the new "all types" permissions, I created another user to test against
-called `$generalUser` and run the first part of the tests in a loop.
-
-## Beginning to Refactor the Tests
-
-With the tests passing, I was able to start refactoring.
-
-```language-php
-// Create a new user with content type specific permissions.
-$specificUser = $this->drupalCreateUser(array(
- 'create page content',
- 'edit any page content',
- 'override page published option',
- 'override page promote to front page option',
- 'override page sticky option',
- 'override page comment setting option',
-));
-
-foreach (array($specificUser) as $account) {
- $this->drupalLogin($account);
-
- // Test all the things.
- ...
-}
-```
-
-I started with a small change, renaming `$this->adminUser` to `$specificUser` to
-make it clearer what permissions it had, and moving the tests into a loop so
-that the tests can be repeated for both users.
-
-After that change, I ran the tests again to check that everything still worked.
-
-## Adding Failing Tests
-
-The next step is to start testing the new permissions.
-
-```language-php
-...
-
-$generalUser = $this->drupalCreateUser(array());
-
-foreach (array($specificUser, $generalUser) as $account) {
- $this->drupalLogin($account);
-
- // Test all the things.
-}
-```
-
-I added a new `$generalUser` to test the general permissions and added to the
-loop, but in order to see the tests failing intially I assigned it no
-permissions. When running the tests again, 6 tests have failed.
-
-```language-markup
-Test summary
-------------
-
-Override node options 183 passes, 6 fails, 0 exceptions, and 49 debug messages
-
-Test run duration: 28 sec
-```
-
-Then it was a case of re-adding more permissions to the user and seeing the
-number of failures decrease, confirming that the functionality was working
-correctly.
-
-TODO: Add another example.
-
-## Gotchas
-
-There was a bug that I found where a permission was added, but wasn't used
-within the implementation code. After initially expecting the test to pass after
-adding the permission to `$generalUser` and the test still failed, I noticed
-that the
-
-This was fixed by adding the extra code into `override_node_options.module`.
-
-```language-diff
-- $form['comment_settings']['#access'] |= user_access('override ' . $node->type . ' comment setting option');
-+ $form['comment_settings']['#access'] |= user_access('override ' . $node->type . ' comment setting option') || user_access('override all comment setting option');
-```
-
-The other issue that I found was within `testNodeRevisions`.
-`assertNodeFieldsUpdated()` was failing after being put in a loop as the `vid`
-was not the same as what was expected.
-
-Note: You can get more verbose output from `run-tests.sh` by adding the
-`--verbose` option.
-
-> Node vid was updated to '3', expected 2.
-
-```language-diff
-- $fields = array(
-- 'revision' => TRUE,
-- );
-- $this->drupalPost('node/' . $this->node->nid . '/edit', $fields, t('Save'));
-- $this->assertNodeFieldsUpdated($this->node, array('vid' => $this->node->vid + 1));
-+ $generalUser = $this->drupalCreateUser(array(
-+ 'create page content',
-+ 'edit any page content',
-+ 'override all revision option',
-+ ));
-+
-+ foreach (array($specificUser, $generalUser) as $account) {
-+ $this->drupalLogin($account);
-+
-+ // Ensure that we have the latest node data.
-+ $node = node_load($this->node->nid, NULL, TRUE);
-+
-+ $fields = array(
-+ 'revision' => TRUE,
-+ );
-+ $this->drupalPost('node/' . $node->nid . '/edit', $fields, t('Save'));
-+ $this->assertNodeFieldsUpdated($node, array('vid' => $node->vid + 1));
-+ }
-```
-
-The crucial part of this change was the addition of
-`$node = node_load($this->node->nid, NULL, TRUE);` to ensure that the latest
-version of the node was loaded during each loop.
-
-## Conclusion
-
-- Ensure that the existing tests were passing before starting to refactor.
-- Start with small changes and continue to run the tests to ensure that nothing
- has broken.
-- After the first change, I committed it as `WIP: Refactoring tests`, and used
- `git commit --amend --no-edit` to amend that commit each time I had refactored
- another test. After the last refactor, I updated the commit message.
-- It’s important to see tests failing before making them pass. This was achieved
- by initially assigning no permissions to `$generalUser` so that the fails
- failed and then added permissions and re-run the tests to ensure that the
- failure count decreased with each new permission.
-
-With the refactoring complete, the number of passing tests increased from 142
-to 213.
-
-```language-markup
-Override node options 213 passes, 0 fails, 0 exceptions, and 60 debug messages
-
-Test run duration: 25 sec
-```
-
-
-
-[Here][3] are my full changes from the previous patch, where I added the new
-tests as well as some small refactors.
-
-[1]: https://www.drupal.org/node/974730
-[2]: https://www.drupal.org/project/override_node_options
-[3]: https://www.drupal.org/files/issues/interdiff_25712.txt
diff --git a/astro/sculpin-old/source/_posts/use-authorized-keys-create-passwordless-ssh-connection.md b/astro/sculpin-old/source/_posts/use-authorized-keys-create-passwordless-ssh-connection.md
deleted file mode 100644
index c445bb7a..00000000
--- a/astro/sculpin-old/source/_posts/use-authorized-keys-create-passwordless-ssh-connection.md
+++ /dev/null
@@ -1,35 +0,0 @@
----
-title: How to use Authorized Keys to Create a Passwordless SSH Connection
-date: 2012-02-01
-excerpt:
- How to generate a SSH key, and how to use to log in to a server using SSH
- without entering a password.
-tags:
- - linux
- - ssh
----
-
-If you're accessing Linux servers or automating tasks between servers, rather
-than having to enter your user password every time, you can also use SSH public
-key authentication. This is a simple process that involves creating a local key
-and storing it within the _authorized_keys_ file on the remote server.
-
-1. Check if you already have a SSH key. `$ ssh-add -L`
-1. If you don't have one, create one. `$ ssh-keygen`
-1. Upload the key onto the server. Replace _myserver_ with the hostname or IP
- address of your remote server. `$ ssh-copy-id myserver`
-
-If you're using Mac OS X and you don't have ssh-copy-id installed, download and
-install [Homebrew](http://mxcl.github.com/homebrew 'Homebrew') and run the
-`brew install ssh-copy-id` command.
-
-If successful, you should now see a message like:
-
-> Now try logging into the machine, with "ssh 'myserver'", and check in:
->
-> ~/.ssh/authorized_keys
->
-> to make sure we haven't added extra keys that you weren't expecting.
-
-Now the next time that you SSH onto the server, it should log you in without
-prompting you for your password.
diff --git a/astro/sculpin-old/source/_posts/use-regular-expressions-search-and-replace-coda-or-textmate.md b/astro/sculpin-old/source/_posts/use-regular-expressions-search-and-replace-coda-or-textmate.md
deleted file mode 100644
index 4079acba..00000000
--- a/astro/sculpin-old/source/_posts/use-regular-expressions-search-and-replace-coda-or-textmate.md
+++ /dev/null
@@ -1,57 +0,0 @@
----
-title: Use Regular Expressions to Search and Replace in Coda or TextMate
-date: 2010-11-04
-excerpt: How to perform searches using regular expressions.
-tags:
- - taxonomy
- - sequel-pro
- - database
- - coda
- - regular-expression
- - textmate
----
-
-As in
-[the original post](/blog/add-taxonomy-term-multiple-nodes-using-sql/ 'Quickly adding a taxonomy term to multiple nodes using SQL'),
-I'd generated a list of node ID values, and needed to add structure the SQL
-update statment formatted in a certain way. However, I changed my inital query
-slightly to out put the same nid value twice.
-
-```language-sql
-SELECT nid, nid FROM node WHERE TYPE = 'blog' ORDER BY nid ASC;
-```
-
-Then, I could select all of the returned rows, copy the values, and paste them
-into Coda:
-
-As before, I needed my SQL update statement to be in the following format:
-
-```language-sql
-INSERT INTO term_node VALUE (nid, vid, tid), (nid2, vid2, tid);
-```
-
-As I mentioned previously, the nid and vid values are the same for each node,
-and the tid will remain constant. In this case, the tid value that I needed to
-use was '63'.
-
-So, using the 'Find and Replace' function within Coda, combined with
-[regular expressions](http://en.wikipedia.org/wiki/Regular_expression) (regex),
-I can easily format the values as needed. To begin with, I need to ensure that
-the RegEx search option is enabled, and that I'm using the correct escape
-character.
-
-The first thing that I wanted to do was add the seperating comma between the two
-values. To do this, I perform a search for `\s*\t`. This searches for everything
-that is whitespace AND is a tab value. I can then add the comma as the
-replacement for each result.
-
-All 31 lines have been changed.
-
-Next, I can use `\n` to target the lines between the rows. I'll replace it with
-the next comma, the number 63 (the tid value), the closing bracket, another
-comma, re-add the line and add the opening bracket.
-
-The only two lines that aren't changed are the first and last, as they don't
-have any line breaks following them. I can complete these lines manually. Now
-all I need to do is add the beginning of the SQL update statement, then copy and
-paste it into Sequel Pro.
diff --git a/astro/sculpin-old/source/_posts/use-sass-and-compass-drupal-7-using-sassy.md b/astro/sculpin-old/source/_posts/use-sass-and-compass-drupal-7-using-sassy.md
deleted file mode 100644
index 05bfde55..00000000
--- a/astro/sculpin-old/source/_posts/use-sass-and-compass-drupal-7-using-sassy.md
+++ /dev/null
@@ -1,80 +0,0 @@
----
-title: How to use SASS and Compass in Drupal 7 using Sassy
-date: 2012-12-06
-excerpt:
- Use PHPSass and the Sassy module to use Sass and Compass in your Drupal theme.
-tags:
- - compass
- - css
- - drupal
- - drupal-7
- - drupal-planet
- - less
- - preprocessing
- - sass
----
-
-I've recently started using [SASS](http://sass-lang.com) rather than LESS to do
-my CSS preprocessing - namely due to its integration with
-[Compass](http://compass-style.org) and it's built-in CSS3 mixins. Here are
-three modules that provide the ability to use SASS within Drupal.
-
-- [Sassy](http://drupal.org/project/sassy 'Sassy module on drupal.org')
-- [Prepro](http://drupal.org/project/prepro 'Prepro module on drupal.org')
-- [Libraries API](http://drupal.org/project/libraries 'Libraries API module on drupal.org')
-
-Alternatively, you could use a base theme like
-[Sasson](http://drupal.org/project/sasson 'Sasson theme on drupal.org') that
-includes a SASS compiler.
-
-## Download the PHPSass Library
-
-The first thing to do is download the PHPSass library from
-[GitHub](https://github.com/richthegeek/phpsass 'PHPSass on GitHub'), as this is
-a requirement of the Sassy module and we can't enable it without the library.
-So, in a Terminal window:
-
-```language-bash
-$ mkdir -p sites/all/libraries;
-$ cd sites/all/libraries;
-$ wget https://github.com/richthegeek/phpsass/archive/master.tar.gz;
-$ tar zxf master.tar.gz;
-$ rm master.tar.gz;
-$ mv phpsass-master/ phpsass
-```
-
-Or, if you're using Drush Make files:
-
-```language-ini
-libraries[phpsass][download][type] = "get"
-libraries[phpsass][download][url] = "https://github.com/richthegeek/phpsass/archive/master.tar.gz"
-```
-
-The PHPSass library should now be located at `sites/all/libraries/phpsass`.
-
-## Download and enable the Drupal modules
-
-This is easy if you use [Drush](http://drupal.org/project/drush):
-
-```language-bash
-$ drush dl libraries prepro sassy
-$ drush en -y libraries prepro sassy sassy_compass
-```
-
-Otherwise, download the each module from it's respective project page and place
-it within your `sites/all/modules` or `sites/all/modules/contrib` directory.
-
-## Configuring the Prepro module
-
-The Prepro module provides various settings that can be changed for each
-preprocessor. Go to `admin/config/media/prepro` to configure the module as
-required.
-
-Personally, in development, I'd set caching to 'uncached' and the error
-reporting method to 'show on page'. In production, I'd change these to "cached"
-and "watchdog" respectively. I'd also set the output style to "compressed",
-
-## Adding SASS files into your theme
-
-With this done, you can now add SASS and SCSS files by adding a line like
-`stylesheets[all][] = css/base.scss` in your theme's .info file.
diff --git a/astro/sculpin-old/source/_posts/useful-drupal-6-modules.md b/astro/sculpin-old/source/_posts/useful-drupal-6-modules.md
deleted file mode 100644
index 966570ac..00000000
--- a/astro/sculpin-old/source/_posts/useful-drupal-6-modules.md
+++ /dev/null
@@ -1,58 +0,0 @@
----
-title: 10 Useful Drupal 6 Modules
-date: 2010-06-25
-excerpt:
- A list of 10 contributed modules that I currently use on each Drupal project.
-tags:
- - drupal-planet
- - drupal-6
- - drupal
- - drupal-modules
----
-
-Aside from the obvious candidates such as Views, CCK etc, here are a list of 10
-contributed modules that I currently use on each Drupal project.
-
-So, in no particular order:
-
-- **[Admin](http://drupal.org/project/admin):** The admin module provides UI
- improvements to the standard Drupal admin interface. I've just upgraded to the
- new [6.x-2.0-beta4](http://drupal.org/node/835870) version, and installed the
- newly-required
- [Rubik](http://code.developmentseed.org/rubik)/[Tao](http://code.developmentseed.org/tao)
- themes. So far, so good!
-- **[Better Permissions](http://drupal.org/project/better_perms)/[Filter Permissions](http://drupal.org/project/filter_perms):
- **Basic permissions is a basic module which enhances the Drupal
- Permissions page to support collapsing and expanding permission rows. Filter
- permissions provides filters at the top of the Permissions page for easier
- management when your site has a large amount of roles and/or permissions.
-- **[Better Formats](http://drupal.org/project/better_formats): **Better
- formats is a module to add more flexibility to Drupal's core input format
- system.
-- **[Clone module](http://drupal.org/project/node_clone):** Allows users to
- make a copy of an existing item of site content (a node) and then edit that
- copy.
-- **[Vertical Tabs](http://drupal.org/project/vertical_tabs): **Integrated
- into Drupal 7 core, this module adds vertical tabs to the node add and edit
- forms.
-- **[Context](http://drupal.org/project/context): **Context allows you to
- manage contextual conditions and reactions for different portions of your
- site. You can think of each context as representing a "section" of your site.
- For each context, you can choose the conditions that trigger this context to
- be active and choose different aspects of Drupal that should react to this
- active context.
-- **[Node Picker](http://drupal.org/project/nodepicker):** A rewrite of the
- module [TinyMCE Node Picker](http://drupal.org/project/tinymce_node_picker).
- Allows you to easily create links to internal nodes.
-- **[Module Filter](http://drupal.org/project/module_filter):** What this
- module aims to accomplish is the ability to quickly find the module you are
- looking for without having to rely on the browsers search feature which more
- times than not shows you the module name in the 'Required by' or 'Depends on'
- sections of the various modules or even some other location on the page like a
- menu item.
-- **[Zenophile](http://drupal.org/project/zenophile):** Quickly create Zen
- subthemes.
-- **[Add Another](http://drupal.org/project/addanother):** Add another
- displays a message after a user creates a node, and/or displays an "Add
- another" tab on nodes allowing them to make another node of the same type. You
- can control what roles and node types see this feature.
diff --git a/astro/sculpin-old/source/_posts/useful-vagrant-commands.md b/astro/sculpin-old/source/_posts/useful-vagrant-commands.md
deleted file mode 100644
index a8aefba0..00000000
--- a/astro/sculpin-old/source/_posts/useful-vagrant-commands.md
+++ /dev/null
@@ -1,26 +0,0 @@
----
-title: Useful Vagrant Commands
-date: 2013-11-27
-excerpt:
- Here are the basic commands that you need to adminster a virtual machine using
- Vagrant.
-tags:
- - vagrant
----
-
-[Vagrant](http://www.vagrantup.com 'About Vagrant') is a tool for managing
-virtual machines within [VirtualBox](https://www.virtualbox.org) from the
-command line. Here are some useful commands to know when using Vagrant.
-
-| Command | Description |
-| :--------------------------- | :----------------------------------------------------------------------------------------------------------- |
-| vagrant init {box} | Initialise a new VM in the current working directory. Specify a box name, or "base" will be used by default. |
-| vagrant status | Shows the status of the Vagrant box(es) within the current working directory tree. |
-| vagrant up (--provision) | Boots the Vagrant box. Including "–provision" also runs the "vagrant provision" command. |
-| vagrant reload (--provision) | Reloads the Vagrant box. Including "--provision" also runs the "vagrant provision" command. |
-| vagrant provision | Provision the Vagrant box using Puppet. |
-| vagrant suspend | Suspend the Vagrant box. Use "vagrant up" to start the box again. |
-| vagrant halt (-f) | Halt the Vagrant box. Use -f to forcefully shut down the box without prompting for confirmation. |
-| vagrant destroy (-f) | Destroys a Vagrant box. Use -f to forcefully shut down the box without prompting for confirmation. |
-
-The full Vagrant documentation can be found at .
diff --git a/astro/sculpin-old/source/_posts/using-environment-variables-settings-docksal.md b/astro/sculpin-old/source/_posts/using-environment-variables-settings-docksal.md
deleted file mode 100644
index d60999bc..00000000
--- a/astro/sculpin-old/source/_posts/using-environment-variables-settings-docksal.md
+++ /dev/null
@@ -1,92 +0,0 @@
----
-title: How to Use Environment Variables for your Drupal Settings with Docksal
-date: 2018-06-04
-excerpt: How to leverage environment variables with Drupal and Docksal.
-tags:
- - drupal
- - drupal-planet
- - docksal
----
-
-Within the [Docksal documentation for Drupal settings][0], the example database
-settings include hard-coded credentials to connect to the Drupal database. For
-example, within a `settings.php` file, you could add this:
-
-```language-php
-$databases['default']['default'] = [
- 'driver' => 'mysql',
- 'host' => 'db',
- 'database' => 'myproject_db',
- 'username' => 'myproject_user',
- 'password' => 'myproject_pass',
-];
-```
-
-Whilst this is fine, it does mean that there is duplication in the codebase as
-the database credentials can also be added as environment variations within
-`.docksal/docksal.env` - this is definitely the case if you want to use a custom
-database name, for example.
-
-Also if one of these values were to change, then Drupal wouldn't be aware of
-that and would no longer be able to connect to the database.
-
-It also means that the file can’t simply be re-used on another project as it
-contains project-specific credentials.
-
-We can improve this by using the environment variables within the settings file.
-
-The relevant environment variables are `MYSQL_DATABASE` for the database name,
-and `MYSQL_USER` and `MYSQL_PASSWORD` for the MySQL username and password. These
-can be set in `.docksal/docksal.env`, and will need to be present for this to
-work.
-
-For example:
-
-```
-DOCKSAL_STACK=default
-MYSQL_DATABASE=myproject_db
-MYSQL_USER=myproject_user
-MYSQL_PASSWORD=myproject_pass
-```
-
-With these in place, they can be referenced within the settings file using the
-`getenv()` function.
-
-```
-$databases['default']['default'] = [
- 'driver' => 'mysql',
- 'host' => 'db',
- 'database' => getenv('MYSQL_DATABASE'),
- 'username' => getenv('MYSQL_USER'),
- 'password' => getenv('MYSQL_PASSWORD'),
-];
-```
-
-Now the credentials are no longer duplicated, and the latest values from the
-environment variables will always be used.
-
-However, you may see a message like this when you try and load the site:
-
-> Drupal\Core\Database\DatabaseAccessDeniedException: SQLSTATE[HY000][1045]
-> Access denied for user ''@'172.19.0.4' (using password: NO) in
-> /var/www/core/lib/Drupal/Core/Database/Driver/mysql/Connection.php on line 156
-
-If you see this, the environment variables aren’t being passed into Docksal’s
-`cli` container, so the values are not being populated. To enable them, edit
-`.docksal/docksal.yml` and add `MYSQL_DATABASE`, `MYSQL_PASSWORD` and
-`MYSQL_USER` to the `environment` section of the `cli` service.
-
-```language-yml
-version: '2.1'
-services:
- cli:
- environment:
- - MYSQL_DATABASE
- - MYSQL_PASSWORD
- - MYSQL_USER
-```
-
-After changing this file, run `fin start` to rebuild the project containers and
-try to load the site again.
-
-[0]: https://docksal.readthedocs.io/en/master/advanced/drupal-settings
diff --git a/astro/sculpin-old/source/_posts/using-feature-flags-in-drupal-development.md b/astro/sculpin-old/source/_posts/using-feature-flags-in-drupal-development.md
deleted file mode 100644
index 235d7bab..00000000
--- a/astro/sculpin-old/source/_posts/using-feature-flags-in-drupal-development.md
+++ /dev/null
@@ -1,9 +0,0 @@
----
-title: Using feature flags in Drupal development
-excerpt: Different ways of using feature flags witin Drupal development
-date: 2020-03-31
-tags: [drupal, drupal-7, drupal-8, php]
-draft: true
----
-
-TODO.
diff --git a/astro/sculpin-old/source/_posts/using-imagecache-and-imagecrop-my-portfolio.md b/astro/sculpin-old/source/_posts/using-imagecache-and-imagecrop-my-portfolio.md
deleted file mode 100644
index b7f87955..00000000
--- a/astro/sculpin-old/source/_posts/using-imagecache-and-imagecrop-my-portfolio.md
+++ /dev/null
@@ -1,45 +0,0 @@
----
-title: Using ImageCache and ImageCrop for my Portfolio
-date: 2010-04-28
-excerpt:
- How to create thumbnail images using the ImageCache and ImageCrop modules.
-tags:
- - drupal
- - drupal-6
- - cck
- - imagecache
- - imagecrop
- - imagefield
----
-
-Whilst working on my own portfolio/testimonial website, I decided to have a
-portfolio page displaying the name of each site and a thumbnail image. For this
-Blog post, I'll be using a site called
-[Popcorn Strips](http://popcornstrips.com) which I built for a friend earlier
-this year as an example.
-
-I created a content type called 'Project' with a CCK ImageField called
-'Screenshot'. I created a project called
-[Popcorn Strips](http://popcornstrips.com), used the
-[ScreenGrab](https://addons.mozilla.org/addon/1146) add-on for Mozilla Firefox
-to take a screenshot of the website, and uploaded it to the project node.
-
-I created a View to display the published projects, and an ImageCache preset to
-create the thumbnail image by scaling and cropping the image to a size of
-200x100 pixels.
-
-Although, this automatically focused the crop on the centre of the image,
-whereas I wanted to crop from the top and left of the image - showing the site's
-logo and header.
-
-I installed the [ImageCrop](http://drupal.org/project/imagecrop) module, which
-add a jQuery crop function to the standard ImageCache presents. I removed the
-original Scale and Crop action and replaced it with a Scale action with a width
-of 200px.
-
-I then added a new 'Javascript crop' action with the following settings:
-
-- Width: 200px
-- Height: 100px
-- xoffset: Left
-- yoffset: Top
diff --git a/astro/sculpin-old/source/_posts/using-remote-files-when-developing-locally-stage-file-proxy-module.md b/astro/sculpin-old/source/_posts/using-remote-files-when-developing-locally-stage-file-proxy-module.md
deleted file mode 100644
index cf0d0d29..00000000
--- a/astro/sculpin-old/source/_posts/using-remote-files-when-developing-locally-stage-file-proxy-module.md
+++ /dev/null
@@ -1,39 +0,0 @@
----
-title: Using Remote Files when Developing Locally with Stage File Proxy Module
-date: 2014-11-20
-excerpt:
- How to install and configure the Stage File Proxy module to serve remote
- images on your local Drupal site.
-tags:
- - drupal
- - drupal-planet
- - servers
----
-
-How to install and configure the
-[Stage File Proxy](https://www.drupal.org/project/stage_file_proxy) module to
-serve remote images on your local Drupal site.
-
-As this module is only going to be needed on pre-production sites, it would be
-better to configure this within your settings.php or settings.local.php file. We
-do this using the `$conf` array which removes the need to configure the module
-through the UI and store the values in the database.
-
-```language-php
-// File proxy to the live site.
-$conf['stage_file_proxy_origin'] = 'http://www.example.com';
-
-// Don't copy the files, just link to them.
-$conf['stage_file_proxy_hotlink'] = TRUE;
-
-// Image style images are the wrong size otherwise.
-$conf['stage_file_proxy_use_imagecache_root'] = FALSE;
-```
-
-If the origin site is not publicly accessible yet, maybe it's a pre-live or
-staging site, and protected with a basic access authentication, you can include
-the username and password within the origin URL.
-
-```language-php
-$conf['stage_file_proxy_origin'] = 'http://user:password@prelive.example.com';
-```
diff --git a/astro/sculpin-old/source/_posts/using-tailwind-css-in-your-drupal-theme.md b/astro/sculpin-old/source/_posts/using-tailwind-css-in-your-drupal-theme.md
deleted file mode 100644
index 6ca5a7c2..00000000
--- a/astro/sculpin-old/source/_posts/using-tailwind-css-in-your-drupal-theme.md
+++ /dev/null
@@ -1,112 +0,0 @@
----
-title: Using Tailwind CSS in your Drupal Theme
-date: 2018-02-05
-excerpt: What is Tailwind CSS, and how do I use it in Drupal theme?
-tags:
- - drupal
- - drupal-planet
- - drupal-theming
- - tailwind-css
----
-
-## What is Tailwind?
-
-> Tailwind is a utility-first CSS framework for rapidly building custom user
-> interfaces.
-
-It generates a number of utility classes that you can add to your theme's markup
-to apply different styling, as well as the ability to apply classes to other
-markup and create components comprised of utility classes using a custom
-`@apply` PostCSS directive.
-
-## Initial Configuration
-
-The installation and configuration steps are essentially the same as those
-outlined within the [Tailwind documentation][1], and should be performed within
-your custom theme's directory (e.g. `sites/all/themes/custom/mytheme` for Drupal
-7 or `themes/custom/mytheme` for Drupal 8:
-
-1. Require PostCSS and Tailwind via `npm` or `yarn`.
-1. Generate a configuration file using `./node_modules/.bin/tailwind init`.
-1. Tweak the settings as needed.
-1. Add a `postcss.config.js` file.
-1. Configure your build tool (Gulp, Grunt, Webpack).
-1. Generate the CSS.
-1. Include a path to the generated CSS in your `MYTHEME.info`,
- `MYTHEME.info.yml` or `MYTHEME.libraries.yml` file.
-
-## PostCSS Configuration
-
-Create a `postcss.config.js` file and add `tailwindcss` as a plugin, passing the
-path to the config file:
-
-```language-js
-module.exports = {
- plugins: [
- require('tailwindcss')('./tailwind.js'),
- ]
-}
-```
-
-## Configuration for Drupal
-
-There are some configuration settings within `tailwind.js` that you’ll need to
-change to make things work nicely with Drupal. These are within the `options`
-section:
-
-```language-js
-options: {
- prefix: 'tw-',
- important: true,
- ...
-}
-```
-
-### Prefix
-
-By adding a prefix like `tw-`, we can ensure that the Tailwind classes don’t
-conflict with core HTML classes like `block`. We can also ensure that they won't
-conflict with any other existing HTML or CSS.
-
-No prefix:
-
-{.with-border}
-
-With prefix:
-
-{.with-border}
-
-### Important
-
-We can also set the `!important` rule on all Tailwind’s generated classes. We
-need to do this if we want to override core styles which have more specific
-rules.
-
-For example: if I had this core markup then the left margin added by `tw-ml-4`
-would be overridden by core’s `.item-list ul` styling.
-
-```language-html
-
-
- ...
-
-
-```
-
-{.with-border}
-
-With the `!important` rule enabled though, the Tailwind’s class takes precedence
-and is applied.
-
-{.with-border}
-
-## Example
-
-For an example of Tailwind within a Drupal 8 theme, see the custom theme for the
-[Drupal Bristol website][0] on GitHub.
-
-[0]:
- https://github.com/drupalbristol/drupal-bristol-website/tree/master/web/themes/custom/drupalbristol
-[1]: https://tailwindcss.com/docs/installation
-[2]: https://www.npmjs.com/get-npm
-[3]: https://yarnpkg.com/lang/en/docs/install
diff --git a/astro/sculpin-old/source/_posts/using-the-pcss-extension-with-webpack-encore.md b/astro/sculpin-old/source/_posts/using-the-pcss-extension-with-webpack-encore.md
deleted file mode 100644
index 7cf49a59..00000000
--- a/astro/sculpin-old/source/_posts/using-the-pcss-extension-with-webpack-encore.md
+++ /dev/null
@@ -1,90 +0,0 @@
----
-title: Using the pcss extension for PostCSS with Webpack Encore
-excerpt: How to use the .pcss file extension for PostCSS files with Webpack Encore.
-date: 2020-04-01
-tags: [webpack, encore, postcss, symfony]
----
-
-I’ve been watching Christopher Pitt ([assertchris][assertchris-twitter])’s [streams on Twitch][assertchris-twitch] over the last few months, in one of which he was doing some work with Tailwind CSS and using a `.pcss` file extension for his PostCSS files.
-
-I couldn’t remember seeing this extension before, but this made a lot of sense to me compared to the standard `.css` extension - both to make it clear that it’s a PostCSS file and features like nesting can be used, and also for better integration and highlighting with IDEs and text editors such as PhpStorm.
-
-It’s also shorter that the `.postcss` extension, and has been suggested by [@PostCSS on Twitter](https://twitter.com/PostCSS/status/661645290622083073) previously.
-
-Some of my projects use [Laravel Mix][] which support this extension by default, but some of them use Symfony’s [Webpack Encore][] which didn’t seem to, so I decided to look into it. (Note that both are agnostic and not coupled to their respective frameworks, so can be used with other projects too including Drupal and Sculpin).
-
-## Updating Webpack Encore’s configuration
-
-I was able to review the existing configuration and confirm this by using `console.log()` to output Encore’s generated webpack configuration - specifically the module rules.
-
-```js
-console.log(Encore.getWebpackConfig().module.rules)
-```
-
-There I can see the the test for PostCSS supports the `.css` and `.postcss` file extensions, but not `.pcss`.
-
-```plain
-test: /\.(css|postcss)$/,
-```
-
-There is documentation on the Symfony website for [adding custom webpack loaders and plugins](https://symfony.com/doc/current/frontend/encore/custom-loaders-plugins.html) but this wasn’t quite what I needed, as I needed to edit the existing `css` loader rather than add a new one.
-
-The page that I needed was [Advanced Webpack Config](https://symfony.com/doc/current/frontend/encore/advanced-config.html#having-the-full-control-on-loaders-rules) - specifically the section on 'Having the full control on Loaders Rules'.
-
-This suggests using `.configureLoaderRule()` and using that to override `test` directly.
-
-It does though come with a warning:
-
-> This is a low-level method. All your modifications will be applied just before pushing the loaders rules to Webpack. It means that you can override the default configuration provided by Encore, which may break things. Be careful when using it.
-
-My first pass was to add the full `.pcss` extension, but as this is a regular expression, I did a second pass that adds an second capturing group that would cover both PostCSS extensions.
-
-```
-// First pass
-loaderRule.test = /\.(css|pcss|postcss)$/
-
-// Second pass
-loaderRule.test = /\.(css|p(ost)?css)$/
-```
-
-To see this running, go to .
-
-## The final configuration
-
-This is my full `webpack.config.js` file for this site, including the `.pcss` extension support:
-
-```js
-Encore
- .disableSingleRuntimeChunk()
- .cleanupOutputBeforeBuild()
- .setOutputPath('source/build/')
- .setPublicPath('/build')
- .addEntry('app', './assets/js/app.js')
- .enablePostCssLoader()
- .configureLoaderRule('css', loaderRule => {
- loaderRule.test = /\.(css|p(ost)?css)$/
- })
- .enableSourceMaps(!Encore.isProduction())
-
-if (Encore.isProduction()) {
- Encore
- .enableVersioning()
- .addPlugin(new PurgecssPlugin(purgecssConfig))
-} else {
- Encore.enableSourceMaps()
-}
-
-module.exports = Encore.getWebpackConfig()
-```
-
-Alternatively, you can view it in the [codebase on GitHub](https://github.com/opdavies/oliverdavies.uk/blob/796578d7f0f3332724cb8335982c69b36bc11e53/webpack.config.js).
-
-## Contributing back to Encore
-
-I’ve also submitted a pull request to Encore to add support for the `.pcss` extension by default: . If accepted, then these changes in `webpack.config.js` would no longer be needed.
-
-[assertchris-twitch]: https://www.twitch.tv/assertchris "assertchris on Twitch"
-[assertchris-twitter]: https://twitter.com/assertchris "assertchris on Twitter"
-[gitstore]: https://gitstore.app
-[laravel mix]: https://laravel-mix.com
-[webpack encore]: https://github.com/symfony/webpack-encore
diff --git a/astro/sculpin-old/source/_posts/using-transition-props-vuejs.md b/astro/sculpin-old/source/_posts/using-transition-props-vuejs.md
deleted file mode 100644
index 80442dc1..00000000
--- a/astro/sculpin-old/source/_posts/using-transition-props-vuejs.md
+++ /dev/null
@@ -1,14 +0,0 @@
----
-title: Using Transition Class Props in Vue.js
-date: 2019-06-06
-type: tweet
-excerpt:
- Adam Wathan shows a more Tailwind-esque approach to writing Vue.js
- transitions.
-tags: [vuejs]
-external_url: https://twitter.com/adamwathan/status/1118670393030537217
----
-
-{% include 'tweet' with {
- content: '🔥 Using the transition class props instead of the `name` prop for @vuejs transitions makes it really easy to compose transitions on the fly using utility classes.
— Adam Wathan (@adamwathan) April 18, 2019'
-} %}
diff --git a/astro/sculpin-old/source/_posts/what-git-flow.md b/astro/sculpin-old/source/_posts/what-git-flow.md
deleted file mode 100644
index f2e1a637..00000000
--- a/astro/sculpin-old/source/_posts/what-git-flow.md
+++ /dev/null
@@ -1,58 +0,0 @@
----
-title: 'DrupalCamp London: What is Git Flow?'
-date: 2014-03-03
-excerpt:
- Here are my slides from my "What is Git Flow?" session at DrupalCamp London.
-tags:
- - git
- - git-flow
- - drupalcamp-london
- - talks
-tweets: true
----
-
-Here are my slides from my "What is Git Flow?" session at
-[DrupalCamp London](http://2014.drupalcamplondon.co.uk).
-
-{% include 'speakerdeck' with { data_id: '201559e0f103013198dd5a5f6f23ab67' } %}
-
-## Take aways
-
-The main take aways are:
-
-- Git Flow adds various commands into Git to enhance its native functionality,
- which creates a branching model to separate your stable production code from
- your unstable development code.
-- Never commit directly to the master branch - this is for production code only!
-- You can commit directly to the develop branch, but this should be done
- sparingly.
-- Use feature branches as much as possible - one per feature, user story or bug.
-- Commit early and often, and push to a remote often to encourage collaboration
- as well as to provide a backup of your code.
-- You can use settings within services like GitHub and Bitbucket to only allow
- certain users to push to the master and develop branches, and restrict other
- Developers to only commit and push to feature branches. Changes can then be
- committed and pushed, then reviewed as part of a peer code review, and merged
- back into the develop branch.
-
-## Feedback
-
-If you've got any questions, please feel free to
-tweet at me
-or fill in the
-session
-evaluation form that you can complete on the DrupalCamp London website.
-
-I've had some great feedback via Twitter:
-
-{% include 'tweet' with {
- content: '
@opdavies@DrupalCampLDN always had trouble with git. Your talk + Git flow has made it all very easy.
— James Tombs (@jtombs) March 2, 2014'
-} %}
-
-{% include 'tweet' with {
- content: '
— Curve Agency (@CurveAgency) March 2, 2014'
-} %}
diff --git a/astro/sculpin-old/source/_posts/writing-article-linux-journal.md b/astro/sculpin-old/source/_posts/writing-article-linux-journal.md
deleted file mode 100644
index f54b71e6..00000000
--- a/astro/sculpin-old/source/_posts/writing-article-linux-journal.md
+++ /dev/null
@@ -1,24 +0,0 @@
----
-title: Writing an Article for Linux Journal
-date: 2012-07-27
-excerpt:
- I'm absolutely delighted to announce that I'm going to be writing an article
- for Linux Journal magazine's upcoming Drupal special.
-tags:
- - drupal
- - distributions
- - installation-profiles
- - writing
- - linux-journal
----
-
-I'm absolutely delighted to announce that I'm going to be writing an article for
-[Linux Journal](http://www.linuxjournal.com) magazine's upcoming Drupal special.
-
-The article is going to be entitled "Speeding Up Your Drupal Development Using
-Installation Profiles and Distributions" and will be mentioning existing
-distributions available on Drupal.org, but mainly focussing on the steps needed
-to create your own custom distribution. Needless to say, I'm quite excited about
-it!
-
-The article is expected to be published in October.
diff --git a/astro/sculpin-old/source/_posts/writing-drupal-module-test-driven-development-tdd.md b/astro/sculpin-old/source/_posts/writing-drupal-module-test-driven-development-tdd.md
deleted file mode 100644
index 50045d9e..00000000
--- a/astro/sculpin-old/source/_posts/writing-drupal-module-test-driven-development-tdd.md
+++ /dev/null
@@ -1,658 +0,0 @@
----
-title: Writing a new Drupal 8 Module using Test Driven Development (TDD)
-date: 2017-11-07
-tags: [drupal, testing, tdd, simpletest, phpunit]
-excerpt:
- How to write automated tests and follow test driven development for Drupal
- modules.
-meta:
- image:
- url: /images/talks/test-driven-drupal-development.png
- width: 2560
- height: 1440
- type: image/png
-promoted: true
----
-
-

-
-I recently gave a [talk on automated testing in Drupal][0] talk at [DrupalCamp
-Dublin][1] and as a lunch and learn session for my colleagues at Microserve. As
-part of the talk, I gave an example of how to build a Drupal 8 module using a
-test driven approach. I’ve released the [module code on GitHub][2], and this
-post outlines the steps of the process.
-
-## Prerequisites
-
-You have created a `core/phpunit.xml` file based on `core/phpunit.xml.dist`, and
-populated it with your database credentials so that PHPUnit can bootstrap the
-Drupal database as part of the tests. [Here is an example][5].
-
-## Acceptance Criteria
-
-For the module, we are going to satisfy this example acceptance criteria:
-
-> As a site visitor, I want to see all published pages at /pages Ordered
-> alphabetically by title
-
-## Initial Setup
-
-Let’s start by writing the minimal code needed in order for the new module to be
-enabled. In Drupal 8, this is the `.info.yml` file.
-
-```language-yaml
-# tdd_dublin.info.yml
-
-name: 'TDD Dublin'
-excerpt: 'A demo module for DrupalCamp Dublin to show test driven module development.'
-core: 8.x
-type: module
-```
-
-We can also add the test file structure at this point too. We’ll call it
-`PageTestTest.php` and put it within a `tests/src/Functional` directory. As this
-is a functional test, it extends the `BrowserTestBase` class, and we need to
-ensure that the tdd_dublin module is enabled by adding it to the `$modules`
-array.
-
-```language-php
-// tests/src/Functional/PageListTest.php
-
-namespace Drupal\Tests\tdd_dublin\Functional;
-
-use Drupal\Tests\BrowserTestBase\BrowserTestBase;
-
-class PageListTest extends BrowserTestBase {
-
- protected static $modules = ['tdd_dublin'];
-
-}
-```
-
-With this in place, we can now start adding test methods.
-
-## Ensure that the Listing page Exists
-
-### Writing the First Test
-
-Let’s start by testing that the listing page exists at /pages. We can do this by
-loading the page and checking the status code. If the page exists, the code will
-be 200, otherwise it will be 404.
-
-I usually like to write comments first within the test method, just to outline
-the steps that I'm going to take and then replace it with code.
-
-```language-php
-public function testListingPageExists() {
- // Go to /pages and check that it is accessible by checking the status
- // code.
-}
-```
-
-We can use the `drupalGet()` method to browse to the required path, i.e.
-`/pages`, and then write an assertion for the response code value.
-
-```language-php
-public function testListingPageExists() {
- $this->drupalGet('pages');
-
- $this->assertSession()->statusCodeEquals(200);
-}
-```
-
-### Running the Test
-
-In order to run the tests, you either need to include `-c core` or be inside the
-`core` directory when running the command, to ensure that the test classes are
-autoloaded so can be found, though the path to the `vendor` directory may be
-different depending on your project structure. You can also specify a path
-within which to run the tests - e.g. within the module’s `test` directory.
-
-```language-plain
-$ vendor/bin/phpunit -c core modules/custom/tdd_dublin/tests
-```
-
-
-Note: I’m using Docksal, and I’ve noticed that I need to run the tests from within the CLI container. You can do this by running the `fin bash` command.
-
-
-```language-plain
-1) Drupal\Tests\tdd_dublin\Functional\PageListTest::testListingPageExists
-Behat\Mink\Exception\ExpectationException: Current response status code is 404, but 200 expected.
-
-FAILURES!
-Tests: 1, Assertions: 1, Errors: 1.
-```
-
-Because the route does not yet exist, the response code returned is 404, so the
-test fails.
-
-Now we can make it pass by adding the page. For this, I will use the Views
-module, though you could achieve the same result with a custom route and a
-Controller.
-
-### Building the View
-
-To begin with, I will create a view showing all types of content with a default
-sort order of newest first. We will use further tests to ensure that only the
-correct content is returned and that it is ordered correctly.
-
- { .with-border }
-
-The only addition I will make to the view is to add a path at `pages`, as per
-the acceptance criteria.
-
- { .with-border }
-
-### Exporting the View
-
-With the first version of the view built, it needs to be incldued within the
-module so that it can be enabled when the test is run. To do this, we need to
-export the configuration for the view, and place it within the module’s
-`config/install` directory. This can be done using the `drush config-export`
-command or from within the Drupal UI. In either case, the `uid` line at the top
-of the file needs to be removed so the configuration can be installed.
-
-Here is the exported view configuration:
-
-```language-yaml
-langcode: en
-status: true
-dependencies:
- module:
- - node
- - user
-id: pages
-label: pages
-module: views
-excerpt: ''
-tag: ''
-base_table: node_field_data
-base_field: nid
-core: 8.x
-display:
- default:
- display_plugin: default
- id: default
- display_title: Master
- position: 0
- display_options:
- access:
- type: perm
- options:
- perm: 'access content'
- cache:
- type: tag
- options: { }
- query:
- type: views_query
- options:
- disable_sql_rewrite: false
- distinct: false
- replica: false
- query_comment: ''
- query_tags: { }
- exposed_form:
- type: basic
- options:
- submit_button: Apply
- reset_button: false
- reset_button_label: Reset
- exposed_sorts_label: 'Sort by'
- expose_sort_order: true
- sort_asc_label: Asc
- sort_desc_label: Desc
- pager:
- type: mini
- options:
- items_per_page: 10
- offset: 0
- id: 0
- total_pages: null
- expose:
- items_per_page: false
- items_per_page_label: 'Items per page'
- items_per_page_options: '5, 10, 25, 50'
- items_per_page_options_all: false
- items_per_page_options_all_label: '- All -'
- offset: false
- offset_label: Offset
- tags:
- previous: ‹‹
- next: ››
- style:
- type: default
- options:
- grouping: { }
- row_class: ''
- default_row_class: true
- uses_fields: false
- row:
- type: fields
- options:
- inline: { }
- separator: ''
- hide_empty: false
- default_field_elements: true
- fields:
- title:
- id: title
- table: node_field_data
- field: title
- entity_type: node
- entity_field: title
- label: ''
- alter:
- alter_text: false
- make_link: false
- absolute: false
- trim: false
- word_boundary: false
- ellipsis: false
- strip_tags: false
- html: false
- hide_empty: false
- empty_zero: false
- settings:
- link_to_entity: true
- plugin_id: field
- relationship: none
- group_type: group
- admin_label: ''
- exclude: false
- element_type: ''
- element_class: ''
- element_label_type: ''
- element_label_class: ''
- element_label_colon: true
- element_wrapper_type: ''
- element_wrapper_class: ''
- element_default_classes: true
- empty: ''
- hide_alter_empty: true
- click_sort_column: value
- type: string
- group_column: value
- group_columns: { }
- group_rows: true
- delta_limit: 0
- delta_offset: 0
- delta_reversed: false
- delta_first_last: false
- multi_type: separator
- separator: ', '
- field_api_classes: false
- filters:
- status:
- value: '1'
- table: node_field_data
- field: status
- plugin_id: boolean
- entity_type: node
- entity_field: status
- id: status
- expose:
- operator: ''
- group: 1
- sorts:
- created:
- id: created
- table: node_field_data
- field: created
- order: DESC
- entity_type: node
- entity_field: created
- plugin_id: date
- relationship: none
- group_type: group
- admin_label: ''
- exposed: false
- expose:
- label: ''
- granularity: second
- header: { }
- footer: { }
- empty: { }
- relationships: { }
- arguments: { }
- display_extenders: { }
- cache_metadata:
- max-age: -1
- contexts:
- - 'languages:language_content'
- - 'languages:language_interface'
- - url.query_args
- - 'user.node_grants:view'
- - user.permissions
- tags: { }
- page_1:
- display_plugin: page
- id: page_1
- display_title: Page
- position: 1
- display_options:
- display_extenders: { }
- path: pages
- cache_metadata:
- max-age: -1
- contexts:
- - 'languages:language_content'
- - 'languages:language_interface'
- - url.query_args
- - 'user.node_grants:view'
- - user.permissions
- tags: { }
-```
-
-When the test is run again, we see a different error that leads us to the next
-step.
-
-```language-plain
-1) Drupal\Tests\tdd_dublin\Functional\PageListTest::testListingPageExists
-Drupal\Core\Config\UnmetDependenciesException: Configuration objects provided by tdd_dublin have unmet dependencies: node.type.page (node), views.view.pages (node, views)
-
-FAILURES!
-Tests: 1, Assertions: 0, Errors: 1.
-```
-
-This error is identifying unmet dependencies within the module’s configuration.
-In this case, the view that we’ve added depends on the node and views modules,
-but these aren’t enabled. To fix this, we can add the extra modules as
-dependencies of tdd_dublin so they will be enabled too.
-
-```language-yaml
-# tdd_dublin.info.yml
-
-dependencies:
- - drupal:node
- - drupal:views
-```
-
-```language-plain
-1) Drupal\Tests\tdd_dublin\Functional\PageListTest::testListingPageExists
-Drupal\Core\Config\UnmetDependenciesException: Configuration objects provided by tdd_dublin have unmet dependencies: views.view.pages (node.type.page)
-
-FAILURES!
-Tests: 1, Assertions: 0, Errors: 1.
-```
-
-With the modules enabled, we can see one more unmet dependency for
-`node.type.page`. This means that we need a page content type to be able to
-install the view. We can fix this in the same way as before, by exporting the
-configuration and copying it into the `config/install` directory.
-
-With this in place, the test should now pass - and it does.
-
-```language-plain
-Time: 26.04 seconds, Memory: 6.00MB
-
-OK (1 test, 1 assertion)
-```
-
-We now have a test to ensure that the listing page exists.
-
-## Ensure that only Published Pages are Shown
-
-### Writing the Test
-
-Now that we have a working page, we can now move on to checking that the correct
-content is returned. Again, I’ll start by writing comments and then translate
-that into code.
-
-The objectives of this test are:
-
-- To ensure that only page nodes are returned.
-- To ensure that only published nodes are returned.
-
-```language-php
-public function testOnlyPublishedPagesAreShown() {
- // Given that a have a mixture of published and unpublished pages, as well
- // as other types of content.
-
- // When I view the page.
-
- // Then I should only see the published pages.
-}
-```
-
-In order to test the different scenarios, I will create an additional "article"
-content type, create a node of this type as well as one published and one
-unpublished page. From this combination, I only expect one node to be visible.
-
-```language-php
-public function testOnlyPublishedPagesAreShown() {
- $this->drupalCreateContentType(['type' => 'article']);
-
- $this->drupalCreateNode(['type' => 'page', 'status' => TRUE]);
- $this->drupalCreateNode(['type' => 'article']);
- $this->drupalCreateNode(['type' => 'page', 'status' => FALSE]);
-
- // When I view the page.
-
- // Then I should only see the published pages.
-}
-```
-
-We could use `drupalGet()` again to browse to the page and write assertions
-based on the rendered HTML, though I’d rather do this against the data returned
-from the view itself. This is so that the test isn’t too tightly coupled to the
-presentation logic, and we won’t be in a situation where at a later date the
-test fails because of changes made to how the data is displayed.
-
-Rather, I’m going to use `views_get_view_result()` to programmatically get the
-result of the view. This returns an array of `Drupal\views\ResultRow` objects,
-which contain the nodes. I can use `array_column` to extract the node IDs from
-the view result into an array.
-
-```language-php
-public function testOnlyPublishedPagesAreShown() {
- $this->drupalCreateContentType(['type' => 'article']);
-
- $this->drupalCreateNode(['type' => 'page', 'status' => TRUE]);
- $this->drupalCreateNode(['type' => 'article']);
- $this->drupalCreateNode(['type' => 'page', 'status' => FALSE]);
-
- $result = views_get_view_result('pages');
- $nids = array_column($result, 'nid');
-
- // Then I should only see the published pages.
-}
-```
-
-From the generated nodes, I can use `assertEquals()` to compare the returned
-node IDs from the view against an array of expected node IDs - in this case, I
-expect only node 1 to be returned.
-
-```language-php
-public function testOnlyPublishedPagesAreShown() {
- $this->drupalCreateContentType(['type' => 'article']);
-
- $this->drupalCreateNode(['type' => 'page', 'status' => TRUE]);
- $this->drupalCreateNode(['type' => 'article']);
- $this->drupalCreateNode(['type' => 'page', 'status' => FALSE]);
-
- $result = views_get_view_result('pages');
- $nids = array_column($result, 'nid');
-
- $this->assertEquals([1], $nids);
-}
-```
-
-### Running the Test
-
-The test fails as no extra conditions have been added to the view, though the
-default "Content: Published" filter is already excluding one of the page nodes.
-We can see from the output from the test that node 1 (a page) and node 2 (the
-article) are both being returned.
-
-```language-plain
-1) Drupal\Tests\tdd_dublin\Functional\PageListTest::testOnlyPublishedPagesAreShown
-Failed asserting that two arrays are equal.
---- Expected
-+++ Actual
-@@ @@
- Array (
-- 0 => 1
-+ 0 => '2'
-+ 1 => '1'
- )
-
-FAILURES!
-Tests: 1, Assertions: 3, Failures: 1.
-```
-
-### Updating the Test
-
-We can fix this by adding another condition to the view, to only show content
-based on the node type - i.e. only return page nodes.
-
- { .with-border }
-
-Once the view is updated and the configuration is updated within the module, the
-test should then pass - and it does.
-
-```language-plain
-Time: 24.76 seconds, Memory: 6.00MB
-
-OK (1 test, 3 assertions)
-```
-
-## Ensure that the Pages are in the Correct Order
-
-### Writing the Test
-
-As we know that the correct content is being returned, we can now focus on
-displaying it in the correct order. We’ll start again by adding a new test
-method and filling out the comments.
-
-```language-php
-public function testResultsAreOrderedAlphabetically() {
- // Given I have multiple nodes with different titles.
-
- // When I view the pages list.
-
- // Then I should see pages in the correct order.
-}
-```
-
-To begin with this time, I’ll create a number of different nodes and specify the
-title for each. These are intentionally in the incorrect order alphabetically so
-that we can see the test fail initially and then see it pass after making a
-change so we know that the change worked.
-
-```language-php
-public function testResultsAreOrderedAlphabetically() {
- $this->drupalCreateNode(['title' => 'Page A']);
- $this->drupalCreateNode(['title' => 'Page D']);
- $this->drupalCreateNode(['title' => 'Page C']);
- $this->drupalCreateNode(['title' => 'Page B']);
-
- // When I view the pages list.
-
- // Then I should see pages in the correct order.
-}
-```
-
-We can use the same method as the previous test to get the returned IDs, using
-`views_get_view_result()` and `array_column()`, and assert that the returned
-node IDs match the expected node IDs in the specified order. Based on the
-defined titles, the order should be 1, 4, 3, 2.
-
-```language-php
-public function testResultsAreOrderedAlphabetically() {
- $this->drupalCreateNode(['title' => 'Page A']);
- $this->drupalCreateNode(['title' => 'Page D']);
- $this->drupalCreateNode(['title' => 'Page C']);
- $this->drupalCreateNode(['title' => 'Page B']);
-
- $nids = array_column(views_get_view_result('pages'), 'nid');
-
- $this->assertEquals([1, 4, 3, 2], $nids);
-}
-```
-
-### Running the Test
-
-As expected the test fails, as the default sort criteria in the view orders the
-results by their created date.
-
-In the test output, we can see the returned results are in sequential order so
-the results array does not match the expected one.
-
-This would be particularly more complicated to test if I was using `drupalGet()`
-and having to parse the HTML, compared to getting the results as an array from
-the view programmatically.
-
-```language-plain
-1) Drupal\Tests\tdd_dublin\Functional\PageListTest::testResultsAreOrderedAlphabetically
-Failed asserting that two arrays are equal.
---- Expected
-+++ Actual
-@@ @@
- Array (
-- 0 => 1
-- 1 => 4
-- 2 => 3
-- 3 => 2
-+ 0 => '1'
-+ 1 => '2'
-+ 2 => '3'
-+ 3 => '4'
- )
-
-FAILURES!
-Tests: 1, Assertions: 2, Failures: 1.
-```
-
-### Updating the Test
-
-This can be fixed by removing the default sort criteria and adding a new one
-based on "Content: Title".
-
- { .with-border }
-
-Again, once the view has been updated and exported, the test should pass - and
-it does.
-
-```language-plain
-Time: 27.55 seconds, Memory: 6.00MB
-
-OK (1 test, 2 assertions)
-```
-
-## Ensure all Tests Still Pass
-
-Now we know that all the tests pass individually, all of the module tests should
-now be run to ensure that they all still pass and that there have been no
-regressions due to any of the changes.
-
-```language-plain
-docker@cli:/var/www$ vendor/bin/phpunit -c core modules/custom/tdd_dublin/tests
-
-Testing modules/custom/tdd_dublin/tests
-...
-
-Time: 1.27 minutes, Memory: 6.00MB
-
-OK (3 tests, 6 assertions)
-```
-
-They all pass, so we be confident that the code works as expected, we can
-continue to refactor if needed, and if any changes are made to this module at a
-later date, we have the tests to ensure that any regressions are caught and
-fixed before deployment.
-
-## Next Steps
-
-I’ve started looking into whether some of the tests can be rewritten as kernel
-tests, which should result in quicker test execution. I will post any updated
-code to the [GitHub repository][3], and will also do another blog post
-highlighting the differences between functional and kernel tests and the steps
-taken to do the conversion.
-
-[0]: {{site.url}}/talks/tdd-test-driven-drupal
-[1]: http://2017.drupal.ie
-[2]: https://github.com/opdavies/tdd_dublin
-[3]: https://packagist.org/packages/tightenco/collect
-[4]: http://php.net/manual/en/function.array-column.php
-[5]: https://gist.github.com/opdavies/dc5f0cea46ccd349b34a9f3a463c14bb
diff --git a/astro/sculpin-old/source/_posts/writing-info-file-drupal-7-theme.md b/astro/sculpin-old/source/_posts/writing-info-file-drupal-7-theme.md
deleted file mode 100644
index a4c0443a..00000000
--- a/astro/sculpin-old/source/_posts/writing-info-file-drupal-7-theme.md
+++ /dev/null
@@ -1,40 +0,0 @@
----
-title: Writing a .info file for a Drupal 7 theme
-date: 2012-05-23
-excerpt: An example .info file for a Drupal 7 theme.
-tags:
- - theming
- - drupal-theming
- - drupal
- - code
----
-
-```language-ini
-name = My Theme
-description = A description of my theme
-core = 7.x
-
-# Add a base theme, if you want to use one.
-base = mybasetheme
-
-# Define regions, otherwise the default regions will be used.
-regions[header] = Header
-regions[navigation] = Navigation
-regions[content] = Content
-regions[sidebar] = Sidebar
-regions[footer] = Footer
-
-# Define which features are available. If none are specified, all the default
-# features will be available.
-features[] = logo
-features[] = name
-features[] = favicon
-
-# Add stylesheets
-stylesheets[all][] = css/reset.css
-stylesheets[all][] = css/mytheme.css
-stylesheets[print][] = css/print.css
-
-# Add javascript files
-styles[] = js/mytheme.js
-```
diff --git a/astro/sculpin-old/source/_posts/zenophile.md b/astro/sculpin-old/source/_posts/zenophile.md
deleted file mode 100644
index 1120efef..00000000
--- a/astro/sculpin-old/source/_posts/zenophile.md
+++ /dev/null
@@ -1,24 +0,0 @@
----
-title: Quickly Create Zen Subthemes Using Zenophile
-date: 2010-05-10
-excerpt: How to use the Zenophile module to create a Zen subtheme.
-tags:
- - drupal-planet
- - drupal-6
- - drupal-modules
- - drupal-theming
- - zen
- - zenophile
----
-
-If you use the [Zen](http://drupal.org/project/zen) theme, then you should also
-be using the [Zenophile](http://drupal.org/project/zenophile) module!
-
-The Zenophile module allows you to very quickly create Zen subthemes from within
-your web browser, as well as editing options such as the site directory where it
-should be placed, the layout type (fixed or fluid), page wrapper and sidebar
-widths, and the placement of the sidebars.
-
-For more information about the Zenophile module, check out
-[this video](http://blip.tv/file/2427703) by
-[Elliott Rothman](http://elliottrothman.com).
diff --git a/astro/sculpin-old/source/_redirects.html.twig b/astro/sculpin-old/source/_redirects.html.twig
deleted file mode 100644
index 13ba9ae7..00000000
--- a/astro/sculpin-old/source/_redirects.html.twig
+++ /dev/null
@@ -1,10 +0,0 @@
----
-use: [posts]
----
-{% for redirect in site.redirects %}
-{{ redirect.from }} {{ redirect.to }}
-{% endfor %}
-
-{% for post in data.posts if post.external_url %}
-{{ post.url|trim('/', 'right') }} {{ post.external_url }}
-{% endfor %}
diff --git a/astro/sculpin-old/source/_talks/building-static-websites-sculpin.md b/astro/sculpin-old/source/_talks/building-static-websites-sculpin.md
deleted file mode 100644
index a4429cfb..00000000
--- a/astro/sculpin-old/source/_talks/building-static-websites-sculpin.md
+++ /dev/null
@@ -1,33 +0,0 @@
----
-title: Building Static Websites with Sculpin
-description:
- A lightning talk on how to use Sculpin to generate static HTML websites.
-type: Lightning talk
-speakerdeck:
- id: 6c9c4be1a1344f1291ff13a391674a66
- ratio: '1.37081659973226'
- url: https://speakerdeck.com/opdavies/building-static-websites-with-sculpin
-code: https://github.com/opdavies/sculpin-demo
-tags: [meetups, phpsw, sculpin]
-tweets: yes
-video:
- type: youtube
- id: aN53arCKZAU
-events:
- - event: phpsw
- date: 2015-10-14
- joindin: https://joind.in/talk/view/15486
----
-
-[Sculpin][0] is a static site generator written in PHP. It converts Markdown
-files, Twig templates and standard HTML into a static HTML site that can be
-easily deployed.
-
-This talk will cover a little of the background to Sculpin and what it is, and
-then will move into some demonstrations of how to build a Sculpin site and what
-it can do!
-
-You can [view the full slides][1], including the embedded videos.
-
-[0]: http://sculpin.io
-[1]: https://opdavies.github.io/slides-phpsw-sculpin
diff --git a/astro/sculpin-old/source/_talks/configuring-all-the-things-drupal-8.md b/astro/sculpin-old/source/_talks/configuring-all-the-things-drupal-8.md
deleted file mode 100644
index 5f22bf4d..00000000
--- a/astro/sculpin-old/source/_talks/configuring-all-the-things-drupal-8.md
+++ /dev/null
@@ -1,22 +0,0 @@
----
-title: 'Configuring all the Things (in Drupal 8)'
-description:
- A short notice talk on configuration management in Drupal 8, and things I’ve
- learned working on my current Drupal 8 project.
-speakerdeck:
- id: 6de3fe8947a34727b79eb9d9dcc66bf2
- ratio: '1.37081659973226'
- url: https://speakerdeck.com/opdavies/configuring-all-the-things-in-drupal-8
-video:
- type: ~
- id: ~
-tags:
- - drupal
- - drupal-8
-events:
- - event: drupal_bristol
- date: 2018-07-25
----
-
-A short notice talk on configuration management in Drupal 8, and things I’ve
-learned working on my current Drupal 8 project.
diff --git a/astro/sculpin-old/source/_talks/dancing-for-drupal.md b/astro/sculpin-old/source/_talks/dancing-for-drupal.md
deleted file mode 100644
index 98a41109..00000000
--- a/astro/sculpin-old/source/_talks/dancing-for-drupal.md
+++ /dev/null
@@ -1,34 +0,0 @@
----
-title: Dancing for Drupal
-description:
- A talk on Drupal, presented alongside others representing Umbraco, Sitecore
- and Episerver.
-speakerdeck:
- id: ffa9b6dea6dc4a8eb207b9982ed6e1bd
- ratio: '1.33333333333333'
- url: https://speakerdeck.com/opdavies/umbristol-dancing-for-drupal
-tags: [meetup, umbristol, drupal]
-tweets: yes
-events:
- - event: umbristol
- date: 2015-08-25
----
-
-As part of their [CMS Dance-Off][1], I was selected to speak about Drupal
-alongside other speakers representing Umbraco, Sitecore and Episerver.
-
-The points to cover were:
-
-- How does your CMS store configuration data, 'structure' and content?
-- How do you manage source-control, versioning and deployment?
-- How do you manage multiple simultaneous editors and/or developers?
-- How do you manage upgrades?
-- What are the 3 best things about your CMS?
-- What are the 3 worst things about your CMS?
-- What does the future of your CMS look like?
-
-In each point, tried to cover the differences between Drupal core and developing
-a project using Drupal, as well as between Drupal 7 and Drupal 8, as things like
-source control and versioning would be approached differently.
-
-[1]: http://www.meetup.com/umBristol/events/223807592
diff --git a/astro/sculpin-old/source/_talks/decoupling-drupal-vuejs.md b/astro/sculpin-old/source/_talks/decoupling-drupal-vuejs.md
deleted file mode 100644
index 9c960862..00000000
--- a/astro/sculpin-old/source/_talks/decoupling-drupal-vuejs.md
+++ /dev/null
@@ -1,24 +0,0 @@
----
-title: Decoupling Drupal with Vue.js
-description: Decoupling Drupal with Vue.js.
-code: https://github.com/opdavies/blue-conf-2019
-speakerdeck:
- id: 60c8b7abdf194946b7a78a1bb74a0982
- ratio: '1.77777777777778'
- url: https://speakerdeck.com/opdavies/decoupling-drupal-with-vue-dot-js
-events:
- - event: blue_conf_19
- date: 2019-06-07
----
-
-Decoupled or headless Drupal has been a trend for a number of years, with
-modules like RESTful Web Services available for Drupal 7 to expose data, and
-Drupal 8 becoming more API-first with JSON:API module now included as part of
-core. This makes it easier for third party systems or alternative front-end
-applications to consume and work with the data provided by Drupal.
-
-In this talk, we’ll look at how to build progressively and fully decoupled
-applications - passing data from a Drupal 8 back-end to a Vue.js front-end.
-
-The demo code used in the talk is
-[available on GitHub](https://github.com/opdavies/blue-conf-2019 'View the demo code for this talk on GitHub.').
diff --git a/astro/sculpin-old/source/_talks/deploying-drupal-fabric.md b/astro/sculpin-old/source/_talks/deploying-drupal-fabric.md
deleted file mode 100644
index 6fbbd6da..00000000
--- a/astro/sculpin-old/source/_talks/deploying-drupal-fabric.md
+++ /dev/null
@@ -1,43 +0,0 @@
----
-title: 'Deploying Drupal with Fabric'
-description:
- How to use Fabric, a Python command line based library, to deploy your Drupal
- applications.
-speakerdeck:
- id: 40d1eca4bd484afc86295924fff5dd41
- ratio: '1.77777777777778'
- url: 'https://speakerdeck.com/opdavies/deploying-drupal-and-anything-else-with-fabric'
- embed:
- ''
-tags: [meetup, conference, php, fabric, drupal]
-meta:
- og:
- title: Deploying Drupal with Fabric
- description:
- "You've built your Drupal site, now learn how to deploy it with Fabric."
- type: website
-events:
- - event: drupalcamp_dublin_17
- date: 2017-10-20
- time: '15:00 - 15:40'
- - event: drupal_somerset
- date: 2017-10-26
----
-
-You’ve built your website, and now you just need to deploy it. There are various
-ways that this could be done - from (S)FTP, to SCP and rsync, to running
-commands like “git pull” and “composer install” directly on the server (not
-recommended).
-
-My favourite deployment tool of late is [Fabric][1] - a Python based command
-line tool for running commands locally as well as on remote servers. It’s
-language and framework agnostic, and unopinionated so you define the steps and
-workflow that you need - from a basic few-step deployment to a full Capistrano
-style zero-downtime deployment.
-
-This talk will cover some introduction to Fabric and how to write your own
-fabfiles, to then covering some examples and demos of different use case
-deployments for your Drupal project.
-
-[1]: http://www.fabfile.org
diff --git a/astro/sculpin-old/source/_talks/deploying-php-ansible-ansistrano.md b/astro/sculpin-old/source/_talks/deploying-php-ansible-ansistrano.md
deleted file mode 100644
index 0807d8ba..00000000
--- a/astro/sculpin-old/source/_talks/deploying-php-ansible-ansistrano.md
+++ /dev/null
@@ -1,60 +0,0 @@
----
-title: Deploying PHP applications with Ansible, Ansible Vault and Ansistrano
-description:
- How to use Ansible and Ansistrano to perform robust, secure deployments of
- your PHP applications.
-speakerdeck:
- id: c11fe635ed8f4741b35bf3ebe53e8323
- ratio: '1.77777777777778'
- url: https://speakerdeck.com/opdavies/deploying-php-applications-with-ansible-ansible-vault-and-ansistrano
-video:
- type: youtube
- id: TmS0FIVwKQg
-tags: [meetup, php, ansible, ansistrano]
-events:
- - event: drupal_bristol
- date: 2019-01-23
- - event: php_south_wales
- date: 2019-07-23
- - event: drupalcon_eu_19
- date: 2019-10-30
- - event: bristol_devops
- date: 2020-01-30
- url: https://www.meetup.com/Bristol-Cloud-Native-DevOps/events/266609627
- - event: drupal_edinburgh
- date: 2020-03-12
- remote: true
- url: https://www.meetup.com/Drupal-Edinburgh/events/267905594
- - event: cms_philly_20
- date: 2020-05-01
- remote: true
- - event: drupal_yorkshire
- date: 2020-05-21
- remote: true
----
-
-Great! You’ve built your website, and now you just need to deploy it. There are
-various ways that this could be done - from (S)FTP, to SCP and rsync, to running
-commands like `git pull` and `composer install` directly on the server which is
-not ideal.
-
-As well provisioning and maintaining your server configuration and running
-commands, you can also use [Ansible](https://www.ansible.com) to deploy your PHP
-application - leveraging relevant Ansible modules such as Git and Composer,
-custom Ansible roles,
-[Ansible Vault](https://docs.ansible.com/ansible/latest/user_guide/vault.html)
-for managing secrets, and features such as idempotency out of the box to build a
-simple deployment playbook.
-
-We can then extend that and make it more robust by adding
-[Ansistrano](https://ansistrano.com) - a port of
-[Capistrano](https://capistranorb.com) - which adds extra features such as
-storing multiple builds for each project and the ability to roll-back if needed,
-customising your build steps using built-in hooks, multi-stage environments and
-more.
-
-I've been using Ansible and Ansistrano to deploy a variety of PHP projects -
-including Drupal 7 & 8, Symfony, Laravel and Sculpin, as well as basic HTML
-websites, and found it to be very flexible and easy to install and use, and by
-the end of this talk we will have a fully working deployment playbook, deploying
-real code onto a real server.
diff --git a/astro/sculpin-old/source/_talks/deploying-php-fabric.md b/astro/sculpin-old/source/_talks/deploying-php-fabric.md
deleted file mode 100644
index 9a4db4b3..00000000
--- a/astro/sculpin-old/source/_talks/deploying-php-fabric.md
+++ /dev/null
@@ -1,52 +0,0 @@
----
-title: Deploying PHP Applications with Fabric
-description:
- How to use Fabric, a Python command line based library, to deploy your PHP
- applications.
-speakerdeck:
- id: c147618ce07546ca92f92983c52d6a41
- ratio: '1.77777777777778'
- url: https://speakerdeck.com/opdavies/deploying-php-applications-with-fabric
-tags: [meetup, conference, php, fabric]
-meta:
- og:
- title: Deploying PHP Applcations with Fabric
- description:
- "You've built your PHP application, now learn how to deploy it with
- Fabric."
- type: website
- image:
- url: /images/talks/deploying-php-fabric.png
- width: 2560
- height: 1440
- type: image/png
-events:
- - event: nomad_php
- date: 2017-04-20
- time: '19:00 (CET)'
- type: 'Lightning talk'
- - event: phpsw
- date: 2017-09-13
- joindin: https://joind.in/talk/a5ff3
- - event: phpnw_17
- date: 2017-10-01
- time: '09:00 - 09:45'
- joindin: https://joind.in/talk/4e35d
----
-
-You’ve built your application, and now you just need to deploy it. There are
-various ways that this could be done – from (S)FTP, to SCP and rsync, to running
-commands like “git pull” and “composer install” directly on the server (not
-recommended).
-
-My favourite deployment tool of late is [Fabric][1] – a Python based command
-line tool for running commands locally as well as on remote servers. It’s
-language and framework agnostic, and unopinionated so you define the steps and
-workflow that you need – from a basic few-step deployment to a full Capistrano
-style zero-downtime deployment.
-
-This talk will cover some introduction to Fabric and how to write your own
-fabfiles, and then look at some examples of different use case deployments for
-your PHP project.
-
-[1]: http://www.fabfile.org
diff --git a/astro/sculpin-old/source/_talks/drupal-8-module-development.md b/astro/sculpin-old/source/_talks/drupal-8-module-development.md
deleted file mode 100644
index 745d205e..00000000
--- a/astro/sculpin-old/source/_talks/drupal-8-module-development.md
+++ /dev/null
@@ -1,42 +0,0 @@
----
-title: Getting Started with Drupal 8 Module Development
-description: How to build your first module for Drupal 8.
-tags: [conference, php, drupal, drupalcamp, drupal-8]
-tweets: yes
-code: https://github.com/opdavies/dclondon16-d8-module
-speakerdeck:
- id: 0041804e52664d12a8e31cd118264813
- ratio: '1.77777777777778'
- url: https://speakerdeck.com/opdavies/getting-started-with-drupal-8-module-development
-video:
- type: youtube
- id: qO_Wh5WE3VA
-meta:
- og:
- title: Getting Started with Drupal 8 Module Development
- image:
- url: /images/talks/dclondon16.png
- type: 'image/png'
- height: 540
- width: 960
-events:
- - event: drupalcamp_london_16
- date: 2016-03-05
----
-
-New to object-orientated PHP, Symfony or YAML, and want to get started building
-modules in Drupal 8? This is the session for you!
-
-In this session, we’ll cover:
-
-- Where Drupal 8 modules are located, and how they are structured.
-- How to build a simple module, including our own permissions and routes.
-- How to add your own controller and service classes.
-- What is the service/dependency injection container, and how do we use it?
-- How we can use tools such as PhpStorm and Drupal Console to speed up the
- process.
-
-What we won’t be covering:
-
-- Automated testing in PHPUnit or Simpletest.
-- Adding third party libraries and external dependencies via Composer.
diff --git a/astro/sculpin-old/source/_talks/drupal-8-php-libraries-drupalorg-api.md b/astro/sculpin-old/source/_talks/drupal-8-php-libraries-drupalorg-api.md
deleted file mode 100644
index ec6c2e57..00000000
--- a/astro/sculpin-old/source/_talks/drupal-8-php-libraries-drupalorg-api.md
+++ /dev/null
@@ -1,61 +0,0 @@
----
-title: Having Fun with Drupal 8, PHP libraries and the Drupal.org API
-description:
- A crash course in developing PHP packages and Drupal 8 modules, based on the
- Drupal.org API.
-speakerdeck:
- id: 6e42ae9620bb4e91b3955f8c30d66934
- ratio: '1.77777777777778'
-image:
- url: /images/talks/having-fun-drupalorg-api.png
- width: 2000
- height: 1125
- type: image/png
-tags:
- - drupal
- - drupal-8
- - drupalorg
- - php
-video:
- type: youtube
- id: JyDjC7gGDpU
-events:
- - event: drupal_bristol
- date: 2018-04-18
- joindin: https://joind.in/talk/14851
- - event: drupalcamp_london_19
- date: 2019-03-03
- time: '12:05 - 12:50'
----
-
-A overview and demo of some of the open source projects that I’ve been working
-on lately that are based on information from the Drupal.org API, including a PHP
-library for the API itself as well as some Drupal 8 modules that use it.
-
-This session will cover various topics including:
-
-- Why would you want to separate your code into reusable packages
-- An overview of how to structure a PHP package (e.g. an API for interacting
- with Drupal.org)
-- How to add a PHP package as a dependency for a Drupal module using Composer
-- How to create routes and services, and use dependency injection in Drupal 8
-- How to use Drupal to configure the packages
-- How to increase performance and reliability by using Drupal's cache system to
- store API results
-
-## Links
-
-- [Drupal.org API library][2]
-- [Drupal.org API documentation][3]
-- [Laravel Collections][4]
-- Example module: [Drupal.org project statistics][5]
-- Example module: [Drupalversary][6]
-- Talk: [Using Laravel Collections outside Laravel][7]
-
-[0]: https://www.drupalbristol.org.uk
-[2]: https://github.com/opdavies/drupalorg-api-php
-[3]: https://www.drupal.org/drupalorg/docs/api
-[4]: https://laravel.com/docs/collections
-[5]: https://github.com/opdavies/drupal-module-drupalorg-project-statistics
-[6]: https://github.com/opdavies/drupal-module-drupalversary
-[7]: /talks/using-laravel-collections-outside-laravel/
diff --git a/astro/sculpin-old/source/_talks/drupal-8-rejoining-the-herd.md b/astro/sculpin-old/source/_talks/drupal-8-rejoining-the-herd.md
deleted file mode 100644
index 7860c055..00000000
--- a/astro/sculpin-old/source/_talks/drupal-8-rejoining-the-herd.md
+++ /dev/null
@@ -1,28 +0,0 @@
----
-title: 'Drupal 8: Rejoining the Herd'
-description:
- A talk highlighting some of the recent technical and non-technical changes in
- Drupal 8.
-tags: [conference, php, drupal, drupal-8]
-speakerdeck:
- id: 440fd6592f474741bc606c96bc32c104
- ratio: '1.37081659973226'
- url: https://speakerdeck.com/opdavies/drupal-rejoining-the-herd
-events:
- - event: php_south_coast_16
- date: 2016-06-11
- joindin: https://joind.in/talk/41d0f
----
-
-[Drupal 8][0] was (finally) released on November 19th 2015, after almost 4 years
-of work and code commits by over 3,200 different contributors. Whilst it’s
-pretty much the same as the Drupal that we know and, hopefully, love, a lot has
-changed behind the scenes and under the hood!
-
-In this talk, I'll highlight some of the new features and improvements in Drupal
-8, and discuss some of the benefits to Drupal site builders, themers, and module
-developers. I'll also talk about some of the non-technical changes and the
-cultural shift from "not invented here" to "proudly found elsewhere", and how we
-are rejoining the PHP herd.
-
-[0]: https://www.drupal.org/8
diff --git a/astro/sculpin-old/source/_talks/drupal-8.md b/astro/sculpin-old/source/_talks/drupal-8.md
deleted file mode 100644
index a0708bad..00000000
--- a/astro/sculpin-old/source/_talks/drupal-8.md
+++ /dev/null
@@ -1,25 +0,0 @@
----
-title: Drupal 8
-description:
- A lightning talk presented to the PHPSW user group, highlighting some of the
- relevant changes in Drupal 8.
-speakerdeck:
- url: https://speakerdeck.com/opdavies/drupal-8
- id: 46ba4ba577d94a32b7abdade610ceb69
- ratio: '1.29456384323641'
-video:
- type: youtube
- id: 36zCxPrOOzM
-tags: [meetup, phpsw, drupal, drupal-8]
-tweets: yes
-events:
- - event: phpsw
- date: 2015-04-08
----
-
-This was a ten minute lightning talk, designed to highlight the major changes
-coming in Drupal 8.
-
-I categorised the technical changes into groups for site builders, developers
-and themers, and also highlighted the cultural shift from "not invented here" to
-"proudly found elsewhere" and the benefits that brings.
diff --git a/astro/sculpin-old/source/_talks/drupal-vm-generator.md b/astro/sculpin-old/source/_talks/drupal-vm-generator.md
deleted file mode 100644
index 9724f58b..00000000
--- a/astro/sculpin-old/source/_talks/drupal-vm-generator.md
+++ /dev/null
@@ -1,23 +0,0 @@
----
-title: Drupal VM Generator
-description: Announcing the Drupal VM Generator CLI tool.
-type: Lightning talk
-code: https://github.com/opdavies/drupal-vm-generator
-tags: [drupal-vm, drupal-vm-generator, meetup, symfony]
-speakerdeck:
- id: a27ee1d2bfed4a209dc395fa455acb41
- ratio: '1.37081659973226'
- url: https://speakerdeck.com/opdavies/bristol-dug-drupal-vm-generator
-video:
- type: youtube
- id: U1pbKAAO2Wo
-events:
- - event: nwdug
- date: 2016-03-08
- - event: drupal_bristol
- date: 2016-04-02
----
-
-An short talk about the [Drupal VM Generator][1] project.
-
-[1]: https://github.com/opdavies/drupal-vm-generator
diff --git a/astro/sculpin-old/source/_talks/drupal-vm-meet-symfony-console.md b/astro/sculpin-old/source/_talks/drupal-vm-meet-symfony-console.md
deleted file mode 100644
index f57c2409..00000000
--- a/astro/sculpin-old/source/_talks/drupal-vm-meet-symfony-console.md
+++ /dev/null
@@ -1,32 +0,0 @@
----
-title: Drupal VM, Meet Symfony Console
-description:
- How to develop command line applications using Symfony Console, using the
- Drupal VM CLI as an example.
-tags: [conference, php, drupal-vm, symfony]
-speakerdeck:
- id: 56c79770f73f4e47a542a30243437c49
- ratio: '1.37081659973226'
- url: https://speakerdeck.com/opdavies/drupal-vm-meet-symfony-console
-image: drupal-vm-meet-symfony-console.png
-events:
- - event: drupalcamp_bristol_16
- date: 2016-07-23
----
-
-_TL;DR - Come and learn about Symfony Console, with examples from a real-world
-project._
-
-The [Drupal VM Generator][2] is a CLI application, built on [Symfony
-Console][0], that generates configuration files for [Drupal VM][1] based on
-personal settings and user interaction.
-
-After an introduction to Drupal VM itself and the Drupal VM Generator, we’ll
-jump into the code and see how Symfony Console applications are structured, how
-to write new commands, and how to integrate additional libraries like Guzzle,
-Twig and other Symfony components - whilst referencing code from the Drupal VM
-Generator project.
-
-[0]: http://symfony.com/doc/current/components/console/introduction.html
-[1]: https://www.drupalvm.com
-[2]: https://www.drupalvmgenerator.com
diff --git a/astro/sculpin-old/source/_talks/drupalorg-2015.md b/astro/sculpin-old/source/_talks/drupalorg-2015.md
deleted file mode 100644
index 3af4cd9a..00000000
--- a/astro/sculpin-old/source/_talks/drupalorg-2015.md
+++ /dev/null
@@ -1,19 +0,0 @@
----
-title: "Drupal.org in 2015: What's Coming Next"
-description:
- A retrospective of the Drupal Association’s work in 2014 and a look forward to
- what we’ll be working on in 2015.
-tags: [conference, drupalcamp, drupalcamp-london, drupal-association]
-speakerdeck:
- id: 0cf8d7b647c94ae289e9db2b46a9e8f2
- ratio: '1.77777777777778'
- url: https://speakerdeck.com/opdavies/drupal-dot-org-in-15
-events:
- - event: drupalcamp_brighton_15
- date: 2015-01-18
- - event: drupalcamp_london_15
- date: 2015-02-28
----
-
-A retrospective of the Drupal Association’s work in 2014 and a look forward to
-what we’ll be working on in 2015.
diff --git a/astro/sculpin-old/source/_talks/drush-make-drupalbristol.md b/astro/sculpin-old/source/_talks/drush-make-drupalbristol.md
deleted file mode 100644
index fa900588..00000000
--- a/astro/sculpin-old/source/_talks/drush-make-drupalbristol.md
+++ /dev/null
@@ -1,15 +0,0 @@
----
-title: drush make drupalbristol
-description: How to Drush Make to build your Drupal websites.
-speakerdeck:
- id: 42605700f102013198de5a5f6f23ab67
- ratio: '1.29456384323641'
- url: https://speakerdeck.com/opdavies/drush-make-drupalbristol
-tags: [meetup, drupal, drupal_bristol, drush, drush-make]
-events:
- - event: drupal_bristol
- date: 2014-08-19
----
-
-An introduction to Drush Make and how to use it to build reusable custom
-installation profiles or entire websites.
diff --git a/astro/sculpin-old/source/_talks/getting-your-data-into-drupal-8.md b/astro/sculpin-old/source/_talks/getting-your-data-into-drupal-8.md
deleted file mode 100644
index 3b7cd4ea..00000000
--- a/astro/sculpin-old/source/_talks/getting-your-data-into-drupal-8.md
+++ /dev/null
@@ -1,44 +0,0 @@
----
-title: Getting (Your Data) Into Drupal 8
-description:
- An overview of Drupal’s Migrate functionality, and a look at how to write your
- own migrations.
-speakerdeck:
- id: 63e5dfce996e46699e304d50e896477b
- ratio: '1.77777777777778'
- url: 'https://speakerdeck.com/opdavies/getting-your-data-into-drupal-8-drupal_bristol'
-video:
- type: youtube
- id: jtmARTuYhp8
-tags: [drupalcamp, migration, drupal-8]
-meta:
- og:
- title: Getting (Your Data) into Drupal 8
- description: 'How I migrated the Drupal Bristol website onto Drupal 8.'
- type: website
- image:
- url: /images/talks/getting-your-data-into-drupal-8.png
- width: 2560
- height: 1440
- type: image/png
-use: [talks]
-events:
- - event: drupal_bristol
- date: 2017-01-18
- - event: drupalcamp_london_17
- date: 2017-03-04
- time: '12:05 - 12:50'
----
-
-If you’ve moved a site from Drupal 6 to 7, the chances are that you’ve either
-used the upgrade path to update your old site in-place, or you built a new site
-from scratch and used the Migrate module from contrib to migrate your data from
-the old database.
-
-In Drupal 8, things have changed as there’s no upgrade path from Drupal 7 and
-the Migrate module has been moved into core, though there are still migration
-related modules available in contrib.
-
-This talk will look at the core Migrate module and how it implements Drupal 8
-features such as YAML and the plugin and configuration systems, and how to write
-your own migrations to get your data into Drupal 8.
diff --git a/astro/sculpin-old/source/_talks/git-flow.md b/astro/sculpin-old/source/_talks/git-flow.md
deleted file mode 100644
index 0abce8e9..00000000
--- a/astro/sculpin-old/source/_talks/git-flow.md
+++ /dev/null
@@ -1,20 +0,0 @@
----
-title: Never Commit to Master - An Introduction to Git Flow
-description:
- An introduction to and demonstration of the Git Flow branching model.
-speakerdeck:
- id: 201559e0f103013198dd5a5f6f23ab67
- ratio: '1.29456384323641'
- url: https://speakerdeck.com/opdavies/never-commit-to-master-an-introduction-to-git-flow
-video:
- type: youtube
- id: T-miCpHxfds
-tags: [conference, drupalcamp, drupalcamp-london, git, git-flow]
-tweets: yes
-events:
- - event: drupalcamp_london_14
- date: 2014-03-01
----
-
-An introduction to the Git Flow branching model and the git-flow plugin, and how
-I’ve used them to manage a Drupal development project.
diff --git a/astro/sculpin-old/source/_talks/goodbye-drush-make-hello-composer.md b/astro/sculpin-old/source/_talks/goodbye-drush-make-hello-composer.md
deleted file mode 100644
index f5b294b1..00000000
--- a/astro/sculpin-old/source/_talks/goodbye-drush-make-hello-composer.md
+++ /dev/null
@@ -1,33 +0,0 @@
----
-title: Goodbye Drush Make. Hello Composer!
-description: How to use Composer to manage your Drupal applications.
-tags: ['meetup', 'drupal', 'composer']
-speakerdeck:
- id: 1c1e0e129ab34816bd4c4edb5f6642c2
- ratio: '1.37081659973226'
- url: https://speakerdeck.com/opdavies/goodbye-drush-make-hello-composer
-video:
- type: youtube
- id: ZL2FtRTX9Y8
-events:
- - event: drupal_bristol
- date: 2016-11-17
- - event: php_uk_18
- date: 2018-02-16
- time: '14:40 - 15:40'
- joindin: https://joind.in/talk/650ab
----
-
-One of the main outcomes of Drupal 8 was “getting off the island” with
-third-party code included in core and adopting modern best practices from the
-wider PHP ecosystem - including [Composer][1], PHP’s dependency manager.
-
-Included to manage core’s dependencies, it has also gained traction in the
-contrib space with the creation of the Drupal Composer project, and the Drupal
-Packagist and now native endpoints on Drupal.org exposing contrib project
-metadata.
-
-In this session, I'll show how to fully manage a Drupal 7 or Drupal 8 website
-including contributed modules and themes and external libraries with Composer.
-
-[1]: https://getcomposer.org
diff --git a/astro/sculpin-old/source/_talks/it-all-started-with-a-patch.md b/astro/sculpin-old/source/_talks/it-all-started-with-a-patch.md
deleted file mode 100644
index 1bfa8496..00000000
--- a/astro/sculpin-old/source/_talks/it-all-started-with-a-patch.md
+++ /dev/null
@@ -1,18 +0,0 @@
----
-title: It All Started With A Patch
-description: A lightning talk on how and why to get involved with open source.
-type: Lightning talk
-tags: [meetup, phpsw, open-source]
-speakerdeck:
- id: 5862bdecb7a24cfaa5fc844696fafa0c
- ratio: '1.37081659973226'
- url: https://speakerdeck.com/opdavies/it-all-started-with-a-patch-phpsw
-video:
- type: youtube
- id: 5FYMRR61sdo
-events:
- - event: phpsw
- date: 2017-02-08
----
-
-A crash course of why and how to get involved with open source.
diff --git a/astro/sculpin-old/source/_talks/modern-drupal-development-with-composer.md b/astro/sculpin-old/source/_talks/modern-drupal-development-with-composer.md
deleted file mode 100644
index 41695772..00000000
--- a/astro/sculpin-old/source/_talks/modern-drupal-development-with-composer.md
+++ /dev/null
@@ -1,27 +0,0 @@
----
-title: Modern Drupal Development with Composer
-description:
- A lightning talk on how to use Composer to manage your Drupal projects.
-type: Lightning talk
-tags: ['meetups', 'phpsw', 'drupal', 'composer']
-speakerdeck:
- id: 7a1358502526425a9cfd288f85fb32f3
- ratio: '1.37081659973226'
- url: https://speakerdeck.com/opdavies/modern-drupal-development-with-composer
-video:
- type: youtube
- id: Yi_FPI3xHwc
-events:
- - event: phpsw
- date: 2016-11-09
----
-
-Building a Drupal application? You no longer need to download archives to add
-new modules or update core, or deal with Drupal specific tools to manage your
-codebase.
-
-With Drupal "getting off the island" there has been an increase in the adoption
-of common PHP tools within the Drupal ecosystem.
-
-In this lightning talk, I’ll show how to build a Drupal application using
-Composer for dependency management.
diff --git a/astro/sculpin-old/source/_talks/out-of-the-box-initiative-update.md b/astro/sculpin-old/source/_talks/out-of-the-box-initiative-update.md
deleted file mode 100644
index d73ec984..00000000
--- a/astro/sculpin-old/source/_talks/out-of-the-box-initiative-update.md
+++ /dev/null
@@ -1,35 +0,0 @@
----
-title: Out of the Box Initiative Update
-description:
- An update on Drupal’s "out of the box" initiative, and core’s new Umami
- installation profile.
-speakerdeck:
- id: 3f66c48653f44ed4867fc3cc05c1db06
- ratio: '1.77777777777778'
- url: https://speakerdeck.com/opdavies/out-of-the-box-initiative-update
-video:
- type: youtube
- id: ~
-tags: [meetup, drupal]
-events:
- - event: drupal_bristol
- date: 2019-03-27
----
-
-From the
-[DrupalCamp London website](https://drupalcamp.london/session/out-box-initiative-update):
-
-> Since the last DrupalCamp London, the Umami Demo install profile is now one of
-> the options shown to anyone installing Drupal. But this doesn't mean we've
-> finished.
-
-> There are many existing Drupal features that we want to showcase, and new
-> features stabilising with each minor release. Join the Out of the Box
-> initiative leads Keith Jay (kjay) and Gareth Goodwin (smaz) for this session,
-> where we'll talk about:
-
-> - Where we are, and how we got here
-
-- Our targets for inclusion in Drupal 8.7.0
-- How you can help!
-- Plans for the more distant future
diff --git a/astro/sculpin-old/source/_talks/so-what-is-this-drupal-thing.md b/astro/sculpin-old/source/_talks/so-what-is-this-drupal-thing.md
deleted file mode 100644
index a29d8f8d..00000000
--- a/astro/sculpin-old/source/_talks/so-what-is-this-drupal-thing.md
+++ /dev/null
@@ -1,14 +0,0 @@
----
-title: So, what is this Drupal thing?
-description:
- My first talk, where I talk about Drupal, what it is and what it can do.
-video:
- type: vimeo
- id: 49827006
-tags: [meetup, drupal, unified-diff]
-events:
- - event: unified_diff
- date: 2012-09-05
----
-
-My very first talk, where I talk about Drupal, what it is and what it can do.
diff --git a/astro/sculpin-old/source/_talks/taking-flight-with-tailwind-css.md b/astro/sculpin-old/source/_talks/taking-flight-with-tailwind-css.md
deleted file mode 100644
index 9a1b5310..00000000
--- a/astro/sculpin-old/source/_talks/taking-flight-with-tailwind-css.md
+++ /dev/null
@@ -1,58 +0,0 @@
----
-title: Taking Flight with Tailwind CSS
-description:
- An introduction to the utility-first approach to writing CSS with a focus on
- the Tailwind CSS framework.
-speakerdeck:
- id: 10ca51f23560443d83b898a92929b4b3
- ratio: '1.77777777777778'
- url: https://speakerdeck.com/opdavies/taking-flight-with-tailwind-css
-video:
- type: youtube
- id: A-EUdvSAi_I
-tags: [css, tailwind, meetup]
-events:
- - event: drupal_bristol
- date: 2018-01-17
- - event: php_south_wales
- date: 2018-07-31
- - event: wpchelt
- date: 2019-04-17
- - event: wordcamp_bristol_2019
- date: 2019-05-18
- - event: blue_conf_19
- date: 2019-06-07
- - event: cms_philly_20
- date: 2020-05-01
- remote: true
-meta:
- og:
- title: Taking Flight with Tailwind CSS
- description: An introduction to utility CSS and Tailwind.
- type: website
- image:
- url: '/images/talks/taking-flight-tailwind.jpg'
- width: 2560
- height: 1440
- type: 'image/png'
----
-
-An introduction to utility class and component based styling, and how to soar
-with [Tailwind CSS][1].
-
-Things we’ll cover:
-
-- Advantages and disadvantages to utility based styling and Tailwind.
-- How to install Tailwind and add it to your build process using tools such as
- Symfony Encore and Laravel Mix.
-- How to configure and customise Tailwind for your project.
-- How to promote repeating classes into re-usable components for better
- maintainability.
-- Strategies to control the file size, and using external tools like PurgeCSS.
-
-Also, if time allows:
-
-- How to extend Tailwind and add extra classes with community written plugins.
-- How to write and test your own custom plugins.
-
-[1]: https://tailwindcss.com
diff --git a/astro/sculpin-old/source/_talks/tdd-test-driven-drupal.md b/astro/sculpin-old/source/_talks/tdd-test-driven-drupal.md
deleted file mode 100644
index 290edce7..00000000
--- a/astro/sculpin-old/source/_talks/tdd-test-driven-drupal.md
+++ /dev/null
@@ -1,88 +0,0 @@
----
-title: TDD - Test Driven Drupal
-description:
- How to write automated tests for Drupal, and how to create a new Drupal module
- using test driven development.
-speakerdeck:
- id: 088cb18033064f5cb18d1079795294a1
- ratio: '1.77777777777778'
- url: 'https://speakerdeck.com/opdavies/tdd-test-driven-drupal'
-video:
- type: youtube
- id: 3AUhpkxZ7DQ
-tags: [drupalcamp, simpletest, phpunit, testing]
-has_tweets: true
-image:
- url: /images/talks/test-driven-drupal-development.png
- width: 2560
- height: 1440
- type: image/png
-use: [talks]
-events:
- - event: drupalcamp_london_17
- date: 2017-03-04
- time: '16:15 - 17:00'
- - event: drupalcamp_dublin_17
- date: 2017-10-21
- time: '12:00 - 12:40'
- - event: drupal_bristol
- date: 2017-11-22
- - event: drupal_somerset
- date: 2018-06-14
- - event: drupal_dev_days_18
- date: 2018-07-05
- time: '12:15 - 13:00'
- - event: drupalcamp_london_19
- date: 2019-03-02
- time: '14:00 - 14:45'
- - event: nwdug
- date: 2020-05-12
- remote: true
----
-
-{% block content %}
-
-
-Testing is important. Why? It allows developers to add new features and edit and
-refactor existing code without the worry of adding regressions, reduces the
-reliance on manual testing to discover bugs, and by taking a test driven
-approach, your implementation code is leaner as you only write what is needed
-for your tests to pass.
-
-Drupal 7 includes the SimpleTest module for unit and functional testing, whilst
-Drupal 8 also includes and supports PHPUnit - the defacto PHP testing framework,
-used by other PHP projects including Symfony and Laravel - making it easier for
-people to test their code. And with testing being one of the Drupal core gates
-with tests needing to be included with every new feature or bug fix, and core’s
-100% pass rate policy, testing has become an essential skill when contributing
-to core, or when working on your own projects.
-
-In this talk, we’ll cover the methodology and terminology involved with
-automated testing, and then take a test driven approach to creating a new Drupal
-module.
-
-
-{% endblock %}
-
-{% block tweets %}
-
-
-
Terrible quality photo but the talk drove me to test and it's great so far, it's really helped give me peace of mind and helped me uncover a bug I wouldn't have otherwise :) so thank you 😁
-{% endblock %}
diff --git a/astro/sculpin-old/source/_talks/test-drive-twig-with-sculpin.md b/astro/sculpin-old/source/_talks/test-drive-twig-with-sculpin.md
deleted file mode 100644
index 2252ba85..00000000
--- a/astro/sculpin-old/source/_talks/test-drive-twig-with-sculpin.md
+++ /dev/null
@@ -1,31 +0,0 @@
----
-title: Test Drive Twig with Sculpin
-description:
- With Drupal 8 just around the corner, see how you can develop your Twig skills
- with Sculpin - a static site generator based on Symfony components and Twig.
-speakerdeck:
- id: 54589d2e50a3476a9a75aed809e9edf1
- ratio: '1.77777777777778'
- url: https://speakerdeck.com/opdavies/test-drive-twig-with-sculpin
-code: https://github.com/opdavies/sculpin-demo
-tags: [conference, drupalcamp, drupalcamp-north, sculpin, twig]
-tweets: yes
-events:
- - event: drupalcamp_north_15
- date: 2015-07-25
----
-
-[Sculpin][1] is a static site generator written in PHP, and based on [Symfony
-components][2]. It uses [YAML][3] and [Twig][4], which makes it very appealing
-to Drupal people wanting to learn these in preparation for Drupal 8.
-
-This session covered how to install Sculpin itself, as well as how to use it to
-build a static site from Markdown, HTML and Twig templates. We also covered
-Sculpin concepts such as content types, themes and partials, and Twig layouts,
-blocks and inheritance, as well as some tips and tricks that I've found whilst
-developing with Sculpin.
-
-[1]: https://sculpin.io
-[2]: http://symfony.com/doc/current/components/index.html
-[3]: http://yaml.org
-[4]: http://twig.sensiolabs.org
diff --git a/astro/sculpin-old/source/_talks/things-you-should-know-about-php.md b/astro/sculpin-old/source/_talks/things-you-should-know-about-php.md
deleted file mode 100644
index c7d5a8e7..00000000
--- a/astro/sculpin-old/source/_talks/things-you-should-know-about-php.md
+++ /dev/null
@@ -1,22 +0,0 @@
----
-title: Things you should know about PHP
-description:
- An introduction to PHP, presented to the Swansea Software Development
- Community (SSDC) meetup.
-speakerdeck:
- id: fe360f1030f34bdb9eb14cdab907bb3c
- ratio: '1.37081659973226'
-tags:
- - meetup
- - php
-meta:
- og:
- image:
- url: /images/talks/things-you-should-know-about-php.png
-events:
- - event: ssdc
- date: 2019-01-28
----
-
-An introduction to PHP, presented to the Swansea Software Development Community
-(SSDC) meetup.
diff --git a/astro/sculpin-old/source/_talks/using-illuminate-collections-outside-laravel.md b/astro/sculpin-old/source/_talks/using-illuminate-collections-outside-laravel.md
deleted file mode 100644
index 077bd70b..00000000
--- a/astro/sculpin-old/source/_talks/using-illuminate-collections-outside-laravel.md
+++ /dev/null
@@ -1,28 +0,0 @@
----
-title: Using Illuminate Collections... Outside Laravel
-description:
- How to include and use Laravel’s Illuminate Collections in your non-Laravel
- PHP projects.
-speakerdeck:
- id: 76f1718a75a74940b0b028aac8b9f78b
- ratio: '1.77777777777778'
- url: https://speakerdeck.com/opdavies/using-laravel-collections-dot-dot-dot-outside-laravel-php-south-wales-august-2018
-video:
- type: youtube
- id: 1l0kO-iaN_o
-tags: [nomad-php, lightning-talk, laravel, collections]
-type: Lightning talk
-events:
- - event: nomad_php
- date: 2017-12-21
- time: 19:00 CET
- - event: php_south_wales
- date: 2018-08-28
----
-
-Laravel's Illuminate Collections are a powerful object-orientated way of
-interacting with PHP arrays, but did you know that they can be used outside of
-Laravel, in any PHP project?
-
-This short talk shows how we can use Composer to include Illuminate Collections
-within a non-Laravel project and put them to use within your own code.
diff --git a/astro/sculpin-old/source/articles/archive.html.twig b/astro/sculpin-old/source/articles/archive.html.twig
deleted file mode 100644
index fed72bba..00000000
--- a/astro/sculpin-old/source/articles/archive.html.twig
+++ /dev/null
@@ -1,26 +0,0 @@
----
-layout: default
-title: Archive
-use: [posts]
----
-{% block content %}
-
-
Everything I've ever published on my site, in reverse chronological order.
I enjoy writing articles, and have written a number of them so far during my career, both to document my own learning as well to act as resources for others.
-
Here are some of my favourites.
-
-
-
- {% for post in data.posts if post.promoted %}
-
- {% include 'blog/post-summary' %}
-
- {% endfor %}
-
-
-
-
diff --git a/astro/sculpin-old/source/articles/tags.html b/astro/sculpin-old/source/articles/tags.html
deleted file mode 100644
index d7a18da8..00000000
--- a/astro/sculpin-old/source/articles/tags.html
+++ /dev/null
@@ -1,32 +0,0 @@
----
-layout: default
-nav: blog
-title: Tags
-use:
- - posts_tags
----
-{% set rows = {} %}
-{% for tag, posts in data.posts_tags %}
- {% set rows = rows|merge({ (tag): posts|length }) %}
-{% endfor %}
-
-
-
-
-
-
Tag
-
Number of posts
-
-
-
- {% for tag, post_count in rows|sort|reverse %}
-
-
- )
-}
diff --git a/astro/src/content/blog/10-years-working-full-time-drupal-php.md b/astro/src/content/blog/10-years-working-full-time-drupal-php.md
deleted file mode 100644
index f0f36b75..00000000
--- a/astro/src/content/blog/10-years-working-full-time-drupal-php.md
+++ /dev/null
@@ -1,29 +0,0 @@
----
-title: 10 years working full time with Drupal and PHP
-excerpt: 10 years ago today, I started working for Horse & Country TV in what was my full-time Drupal development role.
-tags:
- - drupal
- - personal
- - php
-date: 2020-07-19
----
-
-
10 years ago today, I started my first full-time Web Developer job, working for @HorseAndCountry on their (at the time) #Drupal 6 website.
-
-10 years ago today, I started working for [Horse & Country TV](https://horseandcountry.tv) in what was my full-time Drupal development role.
-
-I'd been learning and working with Drupal for a couple of years prior to this, working on some personal and freelance projects, but when I was looking to move back to this area of Wales, this job on my doorstep was ideal.
-
-Initially starting as the sole Developer before another started a few months later, I remember being very excited to see and learn how this site has been built. Some of the main things that I remember working on was re-developing the Events section and adding paid events with [Ubercart](https://www.drupal.org/project/ubercart), and expanding my module development knowledge by adding a custom block that programmatically showed the current and next programme on the channel.
-
-As well as working with Drupal itself, it was a great opportunity to get more hands-on experience with Linux servers and to learn new tools such as [Git](https://git-scm.com) for version control.
-
-I also remember being asked to contribute to a public issue on Drupal.org as part of the interview process to demonstrate my debugging abilities. I decided to look at [this Drupal 6 issue](https://www.drupal.org/node/753898), and posted a comment with some updated code that I then forwarded on, and then uploaded a patch to the issue queue. This is still one of my favourite approaches for interviews, and one that I've used myself since when interviewing people for roles that use open source technologies. I much prefer this to working on internal, company specific coding tests, as it gives the interviewee some real world experience and exposure to the project itself and its community, rather than just how to _use_ it.
-
-Posting on a Drupal core issue and submitting patches was a bit scary at the time, but I think paved the way for me later contributing to core and other Drupal and open source projects. In fact, I was a Contribution Day mentor at DrupalCon Los Angeles in 2015 and helped someone get _their_ first commit to core when [a fix was committed to Drupal 8](https://git.drupalcode.org/project/drupal/commit/9cdd22c).
-
-After this role, I've worked for various agencies working primarily with Drupal and PHP, as well as for the [Drupal Association](https://www.drupal.org/assocation) itself. Whilst in recent years I've also started working with other frameworks like Symfony and Vue.js, Drupal and PHP has always been my core specialism.
-
-I've been very excited by the developments in both PHP and Drupal in recent versions, and I'm looking forward to the next 10 years working with them.
-
-Thank you Horse & Country for giving me the chance to start on my full-time Drupal journey!
diff --git a/astro/src/content/blog/2014.md b/astro/src/content/blog/2014.md
deleted file mode 100644
index 0ecae67b..00000000
--- a/astro/src/content/blog/2014.md
+++ /dev/null
@@ -1,84 +0,0 @@
----
-title: "2014"
-date: 2015-03-20
-excerpt: A look back at 2014.
-tags:
- - drupal-association
- - drupalcamp-london
- - personal
-tweets: true
----
-
-A lot happened in 2014. Here are some of the main things that I'd like to
-highlight.
-
-## Joined the Drupal Association
-
-This was the main thing for me this year, in May I left
-[Precedent](http://precedent.com) and joined the
-[Drupal Association](https://assoc.drupal.org). I work on the Engineering team,
-focused mainly on [Drupal.org](https://www.drupal.org) but I've also done some
-theming work on the DrupalCon [Amsterdam](http://amsterdam2014.drupal.org) and
-[Latin America](http://latinamerica2015.drupal.org) websites, and some
-pre-launch work on [Drupal Jobs](https://jobs.drupal.org).
-
-Some of the tasks that I've worked on so far are:
-
-- Fixing remaining issues from the Drupal.org Drupal 7 upgrade.
-- Improving pages for
- [Supporting Partners](https://www.drupal.org/supporters/partners),
- [Technology Supporters](https://www.drupal.org/supporters/technology) and
- [Hosting Partners](https://www.drupal.org/supporters/hosting). These
- previously were manually updated pages using HTML tables, which are now
- dynamic pages built with [Views](https://www.drupal.org/project/views) using
- organisation nodes.
-- Configuring human-readable paths for user profiles using
- [Pathauto](https://www.drupal.org/project/pathauto). Only a small change, but
- made a big difference to end-users.
-- Migration of user data from profile values to fields, and various user profile
- improvements. This was great because now we can do things like reference
- mentors by their username and display their picture on your profile, as well
- as show lists of peope listing a user as their mentor. This, I think, adds a
- more personal element to Drupal.org because we can see the actual people and
- not just a list of names on a page.
-
-I've started keeping a list of tasks that I've been involved with on my
-[Work](/work/) page, and will be adding more things as I work on them.
-
-### Portland
-
-I was able to travel to Portland, Oregon twice last year to meet with the rest
-of the Association staff. Both times I met new people and it was great to spend
-some work and social time with everyone, and it was great to have everyone
-together as a team.
-
-## My First DrupalCamp
-
-In February, I attended [DrupalCamp London](http://2014.drupalcamplondon.co.uk).
-This was my first time attending a Camp, and I managed to attend some great
-sessions as well as meet people who I'd never previously met in person. I was
-also a volunteer and speaker, where I talked about
-[Git Flow](/blog/what-git-flow/) - a workflow for managing your Git projects.
-
-{% include 'tweet' with {
- content: '
— Greg Franklin (@gfranklin) March 2, 2014'
-} %}
-
-I was also able to do a little bit of sprinting whilst I was there, reviewing
-other people's modules and patches.
-
-Attending this and [DrupalCon Prague](https://prague2013.drupal.org) in 2013
-have really opened my eyes to the face-to-face side of the Drupal community, and
-I plan on attending a lot more Camps and Cons in the future.
-
-## DrupalCon Amsterdam
-
-I was also able to travel to Holland and attend
-[DrupalCon Amsterdam](https://amsterdam2014.drupal.org) along with other members
-of Association staff.
-
-## DrupalCamp Bristol
-
-In October, we started planning for
-[DrupalCamp Bristol](http://www.drupalcampbristol.co.uk). I'm one of the
-founding Committee members,
diff --git a/astro/src/content/blog/accessible-bristol-site.md b/astro/src/content/blog/accessible-bristol-site.md
deleted file mode 100644
index 4c0d7891..00000000
--- a/astro/src/content/blog/accessible-bristol-site.md
+++ /dev/null
@@ -1,30 +0,0 @@
----
-title: Accessible Bristol site launched
-date: 2012-11-15
-excerpt:
- I'm happy to report that the Accessible Bristol was launched this week, on
- Drupal 7.
-tags:
- - accessibility
- - accessible-bristol
- - nomensa
----
-
-I'm happy to announce that the
-[Accessible Bristol](http://www.accessiblebristol.org.uk) website was launched
-this week, on Drupal 7. The site has been developed over the past few months,
-and uses the [User Relationships](http://drupal.org/project/user_relationships)
-and [Privatemsg](http://drupal.org/project/privatemsg) modules to provide a
-community-based platform where people with an interest in accessibility can
-register and network with each other.
-
-The site has been developed over the past few months, and uses the
-[User Relationships](http://drupal.org/project/user_relationships) and
-[Privatemsg](http://drupal.org/project/privatemsg) modules to provide a
-community-based platform where people with an interest in accessibility can
-register and network with each other.
-
-The group is hosting a launch event on the 28th November at the Council House,
-College Green, Bristol. Interested? More information is available at
- or go to
- to register.
diff --git a/astro/src/content/blog/add-taxonomy-term-multiple-nodes-using-sql.md b/astro/src/content/blog/add-taxonomy-term-multiple-nodes-using-sql.md
deleted file mode 100644
index 7b9ca026..00000000
--- a/astro/src/content/blog/add-taxonomy-term-multiple-nodes-using-sql.md
+++ /dev/null
@@ -1,79 +0,0 @@
----
-title: Add a Taxonomy Term to Multiple Nodes Using SQL
-date: 2010-07-07
-excerpt: How to add a new taxonomy term to multiple nodes in Drupal using SQL.
-tags:
- - database
- - drupal-6
- - drupal-planet
- - sequal-pro
- - sql
- - taxonomy
----
-
-In preparation for my Blog posts being added to
-[Drupal Planet](http://drupal.org/planet), I needed to create a new Taxonomy
-term (or, in this case, tag) called 'Drupal Planet', and assign it to new
-content to imported into their aggregator. After taking a quick look though my
-previous posts, I decided that 14 of my previous posts were relevant, and
-thought that it would be useful to also assign these the 'Drupal Planet' tag.
-
-I didn't want to manually open each post and add the new tag, so I decided to
-make the changes myself directly into the database using SQL, and as a follow-up
-to a previous post -
-[Quickly Change the Content Type of Multiple Nodes using SQL](/blog/change-content-type-multiple-nodes-using-sql/).
-
-**Again, before changing any values within the database, ensure that you have an
-up-to-date backup which you can restore if you encounter a problem!**
-
-The first thing I did was create the 'Drupal Planet' term in my Tags vocabulary.
-I decided to do this via the administration area of my site, and not via the
-database. Then, using [Sequel Pro](http://www.sequelpro.com), I ran the
-following SQL query to give me a list of Blog posts on my site - showing just
-their titles and nid values.
-
-```sql
-SELECT title, nid FROM node WHERE TYPE = 'blog' ORDER BY title ASC;
-```
-
-I made a note of the nid's of the returned nodes, and kept them for later. I
-then ran a similar query against the term_data table. This returned a list of
-Taxonomy terms - showing the term's name, and it's unique tid value.
-
-```sql
-SELECT NAME, tid FROM term_data ORDER BY NAME ASC;
-```
-
-The term that I was interested in, Drupal Planet, had the tid of 84. To confirm
-that no nodes were already assigned a taxonomy term with this tid, I ran another
-query against the database. I'm using aliases within this query to link the
-node, term_node and term_data tables. For more information on SQL aliases, take
-a look at .
-
-```sql
-SELECT * FROM node n, term_data td, term_node tn WHERE td.tid = 84 AND n.nid = tn.nid AND tn.tid = td.tid;
-```
-
-As expected, it returned no rows.
-
-The table that links node and term_data is called term_node, and is made up of
-the nid and vid columns from the node table, as well as the tid column from the
-term_data table. Is it is here that the additional rows would need to be
-entered.
-
-To confirm everything, I ran a simple query against an old post. I know that the
-only taxonomy term associated with this post is 'Personal', which has a tid
-value of 44.
-
-```sql
-SELECT nid, tid FROM term_node WHERE nid = 216;
-```
-
-Once the query had confirmed the correct tid value, I began to write the SQL
-Insert statement that would be needed to add the new term to the required nodes.
-The nid and vid values were the same on each node, and the value of my taxonomy
-term would need to be 84.
-
-Once this had completed with no errors, I returned to the administration area of
-my Drupal site to confirm whether or not the nodes had been assigned the new
-term.
diff --git a/astro/src/content/blog/adding-custom-theme-templates-drupal-7.md b/astro/src/content/blog/adding-custom-theme-templates-drupal-7.md
deleted file mode 100644
index 3387875f..00000000
--- a/astro/src/content/blog/adding-custom-theme-templates-drupal-7.md
+++ /dev/null
@@ -1,84 +0,0 @@
----
-title: Adding Custom Theme Templates in Drupal 7
-date: 2012-04-19
-excerpt: >
- Today, I had a situation where I was displaying a list of teasers for news
- article nodes. The article content type had several different fields assigned
- to it, including main and thumbnail images. In this case, I wanted to have
- different output and fields displayed when a teaser was displayed compared to
- when a complete node was displayed.
-tags:
- - drupal
- - drupal-planet
----
-
-Today, I had a situation where I was displaying a list of teasers for news
-article nodes. The article content type had several different fields assigned to
-it, including main and thumbnail images. In this case, I wanted to have
-different output and fields displayed when a teaser was displayed compared to
-when a complete node was displayed.
-
-I have previously seen it done this way by adding this into in a node.tpl.php
-file:
-
-```php
-if ($teaser) {
- // The teaser output.
-}
-else {
- // The whole node output.
-}
-```
-
-However, I decided to do something different and create a separate template file
-just for teasers. This is done using the hook_preprocess_HOOK function that I
-can add into my theme's template.php file.
-
-The function requires the node variables as an argument - one of which is
-theme_hook_suggestions. This is an array of suggested template files that Drupal
-looks for and attempts to use when displaying a node, and this is where I'll be
-adding a new suggestion for my teaser-specific template. Using the `debug()`
-function, I can easily see what's already there.
-
-```php
-array (
- 0 => 'node__article',
- 1 => 'node__343',
- 2 => 'node__view__latest_news',
- 3 => 'node__view__latest_news__page',
-)
-```
-
-So, within my theme's template.php file:
-
-```php
-/**
- * Implementation of hook_preprocess_HOOK().
- */
-function mytheme_preprocess_node(&$variables) {
- $node = $variables['node'];
-
- if ($variables['teaser']) {
- // Add a new item into the theme_hook_suggestions array.
- $variables['theme_hook_suggestions'][] = 'node__' . $node->type . '_teaser';
- }
-}
-```
-
-After adding the new suggestion:
-
-```php
-array (
- 0 => 'node__article',
- 1 => 'node__343',
- 2 => 'node__view__latest_news',
- 3 => 'node__view__latest_news__page',
- 4 => 'node__article_teaser',
-)
-```
-
-Now, within my theme I can create a new node--article-teaser.tpl.php template
-file and this will get called instead of the node--article.tpl.php when a teaser
-is loaded. As I'm not specifying the node type specifically and using the
-dynamic \$node->type value within my suggestion, this will also apply
-for all other content types on my site and not just news articles.
diff --git a/astro/src/content/blog/announcing-the-drupal-vm-generator.md b/astro/src/content/blog/announcing-the-drupal-vm-generator.md
deleted file mode 100644
index e6677791..00000000
--- a/astro/src/content/blog/announcing-the-drupal-vm-generator.md
+++ /dev/null
@@ -1,106 +0,0 @@
----
-title: Announcing the Drupal VM Generator
-date: 2016-02-15
-excerpt: For the past few weeks, I’ve been working on a personal side project based on Drupal VM - the Drupal VM Generator.
-tags:
- - drupal
- - drupal-planet
- - drupal-vm
- - drupal-vm-generator
- - symfony
----
-
-For the past few weeks, I’ve been working on a personal side project based on
-Drupal VM. It’s called the [Drupal VM Generator][1], and over the weekend I’ve
-added the final features and fixed the remaining issues, and tagged the 1.0.0
-release.
-
-
-
-## What is Drupal VM?
-
-[Drupal VM][2] is a project created and maintained by [Jeff Geerling][3]. It’s a
-[Vagrant][4] virtual machine for Drupal development that is provisioned using
-[Ansible][5].
-
-What is different to a regular Vagrant VM is that uses a file called
-`config.yml` to configure the machine. Settings such as `vagrant_hostname`,
-`drupalvm_webserver` and `drupal_core_path` are stored as YAML and passed into
-the `Vagrantfile` and the `playbook.yml` file which is used when the Ansible
-provisioner runs.
-
-In addition to some essential Ansible roles for installing and configuring
-packages such as Git, MySQL, PHP and Drush, there are also some roles that are
-conditional and only installed based on the value of other settings. These
-include Apache, Nginx, Solr, Varnish and Drupal Console.
-
-## What does the Drupal VM Generator do?
-
-> The Drupal VM Generator is a Symfony application that allows you to quickly
-> create configuration files that are minimal and use-case specific.
-
-Drupal VM comes with an [example.config.yml file][6] that shows all of the
-default variables and their values. When I first started using it, I’d make a
-copy of `example.config.yml`, rename it to `config.yml` and edit it as needed,
-but a lot of the examples aren’t needed for every use case. If you’re using
-Nginx as your webserver, then you don’t need the Apache virtual hosts. If you
-are not using Solr on this project, then you don’t need the Solr variables.
-
-For a few months, I’ve kept and used boilerplace versions of `config.yml` - one
-for Apache and one for Nginx. These are minimal, so have most of the comments
-removed and only the variables that I regularly need, but these can still be
-quite time consuming to edit each time, and if there are additions or changes
-upstream, then I have two versions to maintain.
-
-The Drupal VM Generator is a Symfony application that allows you to quickly
-create configuration files that are minimal and use-case specific. It uses the
-[Console component][7] to collect input from the user, [Twig][8] to generate the
-file, the [Filesystem component][9] to write it.
-
-Based on the options passed to it and/or answers that you provide, it generates
-a custom, minimal `config.yml` file for your project.
-
-Here’s an example of it in action:
-
-
-
-You can also define options when calling the command and skip any or all
-questions. Running the following would bypass all of the questions and create a
-new file with no interaction or additional steps.
-
-{{ gist('24e569577ca4b72f049d', 'with-options.sh') }}
-
-## Where do I get it?
-
-The project is hosted on [GitHub][1], and there are installation instructions
-within the [README][10].
-
-
-
-The recommended method is via downloading the phar file (the same as Composer
-and Drupal Console). You can also clone the GitHub repository and run the
-command from there. I’m also wanting to upload it to Packagist so that it can be
-included if you manage your projects with Composer.
-
-Please log any bugs or feature requests in the [GitHub issue tracker][11], and
-I’m more than happy to receive pull requests.
-
-If you’re interested in contributing, please feel free to fork the repository
-and start doing so, or contact me with any questions.
-
-**Update 17/02/16:** The autoloading issue is now fixed if you require the
-package via Composer, and this has been tagged as the [1.0.1 release][12]
-
-[1]: https://github.com/opdavies/drupal-vm-generator
-[2]: http://www.drupalvm.com
-[3]: http://www.jeffgeerling.com
-[4]: http://www.vagrantup.com
-[5]: https://www.ansible.com
-[6]: https://github.com/geerlingguy/drupal-vm/blob/master/example.config.yml
-[7]: http://symfony.com/doc/current/components/console/introduction.html
-[8]: http://twig.sensiolabs.org
-[9]: http://symfony.com/doc/current/components/filesystem/introduction.html
-[10]:
- https://github.com/opdavies/drupal-vm-generator/blob/master/README.md#installation
-[11]: https://github.com/opdavies/drupal-vm-generator/issues
-[12]: https://github.com/opdavies/drupal-vm-generator/releases/tag/1.0.1
diff --git a/astro/src/content/blog/automating-sculpin-jenkins.md b/astro/src/content/blog/automating-sculpin-jenkins.md
deleted file mode 100644
index f42cc60d..00000000
--- a/astro/src/content/blog/automating-sculpin-jenkins.md
+++ /dev/null
@@ -1,192 +0,0 @@
----
-title: Automating Sculpin Builds with Jenkins CI
-date: 2015-07-21
-excerpt: How to use Jenkins to automate building Sculpin websites.
-tags:
- - jenkins
- - sculpin
----
-
-As part of re-building this site with [Sculpin](http://sculpin.io), I wanted to
-automate the deployments, as in I wouldn't need to run a script like
-[publish.sh](https://raw.githubusercontent.com/sculpin/sculpin-blog-skeleton/master/publish.sh)
-locally and have that deploy my code onto my server. Not only did that mean that
-my local workflow was simpler (update, commit and push, rather than update,
-commit, push and deploy), but if I wanted to make a quick edit or hotfix, I
-could log into GitHub or Bitbucket (wherever I decided to host the source code)
-from any computer or my phone, make the change and have it deployed for me.
-
-I'd started using [Jenkins CI](http://jenkins-ci.org) during my time at the
-Drupal Association, and had since built my own Jenkins server to handle
-deployments of Drupal websites, so that was the logical choice to use.
-
-## Installing Jenkins and Sculpin
-
-If you don’t already have Jenkins installed and configured, I'd suggest using
-[Jeff Geerling](http://jeffgeerling.com/) (aka geerlingguy)'s
-[Ansible role for Jenkins CI](https://galaxy.ansible.com/list#/roles/440).
-
-I've also released an
-[Ansible role for Sculpin](https://galaxy.ansible.com/list#/roles/4063) that
-installs the executable so that the Jenkins server can run Sculpin commands.
-
-## Triggering a Build from a Git Commit
-
-I created a new Jenkins item for this task, and restricted where it could be run
-to `master` (i.e. the Jenkins server rather than any of the nodes).
-
-### Polling from Git
-
-I entered the url to the
-[GitHub repo](https://github.com/opdavies/oliverdavies.uk) into the **Source
-Code Management** section (the Git option _may_ have been added by the
-[Git plugin](https://wiki.jenkins-ci.org/display/JENKINS/Git+Plugin) that I have
-installed).
-
-As we don’t need any write access back to the repo, using the HTTP URL rather
-than the SSH one was fine, and I didn’t need to provide any additional
-credentials.
-
-Also, as I knew that I’d be working a lot with feature branches, I entered
-`*/master` as the only branch to build. This meant that pushing changes or
-making edits on any other branches would not trigger a build.
-
-
-
-I also checked the **Poll SCM** option so that Jenkins would be routinely
-checking for updated code. This essentially uses the same syntax as cron,
-specifying minutes, hours etc. I entered `* * * * *` so that Jenkins would poll
-each minute, knowing that I could make this less frequent if needed.
-
-This now that Jenkins would be checking for any updates to the repo each minute,
-and could execute tasks if needed.
-
-### Building and Deploying
-
-Within the **Builds** section of the item, I added an _Execute Shell_ step,
-where I could enter a command to execute. Here, I pasted a modified version of
-the original publish.sh script.
-
-```bash
-#!/bin/bash
-
-set -uex
-
-sculpin generate --env=prod --quiet
-if [ $? -ne 0 ]; then echo "Could not generate the site"; exit 1; fi
-
-rsync -avze 'ssh' --delete output_prod/ prodwww2:/var/www/html/oliverdavies.uk/htdocs
-if [ $? -ne 0 ]; then echo "Could not publish the site"; exit 1; fi
-```
-
-This essentially is the same as the original file, in that Sculpin generates the
-site, and uses rsync to deploy it somewhere else. In my case, `prodwww2` is a
-Jenkins node (this alias is configured in `/var/lib/jenkins/.ssh/config`), and
-`/var/www/html/oliverdavies.uk/htdocs` is the directory from where my site is
-served.
-
-## Building Periodically
-
-There is some dynamic content on my site, specifically on the Talks page. Each
-talk has a date assigned to it, and within the Twig template, the talk is
-positoned within upcoming or previous talks based on whether this date is less
-or greater than the time of the build.
-
-The YAML front matter:
-
-```yaml
----
-...
-talks:
- - title: Test Drive Twig with Sculpin
- location: DrupalCamp North
----
-```
-
-The Twig layout:
-
-```twig
-
-{% for talk in talks|reverse if talk.date >= now %}
- {# Upcoming talks #}
-{% endfor %}
-
-{% for talk in talks if talk.date < now %}
- {# Previous talks #}
-{% endfor%}
-
-```
-
-I also didn’t want to have to push an empty commit or manually trigger a job in
-Jenkins after doing a talk in order for it to be positioned in the correct place
-on the page, so I also wanted Jenkins to schedule a regular build regardless of
-whether or not code had been pushed, so ensure that my talks page would be up to
-date.
-
-After originally thinking that I'd have to split the build steps into a separate
-item and trigger that from a scheduled item, and amend my git commit item
-accordingly, I found a **Build periodically** option that I could use within the
-same item, leaving it intact and not having to make amends.
-
-I set this to `@daily` (the same `H H * * *` - `H` is a Jenkins thing), so that
-the build would be triggered automatically each day without a commit, and deploy
-any updates to the site.
-
-
-
-## Next Steps
-
-This workflow works great for one site, but as I roll out more Sculpin sites,
-I'd like to reduce duplication. I see this mainly as I’ll end up creating a
-separate `sculpin_build` item that’s decoupled from the site that it’s building,
-and instead passing variables such as environment, server name and docroot path
-as parameters in a parameterized build.
-
-I'll probably also take the raw shell script out of Jenkins and save it in a
-text file that's stored locally on the server, and execute that via Jenkins.
-This means that I’d be able to store this file in a separate Git repository with
-my other Jenkins scripts and get the standard advantages of using version
-control.
-
-## Update
-
-Since publishing this post, I've added some more items to the original build
-script.
-
-### Updating Composer
-
-```bash
-if [ -f composer.json ]; then
- /usr/local/bin/composer install
-fi
-```
-
-Updates project dependencies via
-[Composer](https://getcomposer.org/doc/00-intro.md#introduction) if
-composer.json exists.
-
-### Updating Sculpin Dependencies
-
-```bash
-if [ -f sculpin.json ]; then
- sculpin install
-fi
-```
-
-Runs `sculpin install` on each build if the sculpin.json file exists, to ensure
-that the required custom bundles and dependencies are installed.
-
-### Managing Redirects
-
-```bash
-if [ -f scripts/redirects.php ]; then
- /usr/bin/php scripts/redirects.php
-fi
-```
-
-I've been working on a `redirects.php` script that generates redirects from a
-.csv file, after seeing similar things in the
-[Pantheon Documentation](https://github.com/pantheon-systems/documentation) and
-[That Podcast](https://github.com/thatpodcast/thatpodcast.io) repositories. This
-checks if that file exists, and if so, runs it and generates the source file
-containing each redirect.
diff --git a/astro/src/content/blog/back-future-gits-diff-apply-commands.md b/astro/src/content/blog/back-future-gits-diff-apply-commands.md
deleted file mode 100644
index 72adade1..00000000
--- a/astro/src/content/blog/back-future-gits-diff-apply-commands.md
+++ /dev/null
@@ -1,72 +0,0 @@
----
-title: Back to the future with Git’s diff and apply commands
-date: 2018-04-23
-excerpt: How to revert files using Git, but as a new commit to prevent force pushing.
-tags:
- - git
----
-
-This is one of those “there’s probably already a better way to do this”
-situations, but it worked.
-
-I was having some issues this past weekend where, despite everything working
-fine locally, a server was showing a “500 Internal Server” after I pushed some
-changes to a site. In order to bring the site back online, I needed to revert
-the site files back to the previous version, but as part of a new commit.
-
-The `git reset` commands removed the interim commits which meant that I couldn’t
-push to the remote (force pushing, quite rightly, isn’t allowed for the
-production branch), and using `git revert` was resulting in merge conflicts in
-`composer.lock` that I’d rather have avoided if possible.
-
-This is what `git log --oneline -n 4` was outputting:
-
-```
-14e40bc Change webflo/drupal-core-require-dev version
-fc058bb Add services.yml
-60bcf33 Update composer.json and re-generate lock file
-722210c More styling
-```
-
-`722210c` is the commit SHA that I needed to go back to.
-
-## First Solution
-
-My first solution was to use `git diff` to create a single patch file of all of
-the changes from the current point back to the original commit. In this case,
-I’m using `head~3` (four commits before `head`) as the original reference, I
-could have alternatively used a commit ID, tag or branch name.
-
-```
-git diff head head~3 > temp.patch
-git apply -v temp.patch
-```
-
-With the files are back in the former state, I can remove the patch, add the
-files as a new commit and push them to the remote.
-
-```
-rm temp.patch
-
-git add .
-git commit -m 'Back to the future'
-git push
-```
-
-Although the files are back in their previous, working state, as this is a new
-commit with a new commit SHA reference, there is no issue with the remote
-rejecting the commit or needing to attempt to force push.
-
-## Second Solution
-
-The second solution is just a shorter, cleaner version of the first!
-
-Rather than creating a patch file and applying it, the output from `git diff`
-can be piped straight into `git apply`.
-
-```
-git diff head~3 head | git apply -v
-```
-
-This means that there’s only one command to run and no leftover patch file, and
-I can go ahead and add and commit the changes straight away.
diff --git a/astro/src/content/blog/building-gmail-filters-in-php.md b/astro/src/content/blog/building-gmail-filters-in-php.md
deleted file mode 100644
index 684d014f..00000000
--- a/astro/src/content/blog/building-gmail-filters-in-php.md
+++ /dev/null
@@ -1,102 +0,0 @@
----
-title: Building Gmail Filters with PHP
-date: 2016-07-15
-excerpt: How to use PHP to generate and export filters for Gmail.
-tags:
- - gmail
- - php
-promoted: true
----
-
-Earlier this week I wrote a small PHP library called [GmailFilterBuilder][0]
-that allows you to write Gmail filters in PHP and export them to XML.
-
-I was already aware of a Ruby library called [gmail-britta][1] that does the
-same thing, but a) I’m not that familiar with Ruby so the syntax wasn’t that
-natural to me - it’s been a while since I wrote any Puppet manifests, and b) it
-seemed like a interesting little project to work on one evening.
-
-The library contains two classes - `GmailFilter` which is used to create each
-filter, and `GmailFilterBuilder` that parses the filters and generates the XML
-using a [Twig][2] template.
-
-## Usage
-
-For example:
-
-```php
-# test.php
-
-require __DIR__ '/vendor/autoload.php';
-
-use Opdavies\GmailFilterBuilder\Builder;
-use Opdavies\GmailFilterBuilder\Filter;
-
-$filters = [];
-
-$filters[] = Filter::create()
- ->has('from:example@test.com')
- ->labelAndArchive('Test')
- ->neverSpam();
-
-new Builder($filters);
-```
-
-In this case, an email from `example@test.com` would be archived, never marked
-as spam, and have a label of "Test" added to it.
-
-With this code written, and the GmailFilterBuilder library installed via
-Composer, I can run `php test.php` and have the XML written to the screen.
-
-This can also be written to a file - `php test.php > filters.xml` - which can
-then be imported into Gmail.
-
-## Twig Extensions
-
-I also added a custom Twig extension that I moved into a separate
-[twig-extensions][5] library so that I and other people can re-use it in other
-projects.
-
-It’s a simple filter that accepts a boolean and returns `true` or `false` as a
-string, but meant that I could remove three ternary operators from the template
-and replace them with the `boolean_string` filter.
-
-Before:
-
-
-
-This can then be used to generate output like this, whereas having blank values
-would have resulted in errors when importing to Gmail.
-
-```xml
-
-```
-
-## Example
-
-For a working example, see my personal [gmail-filters][3] repository on GitHub.
-
-## Resources
-
-- [The GmailFilterBuilder library on Packagist][4]
-- [My Gmail filters on GitHub][3]
-- [My Twig Extensions on Packagist][5]
-
-[0]: https://github.com/opdavies/gmail-filter-builder
-[1]: https://github.com/antifuchs/gmail-britta
-[2]: http://twig.sensiolabs.org
-[3]: https://github.com/opdavies/gmail-filters
-[4]: https://packagist.org/packages/opdavies/gmail-filter-builder
-[5]: https://packagist.org/packages/opdavies/twig-extensions
diff --git a/astro/src/content/blog/building-oliverdavies-uk-1-initial-setup.md b/astro/src/content/blog/building-oliverdavies-uk-1-initial-setup.md
deleted file mode 100644
index f9fcf680..00000000
--- a/astro/src/content/blog/building-oliverdavies-uk-1-initial-setup.md
+++ /dev/null
@@ -1,19 +0,0 @@
----
-title: 'Building oliverdavies.uk with Sculpin: Part 1 - initial setup and configuration'
-excerpt: |
- First part of the "Building oliverdavies.uk" series, covering the initial
- Sculpin setup and configuration.
-tags: [sculpin]
-draft: true
-date: ~
----
-
-Based on .
-
-Uses .
-
-`app/config/sculpin_kernel.yml`:
-
-`app/config/sculpin_site.yml`:
-
-`app/config/sculpin_site_prod.yml`:
diff --git a/astro/src/content/blog/building-the-new-phpsw-website.md b/astro/src/content/blog/building-the-new-phpsw-website.md
deleted file mode 100644
index 76484a54..00000000
--- a/astro/src/content/blog/building-the-new-phpsw-website.md
+++ /dev/null
@@ -1,37 +0,0 @@
----
-title: Building the new PHPSW Website
-date: 2018-02-28
-excerpt:
- Earlier this week we had another hack night, working on the new PHPSW user
- group website.
-tags:
- - phpsw
- - symfony
- - tailwind-css
-has_tweets: true
----
-
-Earlier this week we had another hack night, working on the new [PHPSW user
-group][0] website.
-
-
-
-It’s built with Symfony so it’s naturally using Twig for templating. I’ve become
-a big fan of the utility based approach to CSS and [Tailwind CSS][1] in
-particular, so I’m using that for all of the styling, and using [Webpack
-Encore][2] to compile all of the assets.
-
-We have an integration with Meetup.com which we’re using to pull all of our
-previous event data and store them as JSON files for Symfony to parse and
-render, which it then uses to generate static HTML to upload onto the server.
-
-We’re in the process of populating all of the past data, but look out for a v1
-launch soon. In the meantime, feel free to take a peek at our [GitHub
-repository][3].
-
-[0]: https://phpsw.uk
-[1]: https://tailwindcss.com
-[2]: https://github.com/symfony/webpack-encore
-[3]: https://github.com/phpsw/phpsw-ng
diff --git a/astro/src/content/blog/change-content-type-multiple-nodes-using-sql.md b/astro/src/content/blog/change-content-type-multiple-nodes-using-sql.md
deleted file mode 100644
index 01744dc2..00000000
--- a/astro/src/content/blog/change-content-type-multiple-nodes-using-sql.md
+++ /dev/null
@@ -1,42 +0,0 @@
----
-title: Change the Content Type of Multiple Nodes Using SQL
-date: 2010-07-01
-excerpt:
- In this post, I will be changing values within my Drupal 6 site's database to quickly change the content type of multiple nodes.
-tags:
- - content-types
- - database
- - drupal
- - drupal-6
- - drupal-planet
- - sequel-pro
- - sql
----
-
-In this post, I will be changing values within my Drupal 6 site's database to
-quickly change the content type of multiple nodes. I will be using a test
-development site with the core Blog module installed, and converting Blog posts
-to a custom content type called 'News article'.
-
-**Before changing any values within the database, ensure that you have an
-up-to-date backup which you can restore if you encounter a problem!**
-
-To begin with, I created the 'News article' content type, and then used the
-Devel Generate module to generate some Blog nodes.
-
-Using [Sequel Pro](http://www.sequelpro.com), I can query the database to view
-the Blog posts (you can also do this via the
-[Terminal](http://guides.macrumors.com/Terminal) in a Mac OS X/Linux,
-[Oracle SQL Developer](http://www.oracle.com/technology/software/products/sql/index.html)
-on Windows, or directly within
-[phpMyAdmin](http://www.phpmyadmin.net/home_page/index.php)):
-
-Using an SQL 'Update' command, I can change the type value from 'blog' to
-'article'. This will change every occurance of the value 'blog'. If I wanted to
-only change certain nodes, I could add a 'Where' clause to only affect nodes
-with a certain nid or title.
-
-Now, when I query the database, the type is shown as 'article'.
-
-Now, when I go back into the administration section of my site and view the
-content, the content type now shows at 'News article'.
diff --git a/astro/src/content/blog/checking-if-user-logged-drupal-right-way.md b/astro/src/content/blog/checking-if-user-logged-drupal-right-way.md
deleted file mode 100644
index 071fc89d..00000000
--- a/astro/src/content/blog/checking-if-user-logged-drupal-right-way.md
+++ /dev/null
@@ -1,68 +0,0 @@
----
-title: Checking if a user is logged into Drupal (the right way)
-date: 2013-01-09
-excerpt: How to check if a user is logged in by using Drupal core API functions.
-tags:
- - drupal
- - drupal-6
- - drupal-7
- - drupal-planet
- - php
----
-
-I see this regularly when working on Drupal sites when someone wants to check
-whether the current user is logged in to Drupal (authenticated) or not
-(anonymous).
-
-```php
-global $user;
-if ($user->uid) {
- // The user is logged in.
-}
-```
-
-or
-
-```php
-global $user;
-if (!$user->uid) {
- // The user is not logged in.
-}
-```
-
-The better way to do this is to use the
-[user_is_logged_in()](http://api.drupal.org/api/drupal/modules!user!user.module/function/user_is_logged_in/7)
-function.
-
-```php
-if (user_is_logged_in()) {
- // Do something.
-}
-```
-
-This returns a boolean (TRUE or FALSE) depending or not the user is logged in.
-Essentially, it does the same thing as the first example, but there's no need to
-load the global variable.
-
-A great use case for this is within a `hook_menu()` implementation within a
-custom module.
-
-```php
-/**
- * Implements hook_menu().
- */
-function mymodule_menu() {
- $items['foo'] = array(
- 'title' => 'Foo',
- 'page callback' => 'mymodule_foo',
- 'access callback' => 'user_is_logged_in',
- );
-
- return $items;
-}
-```
-
-There is also a
-[user_is_anonymous()](http://api.drupal.org/api/drupal/modules!user!user.module/function/user_is_anonymous/7)
-function if you want the opposite result. Both of these functions are available
-in Drupal 6 and higher.
diff --git a/astro/src/content/blog/checkout-specific-revision-svn-command-line.md b/astro/src/content/blog/checkout-specific-revision-svn-command-line.md
deleted file mode 100644
index c3019c01..00000000
--- a/astro/src/content/blog/checkout-specific-revision-svn-command-line.md
+++ /dev/null
@@ -1,22 +0,0 @@
----
-title: Checkout a specific revision from SVN from the command line
-date: 2012-05-23
-excerpt: How to checkout a specific revision from a SVN (Subversion) repository.
-tags:
- - svn
- - version-control
----
-
-How to checkout a specific revision from a SVN (Subversion) repository.
-
-If you're checking out the repository for the first time:
-
-```bash
-$ svn checkout -r 1234 url://repository/path
-```
-
-If you already have the repository checked out:
-
-```bash
-$ svn up -r 1234
-```
diff --git a/astro/src/content/blog/cleanly-retrieving-user-profile-data-using-entity-metadata-wrapper.md b/astro/src/content/blog/cleanly-retrieving-user-profile-data-using-entity-metadata-wrapper.md
deleted file mode 100644
index 4484c1a5..00000000
--- a/astro/src/content/blog/cleanly-retrieving-user-profile-data-using-entity-metadata-wrapper.md
+++ /dev/null
@@ -1,38 +0,0 @@
----
-title: Cleanly retrieving user profile data using an Entity Metadata Wrapper
-excerpt: How to use Drupal 7's EntityMetadataWrapper to cleanly retrieve user profile field data.
-tags:
- - drupal
- - drupal-7
- - drupal planet
- - php
-date: 2021-02-23
----
-
-Today I needed to load some Drupal user data via a [profile2](https://www.drupal.org/project/profile2) profile. When looking into this, most resources that I found suggest using this approach and calling the `profile2_load_by_user()` function directly and passing in the user object:
-
-
-```php
-$account = user_load(...);
-
-$accountWrapper = new EntityDrupalWrapper('user', $account);
-// or `$accountWrapper = entity_metadata_wrapper('user', $account);
-
-$profile = profile2_load_by_user($account->value());
-// or `$profile = profile2_load_by_user($account);`
-
-$profileWrapper = new EntityDrupalWrapper('profile2', $profile);
-
-$firstName = $profileWrapper->get('field_first_name')->value();
-```
-
-This though requires a few steps, and as I'm a fan of object-orientated code and Entity Metadata Wrappers, I wanted to find a cleaner solution.
-
-This is my preferred method that uses method chaining. It returns the same value, is less code, and in my opinion, it's cleaner and easier to read.
-
-```php
-$firstName = $accountWrapper
- ->get('profile_user_basic')
- ->get('field_first_name')
- ->value();
-```
diff --git a/astro/src/content/blog/conditional-email-addresses-webform.md b/astro/src/content/blog/conditional-email-addresses-webform.md
deleted file mode 100644
index dda57b8e..00000000
--- a/astro/src/content/blog/conditional-email-addresses-webform.md
+++ /dev/null
@@ -1,29 +0,0 @@
----
-title: Conditional Email Addresses in a Webform
-date: 2010-05-06
-excerpt:
- How to send webform emails to a different email address based on another
- field.
-tags:
- - conditional-email
- - drupal-6
- - drupal-planet
- - webform
----
-
-I created a new Webform to serve as a simple Contact form, but left the main
-configuration until after I created the form components. I added 'Name',
-'Email', 'Subject' and 'Message' fields, as well as a 'Category' select list.
-Below 'Options', I entered each of my desired options in the following format:
-
-```ini
-Email address|Visible name
-```
-
-I went back to the form configuration page and expanded 'Conditional Email
-Recipients', and selected my Category. Note that the standard 'Email To' field
-above it needs to be empty. Originally, I made the mistake of leaving addresses
-in that field which resulted in people being sent emails regardles of which
-category was selected. I then configured the rest of the form.
-
-Then, when I went to the finished form, the category selection was available.
diff --git a/astro/src/content/blog/configuring-the-reroute-email-module.md b/astro/src/content/blog/configuring-the-reroute-email-module.md
deleted file mode 100644
index 27ece0a8..00000000
--- a/astro/src/content/blog/configuring-the-reroute-email-module.md
+++ /dev/null
@@ -1,70 +0,0 @@
----
-title: Configuring the Reroute Email Module
-date: 2014-12-22
-excerpt:
- How to configure the Reroute Email module, to prevent sending emails to real
- users from your pre-production sites!
-tags:
- - drupal
- - drupal-6
- - drupal-7
- - drupal-planet
- - email
-draft: true
----
-
-[Reroute Email](https://www.drupal.org/project/reroute_email) module uses
-`hook_mail_alter()` to prevent emails from being sent to users from
-non-production sites. It allows you to enter one or more email addresses that
-will receive the emails instead of delivering them to the original user.
-
-> This is useful in case where you do not want email sent from a Drupal site to
-> reach the users. For example, if you copy a live site to a test site for the
-> purpose of development, and you do not want any email sent to real users of
-> the original site. Or you want to check the emails sent for uniform
-> formatting, footers, ...etc.
-
-As we don't need the module configured on production (we don't need to reroute
-any emails there), it's best to do this in code using settings.local.php (if you
-have one) or the standard settings.php file.
-
-The first thing that we need to do is to enable rerouting. Without doing this,
-nothing will happen.
-
-```php
-$conf['reroute_email_enable'] = TRUE;
-```
-
-The next option is to whether to show rerouting description in mail body. I
-usually have this enabled. Set this to TRUE or FALSE depending on your
-preference.
-
-```php
-$conf['reroute_email_enable_message'] = TRUE;
-```
-
-The last setting is the email address to use. If you're entering a single
-address, you can add it as a simple string.
-
-```php
-$conf['reroute_email_address'] = 'person1@example.com';
-```
-
-In this example, all emails from the site will be rerouted to
-person1@example.com.
-
-If you want to add multiple addresses, these should be added in a
-semicolon-delimited list. Whilst you could add these also as a string, I prefer
-to use an array of addresses and the `implode()` function.
-
-```php
-$conf['reroute_email_address'] = implode(';', array(
- 'person1@example.com',
- 'person2@example.com',
- 'person3@example.com',
-));
-```
-
-In this example, person2@example.com and person3@example.com would receive their
-emails from the site as normal. Any emails to addresses not in the array would
-continue to be redirected to person1@example.com.
diff --git a/astro/src/content/blog/continuous-integration-vs-continuous-integration.md b/astro/src/content/blog/continuous-integration-vs-continuous-integration.md
deleted file mode 100644
index d2020c53..00000000
--- a/astro/src/content/blog/continuous-integration-vs-continuous-integration.md
+++ /dev/null
@@ -1,46 +0,0 @@
----
-title: Continuous Integration vs Continuous Integration
-excerpt: My views on the definitions of "continuous integration".
-tags:
- - git
-date: 2021-10-07
----
-
-
-
-There seem to be two different definitions for the term "continuous integration" (or "CI") that I've come across whilst reading blogs, listening to podcasts, and watching video tutorials.
-
-## Tooling
-
-The first is around remote tools such as GitHub Actions, GitLab CI, Bitbucket Pipelines, Circle CI, and Jenkins, which automatically run tasks whenever you push or merge (or "integrate") code - such as code linting, performing static analysis checks, running automated tests, or building a deployment artifact.
-
-These focus on code quality and replicate steps that you can run locally, ensuring that the build is successful and that if the CI checks pass then the code can be deployed.
-
-My issue with this definition is that it may not be continuous. You could push code once a day or once a year, and it would perform the same checks and have the same outcomes and benefits.
-
-## Workflow
-
-The second definition isn't about tools - it's about how often you update, merge and push code (which commonly leads to feature branch vs trunk-based development, and Git Flow vs GitHub Flow discussions). How often are you pulling in the latest code, testing it with your local changes, and pushing your code for everyone else to see?
-
-If you're using feature branches, how long do they last, and how quickly are they merged into the main branch?
-
-Weekly? Daily? Hourly?
-
-The workflow definition doesn't need GitHub, GitLab, or Bitbucket to run checks - it's about keeping your local code continuously (or as often as possible) updated and integrated with the remote code.
-
-This ensures that you're developing from the latest stable version and not one that is days or weeks out of date.
-
-This means that merge conflicts and much less common as you're always pulling in the latest code and ensuring that it can be integrated.
-
-## Conclusion
-
-One definition isn't dependent on the other.
-
-You don't need the tooling and automation to use a continuous integration workflow, but I'd recommend it. It's useful to know and have confidence that the build passes, especially if you're pulling and pushing code several times a day, but it isn't a prerequisite.
-
-If you're working on a new feature or fixing a bug, pull down the latest code,
-test your changes, and push it back as often as possible.
-
-If you watch a video, read a blog post, or listen to a podcast about continuous integration or "How to set up CI", remember that it's not just about the tooling.
-
-There's a different workflow and mindset to consider that introduces other complementary concepts such as automated testing and test-driven development, pair and mob programming, feature flags, and continuous delivery.
diff --git a/astro/src/content/blog/create-better-photo-gallery-drupal-part-1.md b/astro/src/content/blog/create-better-photo-gallery-drupal-part-1.md
deleted file mode 100644
index 3566cf5d..00000000
--- a/astro/src/content/blog/create-better-photo-gallery-drupal-part-1.md
+++ /dev/null
@@ -1,161 +0,0 @@
----
-title: Create a Better Photo Gallery in Drupal - Part 1
-date: 2010-08-11
-excerpt:
- How I started converting and migrating a Coppermine photo gallery into Drupal.
-tags:
- - cck
- - drupal
- - drupal-6
- - drupal-planet
- - photo-gallery
- - sequel-pro
- - sql
- - views
- - views-attach
----
-
-Recently, I converted a client's static HTML website, along with their
-Coppermine Photo Gallery, into a Drupal-powered website.
-
-Over the next few posts, I'll be replicating the process that I used during the
-conversion, and how I added some additional features to my Drupal gallery.
-
-To begin with, I created my photo gallery as described by
-[Jeff Eaton](http://www.lullabot.com/about/team/jeff-eaton) in
-[this screencast](http://www.lullabot.com/articles/photo-galleries-views-attach),
-downloaded all my client's previous photos via FTP, and quickly added them into
-the new gallery using the
-[Imagefield Import](http://drupal.org/project/imagefield_import) module (which I
-mentioned
-[previously](/blog/quickly-import-multiples-images-using-imagefieldimport-module/)).
-
-When I compare this to the previous gallery, I can see several differences which
-I'd like to include. The first of which is the number of photos in each gallery,
-and the date that the most recent photo was added.
-
-To do this, I'd need to query my website's database. To begin with, I wanted to
-have a list of all the galleries on my site which are published, and what
-they're unique node ID values are. To do this, I opened Sequel Pro and entered
-the following code:
-
-```sql
-SELECT title
-AS title, nid
-AS gallery_idFROM node
-WHERE type = 'gallery'
-AND status = 1;
-```
-
-As the nid value of each gallery corresponds with the 'field_gallery_nid' field
-within the content_type_photo field, I can now query the database and retrieve
-information about each specific gallery.
-
-For example, using [aliasing](http://www.w3schools.com/sql/sql_alias.asp) within
-my SQL statement, I can retrieve a list of all the published photos within the
-'British Squad 2008' gallery by using the following code:
-
-```sql
-SELECT n.title, n.nid, p.field_gallery_nid
-FROM node n, content_type_photo p
-WHERE p.field_gallery_nid = 105
-AND n.status = 1
-AND n.nid = p.nid;
-```
-
-I can easily change this to count the number of published nodes by changing the
-first line of the query to read SELECT COUNT(\*).
-
-```sql
-SELECT COUNT(*)
-FROM node n, content_type_photo p
-WHERE p.field_gallery_nid = 105
-AND n.status = 1
-AND n.nid = p.nid;
-```
-
-As I've used the [Views Attach](http://drupal.org/project/views_attach) module,
-and I'm embedding the photos directly into the Gallery nodes, I easily add this
-to each gallery by creating a custom node-gallery.tpl.php file within my theme.
-I can then use the following PHP code to retrieve the node ID for that specific
-gallery:
-
-```php
-
-```
-
-I can then use this variable as part of my next query to count the number of
-photos within that gallery, similar to what I did earlier.
-
-```php
-
-```
-
-Next, I wanted to display the date that the last photo was displayed within each
-album. This was done by using a similar query that also sorted the results in a
-descending order, and limited it to one result - effectively only returning the
-created date for the newest photo.
-
-```php
-
-```
-
-This was all then added into a 'print' statement which displayed it into the
-page.
-
-```php
-There are currently ' . $selected_gallery_total . ' photos in this gallery.';
- $output .= 'Last one added on ' . $latest_photo . '';
- print $output;
-}
-?>
-```
-
-OK, so let's take a look at the Gallery so far:
-
-You will notice that the returned date value for the latest photo added is
-displaying the UNIX timestamp instead of in a more readable format. This can be
-changed by altering the 'print' statement to include a PHP 'date' function:
-
-```php
-There are currently ' . $selected_gallery_total . ' photos in this gallery.';
- $output .= 'Last one added on ' . date("l, jS F, Y", $latest_photo) . '.';
- print $output;
-}
-?>
-```
-
-The values that I've entered are from
-[this page](http://php.net/manual/en/function.date.php) on PHP.net, and can be
-changed according on how you want the date to be displayed.
-
-As I've added all of these photos today, then the correct dates are being
-displayed. However, on the client's original website, the majority of these
-photos were pubished several months or years ago, and I'd like the new website
-to still reflect the original created dates. As opposed to modifying each
-individual photograph, I'll be doing this in bulk in my next post.
diff --git a/astro/src/content/blog/create-better-photo-gallery-drupal-part-2.md b/astro/src/content/blog/create-better-photo-gallery-drupal-part-2.md
deleted file mode 100644
index 9bc6e0b4..00000000
--- a/astro/src/content/blog/create-better-photo-gallery-drupal-part-2.md
+++ /dev/null
@@ -1,58 +0,0 @@
----
-title: Create a Better Photo Gallery in Drupal - Part 2
-date: 2010-08-17
-excerpt: Updating the galleries’ created and modified dates.
-tags:
- - drupal-6
- - drupal-planet
- - photo-gallery
- - sequel-pro
- - sql
----
-
-At the end of my last post, I'd finished creating the first part of the new
-photo gallery, but I wanted to change the dates of the published photos to
-reflect the ones on the client's original website.
-
-Firstly, I'll refer to the previous list of published galleries that I created
-before, and create something different that also displays the created and
-modified dates. Picking the node ID of the required gallery, I used the
-following SQL query to display a list of photos.
-
-```sql
-SELECT n.title, n.nid, n.created, n.changed, p.field_gallery_nid
-FROM node n, content_type_photo pWHERE n.type = 'photo'
-AND p.field_gallery_nid = 103AND n.nid = p.nid
-ORDER BY n.nid ASC;
-```
-
-When I look back at the old photo gallery, I can see that the previous 'last
-added' date was June 27, 2008. So, how do I update my new photos to reflect that
-date? Using , I can enter the
-required date in its readable format, and it will give me the equivilent UNIX
-timestamp. To keep things relatively simple, I'll set all photos within this
-gallery to the same time.
-
-The result that I'm given is '1217149200'. I can now use an UPDATE statement
-within another SQL query to update the created and modified dates.
-
-```sql
-UPDATE node
-INNER JOIN content_type_photo
-ON node.nid = content_type_photo.nid
-SET
- node.created = 1217149200,
- node.changed = 1217149200
-WHERE content_type_photo.field_gallery_nid = 103
-```
-
-Now when I query the database, both the created and modified dates have been
-updated, and when I return to the new photo gallery, the updated value is being
-displayed.
-
-Once the changes have been applied, it's a case of repeating the above process
-for each of the required galleries.
-
-In the next post, I'll explain how to add a count of published galleries and
-photos on the main photo gallery page, as well as how to install and configure
-the [Shadowbox](http://drupal.org/project/shadowbox) module.
diff --git a/astro/src/content/blog/create-better-photo-gallery-drupal-part-21.md b/astro/src/content/blog/create-better-photo-gallery-drupal-part-21.md
deleted file mode 100644
index d4ec05c4..00000000
--- a/astro/src/content/blog/create-better-photo-gallery-drupal-part-21.md
+++ /dev/null
@@ -1,64 +0,0 @@
----
-title: Create a Better Photo Gallery in Drupal - Part 2.1
-date: 2010-10-22
-excerpt: The missing code to get totals of galleries and photos.
-tags:
- - drupal
----
-
-Today, I realised that I hadn't published the code that I used to create the
-total figures of galleries and photos at the top of the gallery (I said at the
-end of
-[Part 2](/blog/create-better-photo-gallery-drupal-part-2/ 'Create a Better Photo Gallery in Drupal - Part 2')
-that I'd include it in
-[Part 3](/blog/create-better-photo-gallery-drupal-part-3/ 'Create a Better Photo Gallery in Drupal - Part 3'),
-but I forgot). So, here it is:
-
-```php
-
-```
-
-It was applied to the view as a header which had the input format set to PHP
-code.
diff --git a/astro/src/content/blog/create-better-photo-gallery-drupal-part-3.md b/astro/src/content/blog/create-better-photo-gallery-drupal-part-3.md
deleted file mode 100644
index bac654ce..00000000
--- a/astro/src/content/blog/create-better-photo-gallery-drupal-part-3.md
+++ /dev/null
@@ -1,49 +0,0 @@
----
-title: Create a Better Photo Gallery in Drupal - Part 3
-date: 2010-10-13
-excerpt: Grouping galleries by category.
-tags:
- - drupal
----
-
-The next part of the new gallery that I want to implement is to group the
-galleries by their respective categories. The first step is to edit my original
-photo_gallery view and add an additional display.
-
-I've called it 'Taxonomy', and it's similar to the original 'All Galleries'
-view. The differences are that I've added the taxonomy term as an argument,
-removed the header, and updated the path to be `gallery/%`. The other thing that
-I need to do is overwrite the output of the original 'All Galleries' View by
-creating a file called `views-view--photo-gallery--page-1.tpl.php` and placing
-it within my theme directory.
-
-Within that file, I can remove the standard content output. This still outputs
-the heading information from the original View. I can now use the function
-called 'views_embed_view' to embed my taxonomy display onto the display. The
-views_embed_view function is as follows:
-
-```php
-
-```
-
-So, to display the galleries that are assigned the taxonomy of 'tournaments', I
-can use the following:
-
-```php
-
-```
-
-To reduce the amount of code needed, I can use the following 'while' loop to
-generate the same code for each taxonomy term. It dynamically retrieves the
-relevant taxonomy terms from the database, and uses each name as the argument
-for the view.
-
-```php
-' . $term['name'] . '';
- print views_embed_view('gallery', 'page_2', $term['name']);
-}
-?>
-```
diff --git a/astro/src/content/blog/create-block-social-media-icons-using-cck-views-and-nodequeue.md b/astro/src/content/blog/create-block-social-media-icons-using-cck-views-and-nodequeue.md
deleted file mode 100644
index fa045366..00000000
--- a/astro/src/content/blog/create-block-social-media-icons-using-cck-views-and-nodequeue.md
+++ /dev/null
@@ -1,44 +0,0 @@
----
-title: Create a Block of Social Media Icons using CCK, Views and Nodequeue
-date: 2010-06-23
-excerpt: How to create a block of social media icons in Drupal.
-tags:
- - drupal
- - drupal-6
- - drupal-planet
- - nodequeue
- - oliverdavies.co.uk
- - views
----
-
-I recently decided that I wanted to have a block displayed in a sidebar on my
-site containing icons and links to my social media profiles -
-[Twitter](http://twitter.com/opdavies), [Facebook](http://facebook.com/opdavies)
-etc. I tried the [Follow](http://drupal.org/project/follow) module, but it
-lacked the option to add extra networks such my
-[Drupal.org](http://drupal.org/user/381388) account, and my
-[RSS feed](http://oliverdavies.co.uk/rss.xml). I started to create my own
-version, and then found
-[this Blog post](http://www.hankpalan.com/blog/drupal-themes/add-your-social-connections-drupal-icons)
-by Hank Palan.
-
-I created a 'Social icon' content type with the body field removed, and with
-fields for a link and image - then downloaded the favicons from the appropriate
-websites to use.
-
-However, instead of using a custom template (node-custom.tpl.php) file, I used
-the Views module.
-
-I added fields for the node titles, and the link from the node's content. Both
-of these are excluded from being displayed on the site. I then re-wrote the
-output of the Icon field to create the link using the URL, and using the node's
-title as the image's alternative text and the link's title.
-
-I also used the [Nodequeue](http://drupal.org/project/nodequeue) module to
-create a nodequeue and arrange the icons in the order that I wanted them to be
-displayed. Once this was added as a relationship within my View, I was able to
-use node's position in the nodequeue as the sort criteria.
-
-To complete the process, I used the
-[CSS Injector](http://drupal.org/project/css_injector) module to add some
-additional CSS styling to position and space out the icons.
diff --git a/astro/src/content/blog/create-flickr-photo-gallery-using-feeds-cck-views.md b/astro/src/content/blog/create-flickr-photo-gallery-using-feeds-cck-views.md
deleted file mode 100644
index 560f08bb..00000000
--- a/astro/src/content/blog/create-flickr-photo-gallery-using-feeds-cck-views.md
+++ /dev/null
@@ -1,71 +0,0 @@
----
-title: Create a Flickr Photo Gallery Using Feeds, CCK and Views
-date: 2010-06-28
-excerpt:
- In this tutorial, I'll show you how to create a photo gallery which uses
- photos imported from Flickr.
-tags:
- - drupal-planet
- - drupal-6
- - photo-gallery
- - views
- - cck
- - imagecache
- - feeds
- - filefield
- - flickr
- - imagefield
----
-
-In this tutorial, I'll show you how to create a photo gallery which uses photos
-imported from [Flickr](http://www.flickr.com).
-
-The modules that I'll use to create the Gallery are:
-
-- [CCK](http://drupal.org/project/cck)
-- [Feeds](http://drupal.org/project/feeds)
-- [Feeds Image Grabber](http://drupal.org/project/feeds_imagegrabber)
-- [FileField](http://drupal.org/project/filefield)
-- [ImageAPI](http://drupal.org/project/imageapi)
-- [ImageCache](http://drupal.org/project/imagecache)
-- [ImageField](http://drupal.org/project/imagefield)
-- [Views](http://drupal.org/project/views)
-
-The first thing that I did was to create a content type to store my imported
-images. I named it 'Photo', removed the Body field, and added an Image field.
-
-Next, I installed and configured the Feeds and Image Grabber module. I used an
-overridden default Feed to import my photos from Flickr using the following
-settings:
-
-- **Basic settings:** I changed the Refresh time to 15 minutes.
-- **Processor settings:** I changed the content type to 'Photo', and the
- author's name from 'anonymous'.
-- **Processor mapping:** I added a new mapping from 'Item URL (link)' to 'Photo
- (FIG)'. The Photo FIG target is added by the Image Grabber module.
-
-Next, I needed to create the actual Feed, which I did by clicking 'Import'
-within the Navigation menu, and clicking 'Feed'. I gave it a title, entered the
-URL to my RSS feed from Flickr, and enabled the Image Grabber for this feed.
-
-Once the Feed is created, the latest 20 images from the RSS feed are imported
-and 20 new Photos nodes are created. In the example below, the image with the
-'Photo' label is the Image field mapped by the Image Grabber module. It is this
-image that I'll be displaying within my Gallery.
-
-With the new Photo nodes created, I then created the View to display them.
-
-The View selects the image within the Photo content type, and displays in it a
-grid using an ImageCache preset. The View is limited to 20 nodes per page, and
-uses a full pager if this is exceeded. The nodes are sorted by the descending
-post date, and filtered by whether or not they are published, and only to
-include Photo nodes.
-
-As an additional effect, I also included the 'Feeds Item - Item Link' field,
-which is basically the original link from the RSS feed. By checking the box the
-exclude the item from the display, it is not shown, but makes the link available
-to be used elsewhere. By checking the box 'Re-write the output for this field'
-on the 'Content: Photo' field, I was able to add the replacement token (in this
-case, [url]) as the path for a link around each image. This meant that when
-someone clicked a thumbnail of a photo, they were directed to the Flickr website
-instead of the node within my Drupal site.
diff --git a/astro/src/content/blog/create-multigroups-drupal-7-using-field-collections.md b/astro/src/content/blog/create-multigroups-drupal-7-using-field-collections.md
deleted file mode 100644
index 7a754cc9..00000000
--- a/astro/src/content/blog/create-multigroups-drupal-7-using-field-collections.md
+++ /dev/null
@@ -1,59 +0,0 @@
----
-title: Create Multigroups in Drupal 7 using Field Collections
-date: 2011-08-28
-excerpt:
- How to replicate CCK’s multigroups in Drupal 7 using the Field Collections
- module.
-tags:
- - cck
- - drupal-7
- - drupal-planet
- - entity-api
- - field-collection
- - fields
- - multigroup
----
-
-One of my favourite things lately in Drupal 6 has been CCK 3, and more
-specifically, the Content Multigroups sub-module. Basically this allows you to
-create a fieldset of various CCK fields, and then repeat that multiple times.
-For example, I use it on this site whist creating invoices for clients. I have a
-fieldset called 'Line Item', containing 'Description', 'Quantity' and 'Price'
-fields. With a standard fieldset, I could only have one instance of each field -
-however, using a multigroup, I can create multiple groups of line items which I
-then use within the invoice.
-
-But at the time of writing this, there is no CCK 3 version for Drupal 7. So, I
-created the same thing using
-[Field Collection](http://drupal.org/project/field_collection) and
-[Entity](http://drupal.org/project/entity) modules.
-
-With the modules uploaded and enabled, go to admin/structure/field-collections
-and create a field collection.
-
-With the module enabled, you can go to your content type and add a Field
-Collection field. By default, the only available Widget type is 'Hidden'.
-
-Next, go to admin/structure/field-collections and add some fields to the field
-collection - the same way that you would for a content type. For this collection
-is going to contain two node reference fields - Image and Link.
-
-With the Field Collection created, I can now add it as a field within my content
-type.
-
-Whilst this works perfectly, the field collection is not editable from the node
-edit form. You need to load the node, and the collection is displayed here with
-add, edit, and delete buttons. This wasn't an ideal solution, and I wanted to be
-able to edit the fields within the collection from the node edit form - the same
-way as I can using multigroups in Drupal 6.
-
-After some searching I found
-[a link to a patch](http://drupal.org/node/977890#comment-4184524) which when
-applied adds a 'subform' widget type to the field collection field and allows
-for it to be embedded into, and editable from within the node form. Going back
-to the content type fields page, and clicking on 'Hidden' (the name of the
-current widget), I can change it to subform and save my changes.
-
-With this change applied, when I go back to add or edit a node within this
-content type, my field collection will be easily editable directly within the
-form.
diff --git a/astro/src/content/blog/create-omega-subtheme-less-css-preprocessor-using-omega-tools-and-drush.md b/astro/src/content/blog/create-omega-subtheme-less-css-preprocessor-using-omega-tools-and-drush.md
deleted file mode 100644
index 08634159..00000000
--- a/astro/src/content/blog/create-omega-subtheme-less-css-preprocessor-using-omega-tools-and-drush.md
+++ /dev/null
@@ -1,62 +0,0 @@
----
-title: Create an Omega Subtheme with LESS CSS Preprocessor using Omega Tools and Drush
-date: 2012-04-16
-excerpt: How to create an Omega subtheme on the command line using Drush.
-tags:
- - drupal
- - drupal-7
- - drupal-planet
- - less
- - omega
- - theming
----
-
-In this tutorial I'll be showing how to create an
-[Omega](http://drupal.org/project/omega) subtheme using the
-[Omega Tools](http://drupal.org/project/omega_tools) module, and have it working
-with the [LESS CSS preprocessor](http://lesscss.org).
-
-The first thing that I need to do is download the Omega theme and the Omega
-Tools and [LESS](http://drupal.org/project/less 'LESS module on drupal.org')
-modules, and then to enable both modules. I'm doing this using Drush, but you
-can of course do this via the admin interface at admin/modules.
-
-```bash
-$ drush dl less omega omega_tools;
-$ drush en -y less omega_tools
-```
-
-With the Omega Tools module enabled I get the drush omega-subtheme command that
-creates my Omega subtheme programatically. Using this command, I'm creating a
-new subtheme, enabling it and setting it as the default theme on my site.
-
-```bash
-$ drush omega-subtheme "Oliver Davies" --machine_name="oliverdavies" --enable --set-default
-```
-
-By default, four stylesheets are created within the subtheme's css directory.
-The first thing that I'm going to do is rename `global.css` to `global.less`.
-
-```bash
-$ mv css/global.css css/global.less
-```
-
-Now I need to find all references to global.css within my oliverdavies.info
-file. I did this using `$ nano oliverdavies.info`, pressing `Ctrl+W` to search,
-then `Ctrl+R` to replace, entering `global.css` as the search phrase, and then
-`global.less` as the replacement text. After making any changes to
-oliverdavies.info, I need to clear Drupal's caches for the changes to be
-applied.
-
-```bash
-$ drush cc all
-```
-
-I tested my changes by making some quick additions to my global.less file and
-reloading the page.
-
-If your changes aren't applied, then confirm that your global.less file is
-enabled within your theme's configuration. I did this by going to
-admin/appearance/settings/oliverdavies, clicking on the Toggle styles tab within
-_Layout configuration_ and finding global.less at the bottom of _Enable optional
-stylesheets_.
diff --git a/astro/src/content/blog/create-slideshow-multiple-images-using-fancy-slide.md b/astro/src/content/blog/create-slideshow-multiple-images-using-fancy-slide.md
deleted file mode 100644
index 3ebe852c..00000000
--- a/astro/src/content/blog/create-slideshow-multiple-images-using-fancy-slide.md
+++ /dev/null
@@ -1,50 +0,0 @@
----
-title: Create a Slideshow of Multiple Images Using Fancy Slide
-date: 2010-05-25
-excerpt: How to create a slideshow of images using Drupal’s Fancy Slide module.
-tags:
- - drupal
- - drupal-6
- - drupal-planet
- - fancy-slide
- - slideshow
----
-
-Whilst updating my About page, I thought about creating a slideshow of several
-images instead of just the one static image. When I looking on Drupal.org, the
-only slideshow modules were to create slideshows of images that were attached to
-different nodes - not multiple images attached to one node. Then, I found the
-[Fancy Slide](http://drupal.org/project/fancy_slide) module. It's a jQuery
-Slideshow module with features that include integration with the
-[CCK](http://drupal.org/project/cck),
-[ImageCache](http://drupal.org/project/imagecache) and
-[Nodequeue](http://drupal.org/project/nodequeue) modules.
-
-I added an CCK Image field to my Page content type, and set the number of values
-to 3, then uploaded my images to the Page.
-
-Whilst updating my About page, I thought about creating a slideshow of several
-images instead of just the one static image. When I looking on Drupal.org, the
-only slideshow modules were to create slideshows of images that were attached to
-different nodes - not multiple images attached to one node. Then, I found the
-[Fancy Slide](http://drupal.org/project/fancy_slide) module. It's a jQuery
-Slideshow module with features that include integration with the
-[CCK](http://drupal.org/project/cck),
-[ImageCache](http://drupal.org/project/imagecache) and
-[Nodequeue](http://drupal.org/project/nodequeue) modules. Once the Images were
-added, I went to the Fancy Slide settings page and created the slideshow.
-
-I added the dimensions of my images, the type of animation, specified the node
-that contained the images, the slideshow field, delay between slides and
-transition speed. With the slideshow created, it now needed embedding into the
-page.
-
-I added the following code into my About page, as described in the Fancy Slide
-readme.txt file - the number representing the ID of the slideshow.
-
-```php
-
-```
-
-In my opinion, this adds a nice effect to the About page. I like it because it's
-easy to set up, and easy to add additional images later on if required.
diff --git a/astro/src/content/blog/create-virtual-hosts-mac-os-x-using-virtualhostx.md b/astro/src/content/blog/create-virtual-hosts-mac-os-x-using-virtualhostx.md
deleted file mode 100644
index 017dfb16..00000000
--- a/astro/src/content/blog/create-virtual-hosts-mac-os-x-using-virtualhostx.md
+++ /dev/null
@@ -1,50 +0,0 @@
----
-title: Create Virtual Hosts on Mac OS X Using VirtualHostX
-date: 2010-07-02
-excerpt:
- How to use the VirtualHostX application to manage virtual hosts on Mac OS X.
-tags:
- - drupal-6
- - drupal-planet
- - mamp
- - virtual-hosts
- - virtualhostx
----
-
-This isn't a Drupal related topic per se, but it is a walk-through of one of the
-applications that I use whilst doing Drupal development work. I assume, like
-most Mac OS X users, I use [MAMP](http://www.mamp.info/en/index.html) to run
-Apache, MySQL and PHP locally whilst developing. I also use virtual hosts in
-Apache to create local .dev domains which are as close as possible to the actual
-live domains. For example, if I was developing a site called mysite.com, my
-local development version would be mysite.dev.
-
-Normally, I would have to edit the hosts file and Apache's httpd.conf file to
-create a virtual host. The first to set the domain and it's associated IP
-address, and the other to configure the domain's directory, default index file
-etc. However, using [VirtualHostX](http://clickontyler.com/virtualhostx), I can
-quickly create a virtual host without having to edt any files. Enter the virtual
-domain name, the local path and the port, and apply the settings. VirtualHostX
-automatically restarts Apache, so the domain is ready to work straight away. You
-can also enter custom directives from within the GUI.
-
-There's also an option to share the host over the local network. Next, I intend
-on configuring a virtual Windows PC within VMware Fusion to view these domains
-so that I can do cross-browser testing before putting a site live.
-
-I ensured that my Apache configuration within MAMP was set to port 80, and that
-VirtualHostX was using Apache from MAMP instead of Apple's built-in Apache.
-
-**Note:** One problem that I had after setting this up, was that I was receving
-an error when attempting to open a Drupal website which said _'No such file or
-directory'._
-
-After some troubleshooting, I found out that Web Sharing on my Mac had become
-enabled (I don't know why, I've never enabled it), and that this was causing a
-conflict with Apache. Once I opened my System Preferences and disabled it,
-everything worked fine!
-
-This, along with [MAMP](http://www.mamp.info/en/index.html),
-[Coda](http://www.panic.com/coda), [Sequel Pro](http://www.sequelpro.com), and
-[Transmit](http://www.panic.com/transmit), has become an essential tool within
-my development environment.
diff --git a/astro/src/content/blog/create-zen-sub-theme-using-drush.md b/astro/src/content/blog/create-zen-sub-theme-using-drush.md
deleted file mode 100644
index ee7981e6..00000000
--- a/astro/src/content/blog/create-zen-sub-theme-using-drush.md
+++ /dev/null
@@ -1,40 +0,0 @@
----
-title: Create a Zen Sub-theme Using Drush
-date: 2013-09-06
-excerpt: How to quickly create a Zen sub-theme using Drush.
-tags:
- - drupal
- - drupal-planet
- - drush
- - zen
- - theming
----
-
-How to use [Drush](https://drupal.org/project/drush) to quickly build a new
-sub-theme of [Zen](https://drupal.org/project/zen).
-
-First, download the [Zen](https://drupal.org/project/zen 'The Zen theme') theme
-if you haven't already done so.
-
-```bash
-$ drush dl zen
-```
-
-This will now enable you to use the "drush zen" command.
-
-```bash
-$ drush zen "Oliver Davies" oliverdavies --description="A Zen sub-theme for oliverdavies.co.uk" --without-rtl
-```
-
-The parameters that I'm passing it are:
-
-1. The human-readable name of the theme.
-2. The machine-readable name of the theme.
-3. The description of the theme (optional).
-4. A flag telling Drush not to include any right-to-left elements within my
- sub-theme as these aren't needed (optional).
-
-This will create a new theme in sites/all/themes/oliverdavies.
-
-For further help, type `$ drush help zen` to see the Drush help page for the zen
-command.
diff --git a/astro/src/content/blog/creating-custom-phpunit-command-ddev.md b/astro/src/content/blog/creating-custom-phpunit-command-ddev.md
deleted file mode 100644
index a1e6b964..00000000
--- a/astro/src/content/blog/creating-custom-phpunit-command-ddev.md
+++ /dev/null
@@ -1,82 +0,0 @@
----
-title: Creating a custom PHPUnit command for DDEV
-excerpt: How to create a custom command to run PHPUnit commands in DDEV.
-tags:
- - ddev
- - drupal
- - drupal-planet
- - php
-date: 2020-08-28
----
-
-To begin with, let's create an empty file for our command:
-
-```bash
-touch .ddev/commands/web/phpunit
-```
-Commands are located within the `.ddev/commands` directory, with a sub-directory for the container name in which the command should be executed - or `host` if it's a command that is to be run on the host machine.
-
-As [the example repo](https://github.com/opdavies/ddev-phpunit-command-example) has a `web` sub-directory to mimic my Drupal application structure, the command should be run inside the web container so the file should be placed within the `.ddev/commands/web` directory.
-
-As we want the command to be 'phpunit', the filename should also be `phpunit`.
-
-This is an example of a basic command, which is a simple bash script:
-
-```bash
-#!/usr/bin/env bash
-
-echo 'running phpunit...'
-```
-
-To begin with, let's echo some simple text to check that the command is working. It should also be listed if you run the `ddev` command.
-
-To check the working directory that it used when the command is run, add the following line in the command file:
-
-```bash
-echo $(pwd)
-```
-
-In the example, it is `/var/www/html/web`. Note that we are already inside the `web` sub-directory.
-
-## Running PHPUnit
-
-To run PHPUnit, I can add the following to the command file:
-
-```
-../vendor/bin/phpunit --config .. $*
-```
-
-As we're already in the `web` directory, the command needs to go up on level before running the PHPUnit command, and uses `--config` to define the path to the `phpunit.xml.dist` file which is also in the parent directory.
-
-Using `$*` adds any additional arguments from the CLI to the command inside the container.
-
-The command could be made simpler by overridding the `working_directory` value in `.ddev/config`:
-
-```json
-working_dir:
- web: /var/www/html
-```
-
-This means that we start in `/var/www/html` rather than inside the `web` directory, and that we can simplify the command to be:
-
-```
-vendor/bin/phpunit $*
-```
-
-Because the `phpunit.xml.dist` file is inside the working directory, I no longer need to specify its path.
-
-## Adding documentation
-
-To add documentation and help text to the command, add these lines to the command file:
-
-```bash
-## Description: Run PHPUnit tests inside the web container.
-## Usage: phpunit
-## Example: "ddev phpunit" or with additional arguments such as "ddev phpunit --testdox"
-```
-
-These will be parsed and shown when someone runs `ddev phpunit -h`, and can be used to show various examples such as adding additional arguments for the PHPUnit command.
-
-With this all in place, we can run commands like `ddev phpunit` or `ddev phpunit --testdox`, or even `ddev phpunit modules/custom/opdavies_talks --filter=TalkEventDateTest` for a Drupal project, and have that command and tests running inside DDEV!
-
-For more information on DDEV and creating custom commands, see the [DDEV documentation](https://ddev.readthedocs.io/en/stable/users/extend/custom-commands).
diff --git a/astro/src/content/blog/creating-custom-phpunit-command-docksal.md b/astro/src/content/blog/creating-custom-phpunit-command-docksal.md
deleted file mode 100644
index 3caeeb3a..00000000
--- a/astro/src/content/blog/creating-custom-phpunit-command-docksal.md
+++ /dev/null
@@ -1,366 +0,0 @@
----
-title: Creating a Custom PHPUnit Command for Docksal
-date: 2018-05-06
-excerpt:
- How to write custom commands for Docksal, including one to easily run PHPUnit
- tests in Drupal 8.
-tags:
- - docksal
- - drupal
- - drupal-8
- - drupal-planet
- - phpunit
- - testing
----
-
-This week I’ve started writing some custom commands for my Drupal projects that
-use Docksal, including one to easily run PHPUnit tests in Drupal 8. This is the
-process of how I created this command.
-
-## What is Docksal?
-
-Docksal is a local Docker-based development environment for Drupal projects and
-other frameworks and CMSes. It is our standard tool for local environments for
-projects at [Microserve][0].
-
-There was a [great talk][1] recently at Drupaldelphia about Docksal.
-
-## Why write a custom command?
-
-One of the things that Docksal offers (and is covered in the talk) is the
-ability to add custom commands to the Docksal’s `fin` CLI, either globally or as
-part of your project.
-
-As an advocate of automated testing and TDD practitioner, I write a lot of tests
-and run PHPUnit numerous times a day. I’ve also given [talks][6] and have
-[written other posts][7] on this site relating to testing in Drupal.
-
-There are a couple of ways to run PHPUnit with Docksal. The first is to use
-`fin bash` to open a shell into the container, move into the docroot directory
-if needed, and run the `phpunit` command.
-
-```bash
-fin bash
-cd /var/www/docroot
-../vendor/bin/phpunit -c core modules/custom
-```
-
-Alternatively, it can be run from the host machine using `fin exec`.
-
-```
-cd docroot
-fin exec '../vendor/bin/phpunit -c core modules/custom'
-```
-
-Both of these options require multiple steps as we need to be in the `docroot`
-directory where the Drupal code is located before the command can be run, and
-both have quite long commands to run PHPUnit itself - some of which is repeated
-every time.
-
-By adding a custom command, I intend to:
-
-1. Make it easier to get set up to run PHPUnit tests - i.e. setting up a
- `phpunit.xml` file.
-1. Make it easier to run the tests that we’d written by shortening the command
- and making it so it can be run anywhere within our project.
-
-I also hoped to make it project agnostic so that I could add it onto any project
-and immediately run it.
-
-## Creating the command
-
-Each command is a file located within the `.docksal/commands` directory. The
-filename is the name of the command (e.g. `phpunit`) with no file extension.
-
-To create the file, run this from the same directory where your `.docksal`
-directory is:
-
-```bash
-mkdir -p .docksal/commands
-touch .docksal/commands/phpunit
-```
-
-This will create a new, empty `.docksal/commands/phpunit` file, and now the
-`phpunit` command is now listed under "Custom commands" when we run `fin`.
-
-
-
-You can write commands with any interpreter. I’m going to use bash, so I’ll add
-the shebang to the top of the file.
-
-```bash
-#!/usr/bin/env bash
-```
-
-With this in place, I can now run `fin phpunit`, though there is no output
-displayed or actions performed as the rest of the file is empty.
-
-## Adding a description and help text
-
-Currently the description for our command when we run `fin` is the default "No
-description" text. I’d like to add something more relevant, so I’ll start by
-adding a new description.
-
-fin interprets lines starting with `##` as documentation - the first of which it
-uses as the description.
-
-```bash
-#!/usr/bin/env bash
-
-## Run automated PHPUnit tests.
-```
-
-Now when I run it, I see the new description.
-
-
-
-Any additional lines are used as help text with running `fin help phpunit`. Here
-I’ll add an example command to demonstrate how to run it as well as some more
-in-depth text about what the command will do.
-
-```bash
-#!/usr/bin/env bash
-
-## Run automated PHPUnit tests.
-##
-## Usage: fin phpunit
-##
-## If a core/phpunit.xml file does not exist, copy one from elsewhere.
-## Then run the tests.
-```
-
-Now when I run `fin help phpunit`, I see the new help text.
-
-
-
-## Adding some content
-
-### Setting the target
-
-As I want the commands to be run within Docksal’s "cli" container, I can specify
-that with `exec_target`. If one isn’t specified, the commands are run locally on
-the host machine.
-
-```
-#: exec_target = cli
-```
-
-### Available variables
-
-These variables are provided by fin and are available to use within any custom
-commands:
-
-- `PROJECT_ROOT` - The absolute path to the nearest `.docksal` directory.
-- `DOCROOT` - name of the docroot folder.
-- `VIRTUAL_HOST` - the virtual host name for the project. Such as
- `myproject.docksal`.
-- `DOCKER_RUNNING` - (string) "true" or "false".
-
-
-**Note:** If the `DOCROOT` variable is not defined within the cli container, ensure that it’s added to the environment variables in `.docksal/docksal.yml`. For example:
-
-```
-version: "2.1"
-
-services:
- cli:
- environment:
- - DOCROOT
-```
-
-
-
-### Running phpunit
-
-When you run the `phpunit` command, there are number of options you can pass to
-it such as `--filter`, `--testsuite` and `--group`, as well as the path to the
-tests to execute, such as `modules/custom`.
-
-I wanted to still be able to do this by running `fin phpunit ` so the
-commands can be customised when executed. However, as the first half of the
-command (`../vendor/bin/phpunit -c core`) is consistent, I can wrap that within
-my custom command and not need to type it every time.
-
-By using `"$@"` I can capture any additional arguments, such as the test
-directory path, and append them to the command to execute.
-
-I’m using `$PROJECT_ROOT` to prefix the command with the absolute path to
-`phpunit` so that I don’t need to be in that directory when I run the custom
-command, and `$DOCROOT` to always enter the sub-directory where Drupal is
-located. In this case, it’s "docroot" though I also use "web" and I’ve seen
-various others used.
-
-```bash
-DOCROOT_PATH="${PROJECT_ROOT}/${DOCROOT}"
-DRUPAL_CORE_PATH="${DOCROOT_PATH}/core"
-
-# If there is no phpunit.xml file, copy one from elsewhere.
-
-# Otherwise run the tests.
-${PROJECT_ROOT}/vendor/bin/phpunit -c ${DRUPAL_CORE_PATH} "$@"
-```
-
-For example, `fin phpunit modules/custom` would execute
-`/var/www/vendor/bin/phpunit -c /var/www/docroot/core modules/custom` within the
-container.
-
-I can then wrap this within a condition so that the tests are only run when a
-`phpunit.xml` file exists, as it is required for them to run successfully.
-
-```bash
-if [ ! -e ${DRUPAL_CORE_PATH}/phpunit.xml ]; then
- # If there is no phpunit.xml file, copy one from elsewhere.
-else
- ${PROJECT_ROOT}/vendor/bin/phpunit -c ${DRUPAL_CORE_PATH} "$@"
-fi
-```
-
-### Creating phpunit.xml - step 1
-
-My first thought was that if a `phpunit.xml` file doesn’t exist was to duplicate
-core’s `phpunit.xml.dist` file. However this isn’t enough to run the tests, as
-values such as `SIMPLETEST_BASE_URL`, `SIMPLETEST_DB` and
-`BROWSERTEST_OUTPUT_DIRECTORY` need to be populated.
-
-As the tests wouldn't run at this point, I’ve exited early and displayed a
-message to the user to edit the new `phpunit.xml` file and run `fin phpunit`
-again.
-
-```bash
-if [ ! -e ${DRUPAL_CORE_PATH}/phpunit.xml ]; then
- echo "Copying ${DRUPAL_CORE_PATH}/phpunit.xml.dist to ${DRUPAL_CORE_PATH}/phpunit.xml."
- echo "Please edit it's values as needed and re-run 'fin phpunit'."
- cp ${DRUPAL_CORE_PATH}/phpunit.xml.dist ${DRUPAL_CORE_PATH}/phpunit.xml
- exit 1;
-else
- ${PROJECT_ROOT}/vendor/bin/phpunit -c ${DRUPAL_CORE_PATH} "$@"
-fi
-```
-
-However this isn’t as streamlined as I originally wanted as it still requires
-the user to perform an additional step before the tests can run.
-
-### Creating phpunit.xml - step 2
-
-My second idea was to keep a pre-configured file within the project repository,
-and to copy that into the expected location. That approach would mean that the
-project specific values would already be populated, as well as any
-customisations made to the default settings. I decided on
-`.docksal/drupal/core/phpunit.xml` to be the potential location.
-
-Also, if this file is copied then we can go ahead and run the tests straight
-away rather than needing to exit early.
-
-If a pre-configured file doesn’t exist, then we can default back to copying
-`phpunit.xml.dist`.
-
-To avoid duplication, I created a reusable `run_tests()` function so it could be
-executed in either scenario.
-
-```bash
-run_tests() {
- ${PROJECT_ROOT}/vendor/bin/phpunit -c ${DRUPAL_CORE_PATH} "$@"
-}
-
-if [ ! -e ${DRUPAL_CORE_PATH}/phpunit.xml ]; then
- if [ -e "${PROJECT_ROOT}/.docksal/drupal/core/phpunit.xml" ]; then
- echo "Copying ${PROJECT_ROOT}/.docksal/drupal/core/phpunit.xml to ${DRUPAL_CORE_PATH}/phpunit.xml"
- cp "${PROJECT_ROOT}/.docksal/drupal/core/phpunit.xml" ${DRUPAL_CORE_PATH}/phpunit.xml
- run_tests "$@"
- else
- echo "Copying ${DRUPAL_CORE_PATH}/phpunit.xml.dist to ${DRUPAL_CORE_PATH}/phpunit.xml."
- echo "Please edit it's values as needed and re-run 'fin phpunit'."
- cp ${DRUPAL_CORE_PATH}/phpunit.xml.dist ${DRUPAL_CORE_PATH}/phpunit.xml
- exit 1;
- fi
-else
- run_tests "$@"
-fi
-```
-
-This means that I can execute less steps and run a much shorter command compared
-to the original, and even if someone didn’t have a `phpunit.xml` file created
-they could have copied into place and have tests running with only one command.
-
-## The finished file
-
-```bash
-#!/usr/bin/env bash
-
-#: exec_target = cli
-
-## Run automated PHPUnit tests.
-##
-## Usage: fin phpunit
-##
-## If a core/phpunit.xml file does not exist, one is copied from
-## .docksal/core/phpunit.xml if that file exists, or copied from the default
-## core/phpunit.xml.dist file.
-
-DOCROOT_PATH="${PROJECT_ROOT}/${DOCROOT}"
-DRUPAL_CORE_PATH="${DOCROOT_PATH}/core"
-
-run_tests() {
- ${PROJECT_ROOT}/vendor/bin/phpunit -c ${DRUPAL_CORE_PATH} "$@"
-}
-
-if [ ! -e ${DRUPAL_CORE_PATH}/phpunit.xml ]; then
- if [ -e "${PROJECT_ROOT}/.docksal/drupal/core/phpunit.xml" ]; then
- echo "Copying ${PROJECT_ROOT}/.docksal/drupal/core/phpunit.xml to ${DRUPAL_CORE_PATH}/phpunit.xml"
- cp "${PROJECT_ROOT}/.docksal/drupal/core/phpunit.xml" ${DRUPAL_CORE_PATH}/phpunit.xml
- run_tests "$@"
- else
- echo "Copying phpunit.xml.dist to phpunit.xml"
- echo "Please edit it's values as needed and re-run 'fin phpunit'."
- cp ${DRUPAL_CORE_PATH}/phpunit.xml.dist ${DRUPAL_CORE_PATH}/phpunit.xml
- exit 0;
- fi
-else
- run_tests "$@"
-fi
-```
-
-It’s currently available as a [GitHub Gist][2], though I’m planning on moving it
-into a public GitHub repository either on my personal account or the [Microserve
-organisation][3], for people to either use as examples or to download and use
-directly.
-
-I’ve also started to add other commands to projects such as `config-export` to
-standardise the way to export configuration from Drupal 8, run Drupal 7 tests
-with SimpleTest, and compile front-end assets like CSS within custom themes.
-
-I think it’s a great way to shorten existing commands, or to group multiple
-commands into one like in this case, and I can see a lot of other potential uses
-for it during local development and continuous integration. Also being able to
-run one command like `fin init` and have it set up everything for your project
-is very convenient and a big time saver!
-
-
-Since writing this post, I’ve had a [pull request][8] accepted for this command to be added as a [Docksal add-on][9]. This means that the command can be added to any Docksal project by running `fin addon install phpunit`. It will be installed into the `.docksal/addons/phpunit` directory, and displayed under "Addons" rather than "Custom commands" when you run `fin`.
-
-
-## Resources
-
-- [PHPUnit](https://phpunit.de)
-- [PHPUnit in Drupal 8][4]
-- [Main Docksal website](https://docksal.io)
-- [Docksal documentation](https://docksal.readthedocs.io)
-- [Docksal: one tool to rule local and CI/CD environments][1] - Docksal talk
- from Drupaldelphia
-- [phpcs example custom command][5]
-- [phpunit command Gist][2]
-- [Docksal addons blog post][9]
-- [Docksal addons repository][10]
-
-[0]: {{site.companies.microserve.url}}
-[1]: https://youtu.be/1sjsvnx1P7g
-[2]: https://gist.github.com/opdavies/72611f198ffd2da13f363ea65264b2a5
-[3]: {{site.companies.microserve.github}}
-[4]: https://www.drupal.org/docs/8/phpunit
-[5]:
- https://github.com/docksal/docksal/blob/develop/examples/.docksal/commands/phpcs
-[6]: /talks/tdd-test-driven-drupal
-[7]: /articles/tags/testing
-[8]: https://github.com/docksal/addons/pull/15
-[9]: https://blog.docksal.io/installing-addons-in-a-docksal-project-172a6c2d8a5b
-[10]: https://github.com/docksal/addons
diff --git a/astro/src/content/blog/creating-local-and-staging-sites-drupals-domain-module-enabled.md b/astro/src/content/blog/creating-local-and-staging-sites-drupals-domain-module-enabled.md
deleted file mode 100644
index a016af6c..00000000
--- a/astro/src/content/blog/creating-local-and-staging-sites-drupals-domain-module-enabled.md
+++ /dev/null
@@ -1,52 +0,0 @@
----
-title: Creating Local and Staging sites with Drupal's Domain Module Enabled
-date: 2013-07-17
-excerpt: How to use aliases within Domain module for pre-production sites.
-tags:
- - databases
- - domain
- - drupal
- - drupal-planet
- - table-prefixing
----
-
-The
-[Domain Access project](https://drupal.org/project/domain 'The Domain Access project on Drupal.org')
-is a suite of modules that provide tools for running a group of affiliated sites
-from one Drupal installation and a single shared database. The issue is that the
-domains are stored within the database so these are copied across when the data
-is migrated between environments, whereas the domains are obviously going to
-change.
-
-Rather than changing the domain settings within the Domain module itself, the
-best solution I think is to use table prefixes and create a different domain
-table per environment. With a live, staging and local domains, the tables would
-be named as follows:
-
-```bash
-live_domain
-local_domain
-staging_domain
-```
-
-Within each site's settings.php file, define the prefix for the domain table
-within the databases array so that each site is looking at the correct table for
-its environment.
-
-```php
-$databases['default']['default'] = array(
- 'driver' => 'mysql',
- 'database' => 'foobar',
- 'username' => 'foo',
- 'password' => 'bar',
- 'host' => 'localhost',
- 'prefix' => array(
- 'default' => '',
- 'domain' => 'local_', // This will use the local_domain table.
- // Add any other prefixed tables here.
- ),
-);
-```
-
-Within each environment-specific domain table, update the subdomain column to
-contain the appropriate domain names.
diff --git a/astro/src/content/blog/creating-using-custom-tokens-drupal-7.md b/astro/src/content/blog/creating-using-custom-tokens-drupal-7.md
deleted file mode 100644
index 978569f1..00000000
--- a/astro/src/content/blog/creating-using-custom-tokens-drupal-7.md
+++ /dev/null
@@ -1,162 +0,0 @@
----
-title: Creating and using custom tokens in Drupal 7
-date: 2013-02-16
-excerpt:
- This post outlines the steps required to create your own custom tokens in
- Drupal.
-tags:
- - drupal
- - drupal-7
- - drupal-planet
- - tokens
----
-
-This post outlines the steps required to create your own custom tokens in
-Drupal.
-
-When writing the recent releases of the
-[Copyright Block](http://drupal.org/project/copyright_block) module, I used
-tokens to allow the user to edit and customise their copyright message and place
-the copyright_message:dates token in the desired position. When the block is
-rendered, the token is replaced by the necessary dates.
-
-We will be using the fictional _foo_ module to demonstrate this.
-
-## Requirements
-
-- [Token module](http://drupal.org/project/token)
-
-## Recommended
-
-- [Devel module](http://drupal.org/project/devel) - useful to run `dpm()` and
- `kpr()` functions
-- [Copyright Block module](http://drupal.org/project/copyright_block) - 7.x-2.x
- and 6.x-1.x use tokens, handy as a reference
-
-## Implementing hook_token_info()
-
-The first thing that we need to do is define the new token type and/or the token
-itself, along with it's descriptive text. To view the existing tokens and types,
-use `dpm(token_get_info());`, assuming that you have the
-[Devel module](http://drupal.org/project/devel) installed.
-
-```php
-/**
- * Implements hook_token_info().
- */
-function foo_token_info() {
- $info = array();
-
- // Add any new tokens.
- $info['tokens']['foo']['bar'] = t('This is my new bar token within the foo type.');
-
- // Return them.
- return $info;
-}
-```
-
-In this case, the token called _bar_ resides within the _foo_ group.
-
-If I needed to add a new token within an existing token type, such as 'node',
-the syntax would be `$info['tokens']['node']['bar']`.
-
-## Implementing hook_tokens()
-
-Now that the Token module is aware of our new token, we now need to determine
-what the token is replaced with. This is done using `hook_tokens()`. Here is the
-basic code needed for an implementation:
-
-```php
-/**
- * Implements hook_tokens().
- */
-function foo_tokens($type, $tokens, array $data = array(), array $options = array()) {
- $replacements = array();
-
- // Code goes here...
-
- // Return the replacements.
- return $replacements;
-}
-```
-
-The first thing to check for is the type of token using an `if()` function, as
-this could be an existing type like 'node', 'user' or 'site', or a custom token
-type like 'foo'. Once we're sure that we're looking at the right type(s), we can
-use `foreach ($tokens as $name => $original)` to loop through each of the
-available tokens using a `switch()`. For each token, you can perform some logic
-to work out the replacement text and then add it into the replacements array
-using `$replacements[$original] = $new;`.
-
-```php
-/**
- * Implements hook_tokens().
- */
-function foo_tokens($type, $tokens, array $data = array(), array $options = array()) {
- $replacements = array();
-
- // The first thing that we're going to check for is the type of token - node,
- // user etc...
- if ($type == 'foo') {
- // Loop through each of the available tokens.
- foreach ($tokens as $name => $original) {
- // Find the desired token by name
- switch ($name) {
- case 'bar':
- $new = '';
-
- // Work out the value of $new...
-
- // Add the new value into the replacements array.
- $replacements[$original] = $new;
- break;
- }
- }
- }
-
- // Return the replacements.
- return $replacements;
-}
-```
-
-## Example
-
-An example from Copyright Block module:
-
-```php
-/**
- * Implements hook_tokens().
- */
-function copyright_block_tokens($type, $tokens, array $data = array(), array $options = array()) {
- $replacements = array();
-
- if ($type == 'copyright_statement') {
- foreach ($tokens as $name => $original) {
- switch ($name) {
- case 'dates':
- $start_year = variable_get('copyright_block_start_year', date('Y'));
- $current_year = date('Y');
-
- $replacements[$original] = $start_year < $current_year ? $start_year . '-' . $current_year : $start_year;
- break;
- }
- }
- }
-
- return $replacements;
-}
-```
-
-## Using token_replace()
-
-With everything defined, all that we now need to do is pass some text through
-the `token_replace()` function to replace it with the values defined within
-`hook_token()`.
-
-```php
-$a = t('Something');
-// This would use any token type - node, user etc.
-$b = token_replace($a);
-// This would only use foo tokens.
-$c = token_replace($a, array('foo'));
-```
diff --git a/astro/src/content/blog/croeso-php-south-wales.md b/astro/src/content/blog/croeso-php-south-wales.md
deleted file mode 100644
index 89f938e6..00000000
--- a/astro/src/content/blog/croeso-php-south-wales.md
+++ /dev/null
@@ -1,82 +0,0 @@
----
-title: Croeso PHP South Wales!
-date: 2018-08-01
-excerpt: Last night was the first meetup of Cardiff’s PHP South Wales user group.
-tags:
- - php
- - php-south-wales
- - meetups
-has_tweets: true
----
-
-Last night was the first meetup of Cardiff’s [PHP South Wales user group][0]! It
-was a great first event, and it was great to meet a lot of new people as well as
-catch up some familiars within the 36 (according to meetup.com) attendees -
-including some [PHP South West][9] regulars.
-
-Organised by Steve and Amy McDougall, it was held in Barclays’ [Eagle Lab][1]
-which was a great space, and it was cool to be back in Brunel House having
-worked in that building previously whilst at Appnovation.
-
-{% include 'tweet' with {
- class: 'my-6',
- data_cards: true,
- content: '
— Oliver Davies (@opdavies) July 31, 2018',
-} %}
-
-## Speakers
-
-[Rob Allen][2] was the main speaker, who gave an interesting talk and a brave
-live demo on serverless PHP and OpenWhisk. I always enjoy watching Rob speak,
-which I’ve done a number of times at different events, and it was great to be
-able to chat for a while after the meetup too.
-
-{% include 'tweet' with {
- class: 'my-6',
- data_cards: true,
- content: '
— Oliver Davies (@opdavies) July 31, 2018',
-} %}
-
-We also had a couple of lightning talks, starting with [Ismael Velasco][3]
-giving an introduction to progressive web applications (PWAs). I can see some
-potential uses for this on my current work project, and I look forward to seeing
-the full talk soon).
-
-I gave an updated version of my [Tailwind CSS lightning talk][4], and enjoyed
-being able to show some examples of new sites using Tailwind such as [Laravel
-Nova][5], [Spatie][6]’s new website and PHP South Wales itself!
-
-{% include 'tweet' with {
- class: 'my-6',
- data_cards: true,
- content: '
— PHP South Wales (@phpSouthWales) July 31, 2018',
-} %}
-
-## Conclusion
-
-It’s great to have a meetup in Cardiff again, and having thought about organsing
-something myself previously, I’m glad to see someone step forward to do so. This
-shows that there's still a strong PHP community in Cardiff and South Wales, and
-hopefully this will be the first meetup of many. I’ll look forward to seeing the
-local community grow!
-
-Thanks again to Steve and Amy for organising, Eagle Labs for hosting, the
-sponsors, and Rob and Ismael for speaking.
-
-It would be great to see even more people at the next one. If you’re interested,
-take a look at the [group’s website][0], [meetup.com group][7] and [Twitter
-profile][8]. Alternatively, get in touch with myself or one of the organisers
-for more information.
-
-**Croeso ac iechyd da PHP South Wales!**
-
-[0]: https://www.phpsouthwales.uk
-[1]: https://labs.uk.barclays/locations/cardiff-en
-[2]: https://twitter.com/akrabat
-[3]: https://twitter.com/IsmaelVelasco
-[4]: /talks/taking-flight-with-tailwind-css
-[5]: https://nova.laravel.com
-[6]: https://spatie.be
-[7]: https://www.meetup.com/PHP-South-Wales
-[8]: https://twitter.com/phpsouthwales
-[9]: https://phpsw.uk
diff --git a/astro/src/content/blog/debugging-drupal-commerce-illuminate-collections.md b/astro/src/content/blog/debugging-drupal-commerce-illuminate-collections.md
deleted file mode 100644
index 6d94c045..00000000
--- a/astro/src/content/blog/debugging-drupal-commerce-illuminate-collections.md
+++ /dev/null
@@ -1,140 +0,0 @@
----
-title: Debugging Drupal Commerce Promotions and Adjustments using Illuminate Collections (Drupal 8)
-date: 2018-10-24
-excerpt: Using Laravel’s Illuminate Collections to debug an issue with a Drupal Commerce promotion.
-tags:
- - drupal
- - drupal-8
- - drupal-commerce
- - drupal-planet
- - illuminate-collections
- - laravel-collections
- - php
-promoted: true
----
-
-Today I found another instance where I decided to use [Illuminate
-Collections][0] within my Drupal 8 code; whilst I was debugging an issue where a
-[Drupal Commerce][1] promotion was incorrectly being applied to an order.
-
-No adjustments were showing in the Drupal UI for that order, so after some
-initial investigation and finding that `$order->getAdjustments()` was empty, I
-determined that I would need to get the adjustments from each order item within
-the order.
-
-If the order were an array, this is how it would be structured in this
-situation:
-
-```php
-$order = [
- 'id' => 1,
- 'items' => [
- [
- 'id' => 1,
- 'adjustments' => [
- ['name' => 'Adjustment 1'],
- ['name' => 'Adjustment 2'],
- ['name' => 'Adjustment 3'],
- ]
- ],
- [
- 'id' => 2,
- 'adjustments' => [
- ['name' => 'Adjustment 4'],
- ]
- ],
- [
- 'id' => 3,
- 'adjustments' => [
- ['name' => 'Adjustment 5'],
- ['name' => 'Adjustment 6'],
- ]
- ],
- ],
-];
-```
-
-## Getting the order items
-
-I started by using `$order->getItems()` to load the order’s items, converted
-them into a Collection, and used the Collection’s `pipe()` method and the
-`dump()` function provided by the [Devel module][2] to output the order items.
-
-```php
-collect($order->getItems())
- ->pipe(function (Collection $collection) {
- dump($collection);
- });
-```
-
-## Get the order item adjustments
-
-Now we have a Collection of order items, for each item we need to get it’s
-adjustments. We can do this with `map()`, then call `getAdjustments()` on the
-order item.
-
-This would return a Collection of arrays, with each array containing it’s own
-adjustments, so we can use `flatten()` to collapse all the adjustments into one
-single-dimensional array.
-
-```php
-collect($order->getItems())
- ->map(function (OrderItem $order_item) {
- return $order_item->getAdjustments();
- })
- ->flatten(1);
-```
-
-There are a couple of refactors that we can do here though:
-
-- Use `flatMap()` to combine the `flatten()` and `map()` methods.
-- Use [higher order messages][3] to delegate straight to the `getAdjustments()`
- method on the order, rather than having to create a closure and call the
- method within it.
-
-```php
-collect($order->getItems())
- ->flatMap->getAdjustments();
-```
-
-## Filtering
-
-In this scenario, each order item had three adjustments - the correct promotion,
-the incorrect one and the standard VAT addition. I wasn’t concerned about the
-VAT adjustment for debugging, so I used `filter()` to remove it based on the
-result of the adjustment’s `getSourceId()` method.
-
-```php
-collect($order->getItems())
- ->flatMap->getAdjustments()
- ->filter(function (Adjustment $adjustment) {
- return $adjustment->getSourceId() != 'vat';
- });
-```
-
-## Conclusion
-
-Now I have just the relevant adjustments, I want to be able to load each one to
-load it and check it’s conditions. To do this, I need just the source IDs.
-
-Again, I can use a higher order message to directly call `getSourceId()` on the
-adjustment and return it’s value to `map()`.
-
-```php
-collect($order->getItems())
- ->flatMap->getAdjustments()
- ->filter(function (Adjustment $adjustment) {
- return $adjustment->getSourceId() != 'vat';
- })
- ->map->getSourceId();
-```
-
-This returns a Collection containing just the relevant promotion IDs being
-applied to the order that I can use for debugging.
-
-Now just to find out why the incorrect promotion was applying!
-
-[0]: https://laravel.com/docs/collections
-[1]: https://drupalcommerce.org
-[2]: https://www.drupal.org/project/devel
-[3]: https://laravel-news.com/higher-order-messaging
diff --git a/astro/src/content/blog/debugging-php-docker-xdebug-neovim-dap.md b/astro/src/content/blog/debugging-php-docker-xdebug-neovim-dap.md
deleted file mode 100755
index a6a0fe3b..00000000
--- a/astro/src/content/blog/debugging-php-docker-xdebug-neovim-dap.md
+++ /dev/null
@@ -1,102 +0,0 @@
----
-title: Debugging PHP in Docker with Xdebug, Neovim and DAP
-date: ~
-tags:
- - docker
- - neovim
- - dap
- - xdebug
- - php
- - drupal
-draft: true
----
-
-I've been a full-time Neovim user for a year at the time of writing this post and whilst I was a semi-regular Xdebug user, it's something that I've managed to work around and have mostly resorted to `var_dump()`, `dump()`, or `dd()` instead for debugging.
-
-This week though, whilst working on some particularly tricky PHP code, I decided to spend some time and get Xdebug working and be able to use a step debugger within Neovim.
-
-https://gist.githubusercontent.com/opdavies/688a3c8917893bf34a3da32ff69c1837/raw/112e16634930d312cd04c525de42a198c8a32bb9/dap.lua
-
-## Installing Xdebug
-
-Installing Xdebug itself within Docker was straight forward. I was able to add two lines to my existing `RUN` command - `pecl install xdebug` to install the extension and `docker-php-ext-enable xdebug` to enable it.
-
-Now when I run `php -v` inside my container, I can see that it mentions Xdebug.
-
-## Configuring Xdebug
-
-https://www.youtube.com/watch?v=ZIGdBSD6zvU
-
-```
-xdebug.mode=develop,debug
-xdebug.client_host=host.docker.internal
-xdebug.discover_client_host=0
-xdebug.output_dir=/tmp/xdebug
-xdebug.log=/tmp/xdebug/xdebug-example.log
-xdebug.start_with_request=yes
-```
-## Installing DAP plugins
-
-I use [Packer](https://github.com/wbthomason/packer.nvim) for managing my Neovim plugins so I needed to install some additional ones to add the DAP (debug adapter protocol) functionality.
-
-```lua
-use "mfussenegger/nvim-dap"
-use "rcarriga/nvim-dap-ui"
-use "theHamsta/nvim-dap-virtual-text"
-use "nvim-telescope/telescope-dap.nvim"
-```
-
-## Installing DAP dependencies
-
-[https://github.com/mfussenegger/nvim-dap/wiki/Debug-Adapter-installation#PHP](https://github.com/mfussenegger/nvim-dap/wiki/Debug-Adapter-installation#PHP)
-
-There's also a prerequisite for install the `vscode-php-debug` adapter.
-
-I configure my laptop with Ansible, so I added a new `debugger` role that is responsible for cloning this repository and installing its contents:
-
-[https://github.com/opdavies/dotfiles/blob/7681c535269049556736f1f857c8c9fd800857a3/roles/debugger/tasks/php.yaml](https://github.com/opdavies/dotfiles/blob/7681c535269049556736f1f857c8c9fd800857a3/roles/debugger/tasks/php.yaml)
-
-## Configuring DAP for Xdebug
-
-```lua
-dap.adapters.php = {
- type = "executable",
- command = "node",
- args = { os.getenv("HOME") .. "/build/vscode-php-debug/out/phpDebug.js" }
-}
-
-dap.configurations.php = {
- {
- type = "php",
- request = "launch",
- name = "Listen for Xdebug",
- port = 9003,
- pathMappings = {
- ["/var/www/html"] = "${workspaceFolder}"
- }
- }
-}
-```
-
-I first needed to configure the adapter to use `vscode-php-debug` and then add a DAP configuration.
-
-The default port for the step debugger is now 9003 rather than 9000 so I changed this from the default, and as I'm working with PHP inside a container, I also added a path mapping so that my code could be found.
-
-## Testing the connection
-
-> [Step Debug] Creating socket for 'host.docker.internal:9003', getaddrinfo: Invalid argument.
-
-```yaml
-services:
- php:
- volumes:
- - "/tmp/xdebug:/tmp/xdebug"
- extra_hosts:
- - "host.docker.internal:host-gateway"
-```
-
----
-
-keymaps:
-
-https://github.com/opdavies/docker-drupal-example
diff --git a/astro/src/content/blog/decorating-entity-metadata-wrapper-add-refactor-methods.md b/astro/src/content/blog/decorating-entity-metadata-wrapper-add-refactor-methods.md
deleted file mode 100644
index 2ef5cd52..00000000
--- a/astro/src/content/blog/decorating-entity-metadata-wrapper-add-refactor-methods.md
+++ /dev/null
@@ -1,141 +0,0 @@
----
-title: Decorating an Entity Metadata Wrapper to add and refactor methods
-excerpt: How to use the Decorator design pattern with Drupal 7's EntityMetadataWrapper to extend it, and add and refactor custom methods.
-tags:
- - drupal
- - drupal-7
- - drupal-planet
- - php
-date: 2021-02-24
----
-
-Following [yesterday's Entity Metadata Wrapper blog post](/blog/cleanly-retrieving-user-profile-data-using-entity-metadata-wrapper) and as I continued to work on this task, I noticed some duplication and found that I was repeating several of the same chaining steps in different methods in the same file. For example:
-
-```php
-public function getFirstName(): string {
- return $this
- ->get('profile_user_basic') // Get the pupil's profile.
- ->get('field_first_name')
- ->value();
-}
-
-private function getTeacherFirstName(): string {
- $this
- ->get('profile_student') // Get the pupil's profile.
- ->get('field_class') // Get the pupil's class.
- ->get('field_teacher') // Get the class' teacher.
- ->get('profile_user_basic') // Get the teacher's profile.
- ->get('field_first_name')
- ->value();
-}
-```
-
-In both cases, the last three lines are the same, where the same profile type is loaded, and the value is loaded from a field.
-
-I wanted to find a way to remove this duplication whilst also making the code more readable. Ideally, this would mean adding a method like `getFirstNameFromBasicProfile()` that would group the last three steps.
-
-## Extending the EntityDrupalWrapper
-
-I've done this before, where I've created a custom wrapper class with its own methods and extends `EntityDrupalWrapper`. This is how that might look:
-
-```php
-final class PupilWrapper extends \EntityDrupalWrapper {
-
- public function __construct(\stdClass $data, $info = []) {
- parent::__construct('user', $data, $info);
- }
-
- public function getFirstName(): string {
- return $this->getFirstNameFromBasicProfile();
- }
-
- public function getTeacherFirstName(): string {
- return $this
- ->get('profile_student')
- ->get('field_class')
- ->get('field_teacher')
- ->getFirstNameFromBasicProfile();
- }
-
- private function getFirstNameFromBasicProfile(): string {
- return $this
- ->get('profile_user_basic')
- ->get('field_first_name')
- ->value();
- }
-
-}
-```
-
-Whilst this has worked in previous situations, this time I had this error:
-
-> Error: Call to undefined method EntityDrupalWrapper::getFirstNameFromBasicProfile() in Drupal\my_module\EntityWrapper\PupilWrapper->getTeacherFirstName
-
-This is because the `get()` method is returning an instance of `EntityStructureWrapper` (another class that extends `EntityDrupalWrapper`) which means that `getFirstNameFromBasicProfile()` is not accessible though it's in the same file.
-
-I tried overridding the `get()` method but wasn't able to get this to work.
-
-## Decorating the EntityDrupalWrapper
-
-Another option that I tried was to follow the Decorator design pattern, and add a new class that takes an `EntityDrupalWrapper` as an argument as uses it internally but doesn't extend it. Here's an example:
-
-```php
-final class PupilWrapper {
-
- private $accountWrapper;
-
- public function __construct(\EntityMetadataWrapper $accountWrapper) {
- $this->accountWrapper = $accountWrapper;
- }
-
- public function getFirstName(): string {
- return $this->getFirstNameFromBasicProfile();
- }
-
- public function getTeacherFirstName(): string {
- return $this
- ->get('profile_student')
- ->get('field_class')
- ->get('field_teacher')
- ->getFirstNameFromBasicProfile();
- }
-
- private function getFirstNameFromBasicProfile(): string {
- return $this
- ->get('profile_user_basic')
- ->get('field_first_name')
- ->value();
- }
-
-}
-```
-
-In this case, the constructor argument is an instance of `EntityMetadataWrapper` so that it could be either an `EntityDrupalWrapper` or `EntityStructureWrapper`.
-
-### Re-adding required wrapper methods
-
-As the `get()` method is missing, this would cause an error:
-
-> Error: Call to undefined method Drupal\my_module\EntityWrapper\PupilWrapper::get() in Drupal\my_module\EntityWrapper\PupilWrapper->getFirstName()
-
-However, we can re-add it, have it get the value from `accountWrapper` and return another instance of `PupilWrapper` so that `getFirstNameFromBasicProfile()` will be available.
-
-```php
-public function get(string $property): self {
- return new self($this->accountWrapper->get($property));
-}
-```
-
-The `value()` method is also required, but this can delegate to the decorated wrapper:
-
-> Error: Call to undefined method Drupal\my_module\EntityWrapper\PupilWrapper::value() in Drupal\my_module\EntityWrapper\PupilWrapper->getFirstName()
-
-```php
-public function value(): string {
- return $this->accountWrapper->value();
-}
-```
-
-## Conclusion
-
-This was the first time that I tried extending Drupal 7's entity metadata wrappers in this way, but it worked well, removes the duplication and cleans up the code further.
diff --git a/astro/src/content/blog/display-custom-menu-drupal-7-theme-template-file.md b/astro/src/content/blog/display-custom-menu-drupal-7-theme-template-file.md
deleted file mode 100644
index 092916fd..00000000
--- a/astro/src/content/blog/display-custom-menu-drupal-7-theme-template-file.md
+++ /dev/null
@@ -1,27 +0,0 @@
----
-title: Display a Custom Menu in a Drupal 7 Theme Template File
-date: 2012-08-18
-excerpt: The code needed to display a menu in a Drupal 7 template file.
-tags:
- - aria
- - drupal
- - drupal-7
- - drupal-planet
- - php
----
-
-For reference, this is the code needed to display a menu in a Drupal 7 template
-file, including the navigation ARIA role.
-
-```php
-$menu_name = 'menu-footer-menu';
-$menu_id = 'footer-menu';
-print theme('links', array(
- 'links' => menu_navigation_links($menu_name),
- 'attributes' => array(
- 'id' => $menu_id,
- 'role' => 'navigation',
- 'class'=> array('links', 'inline')
- )
-));
-```
diff --git a/astro/src/content/blog/display-git-branch-or-tag-names-your-bash-prompt.md b/astro/src/content/blog/display-git-branch-or-tag-names-your-bash-prompt.md
deleted file mode 100644
index 0403bdfa..00000000
--- a/astro/src/content/blog/display-git-branch-or-tag-names-your-bash-prompt.md
+++ /dev/null
@@ -1,67 +0,0 @@
----
-title: Display Git Branch or Tag Names in your Bash Prompt
-date: 2013-04-27
-excerpt: Whilst watching Drupalize.me's recent Introduction to Git series, I thought it was useful the way that the current Git branch or tag name was displayed in the bash prompt. Here's how to do it.
-tags:
- - drupal
- - drupal-planet
- - git
- - terminal
----
-
-Whilst watching [Drupalize.me](http://drupalize.me 'Drupalize.me')'s recent
-[Introduction to Git series](http://drupalize.me/series/introduction-git-series 'Introduction to Git on Drupalize.me'),
-I thought it was useful the way that the current Git branch or tag name was
-displayed in the bash prompt.
-
-Here's how to do it.
-
-For example (with some slight modifications):
-
-```bash
-oliver@oliver-mbp:~/Development/drupal(master) $
-oliver@oliver-mbp:~/Development/a11y_checklist(7.x-1.0) $
-```
-
-Here's how to do it.
-
-To begin with, create a new file to contain the functions,
-
-```bash
-vim ~/.bash/git-prompt
-```
-
-Paste the following code into the file, and save it.
-
-```bash
-parse_git_branch () {
- git branch 2> /dev/null | sed -e '/^[^*]/d' -e 's/* \(.*\)/ (\1)/'
-}
-
-parse_git_tag () {
- git describe --tags 2> /dev/null
-}
-
-parse_git_branch_or_tag() {
- local OUT="$(parse_git_branch)"
- if [ "$OUT" == " ((no branch))" ]; then
- OUT="($(parse_git_tag))";
- fi
- echo $OUT
-}
-```
-
-Edit your `.bashrc` or `.bash_profile` file to override the PS1 value.
-
-```bash
-vim ~/.bashrc
-```
-
-Add the following code at the bottom of the file, and save it.
-
-```bash
-source ~/.bash/git-prompt
-PS1="\u@\h:\w\$(parse_git_branch_or_tag) $ "
-```
-
-Restart your Terminal or type `source ~/.bashrc` to see your changes.
diff --git a/astro/src/content/blog/display-number-facebook-fans-php.md b/astro/src/content/blog/display-number-facebook-fans-php.md
deleted file mode 100644
index fcf28c28..00000000
--- a/astro/src/content/blog/display-number-facebook-fans-php.md
+++ /dev/null
@@ -1,30 +0,0 @@
----
-title: Display the Number of Facebook fans in PHP
-date: 2011-03-15
-excerpt: How to use PHP to display the number of fans of a Facebook page.
-tags:
- - php
----
-
-Replace the \$page_id value with your Page ID number (unless you want to show
-the number of fans for this site).You can find your Page ID by logging into your
-Facebook account, going to 'Adverts and Pages', clicking 'Edit page', and
-looking at the URL.
-
-For example, mine is
-.
-
-I've also wrapped the output in a number_format() function so that it properly
-formatted with commas etc - like where I've used it within the
-[Gold Event listing](http://www.horseandcountry.tv/events/paid) on the Horse &
-Country TV website.
-
-```php
-$page_id = "143394365692197";
-$xml = @simplexml_load_file("http://api.facebook.com/restserver.php?method=facebook.fql.query&query=SELECT%20fan_count%20FROM%20page%20WHERE%20page_id=".$page_id."") or die ("a lot");
-$fans = $xml->page->fan_count;
-print number_format($fans);
-```
-
-This code was originally found at
-.
diff --git a/astro/src/content/blog/dividing-drupals-process-and-preprocess-functions-separate-files.md b/astro/src/content/blog/dividing-drupals-process-and-preprocess-functions-separate-files.md
deleted file mode 100644
index 3e8fec99..00000000
--- a/astro/src/content/blog/dividing-drupals-process-and-preprocess-functions-separate-files.md
+++ /dev/null
@@ -1,93 +0,0 @@
----
-title: Dividing Drupal's process and preprocess functions into separate files
-date: 2012-05-24
-excerpt: If you use a lot of process and preprocess functions within your Drupal theme, then your template.php can get very long and it can become difficult to find a certain piece of code. Following the example of the Omega theme, I've started separating my process and preprocess functions into their own files.
-tags:
- - code
- - drupal
- - preprocessing
- - theming
----
-
-If you use a lot of process and preprocess functions within your Drupal theme,
-then your template.php can get very long and it can become difficult to find a
-certain piece of code. Following the example of the
-[Omega theme](http://drupal.org/project/omega 'The Omega theme on Drupal.org'),
-I've started separating my process and preprocess functions into their own
-files. For example, mytheme_preprocess_node can be placed within a
-preprocess/node.inc file, and mytheme_process_page can be placed within
-process/page.inc.
-
-The first step is to use the default mytheme_process() and mytheme_preprocess()
-functions to utilise my custom function. So within my template.php file:
-
-```php
- This new version makes Media module available for all, improves migrations
-> significantly, stabilizes the Content Moderation and Settings Tray modules,
-> serves dynamic pages faster with BigPipe enabled by default, and introduces a
-> new experimental entity layout user interface. The release includes several
-> very important fixes for workflows of content translations and supports
-> running on PHP 7.2.
-
-I’ve been very impressed by the new release cycle Drupal 8 and the usage of
-semantic versioning. Though it adds a greater maintenance overhead for module,
-theme, installation profile and distribution developers to ensure that our
-projects are still working properly, having the ability to add new modules into
-Drupal core as well as new installation profiles like the [Unami demonstration
-profile][2] is pretty cool!
-
-For example, in addition to Unami, 8.5 alone adds media in core, two
-experimental modules have been marked as stable, an experimental new layout
-builder has been added and lots of PHP 7.2 improvements have been committed to
-make 8.5 fully PHP 7.2 compatible.
-
-I’m already looking forward to see what’s coming in 8.6 later this year!
-
-For more information on the 8.5 release, see the [blog post on Drupal.org][1].
-
-[0]: https://dri.es/drupal-8-5-0-released
-[1]: https://www.drupal.org/blog/drupal-8-5-0
-[2]:
- https://www.drupal.org/docs/8/umami-drupal-8-demonstration-installation-profile
diff --git a/astro/src/content/blog/drupal-8-commerce-fixing-error-on-user-checkout.md b/astro/src/content/blog/drupal-8-commerce-fixing-error-on-user-checkout.md
deleted file mode 100644
index f7fa2212..00000000
--- a/astro/src/content/blog/drupal-8-commerce-fixing-error-on-user-checkout.md
+++ /dev/null
@@ -1,95 +0,0 @@
----
-title: "Drupal 8 Commerce: Fixing 'No Such Customer' error on checkout"
-date: 2018-08-15
-excerpt: Fixing a Drupal Commerce error when a user tries to complete a checkout.
-tags:
- - drupal
- - drupal-8
- - drupal-commerce
- - stripe
----
-
-Recently I was experiencing an issue on the Drupal 8 website I’m working on,
-where a small number of users were not able to complete the checkout process and
-instead got a generic `The site has encountered an unexpected error` message.
-
-Looking at the log, I was able to see the error being thrown (the customer ID
-has been redacted):
-
-> Stripe\Error\InvalidRequest: No such customer: cus_xxxxxxxxxxxxxx in
-> Stripe\ApiRequestor::\_specificAPIError() (line 124 of
-> /var/www/vendor/stripe/stripe-php/lib/ApiRequestor.php).
-
-Logging in to the Stripe account, I was able to confirm that the specified
-customer ID did not exist. So where was it coming from, and why was Drupal
-trying to retrieve a non-existent customer?
-
-## Investigation
-
-After some investigation, I found a table in the database named
-`user__commerce_remote_id` which stores the remote customer ID for each payment
-method (again, the customer ID has been redacted).
-
-{.border.p-1}
-
-The `entity_id` and `revision_id` values in this case refer to the user that the
-Stripe customer has been associated with.
-
-As there was no customer in Stripe with this ID, I think that this must be a
-customer ID from the test environment (the data from which was deleted before
-the site went live).
-
-### Drupal code
-
-This I believe is the Drupal code where the error was being triggered:
-
-```php
-// modules/contrib/commerce_stripe/src/Plugin/Commerce/PaymentGateway/Stripe.php
-
-public function createPayment(PaymentInterface $payment, $capture = TRUE) {
- ...
-
- $owner = $payment_method->getOwner();
- if ($owner && $owner->isAuthenticated()) {
- $transaction_data['customer'] = $this->getRemoteCustomerId($owner);
- }
-
- try {
- $result = \Stripe\Charge::create($transaction_data);
- ErrorHelper::handleErrors($result);
- }
- catch (\Stripe\Error\Base $e) {
- ErrorHelper::handleException($e);
- }
-
- ...
-}
-```
-
-### Stripe code
-
-I can also see in the Stripe library where the original error is generated.
-
-```php
-private static function _specificAPIError($rbody, $rcode, $rheaders, $resp, $errorData)
-{
- $msg = isset($errorData['message']) ? $errorData['message'] : null;
- $param = isset($errorData['param']) ? $errorData['param'] : null;
- $code = isset($errorData['code']) ? $errorData['code'] : null;
-
- switch ($rcode) {
- ...
-
- case 404:
- return new Error\InvalidRequest($msg, $param, $rcode, $rbody, $resp, $rheaders);
-
- ...
- }
-}
-```
-
-## Solution
-
-After confirming that it was the correct user ID, simply removing that row from
-the database allowed the new Stripe customer to be created and for the user to
-check out successfully.
diff --git a/astro/src/content/blog/drupal-association.md b/astro/src/content/blog/drupal-association.md
deleted file mode 100644
index 49805088..00000000
--- a/astro/src/content/blog/drupal-association.md
+++ /dev/null
@@ -1,37 +0,0 @@
----
-title: Drupal Association
-date: 2014-05-03
-excerpt: Next week, I'll be working for the Drupal Association.
-tags:
- - drupal
- - personal
----
-
-Today was my last day working at [Precedent](http://www.precedent.com). Next
-week, I'll be starting my
-[new job](https://assoc.drupal.org/node/18923 'Drupal.org Developer') at the
-[Drupal Association](http://assoc.drupal.org) working on Drupal's home -
-[Drupal.org](http://www.drupal.org).
-
-I was at Precedent for just over a year and had the opportunity to work on
-several Drupal projects from project leading to ad-hoc module and theme
-development, including my largest Drupal build to date.
-
-I was also lucky enough to go to
-[DrupalCon Prague](http://prague2013.drupal.org) as well as
-[DrupalCamp London](http://2014.drupalcamplondon.co.uk).
-
-I was able to [contribute some code](https://drupal.org/project/eventsforce)
-back into the community and encourage other team members to do the same.
-
-It was good to be able to introduce some new tools like
-[Vagrant](http://www.vagrantup.com), [Puppet](http://www.puppetlabs.com),
-[SASS](http://www.sass-lang.com) and [Compass](http://www.compass-style.org)
-into the team. I was pleased to introduce and champion the
-[Git Flow](http://danielkummer.github.io/git-flow-cheatsheet 'Git Flow Cheat Sheet')
-branching model, which them became the standard approach for all Drupal
-projects, and hopefully soon all development projects.
-
-Working for the Drupal Association and on Drupal.org was an opportunity that I
-couldn't refuse, and is certainly going to be a fun and interesting challenge. I
-can't wait to get started!
diff --git a/astro/src/content/blog/drupal-automated-testing-workshop-notes.md b/astro/src/content/blog/drupal-automated-testing-workshop-notes.md
deleted file mode 100644
index 18163f3a..00000000
--- a/astro/src/content/blog/drupal-automated-testing-workshop-notes.md
+++ /dev/null
@@ -1,14 +0,0 @@
----
-title: Drupal automated testing workshop notes
-excerpt: If you attended my automated testing with Drupal workshop this weekend, here are the links.
-tags:
- - drupal
-date: 2020-11-15
----
-
-If you attended my automated testing and test driven development workshop this weekend at DrupalCamp NYC, or at DrupalCamp London in March, [here are the notes][notes] that we went through during the session.
-
-There is also [a separate code repository][code] that contains the example code, broken down commit by commit, and uses GitHub Actions to run the tests automatically on each push.
-
-[code]: https://github.com/opdavies/workshop-drupal-automated-testing-code
-[notes]: https://github.com/opdavies/workshop-drupal-automated-testing
diff --git a/astro/src/content/blog/drupal-body-classes-tailwind-css.md b/astro/src/content/blog/drupal-body-classes-tailwind-css.md
deleted file mode 100644
index e7e15c99..00000000
--- a/astro/src/content/blog/drupal-body-classes-tailwind-css.md
+++ /dev/null
@@ -1,153 +0,0 @@
----
-title: Exporting Drupal body classes to use with Tailwind CSS
-excerpt: How I've exported content from Drupal's body fields so they aren't missed by Tailwind's JIT mode or PurgeCSS.
-date: 2022-07-02
-tags:
- - drupal
- - tailwind-css
----
-
-I was recently [asked a question](https://www.drupal.org/project/tailwindcss/issues/3271487) in the issue queue for my [Tailwind starter kit Drupal theme](https://www.drupal.org/project/tailwindcss), about how to use classes within content with Tailwind CSS.
-
-The 5.x version of the theme has the JIT (just in time) compiler enabled by default and whilst it can work using Twig files in your theme, it doesn't know about classes used within content that is stored within the database.
-
-This is something that I've needed to solve in some of my own projects before too so there are a few options but I'd not recommend turning off the JIT compiler or PurgeCSS.
-
-## Adding classes to a safelist
-
-The first option is to use the `safelist` option within the `tailwind.config.js` file:
-
-```js
-module.exports = {
- content: [
- './templates/**/*.html.twig'
- ],
- safelist: [
- 'bg-red-500',
- 'text-3xl',
- 'lg:text-4xl',
- ]
-}
-```
-
-Adding any classes to the safelist will force them to be generated, or prevent them from being purged, even if they are not found within the theme's templates files.
-
-This is refered to within the Tailwind CSS documentation for [safelisting classes](https://tailwindcss.com/docs/content-configuration#safelisting-classes):
-
-> One example of where this can be useful is if your site displays user-generated content and you want users to be able to use a constrained set of Tailwind classes in their content that might not exist in your own site’s source files.
-
-## Extracting the safelist to a file
-
-In some projects, I found that I was adding a lot of classes to the safelist so I extracted the classes into a file instead.
-
-Whilst it could be a JavaScript object that could be imported, as long as Tailwind sees the classes being used, the files just need to exist in a file that can be scanned - even just a plain text file called `safelist.txt`:
-
-```
-bg-red-500
-text-3xl
-lg:text-4xl
-```
-
-Rather than using the `safelist`, I can add the safelist file to `content` instead:
-
-```js
-module.exports = {
- content: [
- './safelist.txt',
- './templates/**/*.html.twig'
- ]
-}
-```
-
-## Creating a safelist file automatically with Drush
-
-What we could also do is create the safelist file automatically based on the contents of the database using a custom Drush command.
-
-### Creating the command
-
-This can be done by creating a new PHP class within a custom module and use the `@command` annotation to specify the command to run:
-
-```php
-database = $database;
-}
-```
-
-### Completing the handle method
-
-As well as the database, I've added some properties to contain the table names to query as well as the name of the file to output:
-
-```php
-private static array $tableNames = [
- 'block_content__body',
- 'node__body',
-];
-
-private string $filename = 'safelist.txt';
-```
-
-Within the `handle()` method, I'm using an [Illuminate Collection](/talks/using-illuminate-collections-outside-laravel) to loop over the array of tables, query the database, export the values, and write them into the file:
-
-```php
-public function handle(): void {
- $values = collect(self::$tableNames)
- ->flatMap(fn(string $tableName) =>
- $this->getValuesFromTable($tableName))
- ->implode(PHP_EOL);
-
- file_put_contents($this->getFilePath(), $values);
-}
-
-private function getFilePath(): string {
- return drupal_get_path('theme', 'opdavies') . DIRECTORY_SEPARATOR
- . $this->filename;
-}
-
-private function getValuesFromTable(string $tableName): array {
- return $this->database->select($tableName)
- ->fields($tableName, ['body_value'])
- ->execute()
- ->fetchCol();
-}
-```
-
-Now, when Tailwind CSS is run, it will find the exported body contents within the safelist file, and ensure that the appropriate classes are generated.
diff --git a/astro/src/content/blog/drupal-bristol-testing-workshop.md b/astro/src/content/blog/drupal-bristol-testing-workshop.md
deleted file mode 100644
index 9a5a4b4a..00000000
--- a/astro/src/content/blog/drupal-bristol-testing-workshop.md
+++ /dev/null
@@ -1,112 +0,0 @@
----
-title: Drupal Bristol Testing Workshop
-date: 2018-06-28
-excerpt: Yesterday evening, I did my first workshop, held at the Drupal Bristol user group.
-tags:
- - composer
- - docksal
- - drupal
- - drupal-8
- - drupal-bristol
- - php
- - phpunit
- - testing
----
-
-Yesterday evening, I did [my first workshop][16] (and I believe, the first
-workshop) held at the [{{ site.events['drupal_bristol'].name }}][14] user group.
-The subject was automated testing with PHPUnit in Drupal 8, in preparation for
-my talk at [{{ site.events['drupal_dev_days_18'].name }}][12] next week and to
-help process some ideas for my [testing book][15].
-
-Here are some details about what we covered, and some of my thoughts in review.
-
-## Local Environment
-
-Before the meetup, I set up a [repository on GitHub][0] that contains a
-Composer-based Drupal 8 installation, based on the [Drupal 8 Composer
-template][4] along with the [Examples module][5] (which includes some PHPUnit
-tests) with a pre-configured [Docksal][2] environment to use locally - Docksal
-being our standard local development environment that we use at
-{{ site.companies['microserve'].name }} for all of our projects, so something
-that I’m familiar with using.
-
-In addition to the default stack, I added [the PHPUnit add-on that I wrote][6]
-so that it was easier to run tests, [configured settings.php using environment
-variables][7] and added a custom `fin init` command to install the Composer
-dependencies and install Drupal. This meant after that installing Docksal,
-everyone had a running Drupal 8 website after only running `git clone` and
-`fin init`, and could then run tests straight away using
-`fin phpunit web/modules/contrib/examples/phpunit_example`.
-
-## Exercises
-
-Once everyone was set up, we moved on to talk about why testing is important and
-the different options available to run them, before looking at the different
-types of tests available in Drupal 8. For each test type, I explained what it
-was used for and everyone completed an exercise on each - creating a test of
-that type, initially seeing it fail, and then doing the work to get it to pass.
-
-The completed code that I wrote beforehand for these is available in their own
-[GitHub repository][8], including all of the tests as well as the implementation
-code.
-
-Once these exercises were completed, we looked at creating a blog page using
-test driven development - the example that I use in the [TDD - Test-Driven
-Drupal talk][9], to give a more real-word scenario. It would have been good to
-have gone through this as an exercise too, if we’d have had more time.
-
-## Wrap Up
-
-To finish, I demonstrated the PHPUnit integration within PHPStorm (which is
-working with Docksal) and showed some of the tests that I wrote for the [Private
-Message Queue][10] and [System User][11] modules, to see how things like adding
-items to queues and processing them, ensuring that emails are sent, to the right
-users and contain the right data, can be tested, as well as some of the tests
-that we’ve written on my work project over the last few months.
-
-## Slides
-
-I didn’t record this workshop, but I have exported the slides and embedded them
-below:
-
-{% include 'speakerdeck' with {
- data: {
- id: '2679401cb2ad421789d372cb8d38e368',
- ratio: '1.77777777777778',
- }
-} %}
-
-## Thoughts
-
-I was very happy with how my first workshop went, it was a great experience for
-me and it seemed that the attendees all learnt something and found it
-interesting.
-
-A couple of people mentioned about providing handouts to refer the code examples
-whilst working on the exercises, rather than relying on the slides and avoiding
-the need to sometimes switch back and forth between slides. I’ve found that I
-can export the slide deck as PNGs or JPGs from Deckset, so I’ll definitely do
-that next time.
-
-I’m giving the [Test-Driven Drupal][9] talk at the [Drupal Dev Days
-conference][12] next week, and I’m hoping to give it again at other meetups and
-events in the UK. If you’d like me to do either at your meetup or event, [get in
-touch][13].
-
-[0]: https://github.com/opdavies/drupal-testing-workshop
-[1]: https://github.com/drupal-composer/drupal-project
-[2]: https://docksal.io
-
-[3]: {{site.companies['microserve'].url}} [4]:
-https://github.com/drupal-composer/drupal-project [5]:
-https://www.drupal.org/project/examples [6]:
-/articles/creating-a-custom-phpunit-command-for-docksal [7]:
-/articles/using-environment-variables-settings-docksal [8]:
-https://github.com/opdavies/drupal-testing-workshop-exercises [9]:
-/talks/tdd-test-driven-drupal [10]:
-https://www.drupal.org/project/private_message_queue [11]:
-https://www.drupal.org/project/system_user [12]:
-{{site.events.drupal_dev_days_18.url}} [13]: /contact [14]:
-{{site.events.drupal_bristol.url}} [15]: /test-driven-drupal [16]:
-https://groups.drupal.org/node/520891
diff --git a/astro/src/content/blog/drupal-vm-generator-updates.md b/astro/src/content/blog/drupal-vm-generator-updates.md
deleted file mode 100644
index 761d86e0..00000000
--- a/astro/src/content/blog/drupal-vm-generator-updates.md
+++ /dev/null
@@ -1,35 +0,0 @@
----
-title: Drupal VM Generator 2.9.1 Released
-date: 2016-12-30
-excerpt: I’ve released some new versions of the Drupal VM Generator.
-tags:
- - drupal-vm-generator
- - releases
----
-
-The main updates are:
-
-- Fixed an `InvalidResponseException` that was thrown from within the
- `boolean_as_string` Twig filter from the opdavies/twig-extensions library when
- the `config:generate` command was run in non-interactive mode.
-- Adding a working test suite for the existing commands, using PhpUnit and
- Symfony’s Process component. This is now linked to [Travis CI][2], and the
- tests are run on each commit and pull request.
-- The version requirements have been changed to allow 2.7 versions of the used
- Symfony Components, as well as the 3.x versions. This was done to resolve a
- conflict when also installing Drush globally with Composer.
-
-## Next Steps
-
-Currently the project is based on Drupal VM 3.0.0 which is an outdated version
-([4.1.0][3] was released today). Adding updates and supporting the newer
-versions is a high priority, as well as keeping in sync with new releases. This
-will be easier with the test suite in place.
-
-My initial thoughts are that version 2.10.0 will support Drupal VM 4.0.0, and if
-needed, 2.11.0 will ship shortly afterwards and support Drupal VM 4.1.0.
-
-[0]: http://www.drupalvmgenerator.com
-[1]: https://github.com/opdavies/drupal-vm-generator/tree/master/tests/Command
-[2]: https://travis-ci.org/opdavies/drupal-vm-generator
-[3]: https://github.com/geerlingguy/drupal-vm/releases/tag/4.1.0
diff --git a/astro/src/content/blog/drupalcamp-bristol-2018.md b/astro/src/content/blog/drupalcamp-bristol-2018.md
deleted file mode 100644
index a7f75443..00000000
--- a/astro/src/content/blog/drupalcamp-bristol-2018.md
+++ /dev/null
@@ -1,46 +0,0 @@
----
-title: DrupalCamp Bristol 2018 Statement
-date: 2018-01-30
-excerpt: Unfortunately, we won’t be running DrupalCamp Bristol this year.
-tags:
- - drupal-planet
- - drupalcamp-bristol
-meta:
- image:
- url: /images/blog/drupalcamp-bristol-17-logo.jpg
- width: 228
- height: 448
- type: image/img
----
-
-It’s with heavy hearts that we are announcing there won’t be a DrupalCamp
-Bristol 2018. The committee have looked at the amount of work required to put
-the camp on and the capacity we all have and the two numbers are irreconcilable.
-
-Seeing Drupalists from all over the country and from overseas come to Bristol to
-share knowledge and ideas is something we take pride in. The past three camps
-have been fantastic, but as a trend we have left it later and later to organise.
-
-This year is the latest we have left to organise and we believe this is because
-we are all a bit fatigued right now, so it seems like a good place to stop and
-take stock.
-
-In our washup of last year’s camp we spoke a lot about what DrupalCamp is and
-who it is for. Traditionally we have tried to get a good mix of speakers from
-within the Drupal community and from the wider tech community. This does mean we
-dilute the ‘Drupal’ aspect of the camp, but the benefits it brings in terms of
-bringing together different views gives the camp greater value in our eyes.
-
-It’s because of this mix of talks and wider shifts in the community in ‘getting
-us off the island’ that we have been thinking about rebranding to reflect the
-mix of talks that the camp hosts. The fact is DrupalCamps don’t just cover
-Drupal anymore. There is Symfony, Composer, OOP principles, React, etc.
-
-We’ll take the gap this year to reevaluate who DrupalCamp Bristol is for and
-where it fits into the schedule of excellent tech events that take place in
-Bristol through the year, and we look forward to seeing you in 2019, refreshed
-and more enthusiastic than ever!
-
-The DrupalCamp Bristol organising committee
-
-Tom, Ollie, Emily, Sophie, Rob, Mark
diff --git a/astro/src/content/blog/drupalcamp-bristol-2019-speakers-sessions-announced.md b/astro/src/content/blog/drupalcamp-bristol-2019-speakers-sessions-announced.md
deleted file mode 100644
index 6ea91c82..00000000
--- a/astro/src/content/blog/drupalcamp-bristol-2019-speakers-sessions-announced.md
+++ /dev/null
@@ -1,36 +0,0 @@
----
-title: Speakers and sessions announced for DrupalCamp Bristol 2019
-date: 2019-05-31
-excerpt: DrupalCamp Bristol is returning next month, and the accepted speakers and sessions have just been announced.
-tags:
- - dcbristol
- - drupalcamp
- - drupalcamp-bristol
----
-
-
DrupalCamp Bristol is returning next month for a one-day, single-track conference, and we have just finished announcing the accepted sessions and speakers. It includes a mixture of new and returning speakers, presenting sessions including **Drupal in a microservice architecture**, **Automate to manage repetitive tasks with Ansible** and **Doing good with Drupal**.
-
-Find out more about all of our sessions and speakers on [the DrupalCamp Bristol
-website][website], as well as view the schedule for the day.
-
-Also, at the time of writing, [early bird tickets are still available][tickets]
-for a few more days!
-
-In the meantime, the videos from the 2017 Camp are on [our YouTube
-channel][youtube], including the opening keynote from [Emma Karayiannis][emma]:
-
-{% include 'video-embed' with {
- classes: 'video-full',
- video: {
- id: 'honnav4YlAA',
- attr: {
- height: '315',
- width: '560',
- }
- }
-} %}
-
-[emma]: https://twitter.com/embobmaria
-[tickets]: https://2019.drupalcampbristol.co.uk/tickets
-[website]: https://2019.drupalcampbristol.co.uk
-[youtube]: https://opdavi.es/dcbristol17-videos
diff --git a/astro/src/content/blog/drupalcamp-bristol-early-bird-tickets-sessions-sponsors.md b/astro/src/content/blog/drupalcamp-bristol-early-bird-tickets-sessions-sponsors.md
deleted file mode 100644
index a3710daf..00000000
--- a/astro/src/content/blog/drupalcamp-bristol-early-bird-tickets-sessions-sponsors.md
+++ /dev/null
@@ -1,68 +0,0 @@
----
-title: DrupalCamp Bristol 2017 - Early Bird Tickets, Call for Sessions, Sponsors
-date: 2017-05-15
-excerpt: In less than two months time, DrupalCamp Bristol will be back for our third year.
-tags:
- - drupal
- - drupal-planet
- - drupalcamp
- - drupalcamp-bristol
-meta:
- image:
- url: /assets/image/blog/drupalcamp-bristol-17-logo.jpg
- height: 228
- width: 448
- type: image/jpg
----
-
-
-
-In less than two months time, [DrupalCamp Bristol][0] will be back for our third
-year! (July seems to come around quicker each year). This is this year’s
-schedule and venues:
-
-- 30th June - CXO (Business) day - [Watershed][1]
-- 1st July - Developer conference - [University of Bristol, School of
- Chemistry][2]
-- 2nd July - Contribution sprints - Venue TBC
-
-Today we announced [Emma Karayiannis][3] as our Saturday keynote speaker, and
-we’ll be announcing some of the other speakers later this week.
-
-Not submitted your session yet? The [session submissions][12] are open until May
-31st. We’re looking for talks not only on Drupal, but other related topics such
-as PHP, Symfony, server administration/DevOps, project management, case studies,
-being human etc. If you want to submit but want to ask something beforehand,
-please [send us an email][4] or ping us on [Twitter][5].
-
-Not spoken at a DrupalCamp before? No problem. We’re looking for both new and
-experienced speakers, and have both long (45 minutes) and short (20 minutes)
-talk slots available.
-
-Not bought your tickets yet? [Early bird tickets][10] for the CXO and conference
-days are still available! The sprint day tickets are free but limited, so do
-register for a ticket to claim your place.
-
-We still have [sponsorships opportunities][6] available (big thanks to
-[Microserve][7], [Deeson][8] and [Proctors][9]) who have already signed up), but
-be quick if you want to be included in our brochure so that we can get you added
-before our print deadline! Without our sponsors, putting on this event each year
-would not be possible.
-
-Any other questions? Take a look at [our website][0] or get in touch via
-[Twitter][5] or [email][11].
-
-[0]: https://2017.drupalcampbristol.co.uk
-[1]: http://www.watershed.co.uk
-[2]: http://www.bris.ac.uk/chemistry
-[3]: http://emmakarayiannis.com
-[4]: mailto:speakers@drupalcampbristol.co.uk
-[5]: https://twitter.com/DrupalCampBris
-[6]: https://2017.drupalcampbristol.co.uk/sponsorship
-[7]: https://microserve.io
-[8]: https://www.deeson.co.uk
-[9]: http://www.proctors.co.uk
-[10]:
- https://www.eventbrite.co.uk/e/drupalcamp-bristol-2017-tickets-33574193316#ticket
-[11]: mailto:info@drupalcampbristol.co.uk
-[12]: https://2017.drupalcampbristol.co.uk/#block-dcb2017-page-title
diff --git a/astro/src/content/blog/drupalcamp-london-2014.md b/astro/src/content/blog/drupalcamp-london-2014.md
deleted file mode 100644
index a40cd49e..00000000
--- a/astro/src/content/blog/drupalcamp-london-2014.md
+++ /dev/null
@@ -1,24 +0,0 @@
----
-title: DrupalCamp London 2014
-date: 2014-02-09
-excerpt: It's all booked, I'm going to be attending DrupalCamp London.
-tags:
- - drupal
- - drupalcamp-london
- - git
- - git-flow
----
-
-It's all booked, I'm going to be attending
-[DrupalCamp London](http://2014.drupalcamplondon.co.uk) this year, my first
-DrupalCamp!
-
-I'm going as a volunteer, so I'm going to be helping with the registrations on
-the Saturday morning and for another couple hours elsewhere over the weekend.
-I've also offered to help organise and oversee some code sprints, although I'm
-definitely wanting to do some sprinting of my own and attend a few sessions.
-
-I'm looking forward to meeting some new people as well as catching up with some
-people that I met at [DrupalCon Prague](http://prague2013.drupal.org).
-
-If you're also coming, see you there!
diff --git a/astro/src/content/blog/drupalcamp-london-2019-tickets.md b/astro/src/content/blog/drupalcamp-london-2019-tickets.md
deleted file mode 100644
index dcd538ab..00000000
--- a/astro/src/content/blog/drupalcamp-london-2019-tickets.md
+++ /dev/null
@@ -1,39 +0,0 @@
----
-title: DrupalCamp London 2019 - Tickets Available and Call for Sessions
-date: 2018-11-20
-excerpt: DrupalCamp London early-bird tickets are now available, and their call for sessions is open.
-tags:
- - conferences
- - drupal
- - drupalcamp
- - drupalcamp-london
-has_tweets: true
----
-
-It was announced this week that [early-bird tickets are now available][0] for
-[DrupalCamp London 2019][1], as well as their [call for sessions being open][2].
-
-{% include 'tweet' with {
- content: '
The time is finally here. You can now purchase your tickets. Early Bird finishes on 2nd January 2019 - https://t.co/aG6jstmWzv#Drupal
— DrupalCamp London (@DrupalCampLDN) November 19, 2018
-',
-} %}
-
-I’ve attended, given talks and volunteered previously, would definitely
-recommend others doing so, and I plan on attending and submitting again myself
-for 2019. If there’s something in particular that you’d like to see me give a
-talk on, let me know - I’d be happy to hear any suggestions. Alternatively, if
-you’d like to submit and would like some help writing an abstract or want some
-feedback on a talk idea, please get in touch.
-
-_Note: I am not an organiser of DrupalCamp London, nor am I involved with the
-session selection process._
-
-Hopefully there will be no [#uksnow][3] this year!
-
-DrupalCamp London is the 1-3 March 2019. Early bird tickets are available until
-2 January 2019, and the call for sessions is open until 21 January.
-
-[0]: https://twitter.com/DrupalCampLDN/status/1064584179113971712
-[1]: https://drupalcamp.london
-[2]: https://drupalcamp.london/get-involved/submit-a-session
-[3]: /articles/tweets-drupalcamp-london
diff --git a/astro/src/content/blog/drupalcamp-london-testing-workshop.mdx b/astro/src/content/blog/drupalcamp-london-testing-workshop.mdx
deleted file mode 100644
index d43ea9ef..00000000
--- a/astro/src/content/blog/drupalcamp-london-testing-workshop.mdx
+++ /dev/null
@@ -1,29 +0,0 @@
----
-title: Testing Workshop at DrupalCamp London 2020
-excerpt: This year, I’m teaching a workshop at DrupalCamp London.
-tags:
- - drupal
- - drupalcamp
- - testing
-date: 2020-02-05
-lead_image:
- url: /images/blog/testing-workshop-drupalcamp-london/lead.jpg
----
-
-
-
-This year, I’m teaching a workshop at DrupalCamp London.
-
-The subject will be automated testing and test driven development in Drupal 8,
-and it will be on Friday 13th March 2020, between 1pm and 5pm.
-
-In the workshop, I’ll cover the methodology, approaches and terminology involved
-with automated testing, look at some examples and work through some exercises,
-and then take a test driven development approach to creating a new Drupal
-module.
-
-There are also other workshops on topics including Composer, Drupal Commerce,
-profiling, and chatbots.
-
-For more information and to register, go to the
-[DrupalCamp London website](https://opdavi.es/dclondon20 'Find out more and register on the DrupalCamp London website').
diff --git a/astro/src/content/blog/easier-git-repository-cloning-insteadof.md b/astro/src/content/blog/easier-git-repository-cloning-insteadof.md
deleted file mode 100644
index 8ffbb0ed..00000000
--- a/astro/src/content/blog/easier-git-repository-cloning-insteadof.md
+++ /dev/null
@@ -1,82 +0,0 @@
----
-title: Easier Git Repository Cloning with insteadOf
-date: 2019-03-07
-excerpt: How to simplify 'git clone' commands by using the insteadOf configuration option within your .gitconfig file.
-tags:
- - git
----
-
-When working on client or open source projects, I clone a lot of
-[Git](https://git-scm.com) repositories - either from GitHub, GitLab, Bitbucket
-or Drupal.org. The standard `git clone` commands though provided by these sites
-can be quite verbose with long repository URLs and use a mixture of different
-protocols, and I’d regularly need to go back to each website and look up the
-necessary command every time.
-
-For example, here is the command provided to clone Drupal’s
-[Override Node Options module](https://www.drupal.org/project/override_node_options):
-
-```
-git clone --branch 8.x-2.x https://git.drupal.org/project/override_node_options.git
-```
-
-We can though simplify the command to make it easier and quicker to type, using
-a Git configuration option called `insteadOf`.
-
-## What is insteadOf?
-
-From the
-[Git documentation](https://git-scm.com/docs/git-config#git-config-urlltbasegtinsteadOf):
-
-> **url.[base].insteadOf:**
->
-> Any URL that starts with this value will be rewritten to start, instead, with
-> [base]. In cases where some site serves a large number of repositories, and
-> serves them with multiple access methods, and some users need to use different
-> access methods, this feature allows people to specify any of the equivalent
-> URLs and have Git automatically rewrite the URL to the best alternative for
-> the particular user, even for a never-before-seen repository on the site. When
-> more than one insteadOf strings match a given URL, the longest match is used.
-
-Whilst examples are sparse,
-[it seems like](https://stackoverflow.com/questions/1722807/how-to-convert-git-urls-to-http-urls)
-insteadOf is used for resolving protocol issues with repository URLs. However,
-we can use it to simplify our clone commands, as mentioned above.
-
-## Example: cloning Drupal contrib projects
-
-When working on Drupal core, or on a module, theme or distribution, you need to
-have a cloned version of that repository to generate patch files from, and apply
-patches to.
-
-Again, here is the provided command to clone the Override Node Options module:
-
-```
-git clone --branch 8.x-2.x https://git.drupal.org/project/override_node_options.git
-```
-
-At the time of writing, the Git repository URL follow this same format -
-`https://git.drupal.org/project/{name}.git` (also the `.git` file extension is
-optional).
-
-To shorten and simplify this, I can add this snippet to my `~/.gitconfig` file:
-
-```
-[url "https://git.drupal.org/project/"]
- insteadOf = do:
- insteadOf = drupal:
-```
-
-With that added, I can now instead run `git clone drupal:{name}` or
-`git clone do:{name}` to clone the repository, specifying the project’s machine
-name.
-
-For example, to clone the Override Node Options module, I can now do this using
-just `git clone drupal:override_node_options`.
-
-This, I think, is definitely quicker and easier!
-
-## Resources
-
-You can view my entire `.gitconfig` file, as well as my other dotfiles, in
-[my dotfiles repository on GitHub](https://github.com/opdavies/dotfiles/blob/master/.gitconfig).
diff --git a/astro/src/content/blog/easier-sculpin-commands-composer-npm-scripts.md b/astro/src/content/blog/easier-sculpin-commands-composer-npm-scripts.md
deleted file mode 100644
index 9b844e7b..00000000
--- a/astro/src/content/blog/easier-sculpin-commands-composer-npm-scripts.md
+++ /dev/null
@@ -1,78 +0,0 @@
----
-title: Easier Sculpin Commands with Composer and NPM Scripts
-date: 2017-01-07
-excerpt: In this video, I show you how I've simplied my Sculpin and Gulp workflow using custom Composer and NPM scripts.
-tags:
- - composer
- - gulp
- - sculpin
----
-
-In this video, I show you how I've simplied my Sculpin and Gulp workflow using
-custom Composer and NPM scripts.
-
-My website includes several various command line tools - e.g. [Sculpin][4],
-[Gulp][5] and [Behat][6] - each needing different arguments and options,
-depending on the command being run. For example, for Sculpin, I normally include
-several additional options when viewing the site locally - the full command that
-I use is
-`./vendor/bin/sculpin generate --watch --server --clean --no-interaction`.
-Typing this repeatedly is time consuming and could be easily mis-typed,
-forgotten or confused with other commands.
-
-In this video, I show you how I've simplied my Sculpin and Gulp workflow using
-custom Composer and NPM scripts.
-
-
-
-
-
-## Scripts
-
-Here are the scripts that I’m using - they are slightly different from those in
-the video. I use the `--generate` and `--watch` options for Sculpin and the
-`gulp watch` command for NPM. I had to change these before the recording as I
-was using the [demo magic][0] script to run the commands, and existing from a
-watch session was also ending the script process.
-
-### composer.json
-
-```json
-"scripts": {
- "clean": "rm -rf output_*/",
- "dev": "sculpin generate --clean --no-interaction --server --watch",
- "production": "sculpin generate --clean --no-interaction --env='prod' --quiet"
-}
-```
-
-Run with `composer run `, e.g. `composer run dev`.
-
-### package.json
-
-```json
-"scripts": {
- "init": "yarn && bower install",
- "dev": "gulp watch",
- "production": "gulp --production"
-}
-```
-
-Run with `npm run `, e.g. `npm run production`.
-
-You can also take a look at the full [composer.json][1] and [package.json][2]
-files within my site repository on [GitHub][3].
-
-## Resources
-
-- [Composer scripts][7]
-- [oliverdavies.uk composer.json][1]
-- [oliverdavies.uk package.json][2]
-
-[0]: https://github.com/paxtonhare/demo-magic
-[1]: https://github.com/opdavies/oliverdavies.uk/blob/master/composer.json
-[2]: https://github.com/opdavies/oliverdavies.uk/blob/master/package.json
-[3]: https://github.com/opdavies/oliverdavies.uk
-[4]: https://sculpin.io
-[5]: http://gulpjs.com
-[6]: http://behat.org
-[7]: https://getcomposer.org/doc/04-schema.md#scripts
diff --git a/astro/src/content/blog/easily-embed-typekit-fonts-your-drupal-website.md b/astro/src/content/blog/easily-embed-typekit-fonts-your-drupal-website.md
deleted file mode 100644
index 4defa315..00000000
--- a/astro/src/content/blog/easily-embed-typekit-fonts-your-drupal-website.md
+++ /dev/null
@@ -1,32 +0,0 @@
----
-title: Easily Embed TypeKit Fonts into your Drupal Website
-date: 2011-02-14
-excerpt: How to use the @font-your-face module to embed TypeKit fonts into your Drupal website.
-tags:
- - drupal-6
- - drupal-planet
- - typekit
----
-
-To begin with, you will need to
-[register for a TypeKit account](https://typekit.com/plans) - there is a free
-version if you just want to try it out.
-
-Next, you'll need to create a kit that contains the fonts that you want to use
-on your website. I've used
-[FF Tisa Web Pro](http://typekit.com/fonts/ff-tisa-web-pro).
-
-Under 'Kit Settings', ensure that your website domain (e.g. mysite.com) is
-listed under 'Domains'.
-
-Download and install the
-[@font-your-face](http://drupal.org/project/fontyourface) module onto your
-Drupal site, and to go admin/settings/fontyourface to configure it. Enter
-[your TypeKit API key](https://typekit.com/account/tokens), and click 'Import
-Typekit' to import your kits and fonts.
-
-Go to admin/dist/themes/fontyourface, and click 'Browse fonts to enable'. Click
-on the name of the font that you want to enable, check 'Enabled', and click
-'Edit font' to save your changes.
-
-With the font enabled, you can now use it in your CSS.
diff --git a/astro/src/content/blog/entityform.md b/astro/src/content/blog/entityform.md
deleted file mode 100644
index e6029884..00000000
--- a/astro/src/content/blog/entityform.md
+++ /dev/null
@@ -1,62 +0,0 @@
----
-title: Programmatically Load an Entityform in Drupal 7
-date: 2015-12-22
-excerpt: How to programmatically load, render and embed an entityform in Drupal 7.
-tags:
- - drupal
- - drupal-7
- - drupal-planet
- - entityform
----
-
-I recently had my first experience using the
-[Entityform module](https://www.drupal.org/project/entityform) in a project. It
-was quite easy to configure with different form types, but then I needed to
-embed the form into an overlay. I was expecting to use the `drupal_get_form()`
-function and render it, but this didn’t work.
-
-Here are the steps that I took to be able to load, render and embed the form.
-
-## Loading the Form
-
-The first thing that I needed to do to render the form was to load an empty
-instance of the entityform using `entityform_empty_load()`. In this example,
-`newsletter` is the name of my form type.
-
-```php
-$form = entityform_empty_load('newsletter');
-```
-
-This returns an instance of a relevant `Entityform` object.
-
-## Rendering the Form
-
-The next step was to be able to render the form. I did this using the
-`entity_form_wrapper()` function.
-
-As this function is within the `entityform.admin.inc` file and not autoloaded by
-Drupal, I needed to include it using `module_load_include()` so that the
-function was available.
-
-```php
-module_load_include('inc', 'entityform', 'entityform.admin');
-
-$output = entityform_form_wrapper($form, 'submit', 'embedded'),
-```
-
-The first argument is the `Entityform` object that was created in the previous
-step (I’ve [submitted a patch](https://www.drupal.org/node/2639584) to type hint
-this within entityform so that it’s clearer what is expected), which is
-required.
-
-The other two arguments are optional. The second argument is the mode (`submit`
-is the default value), and the last is the form context. `page` is the default
-value, for use on the submit page, however I changed this to `embedded`.
-
-I could then pass this result into my theme function to render it successfully
-within the relevant template file.
-
-## Resources
-
-- [The entityform module](https://www.drupal.org/project/entityform)
-- [My issue and patch to add the type hint to the entityform_form_wrapper function](https://www.drupal.org/node/2639584)
diff --git a/astro/src/content/blog/experimenting-events-drupal-8.md b/astro/src/content/blog/experimenting-events-drupal-8.md
deleted file mode 100644
index 790c7614..00000000
--- a/astro/src/content/blog/experimenting-events-drupal-8.md
+++ /dev/null
@@ -1,81 +0,0 @@
----
-title: Experimenting with events in Drupal 8
-date: 2018-08-21
-excerpt: Trying a different way of structuring Drupal modules, using event subscribers and autowiring.
-tags:
- - drupal
- - drupal-8
- - drupal-planet
- - php
- - symfony
-promoted: true
----
-
-I’ve been experimenting with moving some code to Drupal 8, and I’m quite
-intrigued by a different way that I’ve tried to structure it - using event
-subscribers, building on some of the takeaways from Drupal Dev Days.
-
-Here is how this module is currently structured:
-
-{.border .p-1}
-
-Note that there is no `opdavies_blog.module` file, and rather than calling
-actions from within a hook like `opdavies_blog_entity_update()`, each action
-becomes it’s own event subscriber class.
-
-This means that there are no long `hook_entity_update` functions, and instead
-there are descriptive, readable event subscriber class names, simpler action
-code that is responsibile only for performing one task, and you’re able to
-inject and autowire dependencies into the event subscriber classes as services -
-making it easier and cleaner to use dependency injection, and simpler write
-tests to mock dependencies when needed.
-
-The additional events are provided by the
-[Hook Event Dispatcher module](https://www.drupal.org/project/hook_event_dispatcher).
-
-## Code
-
-`opdavies_blog.services.yml`:
-
-```yaml
-services:
- Drupal\opdavies_blog\EventSubscriber\PostToMedium:
- autowire: true
- tags:
- - { name: event_subscriber }
-
- Drupal\opdavies_blog\EventSubscriber\SendTweet:
- autowire: true
- tags:
- - { name: event_subscriber }
-```
-
-
-Adding `autowire: true` is not required for the event subscriber to work. I’m using it to automatically inject any dependencies into the class rather than specifying them separately as arguments.
-
-
-`src/EventSubscriber/SendTweet.php`:
-
-```php
-namespace Drupal\opdavies_blog\EventSubscriber;
-
-use Drupal\hook_event_dispatcher\Event\Entity\EntityUpdateEvent;
-use Drupal\hook_event_dispatcher\HookEventDispatcherInterface;
-use Symfony\Component\EventDispatcher\EventSubscriberInterface;
-
-class SendTweet implements EventSubscriberInterface {
-
- ...
-
- public static function getSubscribedEvents() {
- return [
- HookEventDispatcherInterface::ENTITY_UPDATE => 'sendTweet',
- ];
- }
-
- public function sendTweet(EntityUpdateEvent $event) {
- // Perform checks and send the tweet.
- }
-
-}
-```
diff --git a/astro/src/content/blog/feature-flags-sculpin.md b/astro/src/content/blog/feature-flags-sculpin.md
deleted file mode 100644
index 18469a91..00000000
--- a/astro/src/content/blog/feature-flags-sculpin.md
+++ /dev/null
@@ -1,107 +0,0 @@
----
-title: "Using Feature Flags with Sculpin"
-excerpt: |
- How I've started using feature flags within a client's Sculpin website.
-tags: [sculpin]
-date: 2022-01-09
----
-
-
-
-
-
-## Background
-
-I was asked last week to add a new feature, a Facebook pixel for measuring and
-building advertising campaigns, to a client's website which I built using the
-[Sculpin](https://sculpin.io) static site generator.
-
-The site uses settings within the `app/config/sculpin_site.yml` file for
-storing site IDs and usernames. For this, I would add something like:
-
-```yaml
-facebook:
- pixel:
- id: "abc123"
-```
-
-It can then be retrieved with `{{ site.facebook.pixel.id }}`.
-
-If I then needed to disable the pixel, then I'd typically remove the pixel
-ID:
-
-```yaml
-facebook:
- pixel:
- id: ~
-```
-
-## Introducing feature flags
-
-A technique that I like to use on other projects is using
-[feature flags](https://www.atlassian.com/continuous-delivery/principles/feature-flags)
-(aka feature toggles).
-
-Whilst, in this instance, a feature flag wouldn't separate deploying code from
-toggling a feature - a static site will need to be re-generated and deployed -
-I thought that there was value in being able to easily toggle a feature without
-changing its configuration or removing code within the site's templates.
-
-## Feature flags in Sculpin
-
-My Sculpin feature flag implementation was to add a `feature_flags` key within
-`sculpin_site.yml`, with each feature's name as the key and a boolean value to
-set whether it's enabled - similar to how the Drupal 7 version of the
-[Feature Toggle module](https://www.drupal.org/project/feature_toggle) works.
-
-This is how I added the Facebook pixel feature flag:
-
-```yaml
-feature_flags:
- add_facebook_pixel: true
-```
-
-## Using the Facebook pixel feature flag
-
-The Facebook pixel code is stored within it's own partial that I can include
-from my `source/_layouts/app.html.twig` layout, including the pixel ID and
-whether or not the feature flag is enabled.
-
-
-
-```twig
-{% include "facebook-pixel" with {
- is_enabled: site.feature_flags.add_facebook_pixel,
- pixel_id: site.facebook.pixel.id,
-} only %}
-```
-
-
-
-Within the partial, I can check that both the feature flag is enabled and that
-there is a Facebook pixel ID, and only add the pixel code if both conditions
-return a truthy value.
-
-
-
-```twig
-{% if is_enabled and pixel_id %}
-
-{% endif %}
-```
-
-
-
-Now the pixel can be removed just by setting `add_facebook_pixel: false` in
-`sculpin_site.yml`, and without changing any other configuration or templates.
diff --git a/astro/src/content/blog/finding-the-last-commit-that-a-patch-applies-to.md b/astro/src/content/blog/finding-the-last-commit-that-a-patch-applies-to.md
deleted file mode 100644
index bf9bbca7..00000000
--- a/astro/src/content/blog/finding-the-last-commit-that-a-patch-applies-to.md
+++ /dev/null
@@ -1,49 +0,0 @@
----
-title: Finding the last commit that a patch applies to
-excerpt: How to find the last commit in a Git repository that a patch applies to.
-date: 2020-03-26
-tags:
- - bash
- - git
-draft: true
----
-
-```bash
-#!/usr/bin/env bash
-
-# https://www.drupal.org/files/issues/2018-08-28/group-configurable-entities-as-group-content-2797793-58.patch
-
-patch_filename=group-configurable-entities-as-group-content-2797793-58.patch
-first_commit=6e8c22a
-last_commit=8.x-1.x
-
-find_commits_between() {
- first_commit=$1
- last_commit=$2
-
- git rev-list --reverse --ancestry-path $first_commit^...$last_commit
-}
-
-reset_repo() {
- git reset --hard $1 >& /dev/null
-}
-
-apply_patch() {
- git apply --check $patch_filename >& /dev/null
-}
-
-for sha1 in $(find_commits_between $first_commit $last_commit); do
- echo "Trying ${sha1}..."
-
- reset_repo $sha1
- apply_patch
-
- if [[ $? -eq 0 ]]; then
- echo "Patch applies"
- continue
- fi
-
- echo "Patch does not apply"
- exit 1
-done
-```
diff --git a/astro/src/content/blog/fixing-drupal-simpletest-issues-inside-docker-containers.md b/astro/src/content/blog/fixing-drupal-simpletest-issues-inside-docker-containers.md
deleted file mode 100644
index ad7e045b..00000000
--- a/astro/src/content/blog/fixing-drupal-simpletest-issues-inside-docker-containers.md
+++ /dev/null
@@ -1,130 +0,0 @@
----
-title: Fixing Drupal SimpleTest issues inside Docker Containers
-date: 2017-05-05
-excerpt: How I managed to get my Drupal SimpleTest tests to run and pass within Docker containers.
-tags:
- - docker
- - drupal
- - drupal-planet
- - simpletest
- - testing
----
-
-I’ve been a Drupal VM user for a long time, but lately I’ve been using a
-combination Drupal VM and Docker for my local development environment. There
-were a couple of issues preventing me from completely switching to Docker - one
-of which being that when I tried running of my Simpletest tests, a lot of them
-would fail where they would pass when run within Drupal VM.
-
-Here’s an excerpt from my `docker-compose.yml` file:
-
-**TL;DR** You need to include the name of your web server container as the
-`--url` option to `run-scripts.php`.
-
-I’ve been a [Drupal VM][1] user for a long time, but lately I’ve been using a
-combination Drupal VM and [Docker][0] for my local development environment.
-There were a couple of issues preventing me from completely switching to
-Docker - one of which being that when I tried running of my Simpletest tests, a
-lot of them would fail where they would pass when run within Drupal VM.
-
-Here’s an excerpt from my `docker-compose.yml` file:
-
-```yaml
-services:
- php:
- image: wodby/drupal-php:5.6
- volumes:
- - ./repo:/var/www/html
-
- nginx:
- image: wodby/drupal-nginx:7-1.10
- environment:
- NGINX_BACKEND_HOST: php
- NGINX_SERVER_ROOT: /var/www/html/web
- ports:
- - "80:80"
- volumes_from:
- - php
-...
-```
-
-Nginx and PHP-FPM are running in separate containers, the volumes are shared
-across both and the Nginx backend is set to use the `php` container.
-
-This is the command that I was using to run the tests:
-
-```bash
-$ docker-compose run --rm \
- -w /var/www/html/web \
- php \
- php scripts/run-tests.sh \
- --php /usr/local/bin/php \
- --class OverrideNodeOptionsTestCase
-```
-
-This creates a new instance of the `php` container, sets the working directory
-to my Drupal root and runs Drupal’s `run-tests.sh` script with some arguments.
-In this case, I'm running the `OverrideNodeOptionsTestCase` class for the
-override_node_options tests. Once complete, the container is deleted because of
-the `--rm` option.
-
-This resulted in 60 of the 112 tests failing, whereas they all passed when run
-within a Drupal VM instance.
-
-```
-Test summary
-------------
-
-Override node options 62 passes, 60 fails, 29 exceptions, and 17 debug messages
-
-Test run duration: 2 min 25 sec
-```
-
-Running the tests again with the`--verbose` option, I saw this message appear in
-the output below some of the failing tests:
-
-> simplexml_import_dom(): Invalid Nodetype to import
-
-\*\*Up After checking that I had all of the required PHP extensions installed, I
-ran `docker-compose exec php bash` to connect to the `php` container and ran
-`curl http://localhost` to check the output. Rather than seeing the HTML for the
-site, I got this error message:
-
-> curl: (7) Failed to connect to localhost port 80: Connection refused
-
-Whereas `curl http://nginx` returns the HTML for the page, so included it with
-the `--url` option to `run-tests.sh`, and this resulted in my tests all passing.
-
-```bash
-$ docker-compose run --rm \
- -w /var/www/html/web \
- php \
- php scripts/run-tests.sh \
- --php /usr/local/bin/php \
- --url http://nginx \
- --class OverrideNodeOptionsTestCase
-```
-
-```
-Test summary
-------------
-
-Override node options 121 passes, 0 fails, 0 exceptions, and 34 debug messages
-
-Test run duration: 2 min 31 sec
-```
-
-**Note:** In this example I have separate `nginx` and `php` containers, but I've
-tried and had the same issue when running Nginx and PHP-FPM in the same
-container - e.g. called `app` - and still needed to add `--url http://app` in
-order for the tests to run successfully.
-
-I don’t know if this issue is macOS specfic (I know that [Drupal CI][2] is based
-on Docker, and I don’t know if it’s an issue) but I’m going to test also on my
-Ubuntu Desktop environment and investigate further and also compare the test run
-times for Docker in macOS, Docker in Ubuntu and within Drupal VM. I’m also going
-to test this with PHPUnit tests with Drupal 8.
-
-[0]: https://www.docker.com
-[1]: https://www.drupalvm.com
-[2]: https://www.drupal.org/drupalorg/docs/drupal-ci
diff --git a/astro/src/content/blog/forward-one-domain-another-using-modrewrite-htaccess.md b/astro/src/content/blog/forward-one-domain-another-using-modrewrite-htaccess.md
deleted file mode 100644
index 54a9bf07..00000000
--- a/astro/src/content/blog/forward-one-domain-another-using-modrewrite-htaccess.md
+++ /dev/null
@@ -1,29 +0,0 @@
----
-title: Forward one domain to another using mod_rewrite and .htaccess
-date: 2012-05-23
-excerpt: How to use the .htaccess file to forward to a different domain.
-tags:
- - .htaccess
- - apache
- - code
- - drupal
- - mod_rewrite
----
-
-How to use the .htaccess file to forward to a different domain.
-
-Within the mod_rewrite section of your .htaccess file, add the following lines:
-
- RewriteCond %{HTTP_HOST} ^yoursite\.co\.uk$
- RewriteRule (.*) http://yoursite.com/$1 [R=301,L]
-
-This automatically forwards any users from http://yoursite.co.uk to
-http://yoursite.com. This can also be used to forward multiple domains:
-
- RewriteCond %{HTTP_HOST} ^yoursite\.co\.uk$ [OR]
- RewriteCond %{HTTP_HOST} ^yoursite\.info$ [OR]
- RewriteCond %{HTTP_HOST} ^yoursite\.biz$ [OR]
- RewriteCond %{HTTP_HOST} ^yoursite\.eu$
- RewriteRule (.*) http://yoursite.com/$1 [R=301,L]
-
-If any of the RewriteCond conditions apply, then the RewriteRule is executed.
diff --git a/astro/src/content/blog/git-format-patch-your-friend.md b/astro/src/content/blog/git-format-patch-your-friend.md
deleted file mode 100644
index 4f929dd3..00000000
--- a/astro/src/content/blog/git-format-patch-your-friend.md
+++ /dev/null
@@ -1,136 +0,0 @@
----
-title: git format-patch is your Friend
-date: 2014-05-21
-excerpt: An explanation of the "git format-patch" command, and how it could be used in Drupal's Git workflow.
-tags:
- - drupal
- - drupal-planet
- - git
- - patches
----
-
-An explanation of the "git format-patch" command, and how it could be used in
-Drupal's Git workflow.
-
-## The Problem
-
-As an active contributor to the [Drupal](http://drupal.org) project, I spend a
-lot of time working with other peoples’ modules and themes, and occassionally
-have to fix a bug or add some new functionality.
-
-In the Drupal community, we use a patch based workflow where any changes that I
-make get exported to a file detailing the differences. The patch file (\*.patch)
-is attached to an item in an issue queue on Drupal.org, applied by the
-maintainer to their local copy of the code and reviewed, and hopefully
-committed.
-
-There is an option that the maintainer can add to the end of their commit
-message.
-
-For example:
-
-```bash
---author="opdavies "
-```
-
-This differs slightly different for each Drupal user, and the code can be found
-on their Drupal.org profile page.
-
-If this is added to the end of the commit message, the resulting commit will
-show that it was committed by the maintainer but authored by a different user.
-This will then display on Drupal.org that you’ve made a commit to that project.
-
-
-
-The problem is that some project maintainers either don’t know about this option
-or occasionally forget to add it. [Dreditor](http://dreditor.org) can suggest a
-commit message and assign an author, but it is optional and, of course, not all
-maintainers use Dreditor (although they probably should).
-
-The `git format-patch` command seems to be the answer, and will be my preferred
-method for generating patch files in the future rather than `git diff`.
-
-## What does it do Differently?
-
-From the [manual page](http://git-scm.com/docs/git-format-patch):
-
-> Prepare each commit with its patch in one file per commit, formatted to
-> resemble UNIX mailbox format. The output of this command is convenient for
-> e-mail submission or for use with git am.
-
-Here is a section of a patch that I created for the
-[Metatag module](http://drupal.org/project/metatag) using `git format-patch`:
-
-```bash
-From 80c8fa14de7f4a83c2e70367aab0aedcadf4f3b0 Mon Sep 17 00:00:00 2001
-From: Oliver Davies <oliver@oliverdavies.co.uk>
-Subject: [PATCH] Exclude comment entities when checking if this is the page,
- otherwise comment_fragment.module will break metatag
----
-```
-
-As mentioned above, the patch is structured in an email format. The commit
-message is used as the subject line, and the date that the commit was made
-locally is used for the date. What we’re interested in is the “From” value. This
-contains your name and email address from your `~/.gitconfig` file and is used
-to author the patch automatically.
-
-Everything below this is the same as a standard patch file, the same as if was
-generated with `git diff`.
-
-The full patch file can be found at
-.
-
-## The Process
-
-How did I create this patch? Here are the steps that I took:
-
-1. Clone the source repository using
- `$ git clone --branch 7.x-1.x http://git.drupal.org/project/metatag.git` and
- move into that directory.
-2. Create a branch for this patch using
- `$ git checkout -b 2265447-comment-fragment-conflict`.
-3. Add and commit any changes as normal.
-4. Generate the patch file using
- `$ git format-patch 7.x-1.x --stdout > metatag-comment-fragment-conflict-2265447-4.patch`.
-
-_Note:_ I am defining 7.x-1.x in the last step as the original branch to compare
-(i.e. the original branch that we forked to make our issue branch). This will
-change depending on the project that you are patching, and it’s version number.
-Also, commits should always be made against the development branch and not the
-stable release.
-
-By default, a separate patch file will be created for each commit that we’ve
-made. This is overridden by the `--stdout` option which combines all of the
-patches into a single file. This is the recommended approach when uploading to
-Drupal.org.
-
-The resulting patch file can be uploaded onto a Drupal.org issue queue, reviewed
-by the Testbot and applied by a module maintainer, and you automatically get the
-commit attributed. Problem solved.
-
-## Committing the Patch
-
-If you need to commit a patch that was created using `git format-patch`, the
-best command to do this with is the `git am` command.
-
-For example, within your repository, run:
-
-```bash
-$ git am /path/to/file
-$ git am ~/Code/metatag-comment-fragment-conflict-2265447-4.patch
-```
-
-You should end up with some output similar to the following:
-
-```bash
-Applying: #2272799 Added supporters section
-Applying: #2272799 Added navigation tabs
-Applying: #2272799 Fixed indentation
-Applying: #2272799 Replaced URL
-```
-
-Each line is the commit message associated with that patch.
-
-Assuming that there are no errors, you can go ahead and push your updated code
-into your remote repository.
diff --git a/astro/src/content/blog/github-actions-phpunit-colours.md b/astro/src/content/blog/github-actions-phpunit-colours.md
deleted file mode 100644
index 5fad2fee..00000000
--- a/astro/src/content/blog/github-actions-phpunit-colours.md
+++ /dev/null
@@ -1,11 +0,0 @@
----
-title: Coloured output with PHPUnit and GitHub Actions
-excerpt: How to have colours in your PHPUnit output when running with GitHub Actions.
-date: 2020-08-12
-tags:
- - github-actions
- - phpunit
- - testing
----
-
-
If you're using GitHub Actions to run tests for your PHP projects and want colours in the output, append `--colors=always` to your phpunit command. pic.twitter.com/0AVwxCP4Bv
diff --git a/astro/src/content/blog/going-drupalcon.md b/astro/src/content/blog/going-drupalcon.md
deleted file mode 100644
index 18ce7b23..00000000
--- a/astro/src/content/blog/going-drupalcon.md
+++ /dev/null
@@ -1,16 +0,0 @@
----
-title: Going to DrupalCon
-date: 2013-07-26
-excerpt: Precedent are sending myself and two of our other Drupal Developers to Drupalcon Prague.
-tags:
- - drupalcon
- - precedent
----
-
-[Precedent](http://www.precedent.co.uk) are sending myself and two of our other
-Drupal Developers to [Drupalcon Prague](http://prague2013.drupal.org).
-
-Having wanted to attend the last few Drupalcons (London, especially) but not
-being able to, I'm definitely looking forward to this one.
-
-See you there!
diff --git a/astro/src/content/blog/going-full-vim.md b/astro/src/content/blog/going-full-vim.md
deleted file mode 100644
index 453e7051..00000000
--- a/astro/src/content/blog/going-full-vim.md
+++ /dev/null
@@ -1,50 +0,0 @@
----
-title: Going "Full Vim" for my development work
-excerpt: I've recently been using Neovim for all of my coding, as well as for my blog posts and slide decks.
-tags:
- - vim
-date: 2021-07-08
----
-
-For the past few months, I've gone "full Vim" ([Neovim][], to be exact) when writing any code - including anything for work or freelance projects, this blog post, and any presentation slide decks.
-
-I've been a long-time casual Vim user, enabling Vi or Vim mode within other editors, including Sublime Text, PhpStorm, and VS Code, and using Vim to write Git commit messages or to edit single files before closing it again. I remember searching how to add Vim features like relative line numbers in other editors, and trying things that would work within Vim but not when using in a plugin or extension.
-
-I've seen people and companies like [Lorna Jane Mitchell][], Suz Hinton ([noopkat][]), and [Thoughtbot][] using Vim in their presentations and videos for a long time but I haven't tried to switch before myself.
-
-Inspired by them and others including [Robin Malfait][], [TheAltF4Stream][], [Codico][], [Michael Dyrynda][], [ThePrimeagen][] with their recent live streams, videos, podcasts, and courses, I decided to give it a try.
-
-## Plugins
-
-You can see the [full list of plugins on GitHub](https://github.com/opdavies/dotfiles/blob/main/.config/nvim/plugins.vim), but here are some of the main ones that I've been using so far:
-
-- [fzf](https://github.com/junegunn/fzf.vim) - a fuzzy-finder to easily locate and open files.
-- [CoC](https://github.com/neoclide/coc.nvim) and [Intelephense](https://intelephense.com) - adds auto-completion and code snippet support, including refactorings such as renaming symbols.
-- [NERDTree](https://github.com/preservim/nerdtree) - a tree explorer, though I usually use the fuzzy finder so this isn't used that often.
-- [Git gutter](https://github.com/airblade/vim-gitgutter) - displays Git diff information in the gutter of the current file.
-- [Blamer](https://github.com/APZelos/blamer.nvim) - inspired by the GitLens plugin for VS Code, displays `git blame` information for the current line.
-- [Nord](https://github.com/arcticicestudio/nord-vim), [jellybeans](https://github.com/nanotech/jellybeans.vim), and [ayu](https://github.com/ayu-theme/ayu-vim) - different themes that I'm trying and switching between.
-
-## Configuration
-
-If you'd like to see my full Neovim configuration, see the `.config/nvim` directory and the `init.vim` file in my [Dotfiles repository on GitHub](https://github.com/opdavies/dotfiles/tree/main/.config/nvim).
-
-## Conclusion
-
-I'm enjoying my first few months of using Vim full-time, and so far, I haven't looked back. I''ve had no issues using it in a Windows/WSL 2 environment either, which was great.
-
-I have a [cheat sheet on GitHub Gists](https://gist.github.com/opdavies/f944261b54f70b43f2297cab6779cf59) where I note the current things that I'm trying to learn and commit to memory.
-
-As I use it and learn more, I'm sure that I'll be posting more Vim-related content here too.
-
-Have any Vim/Neovim suggestions, tips, or tricks? Let me know on Twitter.
-
-[codico]: https://www.twitch.tv/codico
-[lorna jane mitchell]: https://lornajane.net
-[michael dyrynda]: https://dyrynda.com.au
-[neovim]: https://neovim.io
-[noopkat]: https://www.twitch.tv/noopkat
-[robin malfait]: https://twitter.com/malfaitrobin
-[thealtf4stream]: https://www.twitch.tv/thealtf4stream
-[theprimeagen]: https://twitter.com/theprimeagen
-[thoughtbot]: https://thoughtbot.com
diff --git a/astro/src/content/blog/how-add-date-popup-calendar-custom-form.md b/astro/src/content/blog/how-add-date-popup-calendar-custom-form.md
deleted file mode 100644
index 807b6b54..00000000
--- a/astro/src/content/blog/how-add-date-popup-calendar-custom-form.md
+++ /dev/null
@@ -1,44 +0,0 @@
----
-title: How to add a date popup calendar onto a custom form
-date: 2012-05-23
-excerpt: How to use a date popup calendar within your custom module.
-tags:
- - calendar
- - date
- - drupal
- - drupal-7
- - drupal-planet
- - form-api
- - forms
----
-
-How to use a date popup calendar within your custom module.
-
-First, I need to download the
-[Date](http://drupal.org/project/date 'Date module on Drupal.org') module, and
-make my module dependent on date_popup by adding the following line into my
-module's .info file.
-
-```ini
-dependencies[] = date_popup
-```
-
-Within my form builder function:
-
-```php
-$form['date'] = array(
- '#title' => t('Arrival date'),
-
- // Provided by the date_popup module
- '#type' => 'date_popup',
-
- // Uses the PHP date() format - http://php.net/manual/en/function.date.php
- '#date_format' => 'j F Y',
-
- // Limits the year range to the next two upcoming years
- '#date_year_range' => '0:+2',
-
- // Default value must be in 'Y-m-d' format.
- '#default_value' => date('Y-m-d', time()),
-);
-```
diff --git a/astro/src/content/blog/how-create-apply-patches.md b/astro/src/content/blog/how-create-apply-patches.md
deleted file mode 100644
index ab1e67a8..00000000
--- a/astro/src/content/blog/how-create-apply-patches.md
+++ /dev/null
@@ -1,50 +0,0 @@
----
-title: How to Create and Apply Patches
-date: 2010-10-10
-excerpt: How to create and apply patches, ready for the Drupal.org issue queues.
-tags:
- - drupal-6
- - drupal-planet
- - modules
- - patches
----
-
-Earlier this year, I posted a solution to
-[an issue](http://drupal.org/node/753898) on the Drupal.org issue queue.
-Originally, I just posted the code back onto the issue, but have now created a
-patch that can easily be applied to any Drupal 6 installation. Here is a
-run-through of the process of creating and applying a patch. In this case, I
-made changes to the `user_pass_validate()` function that's found within
-`modules/user/user.pages.inc`.
-
-To begin with, a download a fresh copy of Drupal 6.19 and created a copy of the
-original user.pages.inc file. Within the duplicate file, I made the same changes
-to the function that I did in earlier code, and saved the changes. Now, within
-my Terminal, I can navigate to Drupal's root directory and create the patch.
-
-```bash
-diff -rup modules/user/user.pages.inc modules/user/user.pages2.inc > /Users/oliver/Desktop/different_messages_for_blocked_users.patch
-```
-
-This command compares the differences between the two files, and creates the
-specified patch file.
-
-To apply the patch to my Drupal installation, I go back to Terminal and run the
-following code:
-
-```bash
-patch -p0 < /Users/oliver/Desktop/different_messages_for_blocked_users.patch
-```
-
-If, for some reason, I need to reverse the patch, I can run this code:
-
-```bash
-patch -p0 -R < /Users/oliver/Desktop/different_messages_for_blocked_users.patch
-```
-
-And that's it!
-
-There is also a Git patch creation workflow, which is described at
-. Thanks to
-[Randy Fay](http://randyfay.com) for making me aware of this, and suggesting a
-slight change to my original patch creation command.
diff --git a/astro/src/content/blog/how-fix-vagrant-loading-wrong-virtual-machine.md b/astro/src/content/blog/how-fix-vagrant-loading-wrong-virtual-machine.md
deleted file mode 100644
index 38a324dc..00000000
--- a/astro/src/content/blog/how-fix-vagrant-loading-wrong-virtual-machine.md
+++ /dev/null
@@ -1,26 +0,0 @@
----
-title: How to fix Vagrant Loading the Wrong Virtual Machine
-date: 2014-10-06
-excerpt: Here are the steps that I took to fix Vagrant and point it back at the correct VM.
-tags:
- - vagrant
- - virtualbox
----
-
-A few times recently, I've had instances where
-[Vagrant](https://www.vagrantup.com) seems to have forgotten which virtual
-machine it's supposed to load, probably due to renaming a project directory or
-the .vagrant directory being moved accidentally.
-
-Here are the steps that I took to fix this and point Vagrant back at the correct
-VM.
-
-1. Stop the machine from running using the `$ vagrant halt` command.
-1. Use the `$ VBoxManage list vms` command to view a list of the virtual
- machines on your system. Note the ID of the correct VM that should be
- loading. For example,
- `"foo_default_1405481857614_74478" {e492bfc3-cac2-4cde-a396-e81e37e421e2}`.
- The number within the curly brackets is the ID of the virtual machine.
-1. Within the .vagrant directory in your project (it is hidden by default),
- update the ID within the machines/default/virtualbox/id file.
-1. Start the new VM with `$ vagrant up`.
diff --git a/astro/src/content/blog/how-install-configure-subversion-svn-server-ubuntu.md b/astro/src/content/blog/how-install-configure-subversion-svn-server-ubuntu.md
deleted file mode 100644
index 4cfac16e..00000000
--- a/astro/src/content/blog/how-install-configure-subversion-svn-server-ubuntu.md
+++ /dev/null
@@ -1,178 +0,0 @@
----
-title: How to Install and Configure Subversion (SVN) Server on Ubuntu
-date: 2011-10-19
-excerpt: How to install and configure your own SVN server.
-tags:
- - svn
- - ubuntu
- - version-control
----
-
-Recently, I needed to set up a Subversion (SVN) server on a Ubuntu Linux server.
-This post is going to outline the steps taken, and the commands used, to install
-and configure the service.
-
-Note: As I was using Ubuntu, I was using the 'apt-get' command to download and
-install the software packages. If you're using a different distribution of
-Linux, then this command may be different. I'm also assuming that Apache is
-already installed.
-
-Firstly, I'm going to ensure that all of my installed packages are up to date,
-and install any available updates.
-
-```bash
-$ sudo apt-get update
-```
-
-Now, I need to download the subversion, subversion-tools and libapache2
-packages.
-
-```bash
-$ sudo apt-get install subversion subversion-tools libapache2-svn
-```
-
-These are all of the packages that are needed to run a Subversion server.
-
-## Create subversion directory
-
-Now, I need to create the directory where my repositories are going to sit. I've
-chosen this directory as I know that it's one that is accessible to my managed
-backup service.
-
-```bash
-$ sudo mkdir /home/svn
-```
-
-## Create a test repository
-
-First, I'll create a new folder in which I'll create my test project, and then
-I'll create a repository for it.
-
-```bash
-$ sudo mkdir ~/test
-$ sudo svnadmin create /home/svn/test -m 'initial project structure'
-```
-
-This will create a new repository containing the base file structure.
-
-## Adding files into the test project
-
-```bash
-$ cd ~/test
-$ mkdir trunk tags branches
-```
-
-I can now import these new directories into the test repository.
-
-```bash
-$ sudo svn import ~/test file:///home/svn/test -m 'Initial project directories'
-```
-
-This both adds and commits these new directories into the repository.
-
-In order for Apache to access the SVN repositories, the `/home/svn` directory
-needs to be owned by the same user and group that Apache runs as. In Ubuntu,
-this is usually www-data. To change the owner of a directory, use the chown
-command.
-
-```bash
-$ sudo chown -R www-data:www-data /home/svn
-```
-
-## Configuring Apache
-
-The first thing that I need to do is enable the dav_svn Apache module, using the
-a2enmod command.
-
-```bash
-$ sudo a2enmod dav_svn
-```
-
-With this enabled, now I need to modify the Apache configuration file.
-
-```bash
-$ cd /etc/apache2
-$ sudo nano apache2.conf
-```
-
-At the bottom of the file, add the following lines, and then save the file by
-pressing Ctrl+X.
-
-```
-
- DAV svn
- SVNParentPath /home/svn
-
-```
-
-With this saved, restart the Apache service for the changes to be applied.
-
-```bash
-sudo service apache2 restart
-```
-
-I can now browse through my test repository by opening Firefox, and navigating
-to `http://127.0.0.1/svn/test`. Here, I can now see my three directories,
-although they are currently all empty.
-
-## Securing my SVN repositories
-
-Before I start committing any files to the test repository, I want to ensure
-that only authorised users can view it - currently anyone can view the
-repository and it's contents, as well as being able to checkout and commit
-files. To do this, I'm going to require the user to enter a username and a
-password before viewing or performing any actions with the repository.
-
-Re-open apache2.conf, and replace the SVN Location information with this:
-
-```
-
- DAV svn
- SVNParentPath /home/svn
- AuthType Basic
- AuthName "My SVN Repositories"
- AuthUserFile /etc/svn-auth
- Require valid-user
-
-```
-
-Now I need to create the password file.
-
-```bash
-$ htpasswd -cm /etc/svn-auth oliver
-```
-
-I'm prompted to enter and confirm my password, and then my details are saved.
-The Apache service will need to be restarted again, and then the user will need
-to authenticate themselves before viewing the repositories.
-
-## Checking out the repository and commiting files
-
-For example, now want to checkout the files within my repository into a new
-directory called 'test2' within my home directory. Firstly, I need to create the
-new directory, and then I can issue the checkout command.
-
-```bash
-$ cd ~
-$ mkdir test2
-$ svn checkout http://127.0.0.1/svn/test/trunk test2
-```
-
-I'm passing the command two arguments - the first is the URL of the repository's
-trunk directory, and the second is the directory where the files are to be
-placed. As no files have been commited yet into the trunk, it appears to be
-empty - but if you perform an ls -la command, you'll see that there is a hidden
-.svn directory.
-
-Now you can start adding files into the directory. Once you've created your
-files, perform a svn add command, passing in individual filenames as further
-arguments.
-
-```bash
-$ svn add index.php
-$ svn add *
-```
-
-With all the required files added, they can be committed using
-`svn commit -m 'commit message'` command, and the server can be updated using
-the svn up command.
diff --git a/astro/src/content/blog/how-put-your-php-application-subdirectory-another-site-nginx.md b/astro/src/content/blog/how-put-your-php-application-subdirectory-another-site-nginx.md
deleted file mode 100644
index 53bdf7f4..00000000
--- a/astro/src/content/blog/how-put-your-php-application-subdirectory-another-site-nginx.md
+++ /dev/null
@@ -1,29 +0,0 @@
----
-title: How to put your PHP application in a subdirectory of another site with Nginx
-date: 2018-03-12
-excerpt: How to configure Nginx to serve a PHP application from within a subdirectory of another.
-tags:
- - nginx
- - php
----
-
-In January, [Chris Fidao][0] posted a video to [Servers for Hackers][1] showing
-how to put different PHP applications in different subdirectories and have them
-serving on different paths with Nginx. I’ve had to do this a few times
-previously, and it’s great to have this video as a reference.
-
-> In this video, we work through how to put your PHP application in a
-> subdirectory of another site.
->
-> For example, we may have an application running at example.org but need a
-> second application running at example.org/blog.
->
-> This feels like it should be simple, but it turns out to be more complex and
-> fraught with confusing Nginx configurations! To make matter worse (or,
-> perhaps, to illustrate this point), a quick Google search reveals a TON of
-> confusing, non-working examples.
-
-
-
-[0]: https://twitter.com/fideloper
-[1]: https://serversforhackers.com
diff --git a/astro/src/content/blog/how-run-drupal-8-phpunit-tests-within-docksal-phpstorm.md b/astro/src/content/blog/how-run-drupal-8-phpunit-tests-within-docksal-phpstorm.md
deleted file mode 100644
index f9a1af14..00000000
--- a/astro/src/content/blog/how-run-drupal-8-phpunit-tests-within-docksal-phpstorm.md
+++ /dev/null
@@ -1,217 +0,0 @@
----
-title: How to run Drupal 8 PHPUnit Tests within Docksal from PhpStorm
-date: 2018-07-19
-excerpt: How to configure PhpStorm to run automated tests within Docksal.
-tags:
- - docksal
- - drupal
- - drupal-8
- - phpstorm
- - phpunit
- - testing
-promoted: true
----
-
-I’ve recently re-watched [A Clean PHPUnit Workflow in PHPStorm][0] on
-[Laracasts][1], where Jeffrey configures PhpStorm to run tests from within the
-IDE. With Drupal 8 using PHPUnit too, I decided to try and do the same with a
-local D8 site.
-
-Though because I’m using [Docksal][4] for my local development environment
-which, at least on a Mac, runs Docker containers within a virtual machine, there
-were some additional steps needed to achieve this and to have the tests run
-within the Docksal virtual machine and using the correct containers.
-
-In this post, I’ll be using my [Drupal Testing Workshop codebase][2] as an
-example, which is based on the [Drupal Composer project][3] with some
-pre-configured Docksal configuration.
-
-This post is separated into a few different sections:
-
-- [Allow PhpStorm to connect to the CLI container](#allow-phpstorm-to-connect-to-the-cli-container)
-- [Add a new deployment server](#add-a-new-deployment-server)
-- [Configure PHP interpreter](#configuring-the-php-interpreter)
-- [Set up PHPUnit in PhpStorm](#set-up-phpunit-in-phpstorm)
-- [Running tests](#running-tests)
-
-## Allow PhpStorm to connect to the CLI container
-
-The first thing to do is to allow PhpStorm to connect to Docksal’s CLI container
-to allow it to run the tests. We can do this by exposing the container’s SSH
-port so that it’s available to the host machine and PhpStorm.
-
-As this is going to be unique to my environment, I’m going to add this to
-`.docksal/docksal-local.yml` which I have in `.gitignore`, rather than
-committing it into the repository and enforcing the same port number for
-everyone else and potentially causing conflicts.
-
-In this case I’ll expose port 22 in the container to port 2225 locally.
-
-```
-version: '2.1'
-
-services:
- cli:
- ports:
- - '2225:22'
-```
-
-Once added, run `fin start` to rebuild the project’s containers.
-
-You can verify the change by running `fin ps` and you should see something like
-`0.0.0.0:2225->22/tcp` under Ports for the CLI container.
-
-## Add a new Deployment server
-
-Now PhpStorm can connect to Docksal, I can configure it to do so by adding a new
-deployment server.
-
-- Open PhpStorm’s preferences, and go to 'Build, Execution, Deployment' and
- 'Deployment'.
-- Click 'Add' to configure a new deployment server.
-- Enter a name like 'Docksal', and select SFTP as the server type.
-
-{.with-border
-.sm:max-w-sm}
-
-### Connection settings
-
-On the Connection tab:
-
-- Enter your domain name - e.g. `drupaltest.docksal` as the SFTP host. This will
- resolve to the correct local IP address.
-- Enter the exposed port for the CLI container that was entered in the previous
- step.
-- Enter "docker" as both the username and password.
-
-You should now be able to click "Test SFTP connection" and get a successfully
-connected confirmation message.
-
-
-
-### Mapping settings
-
-On the Mappings tab, add `/var/www` as the deployment path so that PhpStorm is
-looking in the correct place for the project code.
-
-{.with-border}
-
-## Configuring the PHP Interpreter
-
-In Preferences, search for 'PHP' within 'Languages & Frameworks', and add a new
-CLI interpreter.
-
-{.with-border}
-
-In this case I’ve called it 'Docksal PHP 7.1', used the Docksal deployment
-configuration, and set the path to the PHP executable to `/usr/local/bin/php`
-(the same path that we would get if we ran `fin run which php`). You should see
-both the deployment host URL displayed as well as the remote PHP version and
-configuration filenames.
-
-{.with-border}
-
-This can now be selected as the CLI interpreter for this project.
-
-{.with-border}
-
-## Set up PHPUnit in PhpStorm
-
-In Preferences, search for 'Test Frameworks' and add a new framework.
-
-{.with-border}
-
-Select 'PHPUnit by Remote Interpreter' and then the 'Docksal PHP 7.1' that we
-created in the last step.
-
-Select 'Use Composer autoloader' for the PHPUnit library setting so that
-PhpStorm uses the version required by Drupal core, and set the path to
-`/var/www/vendor/autoload.php`.
-
-Also specify the path to the default (phpunit.xml) configuration file. This will
-depend on how your project is structured, in this case it’s at
-`/var/www/web/core/phpunit.xml`.
-
-{.with-border}
-
-## Running tests
-
-With PHPUnit configured, next to each test class and method, you can see a green
-circle (or a red one if the test failed the last run). You can click the circle
-and select to run that test class or method. You can also right-click
-directories in the project sidebar to run all of the tests within that
-directory.
-
-{.with-border}
-
-When the tests start running, a new tool window will open that shows you all of
-the selected tests, how long each test took to run and whether it passed or
-failed. You can also see the CLI output from PHPUnit itself next to it.
-
-{.with-border}
-
-From here, you also have the ability to re-run all of the tests, as well as a
-single test method or a specific test class.
-
-Any test failures are shown here too, and for some failures like differences
-between two arrays you can use PhpStorm’s internal comparison tools to view the
-difference rather than needing to do so on the command line.
-
-{.with-border}
-
-{.with-border
-.sm:max-w-md}
-
-### Keyboard shortcuts
-
-As per the video, I’ve also added some keyboard shortcuts to my keymap, so I can
-press ⌘T to run the current test method or class that I’m in, and ⇧⌘T to re-run
-the last test.
-
-{.with-border}
-
-{.with-border}
-
-### Database issues
-
-When running functional tests that require a database, I was getting a database
-error like the one below:
-
-> Drupal\Core\Installer\Exception\InstallerException : Resolve all issues below
-> to continue the installation. For help configuring your database server, see
-> the installation
-> handbook, or contact your hosting provider.
-
-In `settings.php`, I check for the presence of `/.dockerenv` to ensure that
-we’re inside a Docker container, as well as the presence of a
-`docksal.settings.yml` file. The latter contains the database credentials for
-Drupal to connect to the MySQL database.
-
-```php
-if (file_exists('/.dockerenv') && file_exists(__DIR__ . '/docksal.settings.php')) {
- include __DIR__ . '/docksal.settings.php';
-}
-```
-
-In order to get the tests to run, I had to prevent this file from being loaded
-during the tests. I can do this by checking that `SIMPLETEST_DB`, an environment
-variable set in phpunit.xml is not present.
-
-```php
-// settings.php
-
-if (file_exists('/.dockerenv') && file_exists(__DIR__ . '/docksal.settings.php') && !getenv('SIMPLETEST_DB')) {
- include __DIR__ . '/docksal.settings.php';
-}
-```
-
-With this extra condition, the database credentials are loaded correctly and the
-functional tests run properly.
-
-Happy testing!
-
-[0]: https://laracasts.com/series/php-bits/episodes/2
-[1]: https://laracasts.com
-[2]: https://github.com/opdavies/drupal-testing-workshop
-[3]: https://github.com/drupal-composer/drupal-project
-[4]: https://docksal.io
diff --git a/astro/src/content/blog/how-use-environment-variables-your-drupal-settings-docksal.md b/astro/src/content/blog/how-use-environment-variables-your-drupal-settings-docksal.md
deleted file mode 100644
index 54b4431c..00000000
--- a/astro/src/content/blog/how-use-environment-variables-your-drupal-settings-docksal.md
+++ /dev/null
@@ -1,92 +0,0 @@
----
-title: How to Use Environment Variables for your Drupal Settings with Docksal
-date: 2018-06-04
-excerpt: How to leverage environment variables with Drupal and Docksal.
-tags:
- - docksal
- - drupal
- - drupal-planet
----
-
-Within the [Docksal documentation for Drupal settings][0], the example database
-settings include hard-coded credentials to connect to the Drupal database. For
-example, within a `settings.php` file, you could add this:
-
-```php
-$databases['default']['default'] = [
- 'driver' => 'mysql',
- 'host' => 'db',
- 'database' => 'myproject_db',
- 'username' => 'myproject_user',
- 'password' => 'myproject_pass',
-];
-```
-
-Whilst this is fine, it does mean that there is duplication in the codebase as
-the database credentials can also be added as environment variations within
-`.docksal/docksal.env` - this is definitely the case if you want to use a custom
-database name, for example.
-
-Also if one of these values were to change, then Drupal wouldn't be aware of
-that and would no longer be able to connect to the database.
-
-It also means that the file can’t simply be re-used on another project as it
-contains project-specific credentials.
-
-We can improve this by using the environment variables within the settings file.
-
-The relevant environment variables are `MYSQL_DATABASE` for the database name,
-and `MYSQL_USER` and `MYSQL_PASSWORD` for the MySQL username and password. These
-can be set in `.docksal/docksal.env`, and will need to be present for this to
-work.
-
-For example:
-
-```
-DOCKSAL_STACK=default
-MYSQL_DATABASE=myproject_db
-MYSQL_USER=myproject_user
-MYSQL_PASSWORD=myproject_pass
-```
-
-With these in place, they can be referenced within the settings file using the
-`getenv()` function.
-
-```
-$databases['default']['default'] = [
- 'driver' => 'mysql',
- 'host' => 'db',
- 'database' => getenv('MYSQL_DATABASE'),
- 'username' => getenv('MYSQL_USER'),
- 'password' => getenv('MYSQL_PASSWORD'),
-];
-```
-
-Now the credentials are no longer duplicated, and the latest values from the
-environment variables will always be used.
-
-However, you may see a message like this when you try and load the site:
-
-> Drupal\Core\Database\DatabaseAccessDeniedException: SQLSTATE[HY000][1045]
-> Access denied for user ''@'172.19.0.4' (using password: NO) in
-> /var/www/core/lib/Drupal/Core/Database/Driver/mysql/Connection.php on line 156
-
-If you see this, the environment variables aren’t being passed into Docksal’s
-`cli` container, so the values are not being populated. To enable them, edit
-`.docksal/docksal.yml` and add `MYSQL_DATABASE`, `MYSQL_PASSWORD` and
-`MYSQL_USER` to the `environment` section of the `cli` service.
-
-```yaml
-version: '2.1'
-services:
- cli:
- environment:
- - MYSQL_DATABASE
- - MYSQL_PASSWORD
- - MYSQL_USER
-```
-
-After changing this file, run `fin start` to rebuild the project containers and
-try to load the site again.
-
-[0]: https://docksal.readthedocs.io/en/master/advanced/drupal-settings
diff --git a/astro/src/content/blog/ignoring-phpcs-sniffs-phpunit-tests.md b/astro/src/content/blog/ignoring-phpcs-sniffs-phpunit-tests.md
deleted file mode 100644
index d5ec3334..00000000
--- a/astro/src/content/blog/ignoring-phpcs-sniffs-phpunit-tests.md
+++ /dev/null
@@ -1,77 +0,0 @@
----
-title: Ignoring PHPCS sniffs for PHPUnit tests
-excerpt: How to exclude certain PHPCS sniffs within your PHPUnit tests, so that you can write your tests methods how you'd like without getting coding standards errors.
-tags:
- - drupal
- - drupal-planet
- - php
- - phpunit
-date: 2021-01-04
----
-
-**Note:** This post is written with a Drupal context, but applies to any PHP project.
-
-This is a test that I wrote recently, which uses the camel case method name that is recommended by the Drupal and PSR-2 coding standards:
-
-```php
-public function testThatPathAliasesAreNotTransferredToTheNewLanguageWhenOneIsAdded(): void {
- // ...
-}
-```
-It has a long method name that describes the test that is being run. However, it's quite hard to read. Generally, I prefer to write tests like this, using the `@test` annotation (so that I can remove the `test` prefix) and snake case method names:
-
-```php
-/** @test */
-public function path_aliases_are_not_transferred_to_the_new_language_when_one_is_added(): void {
- // ...
-}
-```
-
-This to me is a lot easier to read, particularly for long and descriptive test method names, and is commonly used within parts of the PHP community.
-
-This approach, however, can result in some errors from PHPCS:
-
-- The open comment tag must be the only content on the line
-- Public method name "DefinedLanguageNodeTest::path_aliases_are_not_transferred_to_the_new_language_when_one_is_added" is not in lowerCamel format
-
-We can avoid the errors by excluding the files when running PHPCS, or modifying rules within phpcs.xml (or phpcs.xml.dist) file to change the severity value for the rules. These approaches would mean either ignoring all PHPCS sniffs within the test files or ignoring some checks within all files, neither of which is an ideal approach.
-
-## Ignoring whole or partial files
-
-We can tell PHPCS to ignore whole or partial files by adding comments - there's [an example of this](https://git.drupalcode.org/project/drupal/-/blob/ad34608ab0bb115c53f4aaa0573c30dd8dc5b23a/sites/default/default.settings.php#L3 "Drupal's default.settings.php file with a 'coding standards ignore' comment") at the top of `default.settings.php` file:
-
-```php
-// @codingStandardsIgnoreFile
-```
-
-The `@codingStandards` syntax, however, is deprecated and will be removed in PHP_CodeSniffer version 4.0. The new syntax to do this is:
-
-```php
-// phpcs:ignoreFile
-```
-
-As well as `phpcs:ignoreFile` which ignores all of the sniffs in an entire file, there are also commands to disable and re-enable PHPCS at different points within the same file:
-
-```php
-// Stop PHPCS checking.
-// phpcs:disable
-
-// Start PHPCS checking.
-// phpcs:enable
-```
-
-## Disabling specific rules in a file
-
-As well as excluding a section of code from checks, with `phpcs:ignore` you can also specify a list of sniffs to ignore. For example:
-
-```php
-// phpcs:disable Drupal.Commenting.DocComment, Drupal.NamingConventions.ValidFunctionName
-```
-
-By adding this to the top of the test class, these specific sniffs will be ignored so no errors will be reported, and any other sniffs will continue to work as normal.
-
-If you're unsure what the names of the sniffs are that you want to ignore, add `-s` to the PHPCS command to have it include the sniff names in its output.
-
-For more information on ignoring files, folders, part of files, and limiting results, see the [Advanced Usage page for the PHP CodeSniffer project](https://github.com/squizlabs/PHP_CodeSniffer/wiki/Advanced-Usage) on GitHub.
-
-You can also see this being used in [some of the tests for this website](https://github.com/opdavies/oliverdavies-uk/tree/production/web/modules/custom/blog/tests/src/Kernel).
diff --git a/astro/src/content/blog/imagefield-import-archive.md b/astro/src/content/blog/imagefield-import-archive.md
deleted file mode 100644
index 2a121cc7..00000000
--- a/astro/src/content/blog/imagefield-import-archive.md
+++ /dev/null
@@ -1,35 +0,0 @@
----
-title: Imagefield Import Archive
-date: 2011-05-23
-excerpt: I've finally uploaded my first module onto Drupal.org!
-tags:
- - drupal-planet
- - imagefield-import
----
-
-I've finally uploaded my first module onto Drupal.org!
-
-I've written many custom modules, although the vast majority of them are either
-small tweaks for my own sites, or company/site-specific modules that wouldn't be
-good to anyone else, so there would be nothing achieved by contributing them
-back to the community. Previously, I've blogged about the
-[Imagefield Import](http://drupal.org/project/imagefield_import) module - a
-module that I use on a number of sites, both personal and for clients - and what
-I've looked for lately is for a way to speed up the process again. Gathering my
-images together and manually copying them into the import directory takes time -
-especially if I'm working somewhere with a slow Internet connection and I'm
-FTP-ing the images into the directory. Also, it's not always the easiest
-solution for site users - especially non-technical ones.
-
-So, I wrote the Imagefield Import Archive module. Including comments, the module
-contains 123 lines, and builds upon the existing functionality of the Imagefield
-Import module by adding the ability for the user to upload a .zip archive of
-images. The archive is then moved into the specified import directory and
-unzipped before being deleted, and the user is directed straight to the standard
-Imagefield Import page where their images are waiting to be imported, just as
-usual.
-
-The module is currently a
-[sandbox project](http://drupal.org/sandbox/opdavies/1165110) on Drupal.org,
-although I have applied for full project access so that I can be added as a
-fully-fledged downloadable module.
diff --git a/astro/src/content/blog/improve-jpg-quality-imagecache-and-imageapi.md b/astro/src/content/blog/improve-jpg-quality-imagecache-and-imageapi.md
deleted file mode 100644
index 2fc17e93..00000000
--- a/astro/src/content/blog/improve-jpg-quality-imagecache-and-imageapi.md
+++ /dev/null
@@ -1,25 +0,0 @@
----
-title: Improve JPG Quality in Imagecache and ImageAPI
-date: 2010-06-02
-excerpt: How to fix the quality of uploaded images in Drupal.
-tags:
- - drupal-planet
- - drupal-6
- - imagecache
----
-
-Whilst uploading images for my Projects and Testimonials sections, I noticed
-that the Imagecache-scaled images weren't as high a quality the originals on my
-Mac. I did some searching online and found out that, by default, Drupal
-resamples uploaded jpgs to 75% of their original quality.
-
-To increase the quality of your images, change the setting in the two following
-places:
-
-- admin/settings/imageapi/config
-- admin/settings/image-toolkit
-
-The first one is for ImageAPI. Primarily, this means Imagecache presets. The
-second one is for core's image.inc. This is used for resizing profile pictures
-in core, and some contrib modules. Once changed, I did have to flush each of the
-Imagecache presets (admin/dist/imagecache) for the changes to take effect.
diff --git a/astro/src/content/blog/include-css-fonts-using-sass-each-loop.md b/astro/src/content/blog/include-css-fonts-using-sass-each-loop.md
deleted file mode 100644
index f3e07f3d..00000000
--- a/astro/src/content/blog/include-css-fonts-using-sass-each-loop.md
+++ /dev/null
@@ -1,67 +0,0 @@
----
-title: Include CSS Fonts by Using a SASS each Loop
-date: 2014-11-18
-excerpt: How to use an SASS each loop to easily add multiple fonts to your CSS.
-tags:
- - compass
- - drupal-planet
- - fonts
- - sass
----
-
-How to use an @each loop in SASS to quickly include multiple font files within
-your stylesheet.
-
-Using a file structure similar to this, organise your font files into
-directories, using the the font name for both the directory name and for the
-file names.
-
-```bash
-.
-├── FuturaBold
-│ ├── FuturaBold.eot
-│ ├── FuturaBold.svg
-│ ├── FuturaBold.ttf
-│ └── FuturaBold.woff
-├── FuturaBoldItalic
-│ ├── FuturaBoldItalic.eot
-│ ├── FuturaBoldItalic.svg
-│ ├── FuturaBoldItalic.ttf
-│ └── FuturaBoldItalic.woff
-├── FuturaBook
-│ ├── FuturaBook.eot
-│ ├── FuturaBook.svg
-│ ├── FuturaBook.ttf
-│ └── FuturaBook.woff
-├── FuturaItalic
-│ ├── FuturaItalic.eot
-│ ├── FuturaItalic.svg
-│ ├── FuturaItalic.ttf
-│ └── FuturaItalic.woff
-```
-
-Within your SASS file, start an `@each` loop, listing the names of the fonts. In
-the same way as PHP's `foreach` loop, each font name will get looped through
-using the `$family` variable and then compiled into CSS.
-
-```scss
-@each $family in FuturaBook, FuturaBold, FuturaBoldItalic, FuturaItalic {
- @font-face {
- font-family: #{$family};
- src: url('../fonts/#{$family}/#{$family}.eot');
- src: url('../fonts/#{$family}/#{$family}.eot?#iefix') format('embedded-opentype'),
- url('../fonts/#{$family}/#{$family}.woff') format('woff'),
- url('../fonts/#{$family}/#{$family}.ttf') format('truetype'),
- url('../fonts/#{$family}/#{$family}.svg##{$family}') format('svg');
- font-weight: normal;
- font-style: normal;
- }
-}
-```
-
-When the CSS has been compiled, you can then use in your CSS in the standard
-way.
-
-```scss
-font-family: "FuturaBook";
-```
diff --git a/astro/src/content/blog/include-environment-specific-settings-files-pantheon.md b/astro/src/content/blog/include-environment-specific-settings-files-pantheon.md
deleted file mode 100644
index 237a248e..00000000
--- a/astro/src/content/blog/include-environment-specific-settings-files-pantheon.md
+++ /dev/null
@@ -1,100 +0,0 @@
----
-title: Include environment-specific settings files on Pantheon
-date: 2014-11-27
-excerpt: How to load a different settings file per environment on Pantheon.
-tags:
- - drupal
- - drupal-planet
- - pantheon
- - settings.php
----
-
-I was recently doing some work on a site hosted on
-[Pantheon](http://getpantheon.com) and came across an issue, for which part of
-the suggested fix was to ensure that the `$base_url` variable was explicitly
-defined within settings.php (this is also best practice on all Drupal sites).
-
-The way that was recommended was by using a `switch()` function based on
-Pantheon's environment variable. For example:
-
-```php
-switch ($_SERVER['PANTHEON_ENVIRONMENT']) {
- case 'dev':
- // Development environment.
- $base_url = 'dev-my-site.gotpantheon.com';
- break;
-
-
- case 'test':
- // Testing environment.
- $base_url = 'test-my-site.gotpantheon.com';
- break;
-
-
- case 'live':
- // Production environment.
- $base_url = 'live-my-site.gotpantheon.com';
- break;
-}
-```
-
-Whilst this works, it doesn't conform to the DRY (don't repeat yourself)
-principle and means that you also might get a rather long and complicated
-settings file, especially when you start using multiple switches and checking
-for the value of the environment multiple times.
-
-My alternative solution to this is to include an environment-specific settings
-file.
-
-To do this, add the following code to the bottom of settings.php:
-
-```php
-if (isset($_SERVER['PANTHEON_ENVIRONMENT'])) {
- if ($_SERVER['PANTHEON_ENVIRONMENT'] != 'live') {
- // You can still add things here, for example to apply to all sites apart
- // from production. Mail reroutes, caching settings etc.
- }
-
- // Include an environment-specific settings file, for example
- // settings.dev.php, if one exists.
- $environment_settings = __DIR__ . '/settings.' . $_SERVER['PANTHEON_ENVIRONMENT'] . '.php';
- if (file_exists($environment_settings)) {
- include $environment_settings;
- }
-}
-```
-
-This means that rather than having one long file, each environment has it's own
-dedicated settings file that contains it's own additional configuration. This is
-much easier to read and make changes to, and also means that less code is loaded
-and parsed by PHP. Settings that apply to all environments are still added to
-settings.php.
-
-Below this, I also include a
-[similar piece of code](/blog/include-local-drupal-settings-file-environment-configuration-and-overrides/)
-to include a settings.local.php file. The settings.php file then gets committed
-into the [Git](http://git-scm.com) repository.
-
-Within the sites/default directory, I also include an example file
-(example.settings.env.php) for reference. This is duplicated, renamed and
-populated accordingly.
-
-```php
-. This post was accurate at the time of
-writing, whereas the documentation page will be kept up to date with any future
-changes._
-
-## Initial configuration
-
-### Download the Library
-
-The library can be downloaded directly from GitHub, and should be placed within
-you _sites/all/libraries/nomensa_amp_ directory.
-
-```bash
-drush dl libraries nomensa_amp
-git clone https://github.com/nomensa/Accessible-Media-Player sites/all/libraries/nomensa_amp
-cd sites/all/libraries/nomensa_amp
-rm -rf Accessible-media-player_2.0_documentation.pdf example/ README.md
-drush en -y nomensa_amp
-```
-
-### Configure the Module
-
-Configure the module at admin/config/media/nomensa-amp and enable the
-players that you want to use.
-
-## Adding videos
-
-Within your content add links to your videos. For example:
-
-### YouTube
-
-```html
-Checking colour contrast
-```
-
-### Vimeo
-
-```html
-Screen readers are strange, when you're a stranger by Leonie Watson
-```
-
-## Adding captions
-
-The best way that I can suggest to do this is to use a File field to upload your
-captions file:
-
-1. Add a File field to your content type;
-1. On your page upload the captions file.
-1. Right-click the uploaded file, copy the link location, and use this for the
- path to your captions file.
-
-For example:
-
-```html
-Checking colour contrastCaptions for Checking Colour Contrast
-```
-
-## Screencast
-
-
-
-
diff --git a/astro/src/content/blog/installing-nagios-centos.md b/astro/src/content/blog/installing-nagios-centos.md
deleted file mode 100644
index 75bf0170..00000000
--- a/astro/src/content/blog/installing-nagios-centos.md
+++ /dev/null
@@ -1,15 +0,0 @@
----
-title: Installing Nagios on CentOS
-date: 2012-04-17
-excerpt: How to install Nagios on CentOS.
-tags:
- - nagios
- - centos
- - linux
----
-
-A great post details that details the steps needed to install
-[Nagios](http://nagios.org) - a popular open source system and network
-monitoring software application - on CentOS.
-
-
diff --git a/astro/src/content/blog/interview-drupal-expert-code-enigma.md b/astro/src/content/blog/interview-drupal-expert-code-enigma.md
deleted file mode 100644
index e4063d1e..00000000
--- a/astro/src/content/blog/interview-drupal-expert-code-enigma.md
+++ /dev/null
@@ -1,13 +0,0 @@
----
-title: Interview with a Drupal Expert (with Code Enigma)
-excerpt: I recently did an interview with Code Enigma for their blog.
-tags:
- - drupal
- - interview
- - personal
-date: 2020-08-31
----
-
-I recently did an interview with Drupal and PHP agency [Code Enigma](https://www.codeenigma.com) for their blog, in which we talked about getting started in the Drupal community, [working for 10 years full-time with Drupal and PHP](/blog/10-years-working-full-time-drupal-php), companies adopting open source technologies, and my favourite Drupal events.
-
-To read it, go to [the Code Enigma blog](https://blog.codeenigma.com/interview-with-a-drupal-expert-9fcd8e0fad28 "'Interview with a Drupal Expert' on the Code Enigma blog").
diff --git a/astro/src/content/blog/introducing-drupal-distribution-meetups.md b/astro/src/content/blog/introducing-drupal-distribution-meetups.md
deleted file mode 100644
index f796a766..00000000
--- a/astro/src/content/blog/introducing-drupal-distribution-meetups.md
+++ /dev/null
@@ -1,29 +0,0 @@
----
-title: Introducing a Drupal distribution for meetup websites
-excerpt: I'm starting development on a new Drupal distribution for building meetup group websites.
-tags:
- - drupal
- - drupal-9
- - drupal-distribution
- - drupal-meetup-distribution
- - personal
- - php
- - php-south-wales
-date: 2021-10-07
----
-
-I'm the current organiser of the [PHP South Wales user group](https://www.phpsouthwales.uk) and built the current website with Drupal 8, which I started in 2019.
-
-There are some basic pages, but also functionality to display upcoming and past events, show current sponsors, and to populate event data from Meetup.com - functionality that could needed by other meetup groups for their websites - such as other PHP and Drupal user groups that I've organised and attended.
-
-Inspired by other Drupal distributions like [LocalGov](https://www.drupal.org/project/localgov), I've decided to refactor the current site into a reusable distribution that other meetup groups can use. It's not intended to be a clone of Meetup.com, but to be used for a website for a single meetup group to show their events and showcase their own community.
-
-This also means that any new functionality can be added straight to the distribution and immediately available for everyone.
-
-I've created a [project page on Drupal.org][drupalorg] and a [Drupal Meetup organisation on GitHub][github] which contains repositories for the distribution as well as a project template that are pushed to [Packagist][packagist] to that they can be installed with Composer - e.g. `composer create-project --stability dev drupal-meetup/drupal-meetup-project my-new-meetup`.
-
-This seems like a good opportunity to do some more Drupal contribution and may benefit others too who want to build their own meetup group websites.
-
-[drupalorg]: https://www.drupal.org/project/meetup
-[github]: https://github.com/drupal-meetup
-[packagist]: https://packagist.org/packages/opdavies/?query=drupal-meetup
diff --git a/astro/src/content/blog/introducing-the-drupal-meetups-twitterbot.md b/astro/src/content/blog/introducing-the-drupal-meetups-twitterbot.md
deleted file mode 100644
index cf12e4c1..00000000
--- a/astro/src/content/blog/introducing-the-drupal-meetups-twitterbot.md
+++ /dev/null
@@ -1,29 +0,0 @@
----
-title: Introducing the Drupal Meetups Twitterbot
-date: 2017-06-09
-excerpt: I’ve written a twitterbot for promoting Drupal meetups.
-tags:
- - php
- - twitter
----
-
-

-
-The [Drupal Meetups Twitterbot][0] is a small project that I worked on a few
-months ago, but hadn't got around to promoting yet. It’s intention is to provide
-[one Twitter account][1] where people can get the up to date news from various
-Drupal meetups.
-
-It works by having a whitelist of [Twitter accounts and hashtags][2] to search
-for, uses [Codebird][3] to query the Twitter API and retweets any matching
-tweets on a scheduled basis.
-
-If you would like your meetup group to be added to the list of searched
-accounts, please [open an issue][4] on the GitHub repo.
-
-[0]: https://github.com/opdavies/drupal-meetups-twitterbot
-[1]: https://twitter.com/drupal_meetups
-[2]:
- https://github.com/opdavies/drupal-meetups-twitterbot/blob/master/bootstrap/config.php
-[3]: https://www.jublo.net/projects/codebird/php
-[4]: https://github.com/opdavies/drupal-meetups-twitterbot/issues/new
diff --git a/astro/src/content/blog/leaving-nomensa-joining-precedent.md b/astro/src/content/blog/leaving-nomensa-joining-precedent.md
deleted file mode 100644
index a5b3c45b..00000000
--- a/astro/src/content/blog/leaving-nomensa-joining-precedent.md
+++ /dev/null
@@ -1,32 +0,0 @@
----
-title: Leaving Nomensa, Joining Precedent
-date: 2013-04-20
-excerpt: Yesterday was my last day working at Nomensa. Next week, I'll be starting as a Senior Developer at Precedent.
-tags:
- - nomensa
- - personal
- - precedent
----
-
-Yesterday was my last day working at
-[Nomensa](http://www.nomensa.com 'Nomensa'). Next week, I'll be starting as a
-Senior Developer at [Precedent](http://www.precedent.co.uk 'Precedent').
-
-The last 14 months that I've been working at Nomensa have been absolutely
-fantastic, and had allowed me to work on some great projects for great clients -
-mainly [unionlearn](http://www.unionlearn.org 'unionlearn') and
-[Digital Theatre Plus](http://www.digitaltheatreplus.com 'Digital Theatre Plus').
-I've learned so much about accessibility and web standards, and have pretty much
-changed my whole approach to front-end development to accommodate best
-practices. I've also been involved with the Drupal Accessibility group since
-starting at Nomensa, and have written several accessibility-focused Drupal
-modules, including the
-[Nomensa Accessible Media Player](http://drupal.org/project/nomensa_amp 'The Nomensa Accessible Media Player Drupal module')
-module and the
-[Accessibility Checklist](http://drupal.org/project/a11y_checklist 'The accessibility checklist for Drupal').
-I'll definitely be continuing my interest in accessibility, championing best
-practices, and incorporating it into my future work wherever possible.
-
-With that all said, I'm really looking forward to starting my new role at
-Precedent, tackling some new challenges, and I'm sure that it'll be as great a
-place to work as Nomensa was.
diff --git a/astro/src/content/blog/live-blogging-symfonylive-london-2019.md b/astro/src/content/blog/live-blogging-symfonylive-london-2019.md
deleted file mode 100644
index 1cdc3a9a..00000000
--- a/astro/src/content/blog/live-blogging-symfonylive-london-2019.md
+++ /dev/null
@@ -1,713 +0,0 @@
----
-title: Live Blogging From SymfonyLive London 2019
-date: 2019-09-13
-tags:
- - conference
- - php
- - symfony
- - symfonylive
----
-
-Inspired by [Matt Stauffer](https://twitter.com/stauffermatt)'s
-[live blogging of the keynote](https://mattstauffer.com/blog/introducing-laravel-vapor)
-at Laracon US, I’m going to do the same for the sessions that I’m attending at
-[SymfonyLive London 2019](https://london2019.live.symfony.com)...
-
-## Keynote (Back to the basics)
-
-**Embrace the Linux philosophy**
-
-- How we grow the Symfony ecosystem. Built abstracts.
-- HttpFoundation, HttpKernel
-- Moved to infrastructure
-- A few abstractions on top of PHP. Improved versions of PHP functions (`dump`
- and `var_dump`)
-- Started a add higher level abstractions (e.g. Mailer), built on the lower
- ones.
-- Recently worked on PHPUnit assertions. Mailer in Symony 4.4. Can test if an
- email is sent or queued
-
-**Building flexible high-level abstractions on top of low-level ones**
-
-### What's next?
-
-- Mailer announced in London last year. New component.
-- System emails? e.g. new customer, new invoice.
-- Symfony Mailer = Built-in responsive, flexible, and generic system emails
- - Twig with TwigExtraBundle
- - Twig `inky-extra` package (Twig 1.12+)
- - Zurb Foundation for Emails CSS stylesheet
- - Twig `cssinliner-extra` package (Twig 1.12+)
- - Optimised Twig layouts
-- `SystemEmail` class extends templated email
-- Can set importance,
-- Customisable
-- Always trying to keep flexible, so things can be overidden and customised
-
-### Sending SMS messages
-
-- new `Texter` and `SmsMessage` class for sending SMS messages
-- Same abstraction as emails, but for SMS messages
-- Based on HttpClient + Symfony Messenger and third-party providers (Twilio and
- Nexmo) `twilio://` and `nemxo://`
-- Can set via transport `$sms->setTransport('nexmo')`
-- Extend the `SystemEmail` and do what you want
-- Failover
-
-### Sending Messages
-
-- Create `ChatMessage`
-- Telegram and Slack
-- `$message->setTransport('telegram')`, `$bus->dispatch($message)`
-- Send to Slack **and** Telegram
-- `SlackOptions` and `TelegramOptions` for adding emojis etc
-- Common transport layer `TransportInterface`, `MessageInterface`
-- Failover - e.g. if Twilio is down, send to Telegram
-
-### New component - SymfonyNotifier
-
-- Channels - email, SMS, chat
-- Transport, slack, telegram, twilio
-- Create a notification, arguments are message and transports (array)
-- Receiver
-- Customise notifications, `InvoiceNotification` extends `Notification`.
- `getChannels`
- - Override default rendering
- - `ChatNotificationInterface` - `asChatMessage()`
-- Semantic configuration
- - `composer req twilio-notifier telegram-notifier`
-- Channels
- - Mailer
- - Chatter
- - Texter
- - Browser
- - Pusher (iOS, Android, Desktop native notifications)
- - Database (web notification centre)
- - **A unified way to notify Users via a unified Transport layer**
-- Each integration is only 40 lines of code
-
-### What about a SystemNotification?
-
-- Autoconfigured channels
-- `new SystemNotification`, `Notifier::getSystemReceivers`
-- Importance, automatically configures channels
-- Different channels based on importance
-- `ExceptionNotification` - get email with stack trace attached
-
-Notifier
-
-- send messages via a unified api
-- send to one or many receivers
-- Default configu or custom one
-
-### How can we leverage this new infrastructure?
-
-- `Monolog NotifierHandler` - triggered on `Error` level logs
-- Uses notified channel configuration
-- Converts Error level logs to importance levels
-- Configurablelike other Notifications
-- 40 lines of code
-- Failed Messages Listener - 10 lines of glue code
-
-- **Experimental component in 5.0**
-- Can't in in 4.4 as it's a LTS version
-- First time an experimental component is added
-- Stable in 5.1
-
-## Queues, busses and the Messenger component (Tobias Nyholm)
-
-- Stack is top and buttom - Last-in, first-out
-- Queue is back and front - last in, first out
-
-### 2013
-
-- Using Symfony, used 40 or 50 bundles in a project - too much information!
-- Used to copy and paste, duplicate a lot of code
-- Testing your controllers - controllers as services?
-- Controllers are 'comfortable'
-- Tried adding `CurrentUserProvider` service to core, should be passed as an
- argument. Cannot test.
-- 'Having Symfony all over the place wasn't the best thing' - when to framework
- (Matthias Noback)
- - Hexagonal architecture
- - Keep your kernel away from infrastructure. Let the framework handle the
- infrastructure.
-- Controller -> Command -> Command Bus -> `CommandHandler`
-
-#### What did we win?
-
-- Can leverage Middleware with a command bus
-- Queues as a service (RabbitMQ)
-- Work queue - one producer, multiple consumers
-- Queues should be durable - messages are also stored on disk, consumers should
- acknowledge a message once a message is handled
-- Publish/subscribe
- - Producer -> Fanout/direct with routing (multiple queues) -> multiple
- consumers
-- Topics - wildcards
-
-### 2016
-
-- New intern. Understand everything, 'just PHP'. Plain PHP application, not
- 'scary Symfony'
-
-### Symfony Messenger
-
-- `composer req symfony/messager` - best MessageBus implementation
-- Message -> Message bus -> Message handler
-- Message is a plain PHP class
-- Handler is a normal PHP class which is invokable
-- `messenger:message_hander` tag in config
-- Autowire with `MessageHandlerInterface`
-- What if it takes 20 seconds to send a message? Use asynchronous.
-- Transports as middleware (needs sender, receiver, configurable with DSN,
- encode/decode). `MESSENGER_DSN` added to `.env`
-- Start consumer with `bin/console messager:consume-messages`. Time limit with
- `--time-limit 300`
-- PHP Enqueue - production ready, battle-tested messaging solution for PHP
-
-### Issues
-
-- Transformers, takes an object and transforms into an array -
- `FooTransformer implements TransformerInterface`.
-- Don't break other apps by changing the payload.
-
-#### Multiple buses
-
-- Command bus, query bus, event bus
-- Separate actions from reactions
-
-#### Envelope
-
-- Stamps for metadata - has the item been on the queue already?
-
-#### Failures
-
-- Requeue, different queue or same queue after a period of time
-- Failed queue 1 every minute, failed queue 2 every hour - temporary glitches or
- a bug?
-
-#### Creating entities
-
-- What if two users registered at the same tiem? Use uuids rather than IDs.
-- Symfony validation - can be used on messages, not just forms.
-
-- Cache everything
-
- - Option 1: HTTP request -> Thin app (gets responses from Redis) -> POST to
- queue. Every GET request would warm cache
- - Option 2: HTTP request -> Thin app -> return 200 response -> pass to workers
-
-- Tip: put Command and CommandHandlers in the same directory
-
-## HttpClient (Nicolas Grekas)
-
-- new symfony component, released in may
-- Httpclient contracts, separate package that contains interfaces
- - Symfony
- - PHP-FIG
- - Httplug
-- `HttpClient::create()`. `$client->get()`
-- JSON decoded with error handling
-- Used on symfony.com website (#1391). Replaces Guzzle `Client` for
- `HttpClientInterface`
-- Object is stateless, Guzzle is not. Doesn't handle cookies, cookies are state
-- Remove boilerplate - use `toArray()`
-- Options as third argument - array of headers, similar to Guzzle
-
-### What can we do with the Response?
-
-- `getStatusCode(): int`
-- `getHeaders(): array`
-- `getContent(): string`
-- `toArray(): array`
-- `cancel(): void`
-- `getInfo(): array` - metadata
-- Everything is lazy!
-- 80% of use-cases covered
-
-### What about PSR-18?
-
-- Decorator/adapter to change to PSR compatible
-- Same for Httplug
-
-### What about the remaining 20%?
-
-- Options are part of the abstraction, not the implementation
-
-#### Some of the options
-
-- `timeout` - control inactivity periods
-- `proxy` - get through a http proxy
-- `on_progress` - display a progress bar / build a scoped client
-- `base_url` - resolve relative URLS / build a scoped client
-- `resolve` - protect webhooks against calls to internal endpoints
-- `max_redirects` - disable or limit redirects
-
-- Robust and failsafe by default
-
-- Streamable uploads - `$mimeParts->toIterable()`.
-- donwload a file
-
- ```php
- foreach ($client->stream($response) as $chunk) {
- // ...
- }
- ```
-
-* Responses are lazy, requests are concurrent
-* Asychronus requests. Reading in network order
-
-```
-foreach ($client->stream($responses) as $response => $chunk) {
- if ($chunk->isLast()) {
- // a $response completed
- } else {
- // a $response's got network activity or timeout
- }
-}
-```
-
-- 379 request completed in 0.4s!
-- `Stream` has second argument, max number of seconds to wait before yielding a
- timeout chunk
-- `ResponseInterface::getInfo()` - get response headers, redirect count and URL,
- start time, HTTP method and code, user data and URL
- - `getInfo('debug')` - displays debug information
-
-### The components
-
-- `NativeHttpClient` and `CurlHttpClient`
- - both provide
- - 100% contracts
- - secure directs
- - extended (time) info
- - transparent HTTP compression and (de)chunking
- - automatic HTTP proxy configuration via env vars
-
-#### `NativeHttpClient`
-
-- is most portable, works for everyone
-- based on HTTP stream wrapper with fixed redirect logic
-- blocking until response headers arrive
-
-#### `CurlHttpClient`
-
-- Requires ext-curl with fixed redirection logic
-- Multiplexing response headers and bodies
-- Leverages HTTP/2 and PUSH when available
-- Keeps connections open also between synchronous requests, no DNS resolution so
- things are faster
-
-#### Decorators
-
-- ScopingHttpClient - auto-configure options based on request URL
-- MockHttpClient - for testing, doesn't make actual HTTP requests
-- CachingHttpClient - adds caching on a HTTP request
-- Psr18Client
-- HttplugClient
-- TraceableHttpClient
-
-### Combining
-
-#### FrameworkBundle/Autowiring
-
-```yaml
-framework:
- http_client:
- max_host_connections: 4
- deault_options:
- # ....
- scoped_client:
- # ...
-```
-
-#### HttpBrowser
-
-- HttpClient + DomCrawler + CssSelector + HttpKernel + BrowserKit
-- RIP Goutte!
-
-### Coming in 4.4...
-
-- `max_duration`
-- `buffer` based on a callable
-- `$chunk->isInformational()`
-- `$response->toStream()`
-- Async-compatible extensibility, when decoration is not enough
-
-`composer req symfony/http-client`
-
-## Symfony Checker is coming (Valentine Boineau)
-
-- Static analysis tool for Symfony
- - Does a method exist?
- - Is it deprecated?
-- insight.symfony.com
-- @symfonyinsight
-- Released soon
-
-### Differences
-
-- Specialise in Symfony - can see more relevant things
-- Different interface to other services
-
-## Feeling unfulfilled by SPA promises? Go back to Twig (Dan Blows)
-
-A way on the front-end JS, CSS, images at the beginning of the request, sends a
-HTTP request (XHR/AJAX) to the back-end
-
-### Why SPAs?
-
-- A way on the front-end JS, CSS, images at the beginning of the request, sends
- a HTTP request (XHR/AJAX) to the back-end
-- no full page refresh
-- Supposed to be much quicker
-- 'Right tool for the job' - JS on the front-end, PHP on the back-end
-- Division of responsibility == faster development
-- Reusable API - Api -> Mobile App and SPA - easy to add another consumer
-- Easier to debug?
-
-### Why not SPAs?
-
-- Lots of HTTP requests (400 to load the initial page on one project) == slow
- front end
-- Blurred responsibilities == tightly coupled teams
-- harder to debug, bugs fall between systems and teams. Huge gap between
- front-end and back-end, passing responsibilites.
-- You can fix these problems in SPAs, but is it worth it?
- - Examples of good SPAs - Trello, Flickr
-
-### Using Twig as an alternative to an SPA?
-
-#### Faster UI - Try and figure out where the problem is.
-
-If you're trying to speed things up, find out where the problem is.
-
-- Browser tools
-- Web Debug Toolbar
-- Blackfire
-- Optimise and monitor
-
-#### Speed up Twig
-
-- Speeding up Symfony
-- ext/twig (PHP5 only, not PHP 7)
-- Store compiled templates in Opcache, make sure it's enabled
-- Render assets though the webserver (assetic not running all the time)
-
-#### Edge side includes
-
-- Component cached differently to the rest of the page
-- Varnish/Nginx
-- `render_esi`
-- News block that caches frequently, rest of the page
-
-#### HTTP/2 with Weblink
-
-- slow finding CSS files to load - 'push' over CSS files, doesn't need to wait
-- `preload()` - https://symfony.com/doc/current/web_link.html
-
-#### Live updating pages
-
-- Instantly update when sports results are updated, news articles are added
-- Mercure - https://github.com/symfony/mercure
-- LiveTwig - whole block or whole section, and live update `render_live`
-- Turbolinks - replace whole body, keeps CSS and JS in memory. Merges new stuff
- in. `helthe/turbolinks`
-- ReactPHP - shares kernel between requests
-
-### Writing better code with Twig
-
-- Keep templates simple. Avoid spaghetti code, only about UI. HTML or small
- amounts of Twig.
-- Avoid delimeter chains
- - Bad:`blog_post.authors.first.user_account.email_address`
- - Good `{{ blog_post.authors_email_address }}`
- - Less brittle, slow
-
-* Filters
- - Use filters to be precise
- - Custom filters
- - Avoid chains. Can cause odd results. Create a new filter in PHP
-* Functions
- - Write your own functions
- - Simpler templates
- - Get data, can use boolean statements
-* Components
- - Break a page into components rather than one large page
- - `include()`
- - Use `only` to only pass that data. less tightenly coupled.
- * `render` calls the whole of Symfony, boots Kernel, can be expensive and slow
- * Loosely couple templates and controllers
- - Keep responses simple
- - What makes sense
- - if you need extra data in the template, get it in the template
- * View models
- - Mixed results
- - `BlogPostViewModel`
- - Can result in boilerplate code
- - Can be useful if the view model is different to the Entity
- * DRY
- - "Don't repeat yourself"
-
-- Faster development
- - Separate UI tests from back-end tests. Different layers for different teams.
- People don't need to run everything if they are only changing certain
- things.
-
-* Help your front end
- - Webpack - Encore
- - Type hinting in functions and filters, easier to debug
- - Logging
- - Friendly exceptions - help front-end devs by returning meaningful, readbale
- errors
- - Web Debug Toolbar and Profiler, provide training for toolbar and profilers
- - Twig-friendly development environment - Twig support in IDEs and text
- editors
-
-SPAs are sometimes teh right solution. Why do they want to use it, can the same
-benefits be added with Twig?
-
-3 most important points:
-
-- Profile, identidy, optimise, monitor
-- Loosely couple templates to your app code
-- Help your front ends - put your front end developers first
-- You don't need to use a SPA for single pages, use JavaScript for that one
- page. It doesn't need to be all or nothing.
-
-## BDD Your Symfony Application (Kamil Kokot)
-
-- Applying BDD to Sylius
-- 2 years since release of Sylius (Symfony 2 alpha)
-- The business part is more important than the code part
-
-### What is BDD?
-
-- Behaviour driven development. Combines TDD and DDD, into an agile methodology
-- Encourages communication and creates shared understanding
-- Living, executable documentation that non-programmers understand. Always
- correct.
-- Feature file
- - Feature
- - Scenario - example of the behaviour for this feature. Simple, atomic. (e.g.
- I need a product in order to add it to a cart)
- - In order to...
- - Who gets the benefit?
-
-### BDD in practice
-
-- Feature: booking flight tickets
-- Scenario: booking flight ticket for one person
- - Given there are the following flights...
- - When I visit '/flight/LTN-WAW'
- - Then I should be on '/flight/LTN-WAW'
- - Add I should see "Your flight has been booked." in "#result"
-- In the BDD way - what is the business logic? What is the value for this
- scenario? What is the reason 'why', and who benefits from this?
- - We just need to know that there are 5 seats left on a flight
- - Talk and communicate about how the feature is going to work - not just
- developers
- - BDD aids communication
-- Questions we can ask
- - Can we get a different outcome when the context changes?
- - When there was only one seat available
- - When there were no available seats
- - Can we get the same outcome when the event changes? Can we change 'When' and
- 'Then stays the same'
- - When it is booked for an adult and a child
- - When it is booked for an adult
- - Does anything else happen that is not mentioned?
- - Generate an invoice if a seat is booked
- - a pilot would like to get a notification that a seat was booked.
- * Figuring out the rules
- - Adults are 15+ years old
- - Children are 2-14 years old
- - Infants and children can only travel with an adult
- - We don't allow for overbooking
- - Translating rules into examples
- - Add a new scenario for each rule - e.g. don't allow over booking
- - "And the flight should be no longer available..."
-
-### Behat
-
-- Used to automate and execute BDD tests, also SpecDDD
-- maps steps to PHP code
-- Given a context, when an event, then an outcome
-- Domain Context, API context
-- class implements `Context`, annotations for `@Given`, `@When`, `@Then`. allows
- for arguments and regular expressions
-- Suites: change what code is executed, and what scenarios are executed. context
- and tags
-- FriendsOfBehat SymfonyExtension - integrates Behat with Symfony
- - Contexts registered as Symfony services - inject dependencies, service as a
- context in Behat. Need to be 'public' for it to work
- - Reduces boilerplate code. Supports autowiring.
- - Zero configuration
-
-### Domain context
-
-- `Given` verb matches `@Given` annotation. Same for `When` and `Then`.
-- Transformers, type hint name string, return Client instance
-
-### API context
-
-- inject `FlightBookingService` and `KernelBrowser`
-- Use `$this->kernelBrowser->request()`
-- Use `assert()` function wuthin `@Then`
-
-### Back to reality - how it's done with Sylius
-
-- Business part applies to all context. Start talking about what needs to be
- done, start communicating
-- Implement contexts for UI and API
-- 12716 steps, 1175 scenarios, 8 min 8 sec, 2.4 scenarios /sec
-- 12x faster than JS (17 min 48 sec, 0.19 scenario / sec)
-- Treat test CI environment like production
-
- - Turn off debug settings, add caching
- - Enable OPcache
-
-- Write features in a natural way
-- Too many setup steps - merge steps. less visual debt. e.g. Create currency,
- zone and locale when creating a store
-- Avoid scenarios that are too detailed. You should specify only what's
- important to this scenario.
-
-## Migrating to Symfony one route at a time (Steve Winter)
-
-- New client with an old application, built in an old version of another
- framework with unusual dependency management, no tests, no version control and
- deploying via FTP. Done over a ~3 month period.
-
-- Subscription based index of suppliers
-- New requirements to implement by the client
-- Our requirements: Needed a deployment process, make it testable, fix the build
- chain
-- Solution attempt 1: Migrate to a new version of the current framework
- - Minor template and design changes were fine
- - Modifiy features, add new dependencies.
-- Solution attempt 2: Upgrade to the latest version - same outcome due to
- multiple BC breaks (no semver), lots of manual steps
-- Solution attempt 3: Symfony!
- - Semver! Backwards compatibility promise
- - Symfony app to run in parallel, Apache proxy rules and minor changes to the
- legacy app, added data transfer mechanisms
- - Anything new done in Symfony
- - Installed on the same server with it's own vhost but not publicly accessible
- - Deployed independently of legacy app
-
-### Apache proxy rules
-
-Proxy `/public` to symfony app
-
-### Legacy app
-
-- Shared cookie for single login between apps - user account details (name etc),
- session details (login time)
-
-### Added functionality
-
-- Built in Symfony
-- new proxy rules for new routes
-- Add menu links to legacy app menu
-- How do we show how many reminders are active?
- - Symfony based API called from the front-end
-
-### Migrating routes
-
-- Rebuilt or extend in Symfony app
-- Test and deploy, then update the apache config to add new proxy rules
-
-### A gotcha
-
-- Legacy app uses CSRF
-- Needed to track the token, added to shared cookie and pass through to the
- Symfony side
-
-### Storing data
-
-- Both apps using the same data with different credentials
-- Some shared tables, some tables are specific to each app
-
-### Remaining challenges
-
-- User session management, still handled by legacy app
-- Templating/CSS - two versions of everything
- - Next step: move all CSS to Symfony
-
-### Summary
-
-- Add Symfony app, Apache proxy rules for routes
-- User transfer mechanisms
-- New functionality added in Symfony
-
-### Is this right for you?
-
-It depends. Fine for a 'modest' size. Use a real proxy for larger scale apps,
-use different servers with database replication.
-
-## Closing Keynote: The fabulous World of Emojis and other Unicode symbols (Nicolas Grekas)
-
-- ASCII. Still used today. Map between the first 128 numbers to characters. OK
- for UK and US.
-- 256 numbers in Windows-1252 (character sets). Each country had their own set.
-- It's legacy. 0.2% for Windows-1252. 88.8% for UTF-8 (Feb 2017)
-- Unicode: 130k characters, 135 scripts (alphabets)
-- Validation errors using native alphabet - e.g. invalid last name when
- submitting a form
-- 17 plans, each square is 255 code points
-- Emojis are characters, not images
-- Gliph is a visual representation of a character
-- From code points to bytes
- - UTF-8: 1,2,3 or 4 bytes
- - UTF16: 2 or 4 bytes
- - UTF-32: 4 bytes
-- UTF-8 is compatible with ASCII
-- Case sensitivity - 1k characters are concerned. One uppercase letter, two
- lower case variants. Turkish exception (similar looking letters that are
- different letters with different meanings). Full case folding.
-- Collations - ordering is depends on the language. 'ch' in Spanish is a single
- character.
-- Single number in unicode to represent accents. Combining characters.
-- Composed (NFC) and decomposed (NFD) forms - normalisation for comparison
-- Grapheme clusters - multiple characters, but one letter as you write it
- (separate characters for letters and accent)
-- Emjois - combining characters. e.g. Combine face with colour. Different codes
- and character names. Also applies to ligatures. A way to combine several
- images together into one single visual representation.
-
-### unicode fundamentals
-
-- uppercase, lowercase, folding
-- compositions, ligatures
-- comparistions - normalisations and collations
-- segmentation: characters, words, sentences and hyphens
-- locales: cultural conventions, translitterations
-- identifiers & security, confusables
-- display: direction, width
-
-### unicode in practice
-
-- MySQL - `utf*_*`. `SET NAMES utf8mb4` for security and storing emojis. Cannot
- store emojis with `utf8`
-
-### in php
-
-- `mb_*()`
-- `iconv_*()`
-- `preg_*()`
-- `grapheme_*()` `normalizer_*()`
-- `symfony/polyfill-*` - pure PHP implementation
-- Made a component - **symfony/string** -
- https://github.com/symfony/symfony/pull/33553
-- Object orientated api for strings. Immutable value objects
-- `AbstractString`
- - `GraphemeString`
- - `Utf8String`
- - `BinaryString`
-
-* AbstractString - Methods to serialize, get length, to binary or grapheme or
- utf8
- - Methods for starts with, ends with, is empty, join, prepend, split, trim,
- title etc
diff --git a/astro/src/content/blog/looking-forward-to-drupalcamp-london.md b/astro/src/content/blog/looking-forward-to-drupalcamp-london.md
deleted file mode 100644
index ca95135b..00000000
--- a/astro/src/content/blog/looking-forward-to-drupalcamp-london.md
+++ /dev/null
@@ -1,66 +0,0 @@
----
-title: Looking forward to DrupalCamp London
-date: 2018-02-27
-excerpt: This weekend is DrupalCamp London 2018. I’ll be there along with a number of my Microserve colleagues.
-tags:
- - drupal
- - drupalcamp
- - drupalcamp-london
- - speaking
----
-
-This weekend is [DrupalCamp London 2018][1]. I’ll be there along with a number
-of my [Microserve][2] colleagues.
-
-I look forward to DrupalCamp London every year, partly because it was the first
-DrupalCamp that I attended back in 2014. It was also the first DrupalCamp that I
-[gave a talk][3] at, when I presented a session about Git Flow having given only
-one user group talk before.
-
-I’ve presented sessions at every DrupalCamp London since (including two last
-year), and I’m lucky enough to be [speaking again this year][4] due to one of
-the originally announced speakers no longer being able to make it to the event.
-
-Here are some other sessions that I’m hoping to see (in no particular order):
-
-- Keynote by [Ryan Szrama][5] from [Commerce Guys][6]
-- [Drupal 8 Services And Dependency Injection](https://drupalcamp.london/session/drupal-8-services-and-dependency-injection)
- by Phil Norton
-- [Growing developers with Drupal](https://drupalcamp.london/session/growing-developers-drupal)
- by Fran Garcia-Linares (fjgarlin)
-- [How to make it easier for newcomers to get involved in Drupal](https://drupalcamp.london/session/how-make-it-easier-newcomers-get-involved-drupal)
- by heather
-- [Let’s take the best route - Exploring Drupal 8 Routing System](https://drupalcamp.london/session/lets-take-best-route-exploring-drupal-8-routing-system)
- by surbhi
-- [New recipe of Decoupling: Drupal 8, Symfony and Slim Framework](https://drupalcamp.london/session/new-recipe-decoupling-drupal-8-symfony-and-slim-framework)
- by Jyoti Singh
-- [Plugin API by examples](https://drupalcamp.london/session/plugin-api-examples)
- by Gabriele (gambry)
-- [Value of mentorship in the community](https://drupalcamp.london/session/value-mentorship-community)
- by Hussain Abbas (hussainweb)
-- [Warden - Helping Drupal Agencies Sleep at Night](https://drupalcamp.london/session/warden-helping-drupal-agencies-sleep-night)
- by Mike Davis
-
-Unfortunately there are some time slots where I’d like to see more than one of
-the talks (including when I’m going to be speaking). This regularly happens at
-conferences, but I’ll look forward to watching those on [YouTube][7] after the
-event.
-
-I’m also looking forward to catching up with former colleagues, spending some
-time in the "hallway track" and hopefully doing some sprinting too!
-
-## Finally
-
-For nostalgia, [here’s the blog post][0] that I wrote before I attended my first
-DrupalCamp London.
-
-See everyone this weekend!
-
-[0]: {{site.url}}/blog/2014/02/09/drupalcamp-london-2014
-[1]: https://drupalcamp.london
-[2]: {{site.companies.microserve.url}}
-[3]: {{site.url}}/talks/git-flow
-[4]: {{site.url}}/talks/deploying-drupal-fabric
-[5]: http://ryanszrama.com
-[6]: https://commerceguys.com
-[7]: https://www.youtube.com/channel/UCsaB96zszIP4Y3czs-ndiIA
diff --git a/astro/src/content/blog/mediacurrent-contrib-half-hour-is-back.md b/astro/src/content/blog/mediacurrent-contrib-half-hour-is-back.md
deleted file mode 100644
index 0402a70f..00000000
--- a/astro/src/content/blog/mediacurrent-contrib-half-hour-is-back.md
+++ /dev/null
@@ -1,67 +0,0 @@
----
-title: Yay, the Mediacurrent Contrib Half Hour is Back!
-date: 2018-03-02
-excerpt: Mediacurrent’s "contrib half hour sessions" are back.
-tags:
- - contribution
- - drupal
- - open-source
-has_tweets: true
----
-
-Back in November, [Mediacurrent introduced][1] the contrib half hour - a weekly
-online meeting to provide guidance and assistance on contributing to Drupal and
-Drupal projects. A range of topics were covered in the first few sessions,
-including finding and testing bug fixes, Composer, Drush, and how to re-roll
-patches.
-
-From Damien's [introductory blog post][2]:
-
-> Not sure what this whole "patch" thing is? Have a core change that you can't
-> quite finish? Running into a problem with a contrib module, or a theme, or a
-> 3rd party library, and not sure how to fix it? New to maintaining a module and
-> unsure of what to do next? Wondering how to get your module through the
-> security opt-in process? Is your project's issue queue getting you down? Join
-> us every Thursday at noon EST for the Mediacurrent Contrib Half Hour where
-> we'll be available to help solve contrib challenges.
->
-> Each week we'll host a live meeting to give step-by-step guidance on some best
-> practices for contributing to Drupal, and provide Q and A assistance for our
-> favorite open source (OSS) content management system (CMS). The meetings will
-> be lead by yours truly, Damien McKenna, a prolific contributor to the Drupal
-> community, and my coworkers here at Mediacurrent.
-
-There is also an [updates blog post][3] that continues to show the latest
-information, and the video recordings are [uploaded to YouTube][0] after the
-session. Here is the first one from November:
-
-
-
-I enjoyed watching the first few videos, as I’m always interested in
-contribution to Drupal and open-source and how to encourage it, but then no new
-videos were uploaded for a while and I hoped that it hadn’t faded away.
-
-I’m glad to see today that it’s back and that all of the previous videos have
-been uploaded and added to the [YouTube playlist][0], and that [on the update
-post][3] there are scheduled topics for the rest of this month including
-documentation and automated testing.
-
-
-
-I do enjoy watching these, and I like both the presentation and Q&A format that
-they alternate between. I’ll look forward to catching up over the next few days,
-and to hopefully seeing them continue to be uploaded after future meetings.
-
-Thanks Damien and Mediacurrent!
-
-[0]: https://www.youtube.com/playlist?list=PLu-MxhbnjI9rHroPvZO5LEUhr58Yl0j_F
-[1]:
- https://www.mediacurrent.com/blog/introducing-mediacurrent-contrib-half-hour
-[2]:
- https://www.mediacurrent.com/blog/introducing-mediacurrent-contrib-half-hour
-[3]:
- https://www.mediacurrent.com/blog/updates-mediacurrent-contrib-half-hour-weekly-meeting
diff --git a/astro/src/content/blog/migrating-drupal-8-introduction.md b/astro/src/content/blog/migrating-drupal-8-introduction.md
deleted file mode 100644
index cef81271..00000000
--- a/astro/src/content/blog/migrating-drupal-8-introduction.md
+++ /dev/null
@@ -1,22 +0,0 @@
----
-title: 'Migrating to Drupal 8: Introduction'
-excerpt: An introduction to the 'Migrating to Drupal 8' blog post series.
-date: 2020-08-12
-tags:
- - drupal
- - drupal-8
- - drupal-planet
----
-
-I recently finished porting this website from a static site generator to Drupal 8, meaning that this site has now been powered by three different major versions of Drupal (6, 7 and 8) as well as by two static site generators since it was first launched in early 2010.
-
-The majority of the content was imported using migrations from JSON feeds that I created. This included:
-
-- Blog tags
-- Blog posts
-- Talks
-- Redirects
-
-In some follow-up posts, I'll be looking at each migration separately, describing any issues and look at how it was used to import its respective content.
-
-I'll update this post with the links to the follow-up posts, and they are also available from the [blog series' page](/taxonomy/term/165).
diff --git a/astro/src/content/blog/minimum-core-version.md b/astro/src/content/blog/minimum-core-version.md
deleted file mode 100644
index aaeb69e6..00000000
--- a/astro/src/content/blog/minimum-core-version.md
+++ /dev/null
@@ -1,96 +0,0 @@
----
-title: How to Define a Minimum Drupal Core Version
-date: 2015-04-03
-excerpt: How to define a minimum Drupal core version for your module or theme.
-tags:
- - drupal
- - drupal-7
- - drupal-planet
-meta:
- og:
- title: 'How to Define a Minimum Drupal Core Version'
- excerpt: 'How to define a minimum Drupal core version for your module or theme.'
- type: article
----
-
-This week, my first code patch was
-[committed to Drupal core](https://www.drupal.org/node/2394517#comment-9773143).
-The patch adds the `user_has_role()` function to the user module, to simplify
-the way to check whether a user in Drupal has been assigned a specific role.
-This is something that I normally write a custom function for each project, but
-it's now available in Drupal core as of
-[7.36](https://www.drupal.org/drupal-7.36-release-notes).
-
-But what if someone is using a core version less than 7.36 and tries using the
-function? The site would return an error because that function wouldn't exist.
-
-If you're building a new Drupal site, then I'd assume that you're using a latest
-version of core, or you have the opportunity to update it when needed. But what
-if you're writing a contrib module? How can you be sure that the correct minimum
-version of core?
-
-## Setting Dependencies
-
-What I'm going to be doing for my contrib projects is defining a minimum version
-of Drupal core that the module is compatible with. If this dependency isn't met,
-the module won't be able to be enabled. This is done within your module's .info
-file.
-
-### Adding a Simple Dependency
-
-You can define a simple dependency for your module by adding a line this this to
-your project's .info file:
-
-```bash
-dependencies[] = views
-```
-
-This would make your module dependant on having the
-[Views](https://www.drupal.org/project/views) module present and enabled, which
-you'd need if you were including views as part of your module, for example.
-
-### Adding a Complex Dependency
-
-In the previous example, our module would enable if _any_ version of Views was
-enabled, but we need to specify a specific version. We can do this by including
-version numbers within the dependencies field in the following format:
-
-```bash
-dependencies[] = modulename (major.minor)
-```
-
-This can be a for a specific module release or a branch name:
-
-```bash
-dependencies[] = modulename (1.0)
-dependencies[] = modulename (1.x)
-```
-
-We can also use the following as part of the field for extra granularity:
-
-- = or == equals (this is the default)
-- > greater than
-- < lesser than
-- > = greater than or equal to
-- <= lesser than or equal to
-- != not equal to
-
-In the original scenario, we want to specify that the module can only be enabled
-on Drupal core 7.36 or later. To do this, we can use the "greater than or equal
-to" option.
-
-```ini
-dependencies[] = system (>=7.36)
-```
-
-Because we need to check for Drupal's core version, we're using the system
-module as the dependency and specifying that it needs to be either equal to or
-greater than 7.36. If this dependency is not met, e.g. Drupal 7.35 is being
-used, then the module cannot be enabled rather than showing a function not found
-error for `user_has_role()` when it is called.
-
-
-
-## External Links
-
-- [Writing module .info files (Drupal 7.x)](https://www.drupal.org/node/542202#dependencies)
diff --git a/astro/src/content/blog/my-first-blog-post-published-for-inviqa.md b/astro/src/content/blog/my-first-blog-post-published-for-inviqa.md
deleted file mode 100644
index f1aca7ab..00000000
--- a/astro/src/content/blog/my-first-blog-post-published-for-inviqa.md
+++ /dev/null
@@ -1,12 +0,0 @@
----
-title: My first blog post published for Inviqa
-excerpt: My first blog post has been published on the inviqa.com website.
-date: 2020-04-29
-tags:
- - drupal
- - testing
----
-
-My first blog post was published on the Inviqa website last week. Is an introduction to automated testing in Drupal, which also includes a recap of the workshop that I recently gave at DrupalCamp London.
-
-The blog post can be found at , and there's more information about the workshop specifically at .
diff --git a/astro/src/content/blog/my-first-six-months-transport-wales.md b/astro/src/content/blog/my-first-six-months-transport-wales.md
deleted file mode 100644
index 6f08b3c5..00000000
--- a/astro/src/content/blog/my-first-six-months-transport-wales.md
+++ /dev/null
@@ -1,45 +0,0 @@
----
-title: "My first six months at Transport for Wales"
-excerpt:
- It's been a busy six months since I started working as a Lead Software
- Developer at Transport for Wales.
-date: 2021-12-03
-tags: ["personal"]
----
-
-It's been a busy six months since I started working as a Lead Software
-Developer at Transport for Wales back in June.
-
-My main focus has been being part on the development team for the new
-[tfw.wales] and [trc.cymru] websites, which replaced the previous tfwrail.wales
-and trctrenau.cymru websites.
-
-Some of my personal highlights have been:
-
-- Completion of the initial phase 1 project that went live in September, based
- on Drupal 8.9.
-- Upgrading the phase 1 project from Drupal 8.9 to 9.2 over several iterations
- alongside new development and other BAU tasks.
-- Creating containerised versions of each of our applications using Docker,
- creating consistent local environments for us to use.
-- The introduction of automated testing and other code quality tools, such as
- PHPStan for static analysis, for any new code, and automating this using
- Bitbucket Pipelines and the new Docker images.
-- Continuing to work with a range of technologies - Drupal, Symfony and API
- Platform, Vue.js, TypeScript, Acquia Cloud, and Amazon AWS and S3.
-
-We've already been working on the second phase of the TfW websites, integrating
-some of our other websites, and adding new features whilst continuing to
-maintain and improve the existing codebase.
-
-I'm currently supporting another project team at the moment too - their project
-is going live next week - and will look into writing more week- or month-notes
-going forward.
-
-I've continued [working with Neovim](/blog/going-full-vim) as my daily
-IDE/text-editor tool, have continued working on my [freelance development and
-consulting projects](/drupal-php-developer), and started to squeeze in [some
-more live streams](https://oliverdavies.live) too!
-
-[tfw.wales]: https://tfw.wales
-[trc.cymru]: https://trc.cymru
diff --git a/astro/src/content/blog/my-new-drupal-modules.md b/astro/src/content/blog/my-new-drupal-modules.md
deleted file mode 100644
index 3c2cb4c5..00000000
--- a/astro/src/content/blog/my-new-drupal-modules.md
+++ /dev/null
@@ -1,24 +0,0 @@
----
-title: My new Drupal modules
-date: 2012-07-12
-excerpt: After a busy few days, I've released two new contrib Drupal modules.
-tags:
- - accessibility
- - drupal
- - drupal-6
- - drupal-7
- - drupal-modules
- - drupal-planet
----
-
-After a busy few days, I've released two new contrib Drupal modules.
-
-- [Block Aria Landmark Roles](http://drupal.org/project/block_aria_landmark_roles) -
- Inspired by [Block Class](http://drupal.org/project/block_class), this module
- adds additional elements to the block configuration forms that allow users to
- assign a ARIA landmark role to a block.
-- [Nomensa Accessible Media Player](http://drupal.org/project/nomensa_amp) -
- Provides integration with Nomensa's
- [Accessible Media Player](https://github.com/nomensa/Accessible-Media-Player).
-
-Documentation for both to follow shortly on Drupal.org.
diff --git a/astro/src/content/blog/my-sublime-text-2-settings.md b/astro/src/content/blog/my-sublime-text-2-settings.md
deleted file mode 100644
index 375ace33..00000000
--- a/astro/src/content/blog/my-sublime-text-2-settings.md
+++ /dev/null
@@ -1,106 +0,0 @@
----
-title: My Sublime Text 2 settings
-date: 2012-10-25
-excerpt: Sublime Text 2 has been my text editor of choice for the past few months, and I use it at home, in work, and on any virtual machines that I run. So rather than having to manually re-enter my settings each time, I thought that I'd document them here for future reference.
-tags:
- - sublime-text
----
-
-[Sublime Text 2](http://www.sublimetext.com/2) has been my text editor of choice
-for the past few months, and I use it at home, in work, and on any virtual
-machines that I run. So rather than having to manually re-enter my settings each
-time, I thought that I'd document them here for future reference.
-
-These preferences ensure that the code is compliant with
-[Drupal coding standards](http://drupal.org/coding-standards 'Drupal coding standards on Drupal.org') -
-using two spaces instead of a tab, no trailing whitespace, blank line at the end
-of a file etc.
-
-## Preferences
-
-These can be changed by going to Preferences > Settings - User.
-
-```json
-{
- "color_scheme": "Packages/Theme - Aqua/Color Schemes/Tomorrow Night Aqua.tmTheme",
- "default_line_ending": "unix",
- "ensure_newline_at_eof_on_save": true,
- "fallback_encoding": "UTF-8",
- "file_exclude_patterns":
- [
- "*.pyc",
- "*.pyo",
- "*.exe",
- "*.dll",
- "*.obj",
- "*.o",
- "*.a",
- "*.lib",
- "*.so",
- "*.dylib",
- "*.ncb",
- "*.sdf",
- "*.suo",
- "*.pdb",
- "*.idb",
- ".DS_Store",
- "*.class",
- "*.psd",
- "*.db",
- "*.sublime*"
- ],
- "folder_exclude_patterns":
- [
- ".svn",
- ".git",
- ".hg",
- "CVS",
- "FirePHPCore"
- ],
- "font_options":
- [
- "no_bold",
- "no_italic"
- ],
- "font_size": 16.0,
- "highlight_line": true,
- "ignored_packages":
- [
- ],
- "line_padding_bottom": 1,
- "rulers":
- [
- 80
- ],
- "save_on_focus_lost": true,
- "shift_tab_unindent": true,
- "tab_size": 2,
- "theme": "Soda Light.sublime-theme",
- "translate_tabs_to_spaces": true,
- "trim_automatic_white_space": true,
- "trim_trailing_white_space_on_save": true,
- "word_wrap": false
-}
-```
-
-## Key bindings
-
-These can be changed by going to Preferences > Key Bindings - User.
-
-```json
-[
- { "keys": ["alt+s"], "command": "toggle_side_bar" },
- { "keys": ["alt+r"], "command": "reindent" }
-]
-```
-
-## Packages
-
-These are the packages that I currently have installed.
-
-- [DocBlockr](https://github.com/spadgos/sublime-jsdocs 'DocBlockr on GitHub')
-- [Drupal API](https://github.com/BrianGilbert/Sublime-Text-2-Goto-Drupal-API)
-- [LESS](https://github.com/danro/LESS-sublime)
-- [Package Control](http://wbond.net/sublime_packages/package_control)
-- [Sublime CodeIntel](http://github.com/Kronuz/SublimeCodeIntel)
-- [Theme - Soda](https://github.com/buymeasoda/soda-theme)
diff --git a/astro/src/content/blog/neovim-database-plugin-vim-dadbod-ui.md b/astro/src/content/blog/neovim-database-plugin-vim-dadbod-ui.md
deleted file mode 100644
index ab2e5078..00000000
--- a/astro/src/content/blog/neovim-database-plugin-vim-dadbod-ui.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: test
-draft: true
-date: ~
----
diff --git a/astro/src/content/blog/nginx-redirects-query-string-arguments.md b/astro/src/content/blog/nginx-redirects-query-string-arguments.md
deleted file mode 100644
index cc7be79b..00000000
--- a/astro/src/content/blog/nginx-redirects-query-string-arguments.md
+++ /dev/null
@@ -1,57 +0,0 @@
----
-title: Nginx Redirects With Query String Arguments
-date: 2017-01-31
-excerpt: How to redirect from an old domain to a new one, and also to redirect from the root example.com domain to the canonical www subdomain.
-tags:
- - nginx
----
-
-This is an example of how my Nginx configuration looked to redirect from an old
-domain to a new one, and also to redirect from the root `example.com` domain to
-the canonical `www` subdomain.
-
-```nginx
-server {
- listen 80;
-
- server_name example.com;
- server_name my-old-domain.com;
- server_name www.my-old-domain.com;
-
- return 301 https://www.example.com$uri;
-}
-```
-
-It also redirects the URI value, e.g. from `http://example.com/test` to
-`http://example.com/test`, but I noticed recently though that any the query
-string would be lost - e.g. `http://example.com/?test` would redirect to
-`http://www.example.com` and the `?test` would be dropped. The application that
-I built references images based on the query string, so I wanted these to be
-included within the redirect.
-
-This was fixed by making a small change to my `return` statement.
-
-Before:
-
-```nginx
-return 301 https://www.example.com$uri;
-```
-
-After:
-
-```nginx
-return 301 https://www.example.com$uri$is_args$args;
-```
-
-`$is_args` is an empty string if there are no arguments, or a `?` to signify the
-start of the query string. `$args` then adds the arguments (`$query_string`
-could also be used with the same result).
-
-Here is an demo of it working on this website:
-
-
-
-## Resources
-
-- [Query string](https://en.wikipedia.org/wiki/Query_string)
-- [Nginx ngx_http_core_module](http://nginx.org/en/docs/http/ngx_http_core_module.html)
diff --git a/astro/src/content/blog/null-users-system-users-drupal.md b/astro/src/content/blog/null-users-system-users-drupal.md
deleted file mode 100644
index b63109cf..00000000
--- a/astro/src/content/blog/null-users-system-users-drupal.md
+++ /dev/null
@@ -1,155 +0,0 @@
----
-title: Null Users and System Users in Drupal
-date: 2018-08-16
-excerpt: Announcing the Null User and System User modules.
-tags:
- - drupal
- - drupal-7
- - drupal-8
- - drupal-modules
- - drupal-planet
- - php
----
-
-Have you ever needed to have a 'special user' to perform tasks on your Drupal
-site, such as performing actions based on an API request, or for sending an
-internal site message?
-
-If you just create a new user, how do you identify that user going forward? Do
-you hard-code the 'magic' user ID in your custom code? What if the user has a
-different ID on different environments of your site? You could declare it in
-each environment’s settings file and retrieve it from there, but what then if
-you need to do the same on another site? That would mean some duplication of
-code - and something that could have been abstracted and re-used.
-
-I had to do this recently, and rather than just duplicate the code I decided to
-make it into it’s own module - which then became two modules.
-
-## System users
-
-The [System User module][1] provides a re-usable, generic way to denote users as
-'system users', which is not specific to a certain site or environment as this
-is value is stored against each individual user in the database.
-
-'System user' is a term used in Linux, which I thought also applies well to this
-scenario.
-
-From :
-
-> A system account is a user account that is created by an operating system
-> during installation and that is used for operating system defined purposes.
-> System accounts often have predefiend user ids. Examples of system accounts
-> include the root account in Linux.
-
-A system user isn’t an account that we’d expect a person to log in with and
-perform routine tasks like updating content, but rather for the system (site) to
-use to perform tasks like the earlier examples.
-
-### Declaring a user as a system user
-
-System User module adds a base field to Drupal’s User entity, which determines
-whether or not each user is a system user - i.e. if this field is `TRUE`, that
-user is a system user. This means that users can easily be queried to identify
-which are system users, without having to rely on magic, environment and site
-specific user IDs. This also means that we can have multiple system users, if
-needed.
-
-{.border
-.p-1}
-
-In the Drupal 8 version of the module, a `SystemUser` is a custom entity, that
-contains it’s own `create` method for creating new system users. This is a
-essentially a wrapper around `User::create()` that automatically sets the value
-of the system user field as part of the creation.
-
-The original intention is that system users would always be created manually in
-an custom install or update hook, however since releasing the module, I’ve also
-added an install hook to the module to automatically create a new system user
-when the module is installed, basing the username on the site name.
-
-There is also an open issue to add a Drush command to create a new system user,
-and I’d imagine I’ll also add a Drupal Console command too.
-
-### Retrieving system users
-
-Whilst you could easily write your own query that retrieves users based on the
-value of the system user field, but the module contains a `SystemUserManager`
-service that contains methods to do so. It also provides a static helper class
-that determines if a specified user is a system user by checking the value of
-the system user field.
-
-```
-// Retrieve the first system user.
-$system_user = $this->systemUserManager->getFirst();
-
-// Is the specified user a system user?
-$is_system_user = SystemUserManager::isSystemUser($user);
-```
-
-But what do we return if there are no system users? You could return `NULL` or
-`FALSE`, but I decided to take a different approach, which became the second
-module.
-
-## Null users
-
-The [Null User module][2] is an implementation of the [null object pattern][3]
-for users in Drupal 8. In this case, a [NullUser][4] is an extension of Drupal’s
-`AnonymousUserSession`, which means that it inherits sensible defaults to return
-for a non-existent User. Though, through inheritance, the `id`, `getRoles` and
-`hasPermission` methods are overridden to return relevant values.
-
-```php
-use Drupal\Core\Session\AnonymousUserSession;
-
-class NullUser extends AnonymousUserSession {
- ...
-}
-```
-
-Null User module is a dependency of System User in Drupal 8, so When no system
-user is found from the `getFirst()` method, a `NullUser` is returned. Whilst I
-could alternatively have returned `NULL` or `FALSE`, we then would need to check
-if the returned value was an object or not before calling methods on it.
-
-```php
-$system_user = $this->systemUserManager->getFirst(); // Returns NULL or FALSE.
-
-// Need to check if a user was returned or not.
-if (!$system_user) {
- return;
-}
-
-if ($system_user->isActive()) {
- ...
-}
-```
-
-Because instead we’re returning a `NullUser`, which through class inheritance
-has the same methods and properties as a regular user, there is no need to do
-the additional check as you will always receive a relevant object, and the
-expected methods will always be present.
-
-```php
-$system_user = $this->systemUserManager->getFirst(); // Returns a NullUser.
-
-if ($system_user->isActive()) {
- ...
-}
-```
-
-This means we have less code, which also is simpler and more readable.
-
-System User module is the only one that I’m aware of that makes use of Null
-User, but I’ve added a list to the [project page][2] so let me know if you can
-think of any others.
-
-## Resources
-
-- [Null object pattern][3]
-- [Null User module][2]
-- [System User module][1]
-
-[1]: https://www.drupal.org/project/system_user
-[2]: https://www.drupal.org/project/null_user
-[3]: https://en.wikipedia.org/wiki/Null_object_pattern
-[4]: http://cgit.drupalcode.org/null_user/tree/src/NullUser.php?h=8.x-1.x
diff --git a/astro/src/content/blog/open-sublime-text-2-mac-os-x-command-line.md b/astro/src/content/blog/open-sublime-text-2-mac-os-x-command-line.md
deleted file mode 100644
index 596589c0..00000000
--- a/astro/src/content/blog/open-sublime-text-2-mac-os-x-command-line.md
+++ /dev/null
@@ -1,23 +0,0 @@
----
-title: Open Sublime Text 2 from the Mac OS X Command Line
-date: 2012-11-17
-excerpt: How to open Sublime Text from the command line.
-tags:
- - mac-os-x
- - sublime-text
- - terminal
----
-
-How to open Sublime Text from the command line.
-
-Paste the following code into the Mac OS X Terminal, assuming that you've
-installed Sublime Text 2 into the /Applications folder.
-
-```bash
-$ ln -s "/Applications/Sublime Text 2.app/Contents/SharedSupport/bin/subl" ~/bin/sublime
-```
-
-Now you can type `sublime ` open a file or directory in Sublime Text,
-or `sublime .` to open the current directory.
-
-You can also type `sublime --help` to see a list of the available commands.
diff --git a/astro/src/content/blog/presenting-on-tailwind-css-and-ansible-at-cms-philly.md b/astro/src/content/blog/presenting-on-tailwind-css-and-ansible-at-cms-philly.md
deleted file mode 100644
index e669aa45..00000000
--- a/astro/src/content/blog/presenting-on-tailwind-css-and-ansible-at-cms-philly.md
+++ /dev/null
@@ -1,23 +0,0 @@
----
-title: Presenting on Tailwind CSS and Ansible at CMS Philly
-excerpt: I'll be presenting on Tailwind CSS and deployments with Ansible at CMS Philly on May 1st.
-date: 2020-04-24
-tags:
- - ansible
- - ansistrano
- - conference
- - drupal
- - drupal-planet
- - speaking
- - tailwind-css
----
-
-{.mx-auto}
-
-I'm happy to be presenting two talks remotely at this year's [CMS Philly](https://cmsphilly.org) conference (formerly [Drupaldelphia](https://www.drupaldelphia.org)).
-
-The first talk is [Deploying PHP applications with Ansible, Ansible Vault and Ansistrano](/talks/deploying-php-ansible-ansistrano) at 1pm (6pm UK time) where I'll be doing an introduction to Ansible and show how to use Ansistrano to do deploy a Drupal 8 application.
-
-The second talk is [Taking Flight with Tailwind CSS](/talks/taking-flight-with-tailwind-css) at 2pm (7pm UK time) where I'll show how to configure and use Tailwind CSS.
-
-CMS Philly is happening virtually on Friday, May 1st via GoToWebinar.
diff --git a/astro/src/content/blog/presenting-pdf-slides-using-pdfpc-pdf-presenter-console.md b/astro/src/content/blog/presenting-pdf-slides-using-pdfpc-pdf-presenter-console.md
deleted file mode 100644
index 2275139b..00000000
--- a/astro/src/content/blog/presenting-pdf-slides-using-pdfpc-pdf-presenter-console.md
+++ /dev/null
@@ -1,91 +0,0 @@
----
-title: Presenting from PDF slides using pdfpc (PDF Presenter Console)
-excerpt: My notes from using pdfpc (PDF Presenter Console).
-tags:
- - speaking
-date: 2021-04-23
----
-
-I recently started using PDF files for presentation slides and gave [a talk about a tool called rst2pdf](/talks/building-presenting-slide-decks-rst2pdf) that I use to write slides in reStructuredText and convert them to PDF. This blog post is about another tool that I use to present from the PDF file, which is called the [PDF Presenter Console](https://pdfpc.github.io "The pdfpc website") (or `pdfpc`).
-
-This is the basic version that you get by running `pdfpc slides.pdf`:
-
-
-
-
-
-
Image
-
-
-
-
-
-
-
-It opens a speaker notes window that shows the current and next slide, the total number of slides in the presentation, the current slide number, and an increasing amount of time since you started the presentation.
-
-Here are some tips that I usually use with `pdfpc`.
-
-## Setting a duration
-
-If you don't want a timer that shows the amount of time that you've been presenting so far then you can set a duration for the presentation using `pdfpc --duration 10`, and the timer will count down instead.
-
-
-
-
-
-
Image
-
-
-
-
-
-
-
-This is great if your presentation is has a strict end time such as during a conference schedule.
-
-## Setting a start time
-
-As well as a duration, you can add the start time for the presentation by running `pdfpc --start-time=13:00`. This will show you a timer that will count down until the specified start time when you need to start presenting.
-
-
-
-
-
-
Image
-
-
-
-
-
-
-
-Again, this is great if your presentation is has a strict start time such as during a conference.
-
-## Swapping screens
-
-When using both my laptop screen and external monitor for presenting (one for the slides, and the other for the speaker notes) it seems that the windows usually open on the opposite screens to the ones that I want.
-
-I can override this though using the `--switch-screens` option and swap the presentation/presenter screens.
-
-There are also `--presenter-screen` and `--presentation-screen` options to set the monitor to use for each but I usually find that just swapping them works for me.
-
-## Presentation overview
-
-When presenting, you can press the `Tab` key to see an overview of the presentation, with each slide and its number, and where you can easily navigate between slides which is very helpful if, during the Q&A section of the presentation, someone would like to ask a question about or reference a particular slide.
-
-
-
-
-
-
Image
-
-
-
-
-
-
-
-## And more...
-
-There are a lot more options in `pdfpc`. To see more, run `pdfpc --help` or press `?` within the presenter view to see the help page (or `pdfpc --list-bindings`).
diff --git a/astro/src/content/blog/prevent-apache-displaying-text-files-within-web-browser.md b/astro/src/content/blog/prevent-apache-displaying-text-files-within-web-browser.md
deleted file mode 100644
index 5427894b..00000000
--- a/astro/src/content/blog/prevent-apache-displaying-text-files-within-web-browser.md
+++ /dev/null
@@ -1,28 +0,0 @@
----
-title: Prevent Apache from displaying text files within a web browser
-date: 2012-05-23
-excerpt: How to prevent Apache from displaying the contents of files like CHANGELOG.txt.
-tags:
- - apache
- - code
- - drupal
----
-
-When you download [Drupal](http://drupal.org/project/drupal), there are several
-text files that are placed in the root of your installation. You don't want or
-need these to be visible to anyone attempting to view them in a browser -
-especially CHANGELOG.txt as that includes the exact version of Drupal you are
-running and could therefore have security implications.
-
-Rather than delete these files or change the file permissions manually for each
-file, I can add the following lines into my VirtualHost configuration.
-
-```
-
- Order deny,allow
- Deny from all
-
-```
-
-This prevents any files with a .txt extension from being accessed and rendered
-in a web browser.
diff --git a/astro/src/content/blog/proctor-stevenson.md b/astro/src/content/blog/proctor-stevenson.md
deleted file mode 100644
index eeed687e..00000000
--- a/astro/src/content/blog/proctor-stevenson.md
+++ /dev/null
@@ -1,20 +0,0 @@
----
-title: Proctor & Stevenson
-date: 2011-03-31
-excerpt: I’m moving jobs.
-tags:
- - personal
----
-
-2 weeks ago, I handed in my notice of resignation to
-[Horse & Country TV](http://horseandcountry.tv)because I've been offered a new
-role at [Proctor & Stevenson](http://proctors.co.uk) - a Marketing Design and
-Communications agency in Bristol.
-
-Proctors have an [extensive client list](http://www.proctors.co.uk/clients) -
-including [BMW](http://www.proctors.co.uk/clients/bmw-financial-services),
-[Panasonic](http://www.proctors.co.uk/clients/panasonic), the
-[Open University](http://www.proctors.co.uk/clients/open-university) and
-[VOSA](http://www.proctors.co.uk/clients/vosa), and it's going to be a fantastic
-opportunity for me to continue expanding my skillset whilst gaining vital
-experience.
diff --git a/astro/src/content/blog/proctors-hosting-next-drupal-meetup.md b/astro/src/content/blog/proctors-hosting-next-drupal-meetup.md
deleted file mode 100644
index d9dfc034..00000000
--- a/astro/src/content/blog/proctors-hosting-next-drupal-meetup.md
+++ /dev/null
@@ -1,15 +0,0 @@
----
-title: Proctors Hosting the next Drupal Meetup
-date: 2011-05-20
-excerpt: Proctor & Stevenson are going to be hosting the next Bristol & South West Drupal meetup.
-tags:
- - drupal-bristol
- - meetups
----
-
-My employer, [Proctor & Stevenson](http://www.proctors.co.uk), are going to be
-hosting the next Bristol & South West Drupal meetup on the 25th May at our
-offices.
-
-You can [view more details](http://groups.drupal.org/node/147324), or register
-[on our website](http://www.proctors.co.uk/Drupal-SWUG-Meetup).
diff --git a/astro/src/content/blog/psr4-autoloading-test-cases-drupal-7.md b/astro/src/content/blog/psr4-autoloading-test-cases-drupal-7.md
deleted file mode 100644
index c106daf0..00000000
--- a/astro/src/content/blog/psr4-autoloading-test-cases-drupal-7.md
+++ /dev/null
@@ -1,143 +0,0 @@
----
-title: Using PSR-4 Autoloading for your Drupal 7 Test Cases
-excerpt: How to use the PSR-4 autoloading standard for Drupal 7 Simpletest test cases.
-tags:
- - drupal
- - drupal-planet
- - drupal-7
- - testing
- - simpletest
- - php
- - psr
-date: 2020-02-04
----
-
-
{{ page.excerpt }}
-
-## The Traditional Way
-
-The typical way of including test cases in Drupal 7 is to add one or more
-classes within a `.test` file - e.g. `opdavies.test`. This would typically
-include all of the different test cases for that module, and would be placed in
-the root of the module’s directory alongside the `.info` and `.module` files.
-
-In order to load the files, each file would need to be declared within the
-`.info` file for the module.
-
-There is a convention that if you have multiple tests for your project, these
-can be split into different files and grouped within a `tests` directory.
-
-```ini
-; Load a test file at the root of the module
-files[] = opdavies.test
-
-; Load a test file from within a subdirectory
-files[] = tests/foo.test
-files[] = tests/bar.test
-```
-
-## Using the xautoload Module
-
-Whilst splitting tests into separate files makes things more organised, each
-file needs to be loaded separately. This can be made simpler by using the
-[Xautoload module][], which supports wildcards when declaring files.
-
-[xautoload module]: https://www.drupal.org/project/xautoload
-
-```ini
-files[] = tests/**/*.test
-```
-
-This would load all of the `.test` files within the tests directory.
-
-## Using PSR-4 Autoloading
-
-Another option is to use PSR-4 (or PSR-0) autoloading.
-
-This should be a lot more familiar to those who have worked with Drupal 8,
-Symfony etc, and means that each test case is in its own file which is cleaner,
-files have the `.php` extension which is more standard, and the name of the file
-matches the name of the test class for consistency.
-
-To do this, create a `src/Tests` (PSR-4) or `lib/Drupal/{module_name}/Tests`
-(PSR-0) directory within your module, and then add or move your test cases
-there. Add the appropriate namespace for your module, and ensure that
-`DrupalWebTestCase` or `DrupalUnitTestCase` is also namespaced.
-
-```php
-// src/Tests/Functional/OliverDaviesTest.php
-
-namespace Drupal\opdavies\Tests\Functional;
-
-class OliverDaviesTest extends \DrupalWebTestCase {
- // ...
-}
-```
-
-This also supports subdirectories, so you can group classes within `Functional`
-and `Unit` directories if you like.
-
-If you want to see an real-world example, see the Drupal 7 branch of the
-[Override Node Options module][override_node_options].
-
-[override_node_options]:
- https://git.drupalcode.org/project/override_node_options/tree/7.x-1.x
-
-### Digging into the simpletest_test_get_all function
-
-This is the code within `simpletest.module` that makes this work:
-
-```php
-// simpletest_test_get_all()
-
-// ...
-
-$module_dir = DRUPAL_ROOT . '/' . dirname($filename);
-
-// Search both the 'lib/Drupal/mymodule' directory (for PSR-0 classes)
-// and the 'src' directory (for PSR-4 classes).
-foreach (array(
- 'lib/Drupal/' . $name,
- 'src',
-) as $subdir) {
-
- // Build directory in which the test files would reside.
- $tests_dir = $module_dir . '/' . $subdir . '/Tests';
-
- // Scan it for test files if it exists.
- if (is_dir($tests_dir)) {
- $files = file_scan_directory($tests_dir, '/.*\\.php/');
- if (!empty($files)) {
- foreach ($files as $file) {
-
- // Convert the file name into the namespaced class name.
- $replacements = array(
- '/' => '\\',
- $module_dir . '/' => '',
- 'lib/' => '',
- 'src/' => 'Drupal\\' . $name . '\\',
- '.php' => '',
- );
- $classes[] = strtr($file->uri, $replacements);
- }
- }
- }
-}
-```
-
-It looks for a the tests directory (`src/Tests` or
-`lib/Drupal/{module_name}/Tests`) within the module, and then finds any `.php`
-files within it. It then converts the file name into the fully qualified
-(namespaced) class name and loads it automatically.
-
-### Running the Tests
-
-You can still run the tests from within the Simpletest UI, or from the command
-line using `run-tests.sh`.
-
-If you want to run a specific test case using the `--class` option, you will now
-need to include the fully qualified name.
-
-```
-php scripts/run-tests.sh --class Drupal\\opdavies\\Tests\\Functional\\OliverDaviesTest
-```
diff --git a/astro/src/content/blog/published-my-first-docker-images-docker-hub-adr-tools-sculpin-rst2pdf.md b/astro/src/content/blog/published-my-first-docker-images-docker-hub-adr-tools-sculpin-rst2pdf.md
deleted file mode 100644
index bf2bba18..00000000
--- a/astro/src/content/blog/published-my-first-docker-images-docker-hub-adr-tools-sculpin-rst2pdf.md
+++ /dev/null
@@ -1,97 +0,0 @@
----
-title: Published my first Docker images on Docker Hub (ADR Tools, Sculpin, rst2pdf)
-excerpt: I recently released my first images to the Docker Hub, for ADR Tools, the Sculpin site generator, and rst2pdf.
-date: 2021-04-20
-tags:
- - docker
- - rst2pdf
- - sculpin
----
-
-I've used Docker for some time for local development, making use of container images from Docker Hub and creating my own project-specific images, but I hadn't pushed any to [my Docker Hub profile](https://hub.docker.com/u/opdavies) for anyone else to use - until now.
-
-I've pushed several images to Docker Hub recently:
-
-- One for using [ADR Tools](https://github.com/npryce/adr-tools) to work with architectural decision records.
-- Two for generating and serving sites built with the [Sculpin static site generator](https://sculpin.io).
-- One for working with [rst2pdf](https://rst2pdf.org) that I use for presentation slides, with another image coming for watching and automatically re-compiling the PDF.
-
-
-
-
-
-
Image
-
-
-
-
-
-
-
-## ADR Tools
-
-- GitHub: https://github.com/opdavies/docker-image-adr-tools
-- Docker Hub: https://hub.docker.com/r/opdavies/adr-tools
-
-The ADR Tools image a simple one that allows me to initialise and configure ADR Tools itself as well as creating new ADR documents without needing to install `adr-tools` locally.
-
-For example:
-
-```
-# Initialise the ADR directory
-docker run --rm -v $(pwd):/adr opdavies/adr-tools init
-
-# List the current ADRs.
-docker run --rm -v $(pwd):/adr opdavies/adr-tools list
-
-# Create a new ADR.
-docker run --rm -v $(pwd):/adr opdavies/adr-tools new 'A new ADR'
-```
-
-## Sculpin
-
-- GitHub: https://github.com/opdavies/docker-image-sculpin-serve
-- Docker Hub: https://hub.docker.com/r/opdavies/sculpin, https://hub.docker.com/r/opdavies/sculpin-serve
-
-The Sculpin image repository contains two images - one for running Sculpin commands such as `sculpin content:create page` to create a new page, and one for generating and serving the Sculpin site that uses the `sculpin generate` command to generate and serve the site as well as watching for changes.
-
-```
-# Run a "sculpin" CLI command and "composer install" if needed.
-docker run --rm -v $(pwd):/app opdavies/sculpin
-
-# Generate and serve the Sculpin site.
-docker run --rm -p 8000:8000 -v $(pwd):/app opdavies/sculpin-serve
-```
-
-I've tested this with some of my own personal and client Sculpin projects, as well as the official [Sculpin Blog skeleton](https://github.com/sculpin/sculpin-blog-skeleton).
-
-
-
-
-
-
Image
-
-
-
-
-
-
-
-## rst2pdf
-
-- GitHub: https://github.com/opdavies/docker-image-rst2pdf
-- Docker Hub: https://hub.docker.com/r/opdavies/rst2pdf
-
-rst2pdf is a tool that I use primarily for presentation slide decks (I [gave a talk about this](/talks/building-presenting-slide-decks-rst2pdf) at one of the PHP South Wales meetups).
-
-The rst2pdf image installs Python and rst2pdf so that I can easily generate the PDF files from reStructuredText input files, including any extra arguments that are required.
-
-```
-# A simple example.
-docker run --rm -it -v $(pwd):/rst2pdf rst2pdf input.rst
-
-# An example including some additional arguments.
-docker run --rm -it -v $(pwd):/rst2pdf rst2pdf slides.rst -b2 -s main -e preprocess
-```
-
-I'm currently adding an `rst2pdf-watch` image too, similar to `sculpin-watch` that will watch the files using `nodemon` and automatically regenerate the PDF files when files change. I'm not entirely sure of the syntax for this yet but I'll push it to Docker Hub too once I've figured it out and have it working.
diff --git a/astro/src/content/blog/published-my-first-npm-package.md b/astro/src/content/blog/published-my-first-npm-package.md
deleted file mode 100644
index 2937b23e..00000000
--- a/astro/src/content/blog/published-my-first-npm-package.md
+++ /dev/null
@@ -1,117 +0,0 @@
----
-title: Published my first NPM package
-date: 2018-12-16
-excerpt: Yesterday I published my first module onto NPM, and it’s a plugin for Tailwind CSS to be used alongside Vue.js.
-tags:
- - npm
- - tailwind-css
- - vuejs
----
-
-Yesterday I published my first module onto NPM, and it’s a plugin for [Tailwind
-CSS][tailwind] to be used alongside [Vue.js](https://vuejs.org).
-
-The plugin adds classes for showing and hiding elements in different display
-variations in combination with Vue's
-[v-cloak directive](https://vuejs.org/v2/api/#v-cloak), which I originally saw
-in [the first 'Building Kitetail' video](https://youtu.be/XUXpcbYQ_iQ?t=2360).
-These are useful for when you want an element to be visible whilst Vue is
-compiling, and hidden afterwards.
-
-Here is the compiled CSS that is added by the plugin:
-
-```css
-[v-cloak] .v-cloak-block {
- display: block;
-}
-
-[v-cloak] .v-cloak-flex {
- display: flex;
-}
-
-[v-cloak] .v-cloak-hidden {
- display: none;
-}
-
-[v-cloak] .v-cloak-inline {
- display: inline;
-}
-
-[v-cloak] .v-cloak-inline-block {
- display: inline-block;
-}
-
-[v-cloak] .v-cloak-inline-flex {
- display: inline-flex;
-}
-
-[v-cloak] .v-cloak-invisible {
- visibility: hidden;
-}
-
-.v-cloak-block,
-.v-cloak-flex,
-.v-cloak-inline,
-.v-cloak-inline-block,
-.v-cloak-inline-flex {
- display: none;
-}
-```
-
-The `v-cloak` directive exists on an element until Vue finishes compiling, after
-which it is removed. Therefore adding a `v-cloak-block` class to an element will
-make it `display: block` whilst Vue is compiling and the element is cloaked, and
-`display: none` afterwards when the Vue markup is compiled and rendered.
-
-In my `base.html.twig` template, I’ve added `v-cloak` to the wrapper div within
-the `body`.
-
-
-
-```twig
-
-
- {# ... #}
-
-
-```
-
-
-
-Within my `navbar.html.twig` partial, I have a placeholder div that also
-contains the site name, which is instantly visible but has the `v-cloak-block`
-class so it’s hidden once Vue has compiled and the `Navbar` Vue component is
-visible instead.
-
-
-
-```twig
-
-
-
- {{ site.title }}
-
-
-
-
-
-```
-
-
-
-I was originally surprised that these classes weren’t included as part of
-Tailwind or as part of an existing plugin, but as I’ve already used these styles
-on several projects that include Vue.js with Symfony or Sculpin, it made sense
-to extract it into a plugin and make it available as a npm package which I can
-easily add to any project - as well as making it easier to maintain if I need to
-add additional variations at a later point.
-
-**You can view [the package on npmjs.com][npm], and [the code repository on
-GitHub][github].**
-
-[github]: https://github.com/opdavies/tailwindcss-vuejs
-[npm]: https://www.npmjs.com/package/tailwindcss-vuejs
-[tailwind]: https://tailwindcss.com
diff --git a/astro/src/content/blog/publishing-sculpin-sites-with-github-pages.md b/astro/src/content/blog/publishing-sculpin-sites-with-github-pages.md
deleted file mode 100644
index 25ccce3a..00000000
--- a/astro/src/content/blog/publishing-sculpin-sites-with-github-pages.md
+++ /dev/null
@@ -1,113 +0,0 @@
----
-title: Publishing Sculpin Sites with GitHub Pages
-date: 2017-07-13
-excerpt: How I moved my website to GitHub pages.
-tags:
- - github
- - php
- - sculpin
-meta:
- image:
- url: '/images/blog/jackson-octocat.png'
- type: 'image/png'
- height: 200
- width: 451
----
-
-

-
-Earlier this week I moved this site from my personal Linode server to [GitHub
-Pages][0].
-
-This made sense as I already kept the source code in [on GitHub][1], the issue
-was that GitHub Pages doesn’t know how to dynamically parse and generate a
-Sculpin site like it does with some other static site generators. It can though
-parse and serve HTML files, which is what Sculpin generates. It’s just a case of
-how those files are added to GitHub.
-
-I’ve seen different implementations of this, mostly where the Sculpin code is on
-one branch, and the generated HTML code is on a separate `gh-pages` or `master`
-branch (depending on your repository name). I’m not fond of this approach as it
-means automatically checking out and merging branches which can get messy, and
-also it’s weird to look at a repo’s branches page and see one branch maybe tens
-or hundreds of commits both ahead and behind the default branch.
-
-This has been made simpler and tidier now that we can use a `docs` directory
-within the repository to serve content.
-
-
-
-This means that I can simply re-generate the site after making changes and add
-it as an additional commit to my main branch with no need to switch branches or
-perform a merge.
-
-To simplify this, I’ve added a new [publish.sh script][3] into my repository to
-automate the sites. This is how it currently looks:
-
-```bash
-#!/usr/bin/env bash
-
-SITE_ENV="prod"
-
-# Remove the existing docs directory, build the site and create the new
-# docs directory.
-rm -rf ./docs
-vendor/bin/sculpin generate --no-interaction --clean --env=${SITE_ENV}
-touch output_${SITE_ENV}/.nojekyll
-mv output_${SITE_ENV} docs
-
-# Ensure the correct Git variables are used.
-git config --local user.name 'Oliver Davies'
-git config --local user.email oliver@oliverdavies.uk
-
-# Add, commit and push the changes.
-git add --all docs
-git commit -m 'Build.'
-git push origin HEAD
-```
-
-This begins by removing the deleting the existing `docs` directory and
-re-generating the site with the specified environment. Then I add a `.nojekyll`
-file and rename the output directory to replace `docs`.
-
-Now the changes can be added, committed and pushed. Once pushed, the new code is
-automatically served by GitHub Pages.
-
-## HTTPS
-
-GitHub Pages unfortunately does [not support HTTPS for custom domains][7].
-
-As the site was previously using HTTPS, I didn’t want to have to go back to
-HTTP, break any incoming links and lose any potential traffic. To continue using
-HTTPS, I decided to [use Cloudflare][6] to serve the site via their CDN which
-does allow for HTTPS traffic.
-
-## Next Steps
-
-- Enable automatically running `publish.sh` when new changes are pushed to
- GitHub rather than running it manually. I was previously [using Jenkins][4]
- and Fabric for this, though I’m also going to look into using Travis to
- accomplish this.
-- Add the pre-build steps such as running `composer install` and `yarn` to
- install dependencies, and `gulp` to create the front-end assets. This was
- previously done by Jenkins in my previous setup.
-
-## Resources
-
-- [Publishing your GitHub Pages site from a /docs folder on your master
- branch][2]
-- [Bypassing Jekyll on GitHub Pages][5]
-- [Secure and fast GitHub Pages with CloudFlare][6]
-
-[0]: https://pages.github.com
-[1]: https://github.com/opdavies/oliverdavies.uk
-[2]:
- https://help.github.com/articles/configuring-a-publishing-source-for-github-pages/#publishing-your-github-pages-site-from-a-docs-folder-on-your-master-branch
-[3]: https://github.com/opdavies/oliverdavies.uk/blob/master/publish.sh
-[4]: /articles/2015/07/21/automating-sculpin-jenkins
-[5]: https://github.com/blog/572-bypassing-jekyll-on-github-pages
-[6]: https://blog.cloudflare.com/secure-and-fast-github-pages-with-cloudflare
-[7]: https://github.com/blog/2186-https-for-github-pages
diff --git a/astro/src/content/blog/queuing-private-messages-drupal-8.md b/astro/src/content/blog/queuing-private-messages-drupal-8.md
deleted file mode 100644
index 9fcd1d1c..00000000
--- a/astro/src/content/blog/queuing-private-messages-drupal-8.md
+++ /dev/null
@@ -1,84 +0,0 @@
----
-title: Queuing Private Messages in Drupal 8
-date: 2018-02-27
-excerpt: Introducing the Private Message Queue module for Drupal 8.
-tags:
- - drupal
- - drupal-8
- - drupal-modules
- - drupal-planet
- - open-source
----
-
-My current project at [Microserve][0] is a Drupal 8 website that uses the
-[Private Message][1] module for users to send messages to each other.
-
-In some cases though, the threads could contain hundreds of recipients so I
-decided that it would be good to queue the message requests so that they can be
-processed as part of a background process for better performance. The Private
-Message module does not include this, so I've written and released a separate
-[Private Message Queue][2] module.
-
-## Queuing a Message
-
-The module provices a `PrivateMessageQueuer` service
-(`private_message_queue.queuer`) which queues the items via the `queue()`
-method.
-
-The method accepts an array of `User` objects as the messsage recipients, the
-message body text and another user as the message owner. (I’m currently
-considering [whether to make the owner optional][4], and default to the current
-user if one is not specified)
-
-Here is an example:
-
-```php
-$recipients = $this->getRecipients(); // An array of User objects.
-$message = 'Some message text';
-$owner = \Drupal::currentUser();
-
-$queuer = \Drupal::service('private_message_queue.queuer');
-$queuer->queue($recipients, $message, $owner);
-```
-
-These three pieces of data are then saved as part of the queued item. You can
-see these by checking the "queue" table in the database or by running
-`drush queue-list`.
-
-
-
-```
-$ drush queue-list
-Queue Items Class
-private_message_queue 19 Drupal\Core\Queue\DatabaseQueue
-```
-
-## Processing the Queue
-
-The module also provides a `PrivateMessageQueue` queue worker, which processes
-the queued items. For each item, it creates a new private message setting the
-owner and the message body.
-
-It uses the `PrivateMessageThread` class from the Private Message module to find
-for an existing thread for the specified recipients, or creates a new thread if
-one isn't found. The new message is then added to the thread.
-
-The queue is processed on each cron run, so I recommend adding a module like
-[Ultimate Cron][3] so that you can process the queued items frequently (e.g.
-every 15 minutes) and run the heavier tasks like checking for updates etc less
-frequently (e.g. once a day).
-
-You can also process the queue manually with Drush using the
-`drush queue-run ` command - e.g.
-`drush queue-run private_message_queue`.
-
-```
-$ drush queue-run private_message_queue
-Processed 19 items from the private_message_queue queue in 3.34 sec.
-```
-
-[0]: {{site.companies.microserve.url}}
-[1]: https://www.drupal.org/project/private_message
-[2]: https://www.drupal.org/project/private_message_queue
-[3]: https://www.drupal.org/project/ultimate_cron
-[4]: https://www.drupal.org/project/private_message_queue/issues/2948233
diff --git a/astro/src/content/blog/quick-project-switching-phpstorm.md b/astro/src/content/blog/quick-project-switching-phpstorm.md
deleted file mode 100644
index 86b3c980..00000000
--- a/astro/src/content/blog/quick-project-switching-phpstorm.md
+++ /dev/null
@@ -1,67 +0,0 @@
----
-title: Quick Project Switching in PhpStorm
-date: 2018-09-04
-excerpt: How to quickly switch between projects in PhpStorm.
-tags:
- - phpstorm
-has_tweets: true
----
-
-Following a recent conversation on Twitter with
-[socketwench](https://twitter.com/socketwench) about project switching in
-PhpStorm, I thought I’d document my workflow here.
-
-Here is the original tweet and my initial response. I also have a lot of
-PhpStorm projects, and as I’m always working on multiple projects I regularly
-need to switch between them.
-
-{% include 'tweet' with {
- content: '
I think you can start typing and it will filter?
— Oliver Davies (@opdavies) August 28, 2018',
-} %}
-
-On the PhpStorm welcome screen that displays when you first open it, your recent
-projects are displayed on the left-hand side of the screen, and are filterable.
-That means that I can start typing a project name, e.g. `oli`, and I will only
-see projects that start with that input.
-
-{.with-border
-.with-padding}
-
-That’s great when opening a project from scratch, but what about when we’re
-already within a project and just want to be able to switch to another?
-
-{% include 'tweet' with {
- content: '
You can also use 'Open recent' within the actions list, and then filter the list of projects. pic.twitter.com/k8G9iIQNP0
— Oliver Davies (@opdavies) August 28, 2018',
-} %}
-
-There’s also a way to access this list once PhpStorm is open, by clicking 'Open
-Recent' within the File menu. The issue here though is that this list is not
-filterable.
-
-You can also access this list using the keyboard, though the 'Search everywhere'
-or 'Find action' panes, and these are filterable.
-
-{.with-border
-.with-padding}
-
-Once the 'Open Recent' option is selected, you see the same project list as on
-the welcome screen, which is filtered in the same way by starting to type
-potential project names.
-
-{.with-border
-.with-padding}
-
-## Adding a Keyboard Shortcut
-
-We can make this easier by adding a new keyboard shortcut. Within the Keymap
-preferences, you can search for 'Open Recent' and right-click it to add a new
-keyboard shortcut and define the key combination.
-
-{.with-border
-.with-padding}
-
-{.with-border
-.with-padding}
-
-This this shortcut added, you can now use it to instantly bring up your recent
-projects list, filter it and switch project.
diff --git a/astro/src/content/blog/quickest-way-install-sublime-text-2-ubuntu.md b/astro/src/content/blog/quickest-way-install-sublime-text-2-ubuntu.md
deleted file mode 100644
index 96b67336..00000000
--- a/astro/src/content/blog/quickest-way-install-sublime-text-2-ubuntu.md
+++ /dev/null
@@ -1,25 +0,0 @@
----
-title: The Quickest way to Install Sublime Text 2 in Ubuntu
-date: 2013-03-02
-excerpt: After reading numerous blog posts about how to install Sublime Text 2 in Ubuntu, this is definitely the quickest way!
-tags:
- - linux
- - sublime-text
- - ubuntu
----
-
-After reading numerous blog posts about how to install
-[Sublime Text 2](http://www.sublimetext.com/2 'Sublime Text 2') in
-[Ubuntu](http://www.ubuntu.com/2 'Ubuntu'), this is definitely the quickest way!
-
-Just paste the following lines into your Terminal:
-
-```bash
-$ sudo add-apt-repository ppa:webupd8team/sublime-text-2
-$ sudo apt-get update
-$ sudo apt-get install sublime-text
-```
-
-After running this, Sublime Text 2 has been installed within the
-_/usr/lib/sublime-text-2_ directory and can be launched from the Dashboard, or
-by typing `subl`, `sublime-text` or `sublime-text-2` into a Terminal window.
diff --git a/astro/src/content/blog/quickly-apply-patches-using-git-curl-or-wget.md b/astro/src/content/blog/quickly-apply-patches-using-git-curl-or-wget.md
deleted file mode 100644
index 4af01720..00000000
--- a/astro/src/content/blog/quickly-apply-patches-using-git-curl-or-wget.md
+++ /dev/null
@@ -1,29 +0,0 @@
----
-title: Quickly Apply Patches Using Git and curl or wget
-date: 2013-12-24
-excerpt: How to quickly download a patch file and apply it to a Git repository in one line.
-tags:
- - drupal-planet
- - git
----
-
-Testing a patch file is usually a two-step process. First you download the patch
-file from the source, and then you run a separate command to apply it.
-
-You can save time and typing by running the two commands on one line:
-
-```bash
-$ curl http://drupal.org/files/[patch-name].patch | git apply -v
-```
-
-Or, if you don't have curl installed, you can use wget:
-
-```bash
-$ wget -q -O - http://drupal.org/files/[patch-name].patch | git apply -v
-```
-
-These commands need to be run within the root of your Git repository (i.e. where
-the .git directory is).
-
-These snippets were taken from
-[Applying Patches with Git](https://drupal.org/node/1399218) on Drupal.org.
diff --git a/astro/src/content/blog/quickly-import-multiples-images-using-imagefieldimport-module.md b/astro/src/content/blog/quickly-import-multiples-images-using-imagefieldimport-module.md
deleted file mode 100644
index 7bcab6b6..00000000
--- a/astro/src/content/blog/quickly-import-multiples-images-using-imagefieldimport-module.md
+++ /dev/null
@@ -1,44 +0,0 @@
----
-title: Quickly Import Multiples Images Using the Imagefield_Import Module
-date: 2010-05-29
-excerpt: How to use the Imagefield Import module.
-tags:
- - cck
- - drupal
- - drupal-6
- - drupal-planet
- - imagefield
- - imagefield-import
- - photo-gallery
----
-
-**Thanks to Bob at [Mustardseed Media](http://mustardseedmedia.com) for
-[tweeting](http://twitter.com/mustardseedinc/status/14713096905) about this
-module. It's undoubtedly saved me hours of work today alone!**
-
-I've recently started a personal project converting a website to Drupal. It's
-currently a static HTML/CSS site which also uses the
-[Coppermine Photo Gallery](http://coppermine-gallery.net). As part of building
-the new website, I wanted to move all the photos from the existing site onto the
-new one. However, with 1260 photos in 17 albums, this could have been a lengthy
-process!
-
-I created a new Drupal-powered Gallery as described in
-[this screencast](http://lullabot.com/articles/photo-galleries-views-attach) by
-[Jeff Eaton](http://twitter.com/eaton) - using the CCK and Imagefield modules,
-and re-created each of my existing Gallery nodes. Using the
-[Imagefield_Import](http://drupal.org/project/imagefield_import) module, I was
-then able to quickly import the photos into the new Galleries.
-
-I downloaded all the photos from the previous Gallery via FTP, and installed and
-configured the Imagefield_Import module.
-
-I created an 'Import' folder, selected the target field and mode. In this case,
-I want each image to be imported into its own Photo node. I moved the photos for
-the first album into the Import folder, and loaded the 'Import Images' screen
-(admin/content/imagefield_import).
-
-After clicking 'Import', a node is created for each photo, the image is
-uploaded, and added to the selected Gallery.
-
-Just another 1248 photos to go...
diff --git a/astro/src/content/blog/rebuilding-acquia-dashboard-with-vuejs-tailwind-css.md b/astro/src/content/blog/rebuilding-acquia-dashboard-with-vuejs-tailwind-css.md
deleted file mode 100644
index 799d442e..00000000
--- a/astro/src/content/blog/rebuilding-acquia-dashboard-with-vuejs-tailwind-css.md
+++ /dev/null
@@ -1,163 +0,0 @@
----
-title: Rebuilding Acquia’s Dashboard with Vue.js and Tailwind CSS
-excerpt: How I rebuilt Acquia’s dashboard using Vue.js and Tailwind CSS.
-tags:
- - drupal
- - tailwind-css
- - tweet
- - vuejs
-draft: true
-date: ~
-promoted: true
----
-
-After
-[rebuilding Drupal’s Bartik theme](/blog/rebuilding-bartik-with-vuejs-tailwind-css),
-I’ve now used [Vue.js][vue] and [Tailwind CSS][tailwind] to rebuild another
-Drupal related UI - this time it’s [Acquia’s](https://www.acquia.com) web
-hosting dashboard. Again, you can [view the site on Netlify][netlify] and [the
-code on GitHub][github].
-
-## Why?
-
-The same as the Bartik rebuild, this was a good opportunity for me to gain more
-experience with new technologies - Vue in particular - and to provide another
-demonstration of how Tailwind CSS can be used.
-
-Like the Bartik clone, this was originally going to be another single page
-rebuild, however after completing the first page I decided to expand it to
-include three pages which also gave me the opportunity to use
-[Vue Router](https://router.vuejs.org) - something that I had not used
-previously - and to organise a multi-page Vue application.
-
-## Configuring Vue Router
-
-`src/router/index.js`:
-
-```js
-import Vue from 'vue';
-import Router from 'vue-router';
-import Applications from '@/views/Applications';
-import Environment from '@/views/Environment';
-import Environments from '@/views/Environments';
-
-Vue.use(Router);
-
-export default new Router({
- routes: [
- {
- path: '/',
- name: 'applications',
- component: Applications,
- },
- {
- path: '/:id/environments',
- name: 'environments',
- component: Environments,
- props: true,
- },
- {
- path: '/:id/environments/:environmentName',
- name: 'environment',
- component: Environment,
- props: true,
- },
- ],
-});
-```
-
-## Passing in data
-
-`src/data.json`
-
-```json
-{
- "applications": {
- "1": {
- "id": 1,
- "name": "Rebuilding Acquia",
- "machineName": "rebuildingacquia",
- "type": "Drupal",
- "level": "Enterprise",
- "environments": {
- "dev": {
- "name": "Dev",
- "url": "dev.rebuilding-acquia.com",
- "label": "develop"
- },
- "stage": {
- "name": "Stage",
- "url": "stg.rebuilding-acquia.com",
- "label": "master"
- },
- "prod": {
- "name": "Prod",
- "url": "rebuilding-acquia.com",
- "label": "tags/2018-12-21"
- }
- },
- "tasks": [
- {
- "text": "Commit: fdac923 Merge branch 'update-password-policy' refs/heads/master",
- "user": "system",
- "times": {
- "display": "Dec 19, 2018 3:48:29 PM UTC +0000",
- "started": "Dec 19, 2018 3:48:29 PM UTC +0000",
- "completed": "Dec 19, 2018 3:48:29 PM UTC +0000"
- },
- "loading": false,
- "success": true
- }
- ]
- }
- }
-}
-```
-
-## The Environments page
-
-This was the first page that I rebuilt - the Environments page for an
-application that shows the information of the different configured environments.
-
-Vue Router is configured to show the
-
-{% include 'figure' with {
- image: {
- src: '/images/blog/rebuilding-acquia-vue-tailwind/3-environments.png',
- alt: 'A screenshot of the rebuilt Environments page.',
- },
- caption: 'The rebuilt Environments page for an application.',
-} %}
-
-## The applications page
-
-{% include 'figure' with {
- image: {
- src: '/images/blog/rebuilding-acquia-vue-tailwind/1-applications-grid.png',
- alt: 'The rebuild Applications page, with applications displayed in a grid.',
- },
- caption: 'The rebuilt Applications page - grid view',
-} %}
-
-{% include 'figure' with {
- image: {
- src: '/images/blog/rebuilding-acquia-vue-tailwind/2-applications-list.png',
- alt: 'The rebuild Applications page, with applications displayed as a list.',
- },
- caption: 'The rebuilt Applications page - list view',
-} %}
-
-## An environment page
-
-{% include 'figure' with {
- image: {
- src: '/images/blog/rebuilding-acquia-vue-tailwind/4-environment.png',
- alt: 'A screenshot of the rebuilt Environment page.',
- },
- caption: 'The rebuilt page for an environment within an application.',
-} %}
-
-[github]: https://github.com/opdavies/rebuilding-acquia
-[netlify]: https://rebuilding-acquia.oliverdavies.uk
-[tailwind]: https://tailwindcss.com
-[vue]: https://vuejs.org
diff --git a/astro/src/content/blog/rebuilding-bartik-drupals-default-theme-vuejs-tailwind-css-part-2.md b/astro/src/content/blog/rebuilding-bartik-drupals-default-theme-vuejs-tailwind-css-part-2.md
deleted file mode 100644
index 0a100145..00000000
--- a/astro/src/content/blog/rebuilding-bartik-drupals-default-theme-vuejs-tailwind-css-part-2.md
+++ /dev/null
@@ -1,313 +0,0 @@
----
-title: Rebuilding Bartik (Drupal’s Default Theme) with Vue.js and Tailwind CSS - part 2
-date: 2018-12-27
-excerpt: A follow-up to my original post on rebuilding Bartik with Tailwind and Vue.js.
-tags:
- - drupal
- - tailwind-css
- - tweet
- - vuejs
-has_tweets: true
----
-
-In [the original post](/blog/rebuilding-bartik-with-vuejs-tailwind-css) I
-detailed how I built [a clone of Drupal’s Bartik theme][netlify] with
-[Vue.js][vuejs] and [Tailwind CSS][tailwind]. This follow-up post details some
-updates that I’ve made to it since then.
-
-## Customising Tailwind’s colours
-
-During the first version of the page, my thoughts were to not edit the Tailwind
-configuration, however I changed my mind on this whilst working on the
-subsequent updates and did make some changes and customisations to the
-`tailwind.js` file.
-
-By default, Tailwind includes a full colour palette including colours such as
-yellows, oranges, reds that weren’t being used in this page so they were
-removed. This makes the file more readable as well as reduces the number of
-classes that Tailwind generates.
-
-Whist I was changing the colours, I also took the opportunity to tweak the
-values of the remaining colours to more closely match Bartik’s original colours.
-
-I also added a `black-60` class which uses
-[RGBA](https://css-tricks.com/the-power-of-rgba) to provide a semi-transparent
-background. I used this when adding the
-[skip to main content link](#adding-the-skip-to-main-content-link).
-
-```js
-let colors = {
- transparent: 'transparent',
-
- black: '#22292f',
- 'grey-darkest': '#3d4852',
- 'grey-dark': '#8795a1',
- grey: '#b8c2cc',
- 'grey-light': '#dae1e7',
- 'grey-lighter': '#f0f0f0',
- 'grey-lightest': '#F6F6F2',
- white: '#ffffff',
-
- 'black-60': 'rgba(0, 0, 0, .6)',
-
- 'blue-dark': '#2779bd',
- blue: '#3490dc',
- 'blue-light': '#bcdefa',
-
- 'green-dark': '#325E1C',
- green: '#77B159',
- 'green-light': '#CDE2C2',
- 'green-lighter': '#F3FAEE',
-};
-```
-
-## Adding default styling for links
-
-In the first version, every link was individually styled which resulted in a lot
-of duplicate classes and a potential maintenance issue.
-
-I added a `style` section within `Welcome.vue`, and added some default styling
-for links based on their location on the page -
-[extracting some Tailwind components](https://tailwindcss.com/docs/extracting-components).
-
-
-```html
-
- ...
-
-
-
-```
-
-Within the `style` section, I’m able to use Tailwind’s custom `@apply` directive
-to inject it’s rules into more traditional CSS, rather than needing to add them
-onto every link.
-
-```vue-html
-
-```
-
-
-
-## Extracting a Vue component for Drupal blocks
-
-As well as being able to extract re-usable components within Tailwind, the same
-can be done within Vue. As the page could potentially have multiple sidebar
-blocks, I extracted a `SidebarBlock` component which would act as a wrapper
-around the block’s contents.
-
-```vue-html
-// src/components/Sidebar.vue
-
-
-
-
-
-
-```
-
-The component provides the wrapping div and the appropriate classes in a single
-easy-to-maintain location, and
-[uses a slot](https://vuejs.org/v2/guide/components-slots.html) as a placeholder
-for the main content.
-
-That means that within `Welcome.vue`, the markup within the `sidebar-block` tags
-will be used as the block contents.
-
-```html
-
-
My block contents.
-
-```
-
-## Adding the Skip to Main Content Link
-
-One thing
-[that was missing](https://github.com/opdavies/rebuilding-bartik/issues/1) was
-the 'Skip to main content link'. This an accessibility feature that allows for
-users who are navigating the page using only a keyboard to bypass the navigation
-links and skip straight to the main content if they wish by clicking a link that
-is hidden and only visible whilst it’s focussed on.
-
-Here is the markup that I used, which is placed directly after the opening
-`` tag.
-
-```html
-
- Skip to main content
-
-```
-
-I initially tried to implement the same feature on this website using
-[Tailwind’s visually hidden plugin](https://www.npmjs.com/package/tailwindcss-visuallyhidden)
-which also contains a `focussable` class, though I wasn’t able to style it the
-way that I needed. I created my own
-[Tailwind skip link plugin](https://www.npmjs.com/package/tailwindcss-skip-link)
-and moved the re-usable styling there.
-
-To enable the plugin, I needed to add it within the `plugins` section of my
-`tailwind.js` file:
-
-```js
-plugins: [
- require('tailwindcss/plugins/container')(),
- require('tailwindcss-skip-link')(),
-],
-```
-
-I added only the page-specific styling classes to the link (as well as the
-`skip-link` class that the plugin requires) as well as my own focus state to the
-skip link that I did within the `style` section of `App.vue`.
-
-```vue-html
-
-```
-
-{.border}
-
-## Adding the DrupalMessage component
-
-I also added a version of Drupal’s status message as another Vue component. This
-also uses a slot to include the message contents and accepts a
-[prop](https://vuejs.org/v2/guide/components-props.html) for the message type.
-
-```html
-
-
-
-
-
-
-
-
-```
-
-The value of the `type` prop is then used within some computed properties to
-determine the type specific classes to add (e.g. green for success, and red for
-warning), as well as whether or not to include the checkmark SVG image.
-
-```js
-
-```
-
-I did need to make one change to the `tailwind.js` file in order to change the
-border on links when they are hovered over - within `modules` I needed to enable
-the `borderStyle` module for hover and focus states in order for Tailwind to
-generate the additional classes.
-
-```js
-modules: {
- // ...
- borderStyle: ['responsive', 'hover', 'focus'],
- // ...
-}
-```
-
-The message is included within the Welcome component by including the
-`` element, though rather than importing it there, it’s
-registed as a global component so it would be available to any other components
-that could be added in the future.
-
-This is done within `main.js`:
-
-```js
-// ...
-
-Vue.component('drupal-message', require('@/components/DrupalMessage').default);
-
-new Vue({
- render: h => h(App),
-}).$mount('#app');
-```
-
-{.border}
-
-**The updated version is [live on Netlify][netlify], and the [latest source code
-is available on GitHub][github].**
-
-[github]: https://github.com/opdavies/rebuilding-bartik
-[netlify]: https://rebuilding-bartik.oliverdavies.uk
-[tailwind]: https://tailwindcss.com
-[vuejs]: https://vuejs.org
diff --git a/astro/src/content/blog/rebuilding-bartik-drupals-default-theme-vuejs-tailwind-css.md b/astro/src/content/blog/rebuilding-bartik-drupals-default-theme-vuejs-tailwind-css.md
deleted file mode 100644
index 2e8b0344..00000000
--- a/astro/src/content/blog/rebuilding-bartik-drupals-default-theme-vuejs-tailwind-css.md
+++ /dev/null
@@ -1,345 +0,0 @@
----
-title: Rebuilding Bartik (Drupal’s Default Theme) with Vue.js and Tailwind CSS
-date: 2018-11-20
-excerpt: How I rebuilt Drupal’s Bartik theme using Vue.js and Tailwind CSS.
-tags:
- - drupal
- - tailwind-css
- - tweet
- - vuejs
-has_tweets: true
----
-
-Earlier this week, I built a clone of [Drupal][0]’s default theme, Bartik, with
-[Vue.js][1] and [Tailwind CSS][2]. You can [view the code on GitHub][3] and the
-[site itself on Netlify][4].
-
-{% include 'tweet' with {
- content: '
— Oliver Davies (@opdavies) November 20, 2018',
- data_cards: true,
-} %}
-
-## Why build a Bartik clone?
-
-I’m a big fan of utility based styling and Tailwind CSS in particular, I was and
-originally thinking of a way to more easily integrate Tailwind within Drupal -
-something like I’ve since done with the [Tailwind CSS starter kit theme][5].
-Whilst thinking about that, I wondered about doing the opposite - rebuilding
-Drupal (or Bartik) with Tailwind.
-
-Others including [Adam Wathan](https://adamwathan.me) (one of the creators of
-Tailwind CSS) have rebuilt existing UIs like Netlify, YouTube, Twitter, Coinbase
-and Transistor.fm with Tailwind as an opportunity for learning and also to
-demonstrate using Tailwind - this was my opportunity to do the same.
-
-Whilst
-[Drupal itself has adoped React](https://dri.es/drupal-looking-to-adopt-react),
-I’ve personally been looking into Vue.js and have used it for some small
-personal projects, including some elements of the site. So I decided to use Vue
-for the interactive parts of my Bartik clone to create a fully functional clone
-rather than focussing only on the CSS.
-
-## Building a static template with Tailwind
-
-The first stage was to build the desktop version, which was done as a simple
-HTML file with Tailwind CSS pulled in from it’s CDN. This stage took just over
-an hour to complete.
-
-As Tailwind was added via a CDN, there was no opportunity to customise it’s
-configuration, so I needed to use to Tailwind’s default configuration for
-colours, padding, spacing, fonts, breakpoints etc. The page is built entirely
-with classes provided by Tailwind and uses no custom CSS, except for one inline
-style that is used to add the background colour for the Search block, as there
-wasn’t a suitable Tailwind option.
-
-When I decided that I was going to later add some interactivity onto the mobile
-navigation menu, the existing code was ported into a new Vue.js application
-generated by the Vue CLI, with the majority of the markup within a `Welcome`
-component. This meant that Tailwind was also added as a dependency with it’s own
-configuration file, though although I had the opportunity to customise it I
-decided not to and made no changes to it and continued with the default values.
-
-`src/App.vue`:
-
-```
-
-
-
-
-
-
-````
-
-
-## Making it responsive
-
-The second stage began with making the existing desktop version responsive - particularly making the navigation menu behave and appear differently on mobile and tablet screens, and stacking the main content area and the sidebar on mobile screens. This was all achieved using Tailwind’s responsive variants.
-
-```html
-
- ...
-
-````
-
-In this example, the `pb-4` class adds 1rem of bottom padding to the element by
-default, then increases it to 3rem at large screen sizes due to the `lg:pb-12`
-class.
-
-## Adding interactivity
-
-This is how the main navigation menu works on mobile:
-
-
-
-The show and hide text appears next to a hamburger menu, and clicking it toggles
-the visiblity of the menu links which are stacked below, as well as the wording
-of the text itself.
-
-The code for this was moved into a separate `MainMenu` component, which means
-that it was easier to have dedicated data properties for whether the menu was
-open or not, as well as computed properties for building the show/hide text. The
-`open` value can then be used to apply the appropriate classes to the main menu
-to toggle it.
-
-I also moved the links into `data` too - each link is it’s own object with it's
-`title` and `href` values. This means that I can use a `v-for` directive to loop
-over the data items and inject dynamic values, removing the duplication of
-markup which makes the component easier to read and maintain.
-
-`src/components/MainMenu.vue`:
-
-
-
-```vue-html
-
-
-
-
-
-
-
-
-
-
-
-
-
-```
-
-
-
-## The result
-
-The whole task only took around two hours to complete, and although some of the
-colours and spacings are slightly different due to the decision to stick with
-the default Tailwind configuration values, I’m happy with the result.
-
-### The original version
-
-
-
-### The Vue.js and Tailwind CSS version
-
-
-
-
-I’ve also made some additional changes since this version, which are described in [this follow-up post](/blog/rebuilding-bartik-with-vuejs-tailwind-css-part-2).
-
-
-[0]: https://www.drupal.org
-[1]: https://vuejs.org
-[2]: https://tailwindcss.com
-[3]: https://github.com/opdavies/rebuilding-bartik
-[4]: https://rebuilding-bartik.oliverdavies.uk
-[5]: https://www.drupal.org/project/tailwindcss
diff --git a/astro/src/content/blog/reflections-speaking-unifieddiff.md b/astro/src/content/blog/reflections-speaking-unifieddiff.md
deleted file mode 100644
index 72eac389..00000000
--- a/astro/src/content/blog/reflections-speaking-unifieddiff.md
+++ /dev/null
@@ -1,40 +0,0 @@
----
-title: Reflections on speaking at UnifiedDiff
-date: 2012-09-06
-excerpt: Yesterday evening I went along and spoke at the UnifiedDiff meetup in Cardiff.
-tags:
- - speaking
----
-
-Yesterday evening I went along and spoke at the
-[UnifiedDiff meetup](http://www.unifieddiff.co.uk) in Cardiff, having offered
-previously to do a presentation providing an introduction to Drupal.
-
-I'm an experienced Drupal Developer, but not an experienced public speaker
-(although I have done several user training sessions and Drupal demonstrations
-for clients previously), and I think that some of the nerves that I had
-beforehand were apparent during the presentation, and being the first speaker
-for the evening probably didn't help, although I did get a
-[nice tweet](https://twitter.com/craigmarvelley/status/243418608720543745)
-mid-way through.
-
-Initially, after aiming for a 20-minute presentation plus Q&A, I think I wrapped
-up the presentation in around 14 minutes, although I did about 6 minutes of
-answering questions afterwards including the apparently mandatory "Why use
-Drupal compared to WordPress or Joomla?" question, some Drupal 8 and Symfony
-questions, as well as an interesting question about the White House development
-project after I'd listed it within a list of example sites. Next time, I think
-that some more detailed presenter notes are needed. Typically, as soon as it sat
-back in my seat, the majority of things that I'd managed to remember beforehand
-all came flooding back to me and I thought "I should have said that whilst I was
-up speaking".
-
-Overall, considering my inexperience at speaking to this type of audience, I was
-fairly happy with my presentation, although I'm sure that I'll change my mind
-once I've watched the video of it on the UnifiedDiff website. Regardless, I
-think that it was a great experience and I enjoyed doing it, and I'd like to
-thank the organisers of UnifiedDiff for having me speak at their meetup. It was
-great to have a more relaxed conversation with some people after the other
-speakers had been up, and having introduced Drupal I would be more than happy to
-come back and do a more in-depth presentation if there is an interest for me to
-do so.
diff --git a/astro/src/content/blog/renaming-gray-grey-tailwind-css.md b/astro/src/content/blog/renaming-gray-grey-tailwind-css.md
deleted file mode 100644
index 25194d35..00000000
--- a/astro/src/content/blog/renaming-gray-grey-tailwind-css.md
+++ /dev/null
@@ -1,32 +0,0 @@
----
-title: Renaming gray to grey in Tailwind CSS
-excerpt: How to change the colour "gray" to "grey" in Tailwind CSS.
-tags:
- - tailwind-css
-date: 2020-09-04
----
-
-In `tailwind.config.js`:
-
-```
-const { colors } = require('tailwindcss/defaultTheme')
-
-module.exports = {
- purge: ["./public/**/*.html"],
- theme: {
- extend: {
- colors: {
- // Remove the "gray" colours from the theme.
- gray: {},
-
- // Create a new set of "grey" colours, using the original "gray" values.
- grey: colors['gray']
- }
- },
- },
- variants: {},
- plugins: [],
-};
-```
-
-Based on a configuration file from https://github.com/tailwindlabs/tailwindcss-playground.
diff --git a/astro/src/content/blog/restructuring-my-tailwindjs-configuration-files.md b/astro/src/content/blog/restructuring-my-tailwindjs-configuration-files.md
deleted file mode 100644
index 59bc62c2..00000000
--- a/astro/src/content/blog/restructuring-my-tailwindjs-configuration-files.md
+++ /dev/null
@@ -1,236 +0,0 @@
----
-title: Restructuring my tailwind.js configuration files
-date: 2019-03-08
-excerpt: How I’ve started structuring my tailwind.js configuration files in preparation for Tailwind 1.0.
-tags:
- - laravel-mix
- - tailwind-css
----
-
-After watching Adam Wathan’s recent
-["Working on Tailwind 1.0" YouTube video](https://www.youtube.com/watch?v=SkTKN38wSEM)
-and seeing some of the proposed changes to the `tailwind.js` configuration file,
-I’ve started to structure my current config files a little differently in
-preparation for 1.0.
-
-## The current tailwind.js file format
-
-Currently when you run `tailwind init` to create a new config file, it includes
-all of Tailwind’s default values, and then you can add, edit and remove values
-as needed.
-
-Some values like colours, font families, plugins and modules you are likely to
-change for each project, whilst others like shadows, leading, z-index and
-opacity, you’re less likely to need to change.
-
-It’s 952 lines including comments, which is quite long and could potentially be
-daunting for new Tailwind users.
-
-The contents of the full file can be found in the
-[Tailwind CSS documentation](https://tailwindcss.com/docs/configuration#default-configuration),
-or it can be found in
-[various GitHub repositories](https://github.com/tailwindcss/plugin-examples/blob/master/tailwind.js).
-
-## A preview of the new tailwind.js file format
-
-In Adam’s [Laracon Online](https://laracon.net) talk, Tailwind CSS by Example,
-he showed the new configuration file format. Here is a snippet:
-
-```js
-module.exports {
- theme: {
- extend: {
- spacing: {
- 7: '1.75rem',
- },
- },
- colors: {
- white: {
- default: '#fff',
- 20: 'rgba(255,255,255,.2)',
- 40: 'rgba(255,255,255,.4)',
- 60: 'rgba(255,255,255,.6)',
- 80: 'rgba(255,255,255,.8)',
- },
- ...
- }
- ...
- }
-}
-```
-
-You’ll notice that the structure of the file is quite different, and that all of
-the default values have been removed and are now maintained by Tailwind itself.
-
-This means that the configuration file contains only your custom changes, where
-you've either overridden a default value (e.g. colours) or added your own using
-`extend` (e.g. adding another spacing value, as in this example).
-
-I think that's a great improvement and makes the file so much cleaner, and
-easier to read and understand.
-
-## An interim approach
-
-If you don’t want to wait until 1.0, or potentially 0.8, you can get some of
-this functionality now by restructuring your Tailwind configuration file.
-
-Here is the complete `tailwind.js` file for the
-[DrupalCamp Bristol 2019 static landing page](https://dcb-2019-static.netlify.com),
-which uses Tailwind in addition to the existing traditional CSS:
-
-```js
-let defaultConfig = require('tailwindcss/defaultConfig')();
-
-var colors = {
- ...defaultConfig.colors,
- black: '#000',
-};
-
-module.exports = {
- ...defaultConfig,
- colors: colors,
- textColors: colors,
- backgroundColors: colors,
- borderColors: Object.assign({ default: colors['grey-light'] }, colors),
- plugins: [
- require('tailwindcss-interaction-variants')(),
- require('tailwindcss-spaced-items'),
- ],
- modules: {
- ...defaultConfig.modules,
- textStyle: [...defaultConfig.modules.textStyle, 'hocus'],
- },
- options: {
- ...defaultConfig.options,
- prefix: 'tw-',
- important: true,
- },
-};
-```
-
-Here are the steps that I took to create this file:
-
-
-
-
**Get the default configuration**. This is done using `require('tailwindcss/defaultConfig')()`. Essentially this has the same contents as the current `tailwind.js` file, though now it’s owned and maintained within Tailwind itself, and not by the user.
-
Also any new or updated values within the default configuration will be automatically available.
-
This line is present but commented out in the current generated `tailwind.js` file.
-
-
-
-
**Create the colors object.** This will by default override Tailwind’s default colours, however you can add `...defaultConfig.colors` to include them and then add or edit values as needed.
-
In this example, I’m overridding the value used for the `black` colour classes to match the existing colour in the other CSS.
-
-
-
-
**Return the main configuration object.** For sites with no overrides, this could just be `module.exports = defaultConfig` for a minimal configuration.
-
To extend the defaults, add `...defaultConfig` at the beginning.
-
-
-
-
**Assign our colours.** Use them for `colors`, `textColors`, `backgroundColors` and `borderColours`.
-
-
-
-
**Add any plugins**. I use plugins on most projects, in this case I’m using [tailwindcss-interaction-variants](https://www.npmjs.com/package/tailwindcss-interaction-variants) and [tailwindcss-spaced-items](https://www.npmjs.com/package/tailwindcss-spaced-items). Usually the default `container` plugin would be here too.
-
-
-
-
**Add or override modules.** Here I’m adding the `hocus` (hover and focus) variant provided by the interaction variants plugin to the text style classes.
-
-
-
-
**Add or override options.** As this markup was originally from a Drupal website, I needed to override some of the options values. I’ve added the `tw-` prefix to avoid Tailwind classes from clashing with Drupal’s default markup, and set all Tailwind classes to use `!important` so that they override any existing styles.
-
-
-
-This file is only 27 lines long, so considerably shorter than the default file,
-and I think that it’s much easier to see what your additional and overridden
-values are, as well able to quickly recognise whether a class is generated from
-a custom value or from a Tailwind default value.
-
-To move this file to the new format I think would be much easier as there’s no
-default configuration to filter out, and you can move across only what is
-needed.
-
-## Other changes
-
-### Consistent spacing for padding and margin
-
-Similar to defining colours, you could also set some standard spacing values,
-and using those for padding, margin and negative margin to ensure that they are
-all consistent.
-
-In this case, we can use `defaultConfig.margin` to get the default, add or
-override any values, and then assign it to the relevant sections of the main
-object.
-
-```js
-const spacing = {
- ...defaultConfig.margin,
- '2px': '2px',
-};
-
-module.exports = {
- ...defaultConfig,
- // ...
- padding: spacing,
- margin: spacing,
- negativeMargin: spacing,
- // ...
-};
-```
-
-### Picking values with lodash
-
-In the opposite to extending, if we wanted to limit the number of values within
-a part of the configuration, we can do that too. I’d suggest using the
-[pick method](https://lodash.com/docs/4.17.11#pick) provided by
-[Lodash](https://lodash.com).
-
-From the documentation:
-
-> Creates an object composed of the picked object properties.
-
-For example, if we only wanted normal, medium and bold font weights:
-
-```js
-module.exports = {
- ...defaultConfig,
- // ...
- fontWeights: _.pick(defaultConfig.fontWeights, ['normal', 'medium', 'bold']),
- // ...
-};
-```
-
-### Renaming the file
-
-Also in Tailwind 1.0, it seems that the configuration file name is changing from
-`tailwind.js` to `tailwind.config.js`.
-
-If you use [Laravel Mix](https://laravel-mix.com) and the
-[Laravel Mix Tailwind plugin](https://github.com/JeffreyWay/laravel-mix-tailwind)
-like I do on this site (even though it’s a Sculpin site), it will look for a
-`tailwind.js` file by default or you can specify whatever filename you need.
-
-Here is an excerpt of the Tailwind configuration file for this site, using
-`tailwind.config.js`:
-
-```js
-mix
- .postCss('assets/css/app.css', 'source/dist/css')
- .tailwind('tailwind.config.js');
-```
-
-## Looking foward to Tailwind CSS 1.0!
-
-Adam has said that Tailwind 1.0 should be released within a few weeks of the
-time of writing this, I assume once
-[the 1.0 To-Do list](https://github.com/tailwindcss/tailwindcss/issues/692) is
-completed.
-
-I really like some of the improvements that are coming in 1.0, including the new
-configuration file format and the ability to easily add and extend values, as
-well as the file itself now being completely optional.
-
-I can’t wait for it to land!
diff --git a/astro/src/content/blog/review-adminhover-module.md b/astro/src/content/blog/review-adminhover-module.md
deleted file mode 100644
index fcca7695..00000000
--- a/astro/src/content/blog/review-adminhover-module.md
+++ /dev/null
@@ -1,58 +0,0 @@
----
-title: Review of the Admin:hover Module
-date: 2010-08-10
-excerpt: My review of Drupal’s admin:hover module.
-tags:
- - admin:hover
- - administration
- - drupal-6
- - drupal-modules
- - drupal-planet
----
-
-Sorry for the lack of Blog posts lately, but
-[my new job](http://horseandcountry.tv) that I started a few weeks ago has
-certainly been keeping me busy! I've got a few more posts that I'm preparing
-content for, and I'll hopefully be back into my weekly-post routine before too
-long!
-
-Today, I'd like to just give a quick overview of the
-[Admin:hover](http://drupal.org/project/admin_hover) module. It basically adds
-an administrative menu that pops up when you hover over a node or block within
-your Drupal website - the kind of functionality that was present within previous
-versions of the [Admin module](http://drupal.org/project/admin). It also
-integrates well with the [Devel](http://drupal.org/project/devel) and
-[Clone](http://drupal.org/project/node_clone) modules.
-
-I've found this to be extremely useful whilst working on photo galleries etc.
-where multiple nodes are displayed in a grid format and I quickly need to
-publish or unpublish something for testing purposes. No longer do I need to open
-each node, or go into the administration area to perform the required actions.
-
-It is also possible to customise which links are available from within the
-adminstration area. The possible selections that I currently have on this site
-are as follows:
-
-**Node links:**
-
-- Edit
-- Publish
-- Unpublish
-- Promote
-- Unpromote
-- Make sticky
-- Make unsticky
-- Delete
-- Clone
-- Dev load
-- View author
-- Edit author
-- Add
-
-**Block links:**
-
-- Configure block
-- Add block
-
-Although, as I have additional contributed modules installed, some of these may
-not neccassaily be available out of the box.
diff --git a/astro/src/content/blog/review-image-caption-module.md b/astro/src/content/blog/review-image-caption-module.md
deleted file mode 100644
index d7983ec0..00000000
--- a/astro/src/content/blog/review-image-caption-module.md
+++ /dev/null
@@ -1,40 +0,0 @@
----
-title: Review of the Image Caption Module
-date: 2010-08-20
-excerpt: My review of Drupal’s Image Caption module.
-tags:
- - drupal
- - drupal-6
- - drupal-planet
- - image-caption
- - imagefield
----
-
-Up until as recent as last week, whenever I added an image into one of my Blog
-posts, I was manually adding the caption below each image and styling it
-accordingly. That was until I installed the
-[Image Caption](http://drupal.org/project/image_caption) module.
-
-The Image Caption module uses jQuery to dynamically add captions to images. Here
-is a walkthrough of the process that I followed to install and configure the
-module. As always, I used Drush to download and enable the module, then visited
-the Image Caption Settings page (admin/settings/image_caption). Here, I select
-which node types should be included in image captioning. In my case, I only
-wanted this to apply to Blog posts.
-
-As I use the [FileField](http://drupal.org/project/filefield),
-[ImageField](http://drupal.org/project/imagefield) and
-[Insert](http://drupal.org/project/insert) modules to add images to my posts, as
-opposed to via a WYSIWYG editor, I'm able to add the CSS class of 'caption' to
-my images.
-
-Now, all images inserted this way will have the CSS class of 'caption'.
-
-As the Image Caption module uses the image's title tag to create the displayed
-caption, I enabled the custom title text for my Image field so that when I
-upload an image, I'm prompted to enter text for the caption.
-
-This results in a span called `image-caption-container` around the inserted
-image, and a caption below it called `image-caption` containing the text.
-
-All that's left is to style these classes within your CSS stylesheet.
diff --git a/astro/src/content/blog/review-teleport-module.md b/astro/src/content/blog/review-teleport-module.md
deleted file mode 100644
index 3aa995c7..00000000
--- a/astro/src/content/blog/review-teleport-module.md
+++ /dev/null
@@ -1,39 +0,0 @@
----
-title: Review of the Teleport Module
-date: 2010-07-12
-excerpt: My review of Drupal’s Teleport module.
-tags:
- - drupal-planet
- - drupal-6
- - drupal-modules
- - teleport
----
-
-As a heavily-reliant
-[Quicksilver](http://en.wikipedia.org/wiki/Quicksilver_%28software%29) user on
-my MacBook Pro, I was glad when I found the
-[Teleport](http://drupal.org/project/teleport) module for
-[Drupal](http://drupal.org) _(due to Elliott Rothman's
-[tweet](http://twitter.com/elliotttt/status/18044234238))_.
-
-When you press a configurable hot-key, a jQuery dialog box appears where you can
-search for nodes by title or path, or directly enter the path that you want to
-navigate to. This will greatly reduce the number of clicks that I need to
-perform to get to my desired page - even compared to the
-[Admin](http://drupal.org/project/admin) and
-[Administration Menu](http://drupal.org/project/admin_menu) modules.
-
-Although it's not a new module (the first commits were 2 years ago), I hope that
-they are still planning on achieving the list of future directions listed on
-their Drupal.org project page:
-
-- Make interface act more like Quicksilver (i.e. you should only have to press
- Enter once to launch)
-- 'Actions' like Quicksilver: if you select a node, a second input should appear
- with options to go to the View page, Edit page, (un)publish, etc. Same with
- users.
-- Hook into more non-node content, like taxonomy terms and functions in the API
- module.
-
-Personally, this will make navigation around both the front-end and
-administration area of my Drupal sites so much easier.
diff --git a/astro/src/content/blog/running-drupal-88-symfony-local-server.md b/astro/src/content/blog/running-drupal-88-symfony-local-server.md
deleted file mode 100644
index 33de2ccc..00000000
--- a/astro/src/content/blog/running-drupal-88-symfony-local-server.md
+++ /dev/null
@@ -1,323 +0,0 @@
----
-title: Running Drupal 8.8 with the Symfony Local Server
-excerpt: How to use Symfony's local web server to run a Drupal 8.8 website.
-date: 2020-03-09
-tags:
- - drupal
- - drupal-8
- - symfony
----
-
-
-
-
-
-## Installation
-
-
-
-The Symfony server is bundled as part of the `symfony` binary that is available
-to download from .
-
-To install it, run this command:
-
-```bash
-curl -sS https://get.symfony.com/cli/installer | bash
-```
-
-Even though it’s by Symfony, the local webserver works with any type of
-project - including Drupal 8 (and 9) and Drupal 7.
-
-## Getting started
-
-Here are the basic commands to start and stop the server:
-
-```bash
-# Alias for server:start, starts the server
-symfony serve
-
-# Run the server in daemon mode (in the background)
-symfony serve -d
-
-# Display the status of the server
-symfony server:status
-
-# Stop the server
-symfony server:stop
-```
-
-If your Drupal files are within a `web` or `docroot` directory, it will
-automatically be used as the document root for the server, so files are served
-from there if you run the serve command.
-
-If you use a different subdirectory name - one that isn't loaded automatically -
-you can use the `--document-root` option:
-
-```bash
-symfony serve --document-root www
-```
-
-## Different PHP Versions
-
-One of the most useful features of the Symfony server is that it
-[supports multiple versions of PHP](https://symfony.com/doc/current/setup/symfony_server.html#different-php-settings-per-project)
-if you have them installed, and a different version can be selected per
-directory.
-
-This is done by adding a `.php-version` file to the root of the project that
-contains the PHP version to use. For example:
-
-```bash
-echo "7.3" > .php-version
-```
-
-Next time the server is started, this file will be read and the correct version
-of PHP will be used.
-
-If you’re using macOS and want to install another version of PHP, you can do it
-using Homebrew:
-
-```bash
-# Install PHP 7.3
-brew install php@7.3
-```
-
-[Further PHP customisations can be made per project](https://symfony.com/doc/current/setup/symfony_server.html#overriding-php-config-options-per-project)
-by adding a `php.ini` file.
-
-## Securing Sites Locally
-
-The Symfony server allows for serving sites via HTTPS locally by installing its
-own local certificate authority.
-
-If it’s not installed automatically, run this command to install it:
-
-```
-symfony server:ca:install
-```
-
-Now any site will be served via HTTPS by default, and any HTTP requests will be
-automatically redirected.
-
-If you need to run a site with just HTTP, add the `--no-tls` option to the
-`serve` command.
-
-## Adding Databases (and other services) with Docker
-
-The Symfony server has an integration with Docker for providing extra services -
-such as databases that we’ll need to install Drupal.
-
-This is my `docker-compose.yaml` file which defines a `database` service for
-MySQL:
-
-```yaml
-version: '2.1'
-
-services:
- database:
- image: mysql:5.7
- ports: [3306]
- environment:
- MYSQL_ROOT_PASSWORD: secret
- volumes:
- - mysql-data:/var/lib/mysql
-
-volumes:
- mysql-data:
-```
-
-Because port 3306 is exposed, the server recognises it as a database service and
-automatically creates environment variables prefixed with `DATABASE_`.
-
-A list of all the environment variables can be seen by running
-`symfony var:export` (add `| tr " " "\n"` if you want to view each one on a new
-line, and `| sort` if you want to list them alphabetically):
-
-```
-DATABASE_DATABASE=main
-DATABASE_DRIVER=mysql
-DATABASE_HOST=127.0.0.1
-DATABASE_NAME=main
-DATABASE_PASSWORD=secret
-DATABASE_PORT=32776
-DATABASE_SERVER=mysql://127.0.0.1:32776
-DATABASE_URL=mysql://root:secret@127.0.0.1:32776/main?sslmode=disable&charset=utf8mb4
-DATABASE_USER=root
-DATABASE_USERNAME=root
-SYMFONY_DOCKER_ENV=1
-SYMFONY_TUNNEL=
-SYMFONY_TUNNEL_ENV=
-```
-
-Now these environment variables can be used within `settings.php` file to allow
-configure Drupal’s database connection settings:
-
-```php
-// web/sites/default/settings.php
-
-if ($_SERVER['SYMFONY_DEFAULT_ROUTE_URL']) {
- $databases['default']['default'] = [
- 'driver' => $_SERVER['DATABASE_DRIVER'],
- 'host' => $_SERVER['DATABASE_HOST'],
- 'database' => $_SERVER['DATABASE_NAME'],
- 'username' => $_SERVER['DATABASE_USER'],
- 'password' => $_SERVER['DATABASE_PASSWORD'],
- 'port' => $_SERVER['DATABASE_PORT'],
- 'prefix' => '',
- 'namespace' => 'Drupal\\Core\\Database\\Driver\\mysql',
- 'collation' => 'utf8mb4_general_ci',
- ];
-}
-```
-
-To keep things organised, I usually like to split these settings into their own
-file and include it:
-
-```php
-if ($_SERVER['SYMFONY_DEFAULT_ROUTE_URL'] && file_exists(__DIR__ . '/settings.symfony.php')) {
- require_once __DIR__ . '/settings.symfony.php';
-}
-```
-
-## Installing Drupal
-
-Now that Drupal can connect to the (empty) database, we can install the site. I
-usually do this using Drush, which is added as a dependency via Composer.
-
-The command that I’d usually run is:
-
-```bash
-cd web
-
-../vendor/bin/drush site-install
-```
-
-However, this will cause an error like this because Drupal cannot connect to the
-database when Drush is run in this way.
-
-> Error: Class 'Drush\Sql\Sql' not found in Drush\Sql\SqlBase::getInstance()
-
-To fix this, ensure that the command is prefixed with `symfony php`. This will
-ensure that the correct PHP version and configuration is used, and that the
-appropriate environment variables are available.
-
-```bash
-symfony php ../vendor/bin/drush site-install
-```
-
-This also applies to all other Drush commands.
-
-## Custom Domain Names
-
-Currently we can only access the site via the localhost URL with a specific
-port. The port is determined automatically when the server is started so it can
-change if you have multiple projects running.
-
-Symfony server also allows for
-[adding local domain names through a proxy](https://symfony.com/doc/current/setup/symfony_server.html#local-domain-names).
-This is useful if you always want to access the site from the same URL, or if
-the site relies on using a specific URL such as a multisite setup (multiple
-domains served from the same codebase).
-
-{% include 'figure' with {
- image: {
- src: '/images/blog/running-drupal-with-symfony-local-server/proxy.png',
- alt: 'A screenshot of the proxy overview screen, showing three local projects with their local domains, ports and directories.',
- },
- caption: 'The proxy overview screen'
-} only %}
-
-### Setting up a multisite
-
-Here’s an example of how I would use local domains to configure a multisite
-Drupal installation (taken from
-).
-
-The first thing is to add the subdomain to the proxy. In this example, I’m going
-to set up a version of the Umami demo installation profile at
-`https://umami.wip`.
-
-```bash
-# Add umami.wip to the proxy and attach it to this directory
-symfony proxy:domain:attach umami
-```
-
-Now we can add it to Drupal’s `sites.php` file to route requests to the correct
-site directory:
-
-```php
-// web/sites/sites.php
-
-// This maps https://umami.wip to the sites/umami directory
-$sites['umami.wip'] = 'umami';
-```
-
-To create the directory, we can duplicate the `default` site directory and its
-contents.
-
-```
-cp -R web/sites/default web/sites/umami
-```
-
-To create a separate database, we add a new service to the `docker-compose.yaml`
-file and a new MySQL volume to store the data. We can use labels to generate
-site specific environment variables.
-
-```diff
- version: '2.1'
-
- services:
- database:
- image: mysql:5.7
- ports: [3306]
- environment:
- MYSQL_ROOT_PASSWORD: secret
- volumes:
- - mysql-data:/var/lib/mysql
-
-+ database_umami:
-+ image: mysql:5.7
-+ ports: [3306]
-+ environment:
-+ MYSQL_ROOT_PASSWORD: secret
-+ volumes:
-+ - mysql-data-umami:/var/lib/mysql
-+ labels:
-+ com.symfony.server.service-prefix: 'UMAMI_DATABASE'
-
- volumes:
- mysql-data:
-+ mysql-data-umami:
-```
-
-These can then be added to `sites/umami/settings.php`:
-
-```php
-$databases['default']['default'] = [
- 'driver' => $_SERVER['UMAMI_DATABASE_DRIVER'],
- 'host' => $_SERVER['UMAMI_DATABASE_HOST'],
- 'database' => $_SERVER['UMAMI_DATABASE_NAME'],
- 'username' => $_SERVER['UMAMI_DATABASE_USER'],
- 'password' => $_SERVER['UMAMI_DATABASE_PASSWORD'],
- 'port' => $_SERVER['UMAMI_DATABASE_PORT'],
- 'prefix' => '',
- 'namespace' => 'Drupal\\Core\\Database\\Driver\\mysql',
- 'collation' => 'utf8mb4_general_ci',
-];
-```
-
-Now that the Umami site is able to connect to its own database, we can install
-Drupal - specifying the installation profile to use and also the site directory
-to target.
-
-```bash
-symfony php ../vendor/bin/drush site-install \
- demo_umami \
- -l umami \
- --no-interaction
-```
diff --git a/astro/src/content/blog/sculpin-twig-resources.md b/astro/src/content/blog/sculpin-twig-resources.md
deleted file mode 100644
index 0aeb7915..00000000
--- a/astro/src/content/blog/sculpin-twig-resources.md
+++ /dev/null
@@ -1,51 +0,0 @@
----
-title: Sculpin and Twig Resources
-date: 2015-07-19
-excerpt: A list of resources that I compiled whilst preparing for my Sculpin and Twig talk at DrupalCamp North.
-tags:
- - drupalcamp
- - drupalcamp-north
- - sculpin
- - twig
----
-
-Here’s a list of resources that I compiled whilst preparing for my
-[Sculpin and Twig talk](http://drupalcampnorth.org/session/test-drive-twig-sculpin)
-at [DrupalCamp North](http://drupalcampnorth.org).
-
-## General Information
-
--
--
-
-## Where to Get Sculpin
-
--
--
--
--
-
-## Source Code Examples
-
--
-- - the source repository for this
- site.
--
--
--
--
--
--
-- Google for "`sculpin_site.yml site:github.com`" for more examples.
-
-## Videos
-
-- - a YouTube playlist of Sculpin videos.
-
-## Twig
-
--
-- - variables, filters,
- functions, template inheritance, expressions etc.
-- Go to http://twig.sensiolabs.org/{foo} to search for a tag, filter, test or
- function.
diff --git a/astro/src/content/blog/simplifying-drupal-migrations-xautoload.md b/astro/src/content/blog/simplifying-drupal-migrations-xautoload.md
deleted file mode 100644
index d5792ed3..00000000
--- a/astro/src/content/blog/simplifying-drupal-migrations-xautoload.md
+++ /dev/null
@@ -1,135 +0,0 @@
----
-title: Simplifying Drupal Migrations with xautoload
-date: 2016-05-03
-excerpt: How to use the xautoload module to autoload migration classes within your Drupal 7 migration modules.
-tags:
- - autoloading
- - drupal
- - drupal-7
- - drupal-planet
- - php
----
-
-How to use the [xautoload][1] module to autoload migration classes within your
-Drupal 7 migration modules.
-
-## What is xautoload?
-
-[xautoload][1] is a Drupal module that enables the autoloading of PHP classes,
-in the same way that you would do so in a [Composer][2] based project such as
-Drupal 8 or Symfony.
-
-It supports both the [PSR-0][3] and [PSR-4][4] standards, as well as providing a
-wildcard syntax for Drupal’s `file[]` syntax in .info files.
-
-To use it, download and enable it from Drupal.org as you would for any other
-module, and then add it as a dependency within your module. The xautoload
-project page suggests including a minimum version in this format:
-
-```ini
-dependencies[] = xautoload (>= 7.x-5.0)
-```
-
-This will ensure that the version of xautoload is 7.x-5.0 or newer.
-
-## How to use it
-
-### Wildcard syntax for .info files
-
-Here is an example .info file for a migrate module.
-
-```ini
-; foo_migrate.info
-
-name = Foo Migration
-core = 7.x
-package = Foo
-
-files[] = includes/user.inc
-files[] = includes/nodes/article.inc
-files[] = includes/nodes/page.inc
-```
-
-In this example, each custom migration class is stored in it’s own file within
-the `includes` directory, and each class needs to be loaded separately using the
-`files[] = filename` syntax.
-
-One thing that the xautoload module does to enable for the use of wildcards
-within this syntax. By using wildcards, the module file can be simplified as
-follows:
-
-```ini
-files[] = includes/**/*.inc
-```
-
-This will load any .inc files within the `includes` directory as well as any
-sub-directories, like 'node' in the original example.
-
-This means that any new migration classes that are added will be automatically
-loaded, so you don’t need to declare each include separately within
-foo_migrate.info again. The great thing about this approach is that it works
-with the existing directory and file structure.
-
-### Use the PSR-4 structure
-
-If you want to use the [PSR-4][4] approach, you can do that too.
-
-In order to do so, you’ll need to complete the following steps:
-
-1. Rename the `includes` directory to `src`.
-2. Ensure that there is one PHP class per file, and that the file extension is
- `.php` rather than `.inc`.
-3. Ensure that the name of the file matches the name of the class -
- `FooArticleNodeMigration` would be in a file called
- `FooArticleNodeMigration.php`.
-4. Add a namespace to each PHP file. This uses the same format as Drupal 8,
- including the machine name of the module. For example, `Drupal\foo_migrate`.
- - If the class is within a sub-directory, then this will also need to be
- included within the namespace - e.g. `Drupal\foo_migrate\Node`.
- - You’ll also need to import any class names that you are referencing,
- including class names that are you extending, by adding `use` statements at
- the top of the file. You may be able to prefix it with `\` instead (e.g.
- `\DrupalNode6Migration`), but I prefer to use imports.
-
-Now your class may look something like this:
-
-```php
- 'Drupal\foo_migrate\Node\FooArticleNodeMigration',
- 'source_type' => 'story',
- 'destination_type' => 'article',
-);
-```
-
-## Resources
-
-- [xautoload module][1]
-- [migrate module][5]
-- [migrate_d2d module][6]
-- [PSR-0][3]
-- [PSR-4][4]
-
-[1]: https://www.drupal.org/project/xautoload
-[2]: http://getcomposer.org
-[3]: http://www.php-fig.org/psr/psr-0/
-[4]: http://www.php-fig.org/psr/psr-4/
-[5]: https://www.drupal.org/project/migrate
-[6]: https://www.drupal.org/project/migrate_d2d
diff --git a/astro/src/content/blog/site-upgraded-drupal-7.md b/astro/src/content/blog/site-upgraded-drupal-7.md
deleted file mode 100644
index de4ea387..00000000
--- a/astro/src/content/blog/site-upgraded-drupal-7.md
+++ /dev/null
@@ -1,22 +0,0 @@
----
-title: Site Upgraded to Drupal 7
-date: 2012-01-04
-excerpt: As the vast majority of the Drupal websites that I currently work on are built on Drupal 7, I thought that it was time that I upgraded this site.
-tags:
- - drupal
----
-
-As the vast majority of the Drupal websites that I currently work on are built
-on Drupal 7, I thought that it was time that I upgraded this site. Following the
-[core upgrade process](http://drupal.org/node/570162) and the
-[CCK migration process](http://drupal.org/node/1144136), everything was upgraded
-smoothly without any issues.
-
-I've upgraded a handful of essential contrib modules to the latest stable
-version, [Administration Menu](http://drupal.org/project/admin_menu),
-[Views](http://drupal.org/project/views) etc., and will continue upgrading the
-other modules on the site as time allows.
-
-I also prefer [Bartik](http://drupal.org/project/bartik) to
-[Garland](http://drupal.org/project/garland) - but I will be creating a new
-custom theme when I get a chance.
diff --git a/astro/src/content/blog/some-useful-git-aliases.md b/astro/src/content/blog/some-useful-git-aliases.md
deleted file mode 100644
index 339b67d3..00000000
--- a/astro/src/content/blog/some-useful-git-aliases.md
+++ /dev/null
@@ -1,34 +0,0 @@
----
-title: Some Useful Git Aliases
-date: 2014-01-15
-excerpt: Here are some bash aliases that I use and find helpful for quickly writing Git and Git Flow commands.
-tags:
- - git
----
-
-Here are some bash aliases that I use and find helpful for quickly writing Git
-and Git Flow commands.
-
-These should be placed within your `~/.bashrc` or `~/.bash_profile` file:
-
-```bash
-alias gi="git init"
-alias gcl="git clone"
-alias gco="git checkout"
-alias gs="git status"
-alias ga="git add"
-alias gaa="git add --all"
-alias gc="git commit"
-alias gcm="git commit -m"
-alias gca="git commit -am"
-alias gm="git merge"
-alias gr="git rebase"
-alias gps="git push"
-alias gpl="git pull"
-alias gd="git diff"
-alias gl="git log"
-alias gfi="git flow init"
-alias gff="git flow feature"
-alias gfr="git flow release"
-alias gfh="git flow hotfix"
-```
diff --git a/astro/src/content/blog/some-useful-links-using-simpletest-drupal.md b/astro/src/content/blog/some-useful-links-using-simpletest-drupal.md
deleted file mode 100644
index 9f6f5a23..00000000
--- a/astro/src/content/blog/some-useful-links-using-simpletest-drupal.md
+++ /dev/null
@@ -1,19 +0,0 @@
----
-title: Some useful links for using SimpleTest in Drupal
-date: 2013-06-13
-excerpt: Here are some useful links that I've found when researching about unit testing in Drupal using SimpleTest.
-tags:
- - drupal
- - drupal-planet
- - simpletest
- - tdd
- - test-driven-development
- - testing
----
-
-- [An Introduction to Unit Testing in Drupal](http://www.lullabot.com/blog/articles/introduction-unit-testing-drupal 'An Introduction to Unit Testing in Drupal')
-- [Module Developer's Guide to SimpleTest](http://www.lullabot.com/blog/articles/drupal-module-developers-guide-simpletest "Module Developer's Guide to SimpleTest")
-- [SimpleTest Tutorial (Drupal 6)](https://drupal.org/simpletest-tutorial 'SimpleTest Tutorial (Drupal 6)')
-- [SimpleTest Tutorial (Drupal 7)](https://drupal.org/simpletest-tutorial-drupal7 'SimpleTest Tutorial (Drupal 7)')
-- [SimpleTest Reference](https://drupal.org/node/278126 'SimpleTest Reference')
-- [Testing with SimpleTest](https://drupal.org/node/1128366 'Testing with SimpleTest')
diff --git a/astro/src/content/blog/south-wales-drupal-user-group.md b/astro/src/content/blog/south-wales-drupal-user-group.md
deleted file mode 100644
index 30fedffa..00000000
--- a/astro/src/content/blog/south-wales-drupal-user-group.md
+++ /dev/null
@@ -1,20 +0,0 @@
----
-title: The Inaugural Meetup for the South Wales Drupal User Group
-date: 2010-09-26
-excerpt: If you do Drupal and you're in the area, come and join us for the first SWDUG meetup!
-tags:
- - drupal
- - drupal-planet
- - meetups
- - swdug
----
-
-If you do Drupal and you're in the area, come and join us for the first SWDUG
-meetup!
-
-We'll be meeting in the communal area just outside of the
-[SubHub](http://www.subhub.com) HQ, at:
-
-4, The Studios 3 Burt Street Cardiff CF10 5FZ
-
-For more information and to signup, visit .
diff --git a/astro/src/content/blog/speaking-drupalcon-amsterdam.md b/astro/src/content/blog/speaking-drupalcon-amsterdam.md
deleted file mode 100644
index 8bf23594..00000000
--- a/astro/src/content/blog/speaking-drupalcon-amsterdam.md
+++ /dev/null
@@ -1,39 +0,0 @@
----
-title: Speaking at DrupalCon Amsterdam
-date: 2019-07-25
-excerpt: I’m going to be attending DrupalCon Europe again this year, but for the first time as a speaker.
-tags:
- - drupalcon
- - personal
- - speaking
-has_tweets: true
----
-
-
I’ve attended numerous DrupalCons since my first in Prague in 2013, as a delegate, as a [{{site.companies.drupal_association.name}}]({{site.companies.drupal_association.url}}) staff member, and also as a contribution sprint mentor. I’m excited to be attending DrupalCon Amsterdam again this year - but as my first time as a DrupalCon speaker.
— Oliver Davies (@opdavies) July 16, 2019'
-} %}
-
-The session that I’m going to be presenting is a twenty minute version of my
-[Deploying PHP applications with Ansible, Ansible Vault and Ansistrano](/talks/deploying-php-ansible-ansistrano)
-talk.
-
-{% include 'figure' with {
- image: {
- src: '/images/blog/speaking-drupalcon-amsterdam/drupalcon-schedule.jpg',
- alt: 'My session on the DrupalCon Amsterdam schedule.',
- },
- caption: 'My session on the DrupalCon Amsterdam schedule.',
-} %}
-
-I’ve been working with Drupal since 2007 (or maybe 2008), and it was the subject
-of my [first meetup talk](/talks/so-what-is-this-drupal-thing) in 2012. Since
-then I’ve given 48 more talks
-(including one workshop) at various user groups and conferences on a range of
-development and systems administration topics. So it’s a nice conincedence that
-this will be my fiftieth (50th) talk.
-
-Thanks also to my employer,
-[{{site.companies.inviqa.name}}]({{site.companies.inviqa.url}}), who are giving
-me the time and covering my costs to attend the conference.
diff --git a/astro/src/content/blog/speaking-drupalcon-europe-2020.md b/astro/src/content/blog/speaking-drupalcon-europe-2020.md
deleted file mode 100644
index 8be4cab7..00000000
--- a/astro/src/content/blog/speaking-drupalcon-europe-2020.md
+++ /dev/null
@@ -1,17 +0,0 @@
----
-title: Speaking at DrupalCon Europe 2020
-excerpt: I'm excited to be speaking again at DrupalCon, this time online at DrupalCon Europe.
-tags:
- - drupal
- - conferences
- - speaking
-date: 2020-07-30
----
-
-After giving my [Ansible and Ansistrano talk](/talks/deploying-php-ansible-ansistrano) in Amsterdam, I'm excited that another of my talks has been accepted for DrupalCon!
-
-This year, my [TDD - Test-Driven Drupal](/talks/tdd-test-driven-drupal) talk has been accepted for DrupalCon Europe, will is being held online from December 8-11th.
-
-I first gave this talk at DrupalCamp London 2017 and again a number of times over the last few years including at Drupal Developer Days in Lisbon and most recently for the North West (UK) Drupal user group in May. I've always had good feedback from it, and enjoy teaching others about testing and hopefully continue to inspire people to start writing tests themselves.
-
-This is definitely one of my favourite topics. I've enjoyed updating and improving this talk over the years, and I'm looking forward to giving it at DrupalCon this year.
diff --git a/astro/src/content/blog/speaking-remotely-during-covid-19.md b/astro/src/content/blog/speaking-remotely-during-covid-19.md
deleted file mode 100644
index c72af93c..00000000
--- a/astro/src/content/blog/speaking-remotely-during-covid-19.md
+++ /dev/null
@@ -1,84 +0,0 @@
----
-title: Speaking remotely during COVID-19
-excerpt: I've been quite busy during this lockdown, giving talks remotely at conferences and user groups.
-date: 2020-07-07
-tags:
- - speaking
----
-
-I've been quite busy during COVID-19 and various lockdowns, giving talks remotely at conferences and user groups.
-
-In mid-April, I send a tweet with an open offer to any user groups that needed a speaker, with some suggestions for talks that I'd given recently that I could present remotely.
-
-
-
-As well as this, I also applied to some open calls for papers for remote conferences, such as [CMS Philly](https://cmsphilly.org "The CMS Philly conference") (formerly Drupaldelphia) that was taking place online this year.
-
-At the time of writing, these are the talks that I've given remotely or are already planned for future dates. I'll be updating this list going forward as new talks are added, as well as my [talks page](/talks "My upcoming and past talks").
-
-If you'd like me to speak at your online conference or user group and be added to this list, please contact me and we can see if we can find a suitable date.
-
-## Test-Driven Drupal
-
-An overview of automated testing in Drupal, and a demo of building a new Drupal 8 (or 9) module using test driven development.
-
-- [NWDUG](http://nwdrupal.org.uk) - 11th May
-- [BADCamp 2020](https://2020.badcamp.org/session/tdd-test-driven-drupal) - 16th October
-- [DrupalCon Europe 2020](https://events.drupal.org/europe2020/sessions/tdd-test-driven-drupal) - 8th December
-
-## Deploying PHP with Ansible and Ansistrano
-
-How to use Ansible, Ansible Vault and Ansistrano to deploy PHP applications, using a Drupal 8 application for a demo.
-
-- [Drupal Edinburgh](https://www.meetup.com/Drupal-Edinburgh/events/267905594) - 11th March
-- [CMS Philly](https://cmsphilly.org) - 30th April
-- [Drupal Yorkshire](https://www.meetup.com/DrupalYorkshire/events/zwzsfpybchbcc) - 20th May
-- [PHP London](https://www.meetup.com/phplondon/events/270930524) - 4th June
-- [PHP North East](https://www.meetup.com/phpnortheast) - 16th June
-- [PHP Sussex](https://www.meetup.com/PHP-Sussex) - 1st July
-- [Midwest PHP 2021](https://midwestphp.org/talks/1q5XUF2tTdXXLYOoujMkpF/Deploying_PHP_applications_with_Ansible,_Ansible_Vault_and_Ansistrano) - 23rd April 2021
-
-## Taking Flight with Tailwind CSS
-
-An introduction to utility-based CSS and how to use Tailwind CSS in PHP projects using tools such as Webpack Encore and Laravel Mix.
-
-- [CMS Philly](https://cmsphilly.org) - 30th April
-- [PHP Hampshire](https://www.meetup.com/meetup-group-yzpbvTYv) - 8th July
-- [Drupal Yorkshire](https://www.meetup.com/DrupalYorkshire/events/zwzsfpybclbbc) - 20th August
-- [DigitalCamp Atlanta](https://www.drupalcampatlanta.com/2020/sessions/taking-flight-tailwind-css) - 11th September
-- [Bristol JS](https://techtalks.io/events/f8e26038-2561-484e-8a74-7a1e3a0369b8) - 30th September
-- [Drupal Virtual Cafe](https://groups.drupal.org/node/536142) (Drupal Kyiv) - 15th October
-- [PHP Cambridge](https://www.meetup.com/phpcambridge/events/273686561) - 19th January 2021
-- [Nashville PHP](https://www.meetup.com/nashvillephp/events/kzkdwryccdbmb) - 9th February 2021
-
-## Updating to Drupal 9
-
-How to update your site to Drupal 9, and why it's much different to any major Drupal version upgrade before!
-
-- [Drupal NYC](https://ti.to/drupalnyc/meetup-2020-08-05) - 2nd September
-- [Leeds PHP](https://www.meetup.com/leedsphp/events/272504993) - 23rd September
-- [Midwest PHP 2021](https://midwestphp.org/talks/7C0m4I87vq72cDoXvsHFRp/Upgrading_your_site_to_Drupal_9) - 22nd April 2021
-
-## Working with Workspace
-
-- [NWDUG](https://www.meetup.com/nwdrupal/events/272098270) - 11th August (lightning talk)
-- [PHP South West](https://www.meetup.com/php-sw/events/272787346) - 9th September (lightning talk)
-- PHP North West - 2nd February 2021
-
-## Automated Testing and Test-Driven Development in Drupal 8 (workshop)
-
-- [DrupalCamp London](https://drupalcamp.london/training/Automated-Testing-and-Test-Driven-Development-in-Drupal-8) - 13th March (in-person, just before UK lockdown)
-- [DrupalCamp NYC](https://2020.drupalcamp.nyc/training/automated-testing-and-test-driven-development-drupal-8) - 14th November
-
-## Building Slides and Presenting with rst2pdf
-
-- [PHP South Wales](https://www.meetup.com/PHP-South-Wales/events/275625320) - January 28th 2021
-
-## Soaring with Utility CSS and Tailwind (workshop)
-
-- [DrupalCamp Florida 2021](https://www.fldrupal.camp/training/soaring-utility-css-and-tailwind) - Feburary 18th 2021
-
-## Building Static Websites with Sculpin
-
-- [Drupal Yorkshire](https://www.meetup.com/DrupalYorkshire/events/280100968) - 19th August 2021
-- PHP North West - 7th September
diff --git a/astro/src/content/blog/splitting-new-drupal-project-from-repo.md b/astro/src/content/blog/splitting-new-drupal-project-from-repo.md
deleted file mode 100644
index 4805617d..00000000
--- a/astro/src/content/blog/splitting-new-drupal-project-from-repo.md
+++ /dev/null
@@ -1,163 +0,0 @@
----
-title: How to split a new Drupal contrib project from within another repository
-date: 2018-03-10
-excerpt: How to use Git to split a directory from within an existing repository into it’s own.
-tags:
- - drupal
- - drupal-7
- - drupal-8
- - drupal-planet
- - git
- - open-source
----
-
-Yay! You’ve written a new Drupal module, theme or installation profile as part
-of your site, and now you’ve decided to open source it and upload it to
-Drupal.org as a new contrib project. But how do you split it from the main site
-repository into it’s own?
-
-Well, there are a couple of options.
-
-## Does it need to be part of the site repository?
-
-An interesting thing to consider is, does it _need_ to be a part of the site
-repository in the first place?
-
-If from the beginning you intend to contribute the module, theme or distribution
-and it’s written as generic and re-usable from the start, then it _could_ be
-created as a separate project on Drupal.org or as a private repository on your
-Git server from the beginning, and added as a dependency of the main project
-rather than part of it. It could already have the correct branch name and adhere
-to the Drupal.org release conventions and be managed as a separate project, then
-there is no later need to "clean it up" or split it from the main repo at all.
-
-This is how I worked at the [Drupal Association][2] - with all of the modules
-needed for Drupal.org hosted on Drupal.org itself, and managed as a dependency
-of the site repository with Drush Make.
-
-Whether this is a viable option or not will depend on your processes. For
-example, if your code needs to go through a peer review process before releasing
-it, then pushing it straight to Drupal.org would either complicate that process
-or bypass it completely. Pushing it to a separate private repository may depend
-on your team's level of familiarity with [Composer][3], for example.
-
-It does though avoid the “we’ll clean it up and contribute it later” scenario
-which probably happens less than people intend.
-
-## Create a new, empty repository
-
-If the project is already in the site repo, this is probably the most common
-method - to create a new, empty repository for the new project, add everything
-to it and push it.
-
-For example:
-
-```bash
-cd web/modules/custom/my_new_module
-
-# Create a new Git repository.
-git init
-
-# Add everything and make a new commit.
-git add -A .
-git commit -m 'Initial commit'
-
-# Rename the branch.
-git branch -m 8.x-1.x
-
-# Add the new remote and push everything.
-git remote add origin username@git.drupal.org:project/my_new_module.git
-git push origin 8.x-1.x
-```
-
-There is a huge issue with this approach though - **you now have only one single
-commit, and you’ve lost the commmit history!**
-
-This means that you lose the story and context of how the project was developed,
-and what decisions and changes were made during the lifetime of the project so
-far. Also, if multiple people developed it, now there is only one person being
-attributed - the one who made the single new commit.
-
-Also, if I’m considering adding your module to my project, personally I’m less
-likely to do so if I only see one "initial commit". I’d like to see the activity
-from the days, weeks or months prior to it being released.
-
-What this does allow though is to easily remove references to client names etc
-before pushing the code.
-
-## Use a subtree split
-
-An alternative method is to use [git-subtree][0], a Git command that "merges
-subtrees together and split repository into subtrees". In this scenario, we can
-use `split` to take a directory from within the site repo and split it into it’s
-own separate repository, keeping the commit history intact.
-
-Here is the description for the `split` command from the Git project itself:
-
-> Extract a new, synthetic project history from the history of the
-> subtree. The new history includes only the commits (including merges) that
-> affected , and each of those commits now has the contents of
-> at the root of the project instead of in a subdirectory. Thus, the newly
-> created history is suitable for export as a separate git repository.
-
-
-__Note__: This command needs to be run at the top level of the repository. Otherwise you will see an error like "You need to run this command from the toplevel of the working tree.".
-
-To find the path to the top level, run `git rev-parse --show-toplevel`.
-
-
-
-In order to do this, you need specify the prefix for the subtree (i.e. the
-directory that contains the project you’re splitting) as well as a name of a new
-branch that you want to split onto.
-
-```
-git subtree split --prefix web/modules/custom/my_new_module -b split_my_new_module
-```
-
-When complete, you should see a confirmation message showing the branch name and
-the commit SHA of the branch.
-
-```
-Created branch 'split_my_new_module'
-7edcb4b1f4dc34fc3b636b498f4284c7d98c8e4a
-```
-
-If you run `git branch`, you should now be able to see the new branch, and if
-you run `git log --oneline split_my_new_module`, you should only see commits for
-that module.
-
-If you do need to tidy up a particular commit to remove client references etc,
-change a commit message or squash some commits together, then you can do that by
-checking out the new branch, running an interactive rebase and making the
-required amends.
-
-```
-git checkout split_my_new_module
-git rebase -i --root
-```
-
-Once everything is in the desired state, you can use `git push` to push to the
-remote repo - specifying the repo URL, the local branch name and the remote
-branch name:
-
-```
-git push username@git.drupal.org:project/my_new_module.git split_my_new_module:8.x-1.x
-```
-
-In this case, the new branch will be `8.x-1.x`.
-
-Here is a screenshot of example module that I’ve split and pushed to GitLab.
-Notice that there are multiple commits in the history, and each still attributed
-to it’s original author.
-
-
-
-Also, as this is standard Git functionality, you can follow the same process to
-extract PHP libraries, Symfony bundles, WordPress plugins or anything else.
-
-[0]: https://github.com/git/git/blob/master/contrib/subtree/git-subtree.txt
-[1]:
- https://github.com/git/git/blob/master/contrib/subtree/git-subtree.txt#L101-L108
-[2]: {{site.companies.drupal_association.url}}
-[3]: https://getcomposer.org
diff --git a/astro/src/content/blog/streaming-spabby-gary-hockin-about-drupal.md b/astro/src/content/blog/streaming-spabby-gary-hockin-about-drupal.md
deleted file mode 100644
index d536b76d..00000000
--- a/astro/src/content/blog/streaming-spabby-gary-hockin-about-drupal.md
+++ /dev/null
@@ -1,22 +0,0 @@
----
-title: Streaming with Spabby (Gary Hockin) about Drupal
-excerpt: I recently joined my friend Gary on his stream to discuss Drupal.
-tags:
- - drupal
- - php
- - drupal-9
- - streaming
-date: 2020-07-30
----
-
-I recently joined my friend and fellow [PHP South Wales](https://phpsouthwales.uk) regular [Gary Hockin](https://twitter.com/GeeH "Gary on Twitter") (aka GeeH, aka Spabby) on his stream to discuss one of my favourite topics, Drupal.
-
-I've noticed that a lot of Developers within the wider PHP community have maybe used or looked at an earlier version of Drupal, like 4, 5 or 6, but not a more recent version, so this seemed like a good opportunity to discuss and demo some of the modern features and improvements in Drupal to Gary's mostly PHP focussed audience.
-
-You can currently [view the video on Gary's Twitch page](https://www.twitch.tv/videos/689269586), or I've embedded it below.
-
-We touched on the topic of decoupled Drupal, and we're planning a follow-up stream where we pair program and set up Drupal together with a front-end React application, which would be great fun!
-
-
-
-
diff --git a/astro/src/content/blog/style-drupal-6s-taxonomy-lists-php-css-and-jquery.md b/astro/src/content/blog/style-drupal-6s-taxonomy-lists-php-css-and-jquery.md
deleted file mode 100644
index 783df001..00000000
--- a/astro/src/content/blog/style-drupal-6s-taxonomy-lists-php-css-and-jquery.md
+++ /dev/null
@@ -1,75 +0,0 @@
----
-title: Style Drupal 6's Taxonomy Lists with PHP, CSS and jQuery
-date: 2010-04-05
-excerpt: Getting started with Drupal theming by styling Drupal’s taxonomy lists.
-tags:
- - drupal-6
- - drupal-planet
- - drupal-theming
- - taxonomy
----
-
-Whilst developing this, and other Drupal websites for clients, I decided that I
-wanted to categorise content using the taxonomy system. However, I wasn't happy
-with the way that Drupal displayed the terms lists by default, and I started
-comparing this to other websites that I look at.
-
-To start with, I wanted to have something that described what the list was
-displaying - like in the second example above. I wanted to have the words
-'Posted in' displayed before the list of terms. To do this, I had to edit the
-node template file that exists within my theme folder (sites/all/themes). As I
-only wanted this change to affect my Blog posts, the file that I needed to
-change is **node-blog.tpl.php**
-
-I scrolled down until I found the piece of code that displayed the terms list:
-
-```php
-
-
-
-
-
-```
-
-Adding `print t(' Posted in ')` will print the words 'Posted in' before
-outputing the terms.
-
-I then added some CSS to re-size the spacing between the items, and then add the
-commas between them to seperate them:
-
-```css
-.terms ul.links li {
- margin-right: 1px;
- padding: 0;
-}
-
-.terms ul.links li:after {
- content: ",";
-}
-
-.terms ul.links li.last:after {
- content: ".";
-}
-```
-
-I created a file named **script.js** in my theme folder with the following code
-in it. After clearing Drupal's caches, this file is automatically recognised by
-Drupal 6.
-
-```js
-if (Drupal.jsEnabled) {
- $(document).ready(function() {
- $('.terms ul.links li.last').prev().addClass('test');
- })
-}
-```
-
-This code finds the last item in the list, uses **.prev** to select the one
-before it, and then uses **.addClass** to assign it the HTML class of "test". We
-can then use this class to target it with specific CSS.
-
-```css
-.terms ul.links li.test:after {
- content: " and";
-}
-```
diff --git a/astro/src/content/blog/survey-results-my-drupalcon-europe-session-test-driven-drupal.md b/astro/src/content/blog/survey-results-my-drupalcon-europe-session-test-driven-drupal.md
deleted file mode 100644
index 5f4e7eba..00000000
--- a/astro/src/content/blog/survey-results-my-drupalcon-europe-session-test-driven-drupal.md
+++ /dev/null
@@ -1,96 +0,0 @@
----
-title: Survey results from my DrupalCon Europe session (Test-Driven Drupal)
-excerpt: Here are the results from the session survey for my DrupalCon session (Test-Driven Drupal) on Drupal automated testing and test-driven development.
-tags:
- - drupalcon
- - speaking
-date: 2021-01-22
----
-
-In December [I gave a talk at DrupalCon Europe](/blog/test-driven-drupal-presentation-drupalcon-europe) on automated testing and test-driven development in Drupal. At the end of each session, the attendees were shown a survey to complete and the results have just been released to the speakers.
-
-Here are the results from my session, and I've included the screenshot of the graphs at the bottom of this post. I'd like to thank everyone who attended the session live, and those who left valuable feedback afterward.
-
-If you want to see the slides and video for that session, click the link above to see the embedded slides and video.
-
-## Survey results
-
-Attendance: 134
-
-### Did the session description accurately represent the content presented?
-
-* Yes - 96.8%
-* No - 3.2%
-
-Total survey responses: 62
-
-### Overall, how would you rate this session?
-
-* 5 - 44.8%
-* 4 - 29.3%
-* 3 - 19%
-* 2 - 6.9%
-* 1 - 0%
-
-Total survey responses: 58
-
-### How would you rate the speaker(s)'s mastery of this topic?
-
-* Excellent - 64.4%
-* Very good - 24.4%
-* Good - 11.1%
-* Fair - 0%
-* Poor - 0%
-
-Total survey responses: 45
-
-### How would you rate the speaker(s)'s presentation skills?
-
-* Excellent - 46.8%
-* Very good - 31.9%
-* Good - 10.6%
-* Fair - 8.5%
-* Poor - 2.1%
-
-Total survey responses: 47
-
-### How would you rate the speaker(s)’s slides and other session materials?
-
-* Excellent - 47.8%
-* Very good - 30.4%
-* Good - 15.2%
-* Fair - 6.5%
-* Poor - 0%
-
-Total survey responses: 46
-
-### What changes could the speaker(s) have made for you to give it a higher rating?
-
-* A little more insights (e.g. on test environment setup)
-* Everything was perfect! Thank you :)
-* He ist to fast ;)
-* Just felt the end examples were rushed through slightly compared to the introduction at the start.
-* Less examples to more focus.
-* Nothing, was excellent
-* Not to shy and interact afterwards
-* Slower - too much content in too little time
-* Speak a little slower, especially when going through the example code
-* Yes
-
-### What did the speaker(s) do really well?
-
-* Broken down the steps into real clear examples
-* Clear, concise slides, minimal code (Which can be hard to read)
-* CodeBlocks
-* Covers all relevant topics.
-* End to end examples without just being a high level overview.
-* Examples
-* Good examples
-* Good preparation, Good speed
-* Good structured walkthrough
-* Great knowledge
-* Introduce the idea of TDD
-* Yes
-* You explained your workflow very clearly. You have a skill for making tricky concepts very clear. Thanks for a great talk.
-
-
diff --git a/astro/src/content/blog/test-driven-ansible-role-development-molecule.md b/astro/src/content/blog/test-driven-ansible-role-development-molecule.md
deleted file mode 100644
index 50813d4e..00000000
--- a/astro/src/content/blog/test-driven-ansible-role-development-molecule.md
+++ /dev/null
@@ -1,48 +0,0 @@
----
-title: Test-Driven Ansible Role Development with Molecule
-date: 2019-06-02
-excerpt: Some resources that I found for testing Ansible roles with a tool called Molecule.
-tags:
- - ansible
- - molecule
- - testing
- - video
----
-
-I used to maintain a number of [Ansible roles][roles], and I recently wrote one
-for automatically generating `settings.php` files for Drupal projects that I use
-for some client projects as part of the [Ansible and Ansistrano deployment
-process][talk], as it can populate these files with credentials stored in
-Ansible Vault.
-
-I uploaded an initial version of the role [onto GitHub][github], but haven’t yet
-released it onto Ansible Galaxy.
-
-I’d seen in other people’s roles and read elsewhere about writing automated
-tests for Ansible roles using a tool called [Molecule][molecule], and wanted to
-write some tests for this role before publishing it onto Galaxy.
-
-I looked around for resources about Molecule, and found a [blog post by Jeff
-Geerling][jeff-post], but also this YouTube video that I found very helpful.
-
-I’ve since been re-writing the role from scratch based on Molecule, and plan to
-release an official version of it soon.
-
-{% include 'video-embed' with {
- classes: 'video-full',
- video: {
- id: 'DAnMyBZ8-Qs',
- attr: {
- height: '315',
- width: '560',
- }
- }
-} %}
-
-[github]: https://github.com/opdavies/ansible-role-drupal-settings
-[jeff-post]:
- https://www.jeffgeerling.com/blog/2018/testing-your-ansible-roles-molecule
-[molecule]: https://molecule.readthedocs.io
-[roles]:
- https://docs.ansible.com/ansible/latest/user_guide/playbooks_reuse_roles.html
-[talk]: /talks/deploying-php-ansible-ansistrano
diff --git a/astro/src/content/blog/test-driven-drupal-on-gitstore-leanpub.md b/astro/src/content/blog/test-driven-drupal-on-gitstore-leanpub.md
deleted file mode 100644
index db670b81..00000000
--- a/astro/src/content/blog/test-driven-drupal-on-gitstore-leanpub.md
+++ /dev/null
@@ -1,37 +0,0 @@
----
-title: Test-Driven Drupal on Gitstore and Leanpub
-excerpt: The work-in-progress codebase for the example application is now on Gitstore.
-date: 2020-04-22
-tags:
- - drupal
- - drupal-8
- - drupal-association
- - drupal-planet
- - drupalcares
- - testing
- - test-driven-drupal
-has_tweets: true
----
-
-Some time ago, I announced that I was planning on writing a book on automated testing and test driven development with Drupal. I [created a landing page][landing page] and set up a mailing list, but I wasn't sure at that point what I was going to cover or create as part of the book.
-
-
-{% include 'tweet' with {
- class: 'my-6',
- data_cards: true,
- content: '
I'm going to write a book on automated testing in Drupal. Join the mailing list for updates, and I'm happy to take suggestions on what to cover. https://t.co/YXNpe6f8Ft#drupal
— Oliver Davies (@opdavies) May 15, 2018',
-} %}
-
-Being a meetup and DrupalCamp conference organiser, after some thought I decided to build a website for an example conference, and that some of this code would then be included in the book as example content. This seemed to cover most of what I originally wanted, through features like a call for papers for potential speakers to propose sessions, allowing organisers to administer and moderate those proposals, automatically sending notification emails to submitters and displaying the accepted sessions.
-
-I've started building it with Drupal 8.8 and it is [now available on GitStore][gitstore] to purchase access to, including all future updates as I continue building the application - adding new features and upgrading to Drupal 9 once it is released. There are some other interesting things there too, such as using feature flags to enable or disable functionality, and using GitHub Actions to run the tests automatically.
-
-The book itself I've [added a page for on Leanpub][leanpub], and I'll be continuing to add content to it in parallel to building the example codebase. Once there is enough content, I will release the first draft for purchase.
-
-Any purchases that are made via Gitstore or Leanpub, an amount will be donated to the [Drupal Association][] and the [#DrupalCares campaign][drupalcares] to help sustain the Association during COVID-19.
-
-[drupal association]: https://www.drupal.org/association
-[drupalcares]: https://www.drupal.org/association/drupal-cares-challenge
-[gitstore]: https://enjoy.gitstore.app/repositories/opdavies/test-driven-drupal-conference-app
-[landing page]: /test-driven-drupal
-[leanpub]: https://leanpub.com/test-driven-drupal
diff --git a/astro/src/content/blog/test-driven-drupal-presentation-drupalcon-europe.md b/astro/src/content/blog/test-driven-drupal-presentation-drupalcon-europe.md
deleted file mode 100644
index 41393eaa..00000000
--- a/astro/src/content/blog/test-driven-drupal-presentation-drupalcon-europe.md
+++ /dev/null
@@ -1,22 +0,0 @@
----
-title: Test-Driven Drupal presentation from DrupalCon Europe
-excerpt: Links to the video and slides from my automated testing session from DrupalCon Europe.
-tags:
- - drupal
- - drupal-8
- - drupalcon
- - speaking
-date: 2021-01-12
----
-
-Today, the sessions from DrupalCon Europe were posted on the [Drupal Association YouTube channel](https://www.youtube.com/playlist?list=PLpeDXSh4nHjTP7vRC6LCak9adK2yp1P5S), including my session on automated testing and test-driven development in Drupal 8 (and 9):
-
-Here is the video of my presentation:
-
-
-
-
-
-Here is an embedded version of the slides, which I've updated since the talk:
-
-
diff --git a/astro/src/content/blog/testing-tailwind-css-plugins-jest.md b/astro/src/content/blog/testing-tailwind-css-plugins-jest.md
deleted file mode 100644
index d22568af..00000000
--- a/astro/src/content/blog/testing-tailwind-css-plugins-jest.md
+++ /dev/null
@@ -1,284 +0,0 @@
----
-title: Testing Tailwind CSS plugins with Jest
-date: 2019-04-29
-excerpt: How to write tests for Tailwind CSS plugins using Jest.
-tags:
- - javascript
- - jest
- - tailwind-css
- - testing
-promoted: true
----
-
-
-**Note:** The content of this post is based on tests seen in Adam Wathan’s ["Working on Tailwind 1.0" video][working-on-tailwind-video], the Jest documentation website, and existing tests for other Tailwind plugins that I’ve used such as [Tailwind CSS Interaction Variants][tailwindcss-interaction-variants].
-
-
-## Preface
-
-In Tailwind 0.x, there was a `list-reset` utility that reset the list style and
-padding on a HTML list, though it was removed prior to 1.0 and moved into
-Tailwind’s base styles and applied by default.
-
-However, on a few projects I use Tailwind in addition to either existing custom
-styling or another CSS framework, and don’t use `@tailwind base` (formerly
-`@tailwind preflight`) so don’t get the base styles.
-
-Whilst I could re-create this by replacing it with two other classes
-(`list-none` and `p-0`), I decided to write [my own Tailwind CSS plugin][repo]
-to re-add the `list-reset` class. This way I could keep backwards compatibility
-in my projects and only need to add one class in other future instances.
-
-In this post, I’ll use this as an example to show how to write tests for
-Tailwind CSS plugins with a JavaScript testing framework called [Jest][jest].
-
-More information about plugins for Tailwind CSS themselves can be found on the
-[Tailwind website][tailwind-docs-plugins].
-
-## Add dependencies
-
-To start, we need to include `jest` as a dependency of the plugin, as well as
-`jest-matcher-css` to perform assertions against the CSS that the plugin
-generates.
-
-We also need to add `tailwindcss` and `postcss` so that we can use them within
-the tests.
-
-```
-yarn add -D jest jest-matcher-css postcss tailwindcss@next
-```
-
-This could be done with `yarn add` or `npm install`.
-
-## Writing the first test
-
-In this plugin, the tests are going to be added into a new file called
-`test.js`. This file is automatically loaded by Jest based on it’s [testRegex
-setting][jest-testregex-setting].
-
-This is the format for writing test methods:
-
-```js
-test('a description of the test', () => {
- // Perform tasks and write assertions
-});
-```
-
-The first test is to ensure that the correct CSS is generated from the plugin
-using no options.
-
-We do this by generating the plugin’s CSS, and asserting that it matches the
-expected CSS within the test.
-
-```js
-test('it generates the list reset class', () => {
- generatePluginCss().then(css => {
- expect(css).toMatchCss(`
- .list-reset {
- list-style: none;
- padding: 0
- }
- `);
- });
-});
-```
-
-However, there are some additional steps needed to get this working.
-
-### Generating the plugin’s CSS
-
-Firstly, we need to import the plugin’s main `index.js` file, as well as PostCSS
-and Tailwind. This is done at the beginning of the `test.js` file.
-
-```js
-const plugin = require('./index.js');
-const postcss = require('postcss');
-const tailwindcss = require('tailwindcss');
-```
-
-Now we need a way to generate the CSS so assertions can be written against it.
-
-In this case, I’ve created a function called `generatePluginCss` that accepts
-some optional options, processes PostCSS and Tailwind, and returns the CSS.
-
-```js
-const generatePluginCss = (options = {}) => {
- return postcss(tailwindcss())
- .process('@tailwind utilities;', {
- from: undefined,
- })
- .then(result => result.css);
-};
-```
-
-Alternatively, to test the output of a component, `@tailwind utilities;` would
-be replaced with `@tailwind components`.
-
-```js
-.process('@tailwind components;', {
- from: undefined
-})
-```
-
-Whilst `from: undefined` isn’t required, if it’s not included you will get this
-message:
-
-> Without `from` option PostCSS could generate wrong source map and will not
-> find Browserslist config. Set it to CSS file path or to `undefined` to prevent
-> this warning.
-
-### Configuring Tailwind
-
-In order for the plugin to generate CSS, it needs to be enabled within the test,
-and Tailwind’s core plugins need to be disabled so that we can assert against
-just the output from the plugin.
-
-As of Tailwind 1.0.0-beta5, this can be done as follows:
-
-```
-tailwindcss({
- corePlugins: false,
- plugins: [plugin(options)]
-})
-```
-
-In prior versions, each plugin in `corePlugins` needed to be set to `false`
-separately.
-
-I did that using a `disableCorePlugins()` function and [lodash][lodash], using
-the keys from `variants`:
-
-```
-const _ = require('lodash')
-
-// ...
-
-const disableCorePlugins = () => {
- return _.mapValues(defaultConfig.variants, () => false)
-}
-```
-
-### Enabling CSS matching
-
-In order to compare the generated and expected CSS, [the CSS matcher for
-Jest][jest-css-matcher] needs to be required and added using
-[expect.extend][jest-expect-extend].
-
-```js
-const cssMatcher = require('jest-matcher-css')
-
-...
-
-expect.extend({
- toMatchCss: cssMatcher
-})
-```
-
-Without it, you’ll get an error message like _"TypeError: expect(...).toMatchCss
-is not a function"_ when running the tests.
-
-## The next test: testing variants
-
-To test variants we can specify the required variant names within as options to
-`generatePluginCss`.
-
-For example, this is how to enable `hover` and `focus` variants.
-
-```js
-generatePluginCss({ variants: ['hover', 'focus'] });
-```
-
-Now we can add another test that generates the variant classes too, to ensure
-that also works as expected.
-
-```js
-test('it generates the list reset class with variants', () => {
- generatePluginCss({ variants: ['hover', 'focus'] }).then(css => {
- expect(css).toMatchCss(`
- .list-reset {
- list-style: none;
- padding: 0
- }
-
- .hover\\:list-reset:hover {
- list-style: none;
- padding: 0
- }
-
- .focus\\:list-reset:focus {
- list-style: none;
- padding: 0
- }
- `);
- });
-});
-```
-
-## Running tests locally
-
-Now that we have tests, we need to be able to run them.
-
-With Jest included as a dependency, we can update the `test` script within
-`package.json` to execute it rather than returning a stub message.
-
-```diff
-- "test": "echo \"Error: no test specified\" && exit 1"
-+ "test": "jest"
-```
-
-This means that as well as running the `jest` command directly to run the tests,
-we can also run `npm test` or `yarn test`.
-
-After running the tests, Jest will display a summary of the results:
-
-
-
-## Running tests automatically with Travis CI
-
-As well as running the tests locally, they can also be run automatically via
-services like [Travis CI][travis] when a new pull request is submitted or each
-time new commits are pushed.
-
-This is done by adding a `.travis-ci.yml` file to the repository, like this one
-which is based on the [JavaScript and Node.js example][travis-nodejs-example]:
-
-```yaml
-language: node_js
-
-node_js:
- - '8'
-
-cache:
- directories:
- - node_modules
-
-before_install:
- - npm update
-
-install:
- - npm install
-
-script:
- - npm test
-```
-
-With this in place, the project can now be enabled on the Travis website, and
-the tests will be run automatically.
-
-For this plugin, you can see the results at
-.
-
-[jest-css-matcher]: https://www.npmjs.com/package/jest-matcher-css
-[jest-expect-extend]: https://jestjs.io/docs/en/expect#expectextendmatchers
-[jest-testregex-setting]:
- https://jestjs.io/docs/en/configuration#testregex-string-array-string
-[jest]: https://jestjs.io
-[lodash]: https://lodash.com
-[repo]: https://github.com/opdavies/tailwindcss-list-reset
-[tailwind-docs-plugins]: https://tailwindcss.com/docs/plugins
-[tailwindcss-interaction-variants]:
- https://www.npmjs.com/package/tailwindcss-interaction-variants
-[travis-nodejs-example]:
- https://docs.travis-ci.com/user/languages/javascript-with-nodejs
-[travis]: https://travis-ci.org
-[working-on-tailwind-video]: https://www.youtube.com/watch?v=SkTKN38wSEM
diff --git a/astro/src/content/blog/thanks.md b/astro/src/content/blog/thanks.md
deleted file mode 100644
index ac7ce5fe..00000000
--- a/astro/src/content/blog/thanks.md
+++ /dev/null
@@ -1,14 +0,0 @@
----
-title: Thanks
-date: 2014-05-06
-excerpt: Thanks everyone or their comments about my move to the Drupal Association.
-tags:
- - drupal
- - drupal-association
- - personal
----
-
-This is just a quick post to thank everyone for their comments and
-congratulations after my previous post about
-[joining the Drupal Association](/blog/drupal-association/). I’m looking forward
-to my first day in the job tomorrow.
diff --git a/astro/src/content/blog/turning-drupal-module-into-feature.md b/astro/src/content/blog/turning-drupal-module-into-feature.md
deleted file mode 100644
index b34da9b4..00000000
--- a/astro/src/content/blog/turning-drupal-module-into-feature.md
+++ /dev/null
@@ -1,35 +0,0 @@
----
-title: Turning Your Custom Drupal Module into a Feature
-date: 2017-05-20
-excerpt: How to turn a custom Drupal module into a Feature.
-tags:
- - drupal
- - drupal-7
- - drupal-planet
- - features
----
-
-Yesterday I was fixing a bug in an inherited Drupal 7 custom module, and I
-decided that I was going to add some tests to ensure that the bug was fixed and
-doesn’t get accidentially re-introduced in the future. The test though required
-me to have a particular content type and fields which are specific to this site,
-so weren’t present within the standard installation profile used to run tests.
-
-I decided to convert the custom module into a [Feature][0] so that the content
-type and it’s fields could be added to it, and therefore present on the testing
-site once the module is installed.
-
-To do this, I needed to expose the module to the Features API.
-
-All that’s needed is to add this line to the `mymodule.info` file:
-
-```ini
-features[features_api][] = api:2
-```
-
-After clearing the cache, the module is now visible in the Features list - and
-ready to have the appropriate configuration added to it.
-
-
-
-[0]: https://www.drupal.org/project/features
diff --git a/astro/src/content/blog/tweets-drupalcamp-london.md b/astro/src/content/blog/tweets-drupalcamp-london.md
deleted file mode 100644
index 13506a2b..00000000
--- a/astro/src/content/blog/tweets-drupalcamp-london.md
+++ /dev/null
@@ -1,69 +0,0 @@
----
-title: Tweets from DrupalCamp London
-date: 2018-03-04
-excerpt: I wasn’t able to make it to DrupalCamp London, but here are some of the tweets that I saw.
-tags:
- - drupal
- - drupalcamp
- - drupalcamp-london
-has_tweets: true
----
-
-In the end, I wasn’t able to make it to DrupalCamp London because of the heavy
-snow that’s hit the UK over the last few days. I did though keep a close eye on
-Twitter and still had good conversations with some of the attendees, so it did
-feel that in some ways I was still part of the conference.
-
-Thanks to [@ChandeepKhosa](https://twitter.com/ChandeepKhosa),
-[@OrangePunchUK](https://twitter.com/OrangePunchUK),
-[@hussainweb](https://twitter.com/hussainweb),
-[@littlepixiez](https://twitter.com/littlepixiez),
-[@cferthorney](https://twitter.com/cferthorney) and others for taking the time
-to tweet whilst enjoying the event.
-
-Here are some of my favourites that I saw, and no snow next year, please!
-
-
This weekend at @DrupalCampLDN will be 5 years since my 1st #Drupal conference. It was life-changing, leading to travel across Europe learning, being inspired & speaking at 25 others. Thanks everyone who helped shape my journey, see you soon! #DCLondonpic.twitter.com/BeulE0XqET
A great weekend. Thanks to the organisers for putting on a great show. Thanks to @ReasonDigital for sending me. Lots of new stuff to try out on Monday! https://t.co/Xxvl7ZYcqj
A huge huge huge thank you to all our sponsors, speakers, volunteers, attendees and everyone else involved in that Camp. It was a fantastic weekend! Look out for the post Camp Survey and more! #DCLondon
diff --git a/astro/src/content/blog/uis-ive-rebuilt-tailwind-css.md b/astro/src/content/blog/uis-ive-rebuilt-tailwind-css.md
deleted file mode 100644
index 044ab8d4..00000000
--- a/astro/src/content/blog/uis-ive-rebuilt-tailwind-css.md
+++ /dev/null
@@ -1,22 +0,0 @@
----
-title: UIs that I've Rebuilt with Tailwind CSS
-excerpt: A collection of all of the UIs that I've rebuilt using Tailwind CSS for talk demos etc.
-tags:
- - css
- - tailwind-css
-date: 2020-11-02
----
-
-Like Adam Wathan and other Tailwind CSS users, I've rebuilt a number of existing websites and user interfaces with [Tailwind CSS](https://tailwindcss.com), either for practice, to try out some new features, or for a demo for a talk where I like to have a relevant example for that audience.
-
-I thought that I'd list them all here, and keep the list up to date for future reference. Most of them are [tagged on GitHub](/tailwind-repos), though I have been using [Tailwind Play](https://play.tailwindcss.com) for the newest ones.
-
-Here is the list (last updated in November 2020):
-
-- [Bartik](https://rebuilding-bartik.oliverdavies.uk) (Drupal's default theme), built with Vue.js. I've also made a version using Alpine JS.
-- [Acquia's hosting dashboard](https://rebuilding-acquia.oliverdavies.uk), built with Vue.js.
-- [The WordPress 2019 theme](https://wp-tailwind.oliverdavies.uk), built for WordCamp Bristol 2019.
-- [Symfony.com website](http://rebuilding-symfony.oliverdavies.uk), built for Leeds PHP meetup.
-- [Bristol JS website](https://rebuilding-bristol-js.oliverdavies.uk), built with Vue.js for Bristol JS meetup.
-- [Platform.sh's hosting dashboard](https://rebuilding-platformsh.oliverdavies.uk) - in progress.
-- [Pantheon's hosting dashboard](/rebuilding-pantheon) - in progress.
diff --git a/astro/src/content/blog/updating-features-adding-components-using-drush.md b/astro/src/content/blog/updating-features-adding-components-using-drush.md
deleted file mode 100644
index 144da7e7..00000000
--- a/astro/src/content/blog/updating-features-adding-components-using-drush.md
+++ /dev/null
@@ -1,74 +0,0 @@
----
-title: Updating Features and Adding Components Using Drush
-date: 2014-10-21
-excerpt: How to update features on the command line using Drush.
-tags:
- - drupal
- - drupal-planet
- - drush
- - features
----
-
-If you use the [Features module](http://drupal.org/project/features) to manage
-your Drupal configuration, it can be time consuming to update features through
-the UI, especially if you are working on a remote server and need to keep
-downloading and uploading files.
-
-If you re-create a feature through the UI, you'll be prompted to download a new
-archive of the feature in its entirety onto your local computer. You could
-either commit this into a local repository and then pull it remotely, or use a
-tool such as SCP to upload the archive onto the server and commit it from there.
-You can simplify this process by using [Drush](http://drush.org).
-
-## Finding Components
-
-To search for a component, use the `drush features-components` command. This
-will display a list of all components on the site. As we're only interested in
-components that haven't been exported yet, add the `--not-exported` option to
-filter the results.
-
-To filter further, you can also use the `grep` command to filter the results.
-For example, `drush features-components --not-exported field_base | grep foo`,
-would only return non-exported field bases containing the word "foo".
-
-The result is a source and a component, separated by a colon. For example,
-`field_base:field_foo`.
-
-## Exporting the Feature
-
-Once you have a list of the components that you need to add, you can export the
-feature. This is done using the `drush features-export` command, along with the
-feature name and the component names.
-
-For example:
-
-```bash
-$ drush features-export -y myfeature field_base:field_foo field_instance:user-field_foo
-```
-
-In this example, the base for field_boo and it's instance on the user object is
-being added to the "myfeature" feature.
-
-If you are updating an existing feature, you'll get a message informing you that
-the module already exists and asking if you want to continue. This is fine, and
-is automatically accepted by including `-y` within the command. If a feature
-with the specified name doesn't exist, it will be created.
-
-If you're creating a new feature, you can define where the feature will be
-created using the `--destination` option.
-
-Once complete, you will see a confirmation message.
-
-> Created module: my feature in sites/default/modules/custom/features/myfeature
-
-## The Result
-
-Once finished, the feature is updated in it's original location, so there's no
-download of the feature and then needing to re-upload it. You can add and commit
-your changes into Git or continue with your standard workflow straight away.
-
-## Useful Links
-
-- [The Features project page on Drupal.org](http://www.drupal.org/project/features)
-- [The "drush features-components" command](http://www.drushcommands.com/drush-6x/features/features-components)
-- [The "drush features-export" command](http://www.drushcommands.com/drush-6x/features/features-export)
diff --git a/astro/src/content/blog/updating-forked-github-repos.md b/astro/src/content/blog/updating-forked-github-repos.md
deleted file mode 100644
index e4602b03..00000000
--- a/astro/src/content/blog/updating-forked-github-repos.md
+++ /dev/null
@@ -1,121 +0,0 @@
----
-title: Updating Forked Repositories on GitHub
-date: 2015-06-18
-excerpt: I just had to update a repo that I forked on GitHub. This is how I did it. Did I do it the correct way?
-tags:
- - git
- - github
- - phpstorm
- - sculpin
----
-
-I just had to update a repo that I forked on GitHub. This is how I did it. Did I
-do it the correct way?
-
-## Sculpin
-
-People may or may not know, but this site runs on
-[Sculpin](https://sculpin.io/), a PHP based static site generator (this may be
-the first time that I've mentioned it on this site). The source code is hosted
-on [GitHub](https://github.com/opdavies/oliverdavies.uk), and I've listed the
-site on the [Community page](https://sculpin.io/community/) on the Sculpin
-website.
-
-To get it there, I forked the
-[main sculpin.io repository](https://github.com/sculpin/sculpin.io) so that I
-had [my own copy](https://github.com/opdavies/sculpin.io), created a branch,
-made my additions and submitted a pull request. Easy enough!
-
-## New Domain
-
-In the last week or so, I've changed this site URL from .co.uk to just .uk, and
-also updated the GitHub repo URL to match, so I wanted to update the Community
-page to use the correct URL.
-
-There had been commits to the main repo since my pull request was merged, I
-didn't want to delete my repo and fork again, and making any changes against and
-old codebase isn't best practice, so I wanted to merge the latest changes into
-my forked repo before I did anything else - just to check that I didn't break
-anything!
-
-## Updating my Local Repo
-
-I had a quick look for a _Update my fork_ button or something, but couldn't see
-one to I added the main repository as an additional remote called `upstream` and
-fetched the changes.
-
-```bash
-$ git remote add upstream https://github.com/sculpin/sculpin.io.git
-
-$ git fetch upstream
-remote: Counting objects: 33, done.
-remote: Total 33 (delta 6), reused 6 (delta 6), pack-reused 27
-Unpacking objects: 100% (33/33), done.
-From https://github.com/sculpin/sculpin.io
-* [new branch] master -> upstream/master
-* [new branch] pr/4 -> upstream/pr/4
-```
-
-Now my local site knows about the upstream repo, and I could rebase the changes
-(`git pull upstream master` should have worked too) and push them back to
-origin.
-
-```bash
-$ git rebase upstream/master
-First, rewinding head to replay your work on top of it...
-...
-Fast-forwarded master to upstream/master.
-
-$ git push origin master
-```
-
-This seems to have worked OK - the commits are still authored by the correct
-people and at the correct date and time - and I went ahead and created a new
-feature branch and pull request based on that master branch.
-
-{% include 'figure' with {
- image: {
- src: '/images/blog/forked-github-repo-commits.png',
- alt: 'The commits on my master branch after rebasing',
- },
- caption: 'The commits on my forked master branch after rebasing and pushing. All good!',
-} %}
-
-{% include 'figure' with {
- image: {
- src: '/images/blog/my-commit-to-the-rebased-branch.png',
- alt: 'The new feature branch with my additional commit',
- },
- caption: 'The new feature branch with the new commit.',
-} %}
-
-## Is There a Better Way?
-
-Did I miss something? Is there a recommended and/or better way to update your
-forked repos, maybe through the UI? Please
-send
-me a tweet with any comments.
-
-## Up
-
-**December 2015:** I’ve found that PhpStorm has an option available to rebase a
-fork from within the IDE. This is within the _VCS_ > _Git_ menu.
-
-I believe that it will use an existing "upstream" remote if it exists, otherwise
-it will add one automatically for you, linking to the repository that you forked
-from.
-
-Once you’ve completed the rebase, you can then push your updated branch either
-from the terminal, or using the _Push_ command from the same menu.
-
-
-
-It would be great to see something similar added to
-[hub](https://hub.github.com) too (I’ve created
-[an issue](https://github.com/github/hub/issues/1047))!
-
-## Resources
-
-- [PhpStorm - Advanced GitHub Integration: Rebase My GitHub Fork (blog post)](http://blog.jetbrains.com/idea/2011/02/advanced-github-integration-rebase-my-github-fork/)
-- [Rebasing a GitHub fork inside PhpStorm (video)](https://www.youtube.com/watch?v=Twy-dhVgN4k)
-- [hub](https://hub.github.com) - makes Git better with GitHub
diff --git a/astro/src/content/blog/updating-override-node-options-tests.md b/astro/src/content/blog/updating-override-node-options-tests.md
deleted file mode 100644
index dbf62193..00000000
--- a/astro/src/content/blog/updating-override-node-options-tests.md
+++ /dev/null
@@ -1,239 +0,0 @@
----
-title: Updating Override Node Options Tests
-date: 2017-05-05
-excerpt: ~
-tags:
- - drupal
- - drupal-modules
- - drupal-planet
- - testing
-draft: true
----
-
-Recently, I reviewed [a patch][1] in the [Override Node Options][2] module issue
-queue. For those not familiar with it, the module adds extra permissions for
-node options like "authored by" and "published on" which are normally only
-available to users with the `administer nodes` permission. What the patch does
-is to optionally add another set of permissions that enable options for all
-content types - e.g. "override published option for all node types", in addition
-to or instead of the content type specific ones.
-
-It was quite an old issue and the latest patch needed to be re-rolled due to
-merge conflicts, but the existing tests still passed. Though as no new tests
-were added for the new functionality, these needed to be added before I
-committed it.
-
-## Reviewing the Existing Tests
-
-The first thing to do was to run the existing tests and check that they still
-passed. I do this on the command line by typing
-`php scripts/run-tests.sh --class OverrideNodeOptionsTestCase`.
-
-```
-Drupal test run
----------------
-
-Tests to be run:
- - Override node options (OverrideNodeOptionsTestCase)
-
-Test run started:
- Saturday, April 29, 2017 - 14:44
-
-Test summary
-------------
-
-Override node options 142 passes, 0 fails, 0 exceptions, and 38 debug messages
-
-Test run duration: 32 sec
-```
-
-After confirming that the existing tests still passed, I reviewed them to see
-what could be re-used.
-
-This is one of the original tests:
-
-```php
-/**
- * Test the 'Authoring information' fieldset.
- */
-protected function testNodeOptions() {
- $this->adminUser = $this->drupalCreateUser(array(
- 'create page content',
- 'edit any page content',
- 'override page published option',
- 'override page promote to front page option',
- 'override page sticky option',
- 'override page comment setting option',
- ));
- $this->drupalLogin($this->adminUser);
-
- $fields = array(
- 'status' => (bool) !$this->node->status,
- 'promote' => (bool) !$this->node->promote,
- 'sticky' => (bool) !$this->node->sticky,
- 'comment' => COMMENT_NODE_OPEN,
- );
- $this->drupalPost('node/' . $this->node->nid . '/edit', $fields, t('Save'));
- $this->assertNodeFieldsUpdated($this->node, $fields);
-
- $this->drupalLogin($this->normalUser);
- $this->assertNodeFieldsNoAccess($this->node, array_keys($fields));
-}
-```
-
-The first part of the test is creating and logging in a user with some content
-type specific override permissions (`$this->adminUser`), and then testing that
-the fields were updated when the node is saved. The second part is testing that
-the fields are not visible for a normal user without the extra permissions
-(`$this->normalUser`), which is created in the `setUp()` class' method.
-
-To test the new "all types" permissions, I created another user to test against
-called `$generalUser` and run the first part of the tests in a loop.
-
-## Beginning to Refactor the Tests
-
-With the tests passing, I was able to start refactoring.
-
-```php
-// Create a new user with content type specific permissions.
-$specificUser = $this->drupalCreateUser(array(
- 'create page content',
- 'edit any page content',
- 'override page published option',
- 'override page promote to front page option',
- 'override page sticky option',
- 'override page comment setting option',
-));
-
-foreach (array($specificUser) as $account) {
- $this->drupalLogin($account);
-
- // Test all the things.
- ...
-}
-```
-
-I started with a small change, renaming `$this->adminUser` to `$specificUser` to
-make it clearer what permissions it had, and moving the tests into a loop so
-that the tests can be repeated for both users.
-
-After that change, I ran the tests again to check that everything still worked.
-
-## Adding Failing Tests
-
-The next step is to start testing the new permissions.
-
-```php
-...
-
-$generalUser = $this->drupalCreateUser(array());
-
-foreach (array($specificUser, $generalUser) as $account) {
- $this->drupalLogin($account);
-
- // Test all the things.
-}
-```
-
-I added a new `$generalUser` to test the general permissions and added to the
-loop, but in order to see the tests failing intially I assigned it no
-permissions. When running the tests again, 6 tests have failed.
-
-```
-Test summary
-------------
-
-Override node options 183 passes, 6 fails, 0 exceptions, and 49 debug messages
-
-Test run duration: 28 sec
-```
-
-Then it was a case of re-adding more permissions to the user and seeing the
-number of failures decrease, confirming that the functionality was working
-correctly.
-
-TODO: Add another example.
-
-## Gotchas
-
-There was a bug that I found where a permission was added, but wasn't used
-within the implementation code. After initially expecting the test to pass after
-adding the permission to `$generalUser` and the test still failed, I noticed
-that the
-
-This was fixed by adding the extra code into `override_node_options.module`.
-
-```diff
-- $form['comment_settings']['#access'] |= user_access('override ' . $node->type . ' comment setting option');
-+ $form['comment_settings']['#access'] |= user_access('override ' . $node->type . ' comment setting option') || user_access('override all comment setting option');
-```
-
-The other issue that I found was within `testNodeRevisions`.
-`assertNodeFieldsUpdated()` was failing after being put in a loop as the `vid`
-was not the same as what was expected.
-
-Note: You can get more verbose output from `run-tests.sh` by adding the
-`--verbose` option.
-
-> Node vid was updated to '3', expected 2.
-
-```diff
-- $fields = array(
-- 'revision' => TRUE,
-- );
-- $this->drupalPost('node/' . $this->node->nid . '/edit', $fields, t('Save'));
-- $this->assertNodeFieldsUpdated($this->node, array('vid' => $this->node->vid + 1));
-+ $generalUser = $this->drupalCreateUser(array(
-+ 'create page content',
-+ 'edit any page content',
-+ 'override all revision option',
-+ ));
-+
-+ foreach (array($specificUser, $generalUser) as $account) {
-+ $this->drupalLogin($account);
-+
-+ // Ensure that we have the latest node data.
-+ $node = node_load($this->node->nid, NULL, TRUE);
-+
-+ $fields = array(
-+ 'revision' => TRUE,
-+ );
-+ $this->drupalPost('node/' . $node->nid . '/edit', $fields, t('Save'));
-+ $this->assertNodeFieldsUpdated($node, array('vid' => $node->vid + 1));
-+ }
-```
-
-The crucial part of this change was the addition of
-`$node = node_load($this->node->nid, NULL, TRUE);` to ensure that the latest
-version of the node was loaded during each loop.
-
-## Conclusion
-
-- Ensure that the existing tests were passing before starting to refactor.
-- Start with small changes and continue to run the tests to ensure that nothing
- has broken.
-- After the first change, I committed it as `WIP: Refactoring tests`, and used
- `git commit --amend --no-edit` to amend that commit each time I had refactored
- another test. After the last refactor, I updated the commit message.
-- It’s important to see tests failing before making them pass. This was achieved
- by initially assigning no permissions to `$generalUser` so that the fails
- failed and then added permissions and re-run the tests to ensure that the
- failure count decreased with each new permission.
-
-With the refactoring complete, the number of passing tests increased from 142
-to 213.
-
-```
-Override node options 213 passes, 0 fails, 0 exceptions, and 60 debug messages
-
-Test run duration: 25 sec
-```
-
-
-
-[Here][3] are my full changes from the previous patch, where I added the new
-tests as well as some small refactors.
-
-[1]: https://www.drupal.org/node/974730
-[2]: https://www.drupal.org/project/override_node_options
-[3]: https://www.drupal.org/files/issues/interdiff_25712.txt
diff --git a/astro/src/content/blog/upgrading-dransible-project-drupal-9.md b/astro/src/content/blog/upgrading-dransible-project-drupal-9.md
deleted file mode 100644
index 33e7d352..00000000
--- a/astro/src/content/blog/upgrading-dransible-project-drupal-9.md
+++ /dev/null
@@ -1,51 +0,0 @@
----
-title: Upgrading the Dransible project to Drupal 9
-excerpt: How I recently upgraded the Dransible example project from Drupal 8.8 to 9.0.
-tags:
- - composer
- - dransible
- - drupal
- - drupal-9
- - drupal-planet
- - php
-date: 2020-09-05
----
-
-This week I gave [a new talk on upgrading to Drupal 9](/talks/upgrading-your-site-drupal-9) for the Drupal NYC meetup. Whilst preparing for that, I decided to upgrade my [Dransible example project](https://github.com/opdavies/dransible) that I use for my [Ansible and Ansistrano talk](/talks/deploying-php-ansible-ansistrano) to Drupal 9 and document the process.
-
-Whilst the steps taken are in the slides for that talk, here is the full list of steps that I took including the Composer commands.
-
-## Updating from Drupal 8.8 to 8.9 { #updating-from-drupal-88-to-89 }
-
-To begin with, let's update to the latest version of Drupal 8 so that we can do some testing and see all of the latest deprecation notices before moving to Drupal 9.
-
-1. Remove Drush temporarily using `composer remove drush/drush` as it will cause us being stuck on Drupal 8.9.0-beta2 rather than a newer, stable 8.9 version.
-1. Update `^8.8` to `^8.9` in composer.json for `drupal/core-recommended`, `drupal/core-dev` and `drupal/core-composer-scaffold`, and run `composer update drupal/core-* --with-dependencies` to update core to 8.9.5.
-1. Re-add Drush so that it's present for the deployment by running `composer require drush/drush:^9`.
-
-## Preparing for Drupal 9 {#preparing-drupal-9}
-
-1. Add the [Upgrade Status module](https://www.drupal.org/project/upgrade_status) by running `composer require drupal/upgrade_status`.
-1. Upgrade to Drush 10 by running `composer require drush/drush:^10`.
-1. Remove the [Config Installer module](https://www.drupal.org/project/config_installer) by running `composer remove drupal/config_installer`. This is no longer needed since Drupal 8.6, and there will be no Drupal 9 version.
-1. Update the [Admin Toolbar module](https://www.drupal.org/project/admin_toolbar) to 2.3, a Drupal 9 compatible version, by running `composer update drupal/admin_toolbar`.
-
-As I'd previously updated the Simple Message custom module to be Drupal 9 compatible (adding the `core_version_requirement` key to the info.yml file, and removing usages of deprecated code), no changes needed to be made to that.
-
-## Upgrading to Drupal 9 {#upgrading-drupal-9}
-
-1. Update `^8.9` to `^9.0` for the core packages in composer.json, and run `composer update drupal/core-* --with-dependencies` to update to 9.0.5.
-1. Re-add Drush by running `composer require drush/drush`. This will install Drush 10 by default.
-
-## Post upgrade {#post-upgrade}
-
-Although everything seemed to have updated OK locally, there were some errors when running a deployment to the Vagrant virtual machine that needed to be addressed, as well as some post-upgrade housekeeping steps to perform.
-
-1. Fix the deployment error by adding the [Symfony Configuration component](https://symfony.com/components/Config) as a dependency by running `composer require symfony/config:^4`.
-1. Alias `Drupal\Core\Messenger\MessengerInterface` to `messenger` in `simple_message.services.yml` to fix the autowiring error.
-1. Add `settings["config_sync_directory"]` to settings file variables (this will be added automatically in the next version of the [Drupal settings Ansible role](https://github.com/opdavies/ansible-role-drupal-settings)).
-1. Remove the Upgrade Status module by running `composer remove drupal/upgrade_status`, as it's no longer needed.
-
-And that's it! The Dransible demo project is upgraded, and if you see my Ansible deployments talk in the future, the demo site will be running on Drupal 9.
-
-If you want to see the original pull request, it's at .
diff --git a/astro/src/content/blog/use-authorized-keys-create-passwordless-ssh-connection.md b/astro/src/content/blog/use-authorized-keys-create-passwordless-ssh-connection.md
deleted file mode 100644
index eda31b02..00000000
--- a/astro/src/content/blog/use-authorized-keys-create-passwordless-ssh-connection.md
+++ /dev/null
@@ -1,33 +0,0 @@
----
-title: How to use Authorized Keys to Create a Passwordless SSH Connection
-date: 2012-02-01
-excerpt: How to generate a SSH key, and how to use to log in to a server using SSH without entering a password.
-tags:
- - linux
- - ssh
----
-
-If you're accessing Linux servers or automating tasks between servers, rather
-than having to enter your user password every time, you can also use SSH public
-key authentication. This is a simple process that involves creating a local key
-and storing it within the _authorized_keys_ file on the remote server.
-
-1. Check if you already have a SSH key. `$ ssh-add -L`
-1. If you don't have one, create one. `$ ssh-keygen`
-1. Upload the key onto the server. Replace _myserver_ with the hostname or IP
- address of your remote server. `$ ssh-copy-id myserver`
-
-If you're using Mac OS X and you don't have ssh-copy-id installed, download and
-install [Homebrew](http://mxcl.github.com/homebrew 'Homebrew') and run the
-`brew install ssh-copy-id` command.
-
-If successful, you should now see a message like:
-
-> Now try logging into the machine, with "ssh 'myserver'", and check in:
->
-> ~/.ssh/authorized_keys
->
-> to make sure we haven't added extra keys that you weren't expecting.
-
-Now the next time that you SSH onto the server, it should log you in without
-prompting you for your password.
diff --git a/astro/src/content/blog/use-regular-expressions-search-replace-coda-or-textmate.md b/astro/src/content/blog/use-regular-expressions-search-replace-coda-or-textmate.md
deleted file mode 100644
index eaacc8f3..00000000
--- a/astro/src/content/blog/use-regular-expressions-search-replace-coda-or-textmate.md
+++ /dev/null
@@ -1,57 +0,0 @@
----
-title: Use Regular Expressions to Search and Replace in Coda or TextMate
-date: 2010-11-04
-excerpt: How to perform searches using regular expressions.
-tags:
- - coda
- - database
- - regular-expression
- - sequel-pro
- - taxonomy
- - textmate
----
-
-As in
-[the original post](/blog/add-taxonomy-term-multiple-nodes-using-sql/ 'Quickly adding a taxonomy term to multiple nodes using SQL'),
-I'd generated a list of node ID values, and needed to add structure the SQL
-update statment formatted in a certain way. However, I changed my inital query
-slightly to out put the same nid value twice.
-
-```sql
-SELECT nid, nid FROM node WHERE TYPE = 'blog' ORDER BY nid ASC;
-```
-
-Then, I could select all of the returned rows, copy the values, and paste them
-into Coda:
-
-As before, I needed my SQL update statement to be in the following format:
-
-```sql
-INSERT INTO term_node VALUE (nid, vid, tid), (nid2, vid2, tid);
-```
-
-As I mentioned previously, the nid and vid values are the same for each node,
-and the tid will remain constant. In this case, the tid value that I needed to
-use was '63'.
-
-So, using the 'Find and Replace' function within Coda, combined with
-[regular expressions](http://en.wikipedia.org/wiki/Regular_expression) (regex),
-I can easily format the values as needed. To begin with, I need to ensure that
-the RegEx search option is enabled, and that I'm using the correct escape
-character.
-
-The first thing that I wanted to do was add the seperating comma between the two
-values. To do this, I perform a search for `\s*\t`. This searches for everything
-that is whitespace AND is a tab value. I can then add the comma as the
-replacement for each result.
-
-All 31 lines have been changed.
-
-Next, I can use `\n` to target the lines between the rows. I'll replace it with
-the next comma, the number 63 (the tid value), the closing bracket, another
-comma, re-add the line and add the opening bracket.
-
-The only two lines that aren't changed are the first and last, as they don't
-have any line breaks following them. I can complete these lines manually. Now
-all I need to do is add the beginning of the SQL update statement, then copy and
-paste it into Sequel Pro.
diff --git a/astro/src/content/blog/use-sass-and-compass-drupal-7-using-sassy.md b/astro/src/content/blog/use-sass-and-compass-drupal-7-using-sassy.md
deleted file mode 100644
index 2ebae84f..00000000
--- a/astro/src/content/blog/use-sass-and-compass-drupal-7-using-sassy.md
+++ /dev/null
@@ -1,79 +0,0 @@
----
-title: How to use SASS and Compass in Drupal 7 using Sassy
-date: 2012-12-06
-excerpt: Use PHPSass and the Sassy module to use Sass and Compass in your Drupal theme.
-tags:
- - compass
- - css
- - drupal
- - drupal-7
- - drupal-planet
- - less
- - preprocessing
- - sass
----
-
-I've recently started using [SASS](http://sass-lang.com) rather than LESS to do
-my CSS preprocessing - namely due to its integration with
-[Compass](http://compass-style.org) and it's built-in CSS3 mixins. Here are
-three modules that provide the ability to use SASS within Drupal.
-
-- [Sassy](http://drupal.org/project/sassy 'Sassy module on drupal.org')
-- [Prepro](http://drupal.org/project/prepro 'Prepro module on drupal.org')
-- [Libraries API](http://drupal.org/project/libraries 'Libraries API module on drupal.org')
-
-Alternatively, you could use a base theme like
-[Sasson](http://drupal.org/project/sasson 'Sasson theme on drupal.org') that
-includes a SASS compiler.
-
-## Download the PHPSass Library
-
-The first thing to do is download the PHPSass library from
-[GitHub](https://github.com/richthegeek/phpsass 'PHPSass on GitHub'), as this is
-a requirement of the Sassy module and we can't enable it without the library.
-So, in a Terminal window:
-
-```bash
-$ mkdir -p sites/all/libraries;
-$ cd sites/all/libraries;
-$ wget https://github.com/richthegeek/phpsass/archive/master.tar.gz;
-$ tar zxf master.tar.gz;
-$ rm master.tar.gz;
-$ mv phpsass-master/ phpsass
-```
-
-Or, if you're using Drush Make files:
-
-```ini
-libraries[phpsass][download][type] = "get"
-libraries[phpsass][download][url] = "https://github.com/richthegeek/phpsass/archive/master.tar.gz"
-```
-
-The PHPSass library should now be located at `sites/all/libraries/phpsass`.
-
-## Download and enable the Drupal modules
-
-This is easy if you use [Drush](http://drupal.org/project/drush):
-
-```bash
-$ drush dl libraries prepro sassy
-$ drush en -y libraries prepro sassy sassy_compass
-```
-
-Otherwise, download the each module from it's respective project page and place
-it within your `sites/all/modules` or `sites/all/modules/contrib` directory.
-
-## Configuring the Prepro module
-
-The Prepro module provides various settings that can be changed for each
-preprocessor. Go to `admin/config/media/prepro` to configure the module as
-required.
-
-Personally, in development, I'd set caching to 'uncached' and the error
-reporting method to 'show on page'. In production, I'd change these to "cached"
-and "watchdog" respectively. I'd also set the output style to "compressed",
-
-## Adding SASS files into your theme
-
-With this done, you can now add SASS and SCSS files by adding a line like
-`stylesheets[all][] = css/base.scss` in your theme's .info file.
diff --git a/astro/src/content/blog/useful-drupal-6-modules.md b/astro/src/content/blog/useful-drupal-6-modules.md
deleted file mode 100644
index 1b482bd7..00000000
--- a/astro/src/content/blog/useful-drupal-6-modules.md
+++ /dev/null
@@ -1,57 +0,0 @@
----
-title: 10 Useful Drupal 6 Modules
-date: 2010-06-25
-excerpt: A list of 10 contributed modules that I currently use on each Drupal project.
-tags:
- - drupal
- - drupal-6
- - drupal-modules
- - drupal-planet
----
-
-Aside from the obvious candidates such as Views, CCK etc, here are a list of 10
-contributed modules that I currently use on each Drupal project.
-
-So, in no particular order:
-
-- **[Admin](http://drupal.org/project/admin):** The admin module provides UI
- improvements to the standard Drupal admin interface. I've just upgraded to the
- new [6.x-2.0-beta4](http://drupal.org/node/835870) version, and installed the
- newly-required
- [Rubik](http://code.developmentseed.org/rubik)/[Tao](http://code.developmentseed.org/tao)
- themes. So far, so good!
-- **[Better Permissions](http://drupal.org/project/better_perms)/[Filter Permissions](http://drupal.org/project/filter_perms):
- **Basic permissions is a basic module which enhances the Drupal
- Permissions page to support collapsing and expanding permission rows. Filter
- permissions provides filters at the top of the Permissions page for easier
- management when your site has a large amount of roles and/or permissions.
-- **[Better Formats](http://drupal.org/project/better_formats): **Better
- formats is a module to add more flexibility to Drupal's core input format
- system.
-- **[Clone module](http://drupal.org/project/node_clone):** Allows users to
- make a copy of an existing item of site content (a node) and then edit that
- copy.
-- **[Vertical Tabs](http://drupal.org/project/vertical_tabs): **Integrated
- into Drupal 7 core, this module adds vertical tabs to the node add and edit
- forms.
-- **[Context](http://drupal.org/project/context): **Context allows you to
- manage contextual conditions and reactions for different portions of your
- site. You can think of each context as representing a "section" of your site.
- For each context, you can choose the conditions that trigger this context to
- be active and choose different aspects of Drupal that should react to this
- active context.
-- **[Node Picker](http://drupal.org/project/nodepicker):** A rewrite of the
- module [TinyMCE Node Picker](http://drupal.org/project/tinymce_node_picker).
- Allows you to easily create links to internal nodes.
-- **[Module Filter](http://drupal.org/project/module_filter):** What this
- module aims to accomplish is the ability to quickly find the module you are
- looking for without having to rely on the browsers search feature which more
- times than not shows you the module name in the 'Required by' or 'Depends on'
- sections of the various modules or even some other location on the page like a
- menu item.
-- **[Zenophile](http://drupal.org/project/zenophile):** Quickly create Zen
- subthemes.
-- **[Add Another](http://drupal.org/project/addanother):** Add another
- displays a message after a user creates a node, and/or displays an "Add
- another" tab on nodes allowing them to make another node of the same type. You
- can control what roles and node types see this feature.
diff --git a/astro/src/content/blog/useful-vagrant-commands.md b/astro/src/content/blog/useful-vagrant-commands.md
deleted file mode 100644
index 0e63a7e7..00000000
--- a/astro/src/content/blog/useful-vagrant-commands.md
+++ /dev/null
@@ -1,24 +0,0 @@
----
-title: Useful Vagrant Commands
-date: 2013-11-27
-excerpt: Here are the basic commands that you need to adminster a virtual machine using Vagrant.
-tags:
- - vagrant
----
-
-[Vagrant](http://www.vagrantup.com 'About Vagrant') is a tool for managing
-virtual machines within [VirtualBox](https://www.virtualbox.org) from the
-command line. Here are some useful commands to know when using Vagrant.
-
-| Command | Description |
-| :--------------------------- | :----------------------------------------------------------------------------------------------------------- |
-| vagrant init {box} | Initialise a new VM in the current working directory. Specify a box name, or "base" will be used by default. |
-| vagrant status | Shows the status of the Vagrant box(es) within the current working directory tree. |
-| vagrant up (--provision) | Boots the Vagrant box. Including "–provision" also runs the "vagrant provision" command. |
-| vagrant reload (--provision) | Reloads the Vagrant box. Including "--provision" also runs the "vagrant provision" command. |
-| vagrant provision | Provision the Vagrant box using Puppet. |
-| vagrant suspend | Suspend the Vagrant box. Use "vagrant up" to start the box again. |
-| vagrant halt (-f) | Halt the Vagrant box. Use -f to forcefully shut down the box without prompting for confirmation. |
-| vagrant destroy (-f) | Destroys a Vagrant box. Use -f to forcefully shut down the box without prompting for confirmation. |
-
-The full Vagrant documentation can be found at .
diff --git a/astro/src/content/blog/using-feature-flags-in-drupal-development.md b/astro/src/content/blog/using-feature-flags-in-drupal-development.md
deleted file mode 100644
index b57ac762..00000000
--- a/astro/src/content/blog/using-feature-flags-in-drupal-development.md
+++ /dev/null
@@ -1,13 +0,0 @@
----
-title: Using feature flags in Drupal development
-excerpt: Different ways of using feature flags witin Drupal development
-date: 2020-03-31
-tags:
- - drupal
- - drupal-7
- - drupal-8
- - php
-draft: true
----
-
-TODO.
diff --git a/astro/src/content/blog/using-imagecache-and-imagecrop-my-portfolio.md b/astro/src/content/blog/using-imagecache-and-imagecrop-my-portfolio.md
deleted file mode 100644
index 422901aa..00000000
--- a/astro/src/content/blog/using-imagecache-and-imagecrop-my-portfolio.md
+++ /dev/null
@@ -1,44 +0,0 @@
----
-title: Using ImageCache and ImageCrop for my Portfolio
-date: 2010-04-28
-excerpt: How to create thumbnail images using the ImageCache and ImageCrop modules.
-tags:
- - drupal
- - drupal-6
- - cck
- - imagecache
- - imagecrop
- - imagefield
----
-
-Whilst working on my own portfolio/testimonial website, I decided to have a
-portfolio page displaying the name of each site and a thumbnail image. For this
-Blog post, I'll be using a site called
-[Popcorn Strips](http://popcornstrips.com) which I built for a friend earlier
-this year as an example.
-
-I created a content type called 'Project' with a CCK ImageField called
-'Screenshot'. I created a project called
-[Popcorn Strips](http://popcornstrips.com), used the
-[ScreenGrab](https://addons.mozilla.org/addon/1146) add-on for Mozilla Firefox
-to take a screenshot of the website, and uploaded it to the project node.
-
-I created a View to display the published projects, and an ImageCache preset to
-create the thumbnail image by scaling and cropping the image to a size of
-200x100 pixels.
-
-Although, this automatically focused the crop on the centre of the image,
-whereas I wanted to crop from the top and left of the image - showing the site's
-logo and header.
-
-I installed the [ImageCrop](http://drupal.org/project/imagecrop) module, which
-add a jQuery crop function to the standard ImageCache presents. I removed the
-original Scale and Crop action and replaced it with a Scale action with a width
-of 200px.
-
-I then added a new 'Javascript crop' action with the following settings:
-
-- Width: 200px
-- Height: 100px
-- xoffset: Left
-- yoffset: Top
diff --git a/astro/src/content/blog/using-laravel-collections-drupal.md b/astro/src/content/blog/using-laravel-collections-drupal.md
deleted file mode 100644
index e3345206..00000000
--- a/astro/src/content/blog/using-laravel-collections-drupal.md
+++ /dev/null
@@ -1,71 +0,0 @@
----
-title: Examples of using Laravel Collections in Drupal
-date: 2018-08-23
-excerpt: Some examples of using Laravel’s Illuminate Collections within Drupal projects.
-tags:
- - drupal
- - drupal-7
- - drupal-8
- - drupal-planet
- - laravel
- - laravel-collections
- - php
-has_tweets: true
----
-
-Since starting to work with Laravel as well as Drupal and Symfony, watching Adam
-Wathan’s [Refactoring to Collections][0] course as well as [lessons on
-Laracasts][6], I’ve become a fan of [Laravel’s Illuminate Collections][1] and
-the object-orientated pipeline approach for interacting with PHP arrays.
-
-In fact I’ve given a talk on [using Collections outside Laravel][2] and have
-written a [Collection class module][3] for Drupal 7.
-
-I’ve also tweeted several examples of code that I’ve written within Drupal that
-use Collections, and I thought it would be good to collate them all here for
-reference.
-
-Thanks again to [Tighten][4] for releasing and maintaining the
-[tightenco/collect library][5] that makes it possible to pull in Collections via
-Composer.
-
-
- {% include 'tweet' with {
- class: 'block mb-4 lg:w-1/2 lg:px-2 lg:mb-0',
- data_cards: true,
- content: '
— Oliver Davies (@opdavies) February 14, 2018',
- } %}
-
- {% include 'tweet' with {
- class: 'block mb-4 lg:w-1/2 lg:px-2 lg:mb-0',
- data_cards: true,
- content: '
I knew that you could specify a property like 'price' in Twig and it would also look for methods like 'getPrice()', but I didn't know (or had maybe forgotten) that @laravelphp Collections does it too.
This means that these two Collections return the same result.
— Oliver Davies (@opdavies) August 10, 2018',
- } %}
-
- {% include 'tweet' with {
- class: 'block mb-4 lg:w-1/2 lg:px-2 lg:mb-0',
- data_cards: true,
- content: '
Some more #Drupal 8 fun with Laravel Collections. Loading the tags for a post and generating a formatted string of tweetable hashtags. pic.twitter.com/GbyiRPzIRo
-
-[0]: https://adamwathan.me/refactoring-to-collections
-[1]: https://laravel.com/docs/collections
-[2]: /talks/using-laravel-collections-outside-laravel
-[3]: https://www.drupal.org/project/collection_class
-[4]: https://tighten.co
-[5]: https://packagist.org/packages/tightenco/collect
-[6]: https://laracasts.com/series/how-do-i/episodes/18
diff --git a/astro/src/content/blog/using-pcss-extension-postcss-webpack-encore.md b/astro/src/content/blog/using-pcss-extension-postcss-webpack-encore.md
deleted file mode 100644
index 9033e5dc..00000000
--- a/astro/src/content/blog/using-pcss-extension-postcss-webpack-encore.md
+++ /dev/null
@@ -1,94 +0,0 @@
----
-title: Using the pcss extension for PostCSS with Webpack Encore
-excerpt: How to use the .pcss file extension for PostCSS files with Webpack Encore.
-date: 2020-04-01
-tags:
- - encore
- - postcss
- - symfony
- - webpack
----
-
-I’ve been watching Christopher Pitt ([assertchris][assertchris-twitter])’s [streams on Twitch][assertchris-twitch] over the last few months, in one of which he was doing some work with Tailwind CSS and using a `.pcss` file extension for his PostCSS files.
-
-I couldn’t remember seeing this extension before, but this made a lot of sense to me compared to the standard `.css` extension - both to make it clear that it’s a PostCSS file and features like nesting can be used, and also for better integration and highlighting with IDEs and text editors such as PhpStorm.
-
-It’s also shorter that the `.postcss` extension, and has been suggested by [@PostCSS on Twitter](https://twitter.com/PostCSS/status/661645290622083073) previously.
-
-Some of my projects use [Laravel Mix][] which support this extension by default, but some of them use Symfony’s [Webpack Encore][] which didn’t seem to, so I decided to look into it. (Note that both are agnostic and not coupled to their respective frameworks, so can be used with other projects too including Drupal and Sculpin).
-
-## Updating Webpack Encore’s configuration
-
-I was able to review the existing configuration and confirm this by using `console.log()` to output Encore’s generated webpack configuration - specifically the module rules.
-
-```js
-console.log(Encore.getWebpackConfig().module.rules)
-```
-
-There I can see the the test for PostCSS supports the `.css` and `.postcss` file extensions, but not `.pcss`.
-
-```
-test: /\.(css|postcss)$/,
-```
-
-There is documentation on the Symfony website for [adding custom webpack loaders and plugins](https://symfony.com/doc/current/frontend/encore/custom-loaders-plugins.html) but this wasn’t quite what I needed, as I needed to edit the existing `css` loader rather than add a new one.
-
-The page that I needed was [Advanced Webpack Config](https://symfony.com/doc/current/frontend/encore/advanced-config.html#having-the-full-control-on-loaders-rules) - specifically the section on 'Having the full control on Loaders Rules'.
-
-This suggests using `.configureLoaderRule()` and using that to override `test` directly.
-
-It does though come with a warning:
-
-> This is a low-level method. All your modifications will be applied just before pushing the loaders rules to Webpack. It means that you can override the default configuration provided by Encore, which may break things. Be careful when using it.
-
-My first pass was to add the full `.pcss` extension, but as this is a regular expression, I did a second pass that adds an second capturing group that would cover both PostCSS extensions.
-
-```
-// First pass
-loaderRule.test = /\.(css|pcss|postcss)$/
-
-// Second pass
-loaderRule.test = /\.(css|p(ost)?css)$/
-```
-
-To see this running, go to .
-
-## The final configuration
-
-This is my full `webpack.config.js` file for this site, including the `.pcss` extension support:
-
-```js
-Encore
- .disableSingleRuntimeChunk()
- .cleanupOutputBeforeBuild()
- .setOutputPath('source/build/')
- .setPublicPath('/build')
- .addEntry('app', './assets/js/app.js')
- .enablePostCssLoader()
- .configureLoaderRule('css', loaderRule => {
- loaderRule.test = /\.(css|p(ost)?css)$/
- })
- .enableSourceMaps(!Encore.isProduction())
-
-if (Encore.isProduction()) {
- Encore
- .enableVersioning()
- .addPlugin(new PurgecssPlugin(purgecssConfig))
-} else {
- Encore.enableSourceMaps()
-}
-
-module.exports = Encore.getWebpackConfig()
-```
-
-Alternatively, you can view it in the [codebase on GitHub](https://github.com/opdavies/oliverdavies.uk/blob/796578d7f0f3332724cb8335982c69b36bc11e53/webpack.config.js).
-
-## Contributing back to Encore
-
-I’ve also submitted a pull request to Encore to add support for the `.pcss` extension by default: . If accepted, then these changes in `webpack.config.js` would no longer be needed.
-
-[assertchris-twitch]: https://www.twitch.tv/assertchris "assertchris on Twitch"
-[assertchris-twitter]: https://twitter.com/assertchris "assertchris on Twitter"
-[gitstore]: https://gitstore.app
-[laravel mix]: https://laravel-mix.com
-[webpack encore]: https://github.com/symfony/webpack-encore
diff --git a/astro/src/content/blog/using-remote-files-when-developing-locally-stage-file-proxy-module.md b/astro/src/content/blog/using-remote-files-when-developing-locally-stage-file-proxy-module.md
deleted file mode 100644
index 084212cf..00000000
--- a/astro/src/content/blog/using-remote-files-when-developing-locally-stage-file-proxy-module.md
+++ /dev/null
@@ -1,37 +0,0 @@
----
-title: Using Remote Files when Developing Locally with Stage File Proxy Module
-date: 2014-11-20
-excerpt: How to install and configure the Stage File Proxy module to serve remote images on your local Drupal site.
-tags:
- - drupal
- - drupal-planet
- - servers
----
-
-How to install and configure the
-[Stage File Proxy](https://www.drupal.org/project/stage_file_proxy) module to
-serve remote images on your local Drupal site.
-
-As this module is only going to be needed on pre-production sites, it would be
-better to configure this within your settings.php or settings.local.php file. We
-do this using the `$conf` array which removes the need to configure the module
-through the UI and store the values in the database.
-
-```php
-// File proxy to the live site.
-$conf['stage_file_proxy_origin'] = 'http://www.example.com';
-
-// Don't copy the files, just link to them.
-$conf['stage_file_proxy_hotlink'] = TRUE;
-
-// Image style images are the wrong size otherwise.
-$conf['stage_file_proxy_use_imagecache_root'] = FALSE;
-```
-
-If the origin site is not publicly accessible yet, maybe it's a pre-live or
-staging site, and protected with a basic access authentication, you can include
-the username and password within the origin URL.
-
-```php
-$conf['stage_file_proxy_origin'] = 'http://user:password@prelive.example.com';
-```
diff --git a/astro/src/content/blog/using-tailwind-css-your-drupal-theme.md b/astro/src/content/blog/using-tailwind-css-your-drupal-theme.md
deleted file mode 100644
index 2a81d89c..00000000
--- a/astro/src/content/blog/using-tailwind-css-your-drupal-theme.md
+++ /dev/null
@@ -1,112 +0,0 @@
----
-title: Using Tailwind CSS in your Drupal Theme
-date: 2018-02-05
-excerpt: What is Tailwind CSS, and how do I use it in Drupal theme?
-tags:
- - drupal
- - drupal-planet
- - drupal-theming
- - tailwind-css
----
-
-## What is Tailwind?
-
-> Tailwind is a utility-first CSS framework for rapidly building custom user
-> interfaces.
-
-It generates a number of utility classes that you can add to your theme's markup
-to apply different styling, as well as the ability to apply classes to other
-markup and create components comprised of utility classes using a custom
-`@apply` PostCSS directive.
-
-## Initial Configuration
-
-The installation and configuration steps are essentially the same as those
-outlined within the [Tailwind documentation][1], and should be performed within
-your custom theme's directory (e.g. `sites/all/themes/custom/mytheme` for Drupal
-7 or `themes/custom/mytheme` for Drupal 8:
-
-1. Require PostCSS and Tailwind via `npm` or `yarn`.
-1. Generate a configuration file using `./node_modules/.bin/tailwind init`.
-1. Tweak the settings as needed.
-1. Add a `postcss.config.js` file.
-1. Configure your build tool (Gulp, Grunt, Webpack).
-1. Generate the CSS.
-1. Include a path to the generated CSS in your `MYTHEME.info`,
- `MYTHEME.info.yml` or `MYTHEME.libraries.yml` file.
-
-## PostCSS Configuration
-
-Create a `postcss.config.js` file and add `tailwindcss` as a plugin, passing the
-path to the config file:
-
-```js
-module.exports = {
- plugins: [
- require('tailwindcss')('./tailwind.js'),
- ]
-}
-```
-
-## Configuration for Drupal
-
-There are some configuration settings within `tailwind.js` that you’ll need to
-change to make things work nicely with Drupal. These are within the `options`
-section:
-
-```js
-options: {
- prefix: 'tw-',
- important: true,
- ...
-}
-```
-
-### Prefix
-
-By adding a prefix like `tw-`, we can ensure that the Tailwind classes don’t
-conflict with core HTML classes like `block`. We can also ensure that they won't
-conflict with any other existing HTML or CSS.
-
-No prefix:
-
-{.with-border}
-
-With prefix:
-
-{.with-border}
-
-### Important
-
-We can also set the `!important` rule on all Tailwind’s generated classes. We
-need to do this if we want to override core styles which have more specific
-rules.
-
-For example: if I had this core markup then the left margin added by `tw-ml-4`
-would be overridden by core’s `.item-list ul` styling.
-
-```html
-
-
- ...
-
-
-```
-
-{.with-border}
-
-With the `!important` rule enabled though, the Tailwind’s class takes precedence
-and is applied.
-
-{.with-border}
-
-## Example
-
-For an example of Tailwind within a Drupal 8 theme, see the custom theme for the
-[Drupal Bristol website][0] on GitHub.
-
-[0]:
- https://github.com/drupalbristol/drupal-bristol-website/tree/master/web/themes/custom/drupalbristol
-[1]: https://tailwindcss.com/docs/installation
-[2]: https://www.npmjs.com/get-npm
-[3]: https://yarnpkg.com/lang/en/docs/install
diff --git a/astro/src/content/blog/using-traefik-local-proxy-sculpin.md b/astro/src/content/blog/using-traefik-local-proxy-sculpin.md
deleted file mode 100644
index 0f663c72..00000000
--- a/astro/src/content/blog/using-traefik-local-proxy-sculpin.md
+++ /dev/null
@@ -1,64 +0,0 @@
----
-title: Using Traefik as a local proxy with Sculpin
-tags:
- - docker
- - sculpin
-draft: true
-date: ~
----
-
-
-
-## Before
-
-```yaml
-services:
- app:
- build:
- context: .
- dockerfile: tools/docker/images/Dockerfile
- target: app
- volumes:
- - assets:/app/source/build
- - /app/output_dev
- - .:/app
- ports:
- - 8000:8000
-```
-
-## Adding the proxy service
-
-```yaml
-services:
- proxy:
- image: traefik:v2.0-alpine
- command:
- - --api.insecure=true
- - --providers.docker
- volumes:
- - /var/run/docker.sock:/var/run/docker.sock
- ports:
- - 80:80
- - 8080:8080
- labels:
- - "traefik.enable=false"
-```
-
-## Updating the app service
-
-```yaml
-app:
- build:
- context: .
- dockerfile: tools/docker/images/Dockerfile
- target: app
- expose:
- - 80
- command: [generate, --server, --watch, --port, '80', --url, http://oliverdavies.localhost]
- volumes:
- - assets:/app/source/build
- - /app/output_dev
- - .:/app
- labels:
- - "traefik.http.routers.oliverdavies.rule=Host(`oliverdavies.localhost`)"
-```
diff --git a/astro/src/content/blog/using-transition-props-vuejs.md b/astro/src/content/blog/using-transition-props-vuejs.md
deleted file mode 100644
index 5d6d8d4c..00000000
--- a/astro/src/content/blog/using-transition-props-vuejs.md
+++ /dev/null
@@ -1,13 +0,0 @@
----
-title: Using Transition Class Props in Vue.js
-date: 2019-06-06
-type: tweet
-excerpt: Adam Wathan shows a more Tailwind-esque approach to writing Vue.js transitions.
-tags:
- - vuejs
-external_url: https://twitter.com/adamwathan/status/1118670393030537217
----
-
-{% include 'tweet' with {
- content: '🔥 Using the transition class props instead of the `name` prop for @vuejs transitions makes it really easy to compose transitions on the fly using utility classes.
This is how I do all my transitions in Vue these days — fits a lot better with the @tailwindcss philosophy 👌🏻 pic.twitter.com/shQCxaFZ8A— Adam Wathan (@adamwathan) April 18, 2019'
-} %}
diff --git a/astro/src/content/blog/weeknotes-2021-06-05.md b/astro/src/content/blog/weeknotes-2021-06-05.md
deleted file mode 100644
index b9719fae..00000000
--- a/astro/src/content/blog/weeknotes-2021-06-05.md
+++ /dev/null
@@ -1,26 +0,0 @@
----
-title: 'Weeknotes: June 5th'
-excerpt: Starting at Transport for Wales.
-date: ~
-tags:
- - personal
- - week-notes
----
-
-After the Bank Holiday weekend, I started working this week as a Lead Developer at [Transport for Wales](https://trc.cymru). I really enjoyed working at Inviqa, but felt that moving again to an in-house team would offer some new types of challenges whilst also getting to lead and manage a team.
-
-It's been an interesting first week, and I've met a lot of new colleagues whilst also going through the regular TfW induction processes and getting to know the current team.
-
-
-
-
-
-
Image
-
-
-
-
-
-
-
-I'm looking forward to helping build and lead the development team at TfW, and plan on publishing regular weeknotes on the work that we're doing at Transport for Wales and TfW Rail.
diff --git a/astro/src/content/blog/weeknotes-2021-06-12.md b/astro/src/content/blog/weeknotes-2021-06-12.md
deleted file mode 100644
index 2c68a4bb..00000000
--- a/astro/src/content/blog/weeknotes-2021-06-12.md
+++ /dev/null
@@ -1,36 +0,0 @@
----
-title: 'Weeknotes: June 12th'
-excerpt: Developing on Windows, organising dotfiles, and helping organise DrupalCon.
-date: 2021-06-12
-tags:
- - personal
- - week-notes
----
-
-## Local development with Windows and WSL 2
-
-As a long-time Linux and macOS user, the last couple of weeks have been my first experience of using the Windows operating system for some time. After some research, I've been using the WSL 2 (Windows Subsystem for Linux) functionality built into Windows 10, with Ubuntu 20.04 installed within it. The codebase that I'm currently working on is using Lando, and that seems to be running fine within this setup after following some [instructions on the Lando documentation](https://docs.lando.dev/guides/setup-lando-on-windows-with-wsl-2.html) and a [blog post by Cal Evans](https://blog.calevans.com/2020/06/18/making-lando-work-inside-wsl2).
-
-I spend most of the day working within the WSL 2 environment which is a lot more familiar for me for development, but also for more simple tasks like generating SSH keys and cloning and configuring [my dotfiles](https://github.com/opdavies/dotfiles).
-
-## Re-organised dotfiles
-
-It was easy to clone my Dotfiles repository into the WSL 2 container but they still required to be symlinked into the correct place for them to be used. I'd previously used [rcm](https://github.com/thoughtbot/rcm), a tool from Thoughtbot, to do this but I wanted to review other approaches.
-
-I decided to try an approach of [using a local bare Git repository](https://www.atlassian.com/git/tutorials/dotfiles) and using Git's worktree functionality to clone the files into my home directory. This means no more symlinks, and no additional tool to manage the files. The structure of my dotfiles repo is now a lot simpler, though I do miss the grouping of files by 'tag' so I might look to re-implement this somehow in the future.
-
-## DrupalCon Europe kick-off meeting
-
-This week was the kick-off meeting for the DrupalCon Program Track Chair team, which I'm a part of this year.
-
-I've been proud to speak at the last two DrupalCon Europe conferences (2019 in Amsterdam, and online in 2020) and this year I wanted to contribute in a different way.
-
-I'm part of the Open Web & Community track and I'm looking forward to reviewing all of the sessions and experiencing DrupalCon in a new way again this year.
-
-## Inviqa blog post published
-
-My final task before leaving Inviqa a few weeks ago was to upgrade the inviqa.com and inviqa.de sites, which I co-developed, to Drupal 9.
-
-I wrote an article for the Inviqa blog, [Drupal 9 upgrade from Drupal 8](https://inviqa.com/blog/drupal-9-upgrade-from-drupal-8), which was published this week.
-
-I wrote my own post, [Upgrading the Dransible project to Drupal 9](/blog/upgrading-dransible-project-drupal-9) last year where I reviewed the commands and steps that I ran to upgrade one of my personal projects, whereas this post covers more about the process that we took, and the differences between this upgrade and previous Drupal upgrades that I've done.
diff --git a/astro/src/content/blog/weeknotes-2021-07-24.md b/astro/src/content/blog/weeknotes-2021-07-24.md
deleted file mode 100644
index de5dfd10..00000000
--- a/astro/src/content/blog/weeknotes-2021-07-24.md
+++ /dev/null
@@ -1,44 +0,0 @@
----
-title: 'Weeknotes: July 24th'
-excerpt: Windows utilities, continuous integration and delivery, and writing tests.
-tags:
- - personal
- - week-notes
-date: ~
----
-
-## Using PowerToys and FancyZones
-
-I've been missing some of the features from Pop!_OS whilst working on my Windows laptop, so this week, I've been experimenting with [Microsoft PowerToys](https://docs.microsoft.com/en-us/windows/powertoys) which adds additional utilities to Windows 10 - similar to Gnome Tweak Tools.
-
-The main features that I'm trying are [FancyZones](https://docs.microsoft.com/en-us/windows/powertoys/fancyzones), which is similar to Pop!_OS's tiling window manager, and [Keyboard Manager](https://docs.microsoft.com/en-us/windows/powertoys/keyboard-manager](https://docs.microsoft.com/en-us/windows/powertoys/keyboard-manager)) so that I can remap some keys to match my personal laptop.
-
-## Continuous integration vs. feature branching
-
-I've been researching more about the continuous integration, or trunk-based development, approach to version control. Dave Farley's blog and [Continuous Delivery YouTube channel](https://www.youtube.com/channel/UCCfqyGl3nq_V0bo64CjZh8g) have been a great resource for this. I've also purchased his and Jez Humble's "Continuous Delivery" book, and have moved it to the top of my "To read" list.
-
-My current team at Transport for Wales is following a CI workflow, and it's been interesting to see code being pushed more often and moving from local to staging compared to waiting for async code reviews, so I'm looking forward to learning more about this approach and how to integrate it more with pair programming and test-driven development.
-
-I gave my first conference talk at DrupalCamp London 2014 on [Git Flow](/talks/git-flow), so I've been using the feature branch workflow for some time. As always, I'm willing to try and evaluate new approaches with an open mind.
-
-## Growing an automated test suite
-
-I [posted a tweet yesterday](https://twitter.com/opdavies/status/1418500778428338177) with a screenshot of the output from running some of the tests that I've added to my current work codebase. These are Drupal-based PHPUnit tests and are a combination of browser/functional and unit tests.
-
-I'm very keen on adding tests where possible for new functionality or when fixing bugs, which will make it much easier and less risky to refactor that code and ensure that the same bugs aren't re-added again.
-
-## Git hooks
-
-I've been using Git hooks for a few months to run checks locally, such as code linting and static analysis prior to pushing to a CI pipeline, to shorten the feedback loop and more quickly fix any failures.
-
-I've added some initial pre-push hooks to the current work codebase, to run some non-intrusive tasks such as code linting, with a view to adding to it over time.
-
-Sebastian Feldmann gave a talk in May for PHP South Wales, which included Git hooks. [The video is available on YouTube](https://www.youtube.com/watch?v=b85MoYmwUYs).
-
-## Deploying (and reverting) with CI and feature toggles
-
-Continuing with the CI/CD topic, I pushed a new, incomplete feature to production for one of my freelance clients' projects alongside some other changes.
-
-It was hidden behind a feature flag and not enabled, but it was merged and pushed to production.
-
-We decided to remove that implementation and use a different approach, so the code and the feature flag were removed, but for a time, that code was on production.
diff --git a/astro/src/content/blog/weeknotes-2021-08-06.md b/astro/src/content/blog/weeknotes-2021-08-06.md
deleted file mode 100644
index d08f0a77..00000000
--- a/astro/src/content/blog/weeknotes-2021-08-06.md
+++ /dev/null
@@ -1,32 +0,0 @@
----
-title: 'Weeknotes: August 6th'
-excerpt: TODO
-tags:
- - personal
- - week-notes
-draft: true
-date: ~
----
-
-## Vim
-
-- https://gist.github.com/opdavies/f944261b54f70b43f2297cab6779cf59
-- surround.vim - https://github.com/tpope/vim-surround
-- https://towardsdatascience.com/how-i-learned-to-enjoy-vim-e310e53e8d56
-
-## Re-watching invoice.space streams
-
-https://www.youtube.com/playlist?list=PLasJXc7CbyYfsdXu6t0406-kGwDN8aUG9
-
-## Trialing Conventional Commits
-
-https://nitayneeman.com/posts/understanding-semantic-commit-messages-using-git-and-angular
-
-https://www.conventionalcommits.org/en/v1.0.0-beta.2
-
-https://github.com/angular/angular/blob/22b96b9/CONTRIBUTING.md#-commit-message-guidelines
-
-https://github.com/vuejs/vue/commits/dev
-https://github.com/vuejs/vue-cli/commits/dev
-
-https://github.com/pestphp/pest-intellij/commits/main
diff --git a/astro/src/content/blog/what-git-flow.md b/astro/src/content/blog/what-git-flow.md
deleted file mode 100644
index 7f1ad412..00000000
--- a/astro/src/content/blog/what-git-flow.md
+++ /dev/null
@@ -1,57 +0,0 @@
----
-title: 'DrupalCamp London: What is Git Flow?'
-date: 2014-03-03
-excerpt: Here are my slides from my "What is Git Flow?" session at DrupalCamp London.
-tags:
- - git
- - git-flow
- - drupalcamp-london
- - talks
-tweets: true
----
-
-Here are my slides from my "What is Git Flow?" session at
-[DrupalCamp London](http://2014.drupalcamplondon.co.uk).
-
-{% include 'speakerdeck' with { data_id: '201559e0f103013198dd5a5f6f23ab67' } %}
-
-## Take aways
-
-The main take aways are:
-
-- Git Flow adds various commands into Git to enhance its native functionality,
- which creates a branching model to separate your stable production code from
- your unstable development code.
-- Never commit directly to the master branch - this is for production code only!
-- You can commit directly to the develop branch, but this should be done
- sparingly.
-- Use feature branches as much as possible - one per feature, user story or bug.
-- Commit early and often, and push to a remote often to encourage collaboration
- as well as to provide a backup of your code.
-- You can use settings within services like GitHub and Bitbucket to only allow
- certain users to push to the master and develop branches, and restrict other
- Developers to only commit and push to feature branches. Changes can then be
- committed and pushed, then reviewed as part of a peer code review, and merged
- back into the develop branch.
-
-## Feedback
-
-If you've got any questions, please feel free to
-tweet at me
-or fill in the
-session
-evaluation form that you can complete on the DrupalCamp London website.
-
-I've had some great feedback via Twitter:
-
-{% include 'tweet' with {
- content: '
@opdavies@DrupalCampLDN always had trouble with git. Your talk + Git flow has made it all very easy.
— James Tombs (@jtombs) March 2, 2014'
-} %}
-
-{% include 'tweet' with {
- content: '
— Curve Agency (@CurveAgency) March 2, 2014'
-} %}
diff --git a/astro/src/content/blog/writing-article-linux-journal.md b/astro/src/content/blog/writing-article-linux-journal.md
deleted file mode 100644
index 13b5dc7b..00000000
--- a/astro/src/content/blog/writing-article-linux-journal.md
+++ /dev/null
@@ -1,22 +0,0 @@
----
-title: Writing an Article for Linux Journal
-date: 2012-07-27
-excerpt: I'm absolutely delighted to announce that I'm going to be writing an article for Linux Journal magazine's upcoming Drupal special.
-tags:
- - distributions
- - drupal
- - installation-profiles
- - linux-journal
- - writing
----
-
-I'm absolutely delighted to announce that I'm going to be writing an article for
-[Linux Journal](http://www.linuxjournal.com) magazine's upcoming Drupal special.
-
-The article is going to be entitled "Speeding Up Your Drupal Development Using
-Installation Profiles and Distributions" and will be mentioning existing
-distributions available on Drupal.org, but mainly focussing on the steps needed
-to create your own custom distribution. Needless to say, I'm quite excited about
-it!
-
-The article is expected to be published in October.
diff --git a/astro/src/content/blog/writing-info-file-drupal-7-theme.md b/astro/src/content/blog/writing-info-file-drupal-7-theme.md
deleted file mode 100644
index e3d623c1..00000000
--- a/astro/src/content/blog/writing-info-file-drupal-7-theme.md
+++ /dev/null
@@ -1,40 +0,0 @@
----
-title: Writing a .info file for a Drupal 7 theme
-date: 2012-05-23
-excerpt: An example .info file for a Drupal 7 theme.
-tags:
- - code
- - drupal
- - drupal-theming
- - theming
----
-
-```ini
-name = My Theme
-description = A description of my theme
-core = 7.x
-
-# Add a base theme, if you want to use one.
-base = mybasetheme
-
-# Define regions, otherwise the default regions will be used.
-regions[header] = Header
-regions[navigation] = Navigation
-regions[content] = Content
-regions[sidebar] = Sidebar
-regions[footer] = Footer
-
-# Define which features are available. If none are specified, all the default
-# features will be available.
-features[] = logo
-features[] = name
-features[] = favicon
-
-# Add stylesheets
-stylesheets[all][] = css/reset.css
-stylesheets[all][] = css/mytheme.css
-stylesheets[print][] = css/print.css
-
-# Add javascript files
-styles[] = js/mytheme.js
-```
diff --git a/astro/src/content/blog/writing-new-drupal-8-module-using-test-driven-development-tdd.md b/astro/src/content/blog/writing-new-drupal-8-module-using-test-driven-development-tdd.md
deleted file mode 100644
index d3990975..00000000
--- a/astro/src/content/blog/writing-new-drupal-8-module-using-test-driven-development-tdd.md
+++ /dev/null
@@ -1,661 +0,0 @@
----
-title: Writing a new Drupal 8 Module using Test-Driven Development (TDD)
-date: 2017-11-07
-tags:
- - drupal
- - phpunit
- - simpletest
- - tdd
- - testing
-excerpt: How to write automated tests and follow test driven development for Drupal modules.
-meta:
- image:
- url: /images/talks/test-driven-drupal-development.png
- width: 2560
- height: 1440
- type: image/png
-promoted: true
----
-
-

-
-I recently gave a [talk on automated testing in Drupal][0] talk at [DrupalCamp
-Dublin][1] and as a lunch and learn session for my colleagues at Microserve. As
-part of the talk, I gave an example of how to build a Drupal 8 module using a
-test driven approach. I’ve released the [module code on GitHub][2], and this
-post outlines the steps of the process.
-
-## Prerequisites
-
-You have created a `core/phpunit.xml` file based on `core/phpunit.xml.dist`, and
-populated it with your database credentials so that PHPUnit can bootstrap the
-Drupal database as part of the tests. [Here is an example][5].
-
-## Acceptance Criteria
-
-For the module, we are going to satisfy this example acceptance criteria:
-
-> As a site visitor, I want to see all published pages at /pages Ordered
-> alphabetically by title
-
-## Initial Setup
-
-Let’s start by writing the minimal code needed in order for the new module to be
-enabled. In Drupal 8, this is the `.info.yml` file.
-
-```yaml
-# tdd_dublin.info.yml
-
-name: 'TDD Dublin'
-excerpt: 'A demo module for DrupalCamp Dublin to show test driven module development.'
-core: 8.x
-type: module
-```
-
-We can also add the test file structure at this point too. We’ll call it
-`PageTestTest.php` and put it within a `tests/src/Functional` directory. As this
-is a functional test, it extends the `BrowserTestBase` class, and we need to
-ensure that the tdd_dublin module is enabled by adding it to the `$modules`
-array.
-
-```php
-// tests/src/Functional/PageListTest.php
-
-namespace Drupal\Tests\tdd_dublin\Functional;
-
-use Drupal\Tests\BrowserTestBase\BrowserTestBase;
-
-class PageListTest extends BrowserTestBase {
-
- protected static $modules = ['tdd_dublin'];
-
-}
-```
-
-With this in place, we can now start adding test methods.
-
-## Ensure that the Listing page Exists
-
-### Writing the First Test
-
-Let’s start by testing that the listing page exists at /pages. We can do this by
-loading the page and checking the status code. If the page exists, the code will
-be 200, otherwise it will be 404.
-
-I usually like to write comments first within the test method, just to outline
-the steps that I'm going to take and then replace it with code.
-
-```php
-public function testListingPageExists() {
- // Go to /pages and check that it is accessible by checking the status
- // code.
-}
-```
-
-We can use the `drupalGet()` method to browse to the required path, i.e.
-`/pages`, and then write an assertion for the response code value.
-
-```php
-public function testListingPageExists() {
- $this->drupalGet('pages');
-
- $this->assertSession()->statusCodeEquals(200);
-}
-```
-
-### Running the Test
-
-In order to run the tests, you either need to include `-c core` or be inside the
-`core` directory when running the command, to ensure that the test classes are
-autoloaded so can be found, though the path to the `vendor` directory may be
-different depending on your project structure. You can also specify a path
-within which to run the tests - e.g. within the module’s `test` directory.
-
-```
-$ vendor/bin/phpunit -c core modules/custom/tdd_dublin/tests
-```
-
-
-Note: I’m using Docksal, and I’ve noticed that I need to run the tests from within the CLI container. You can do this by running the `fin bash` command.
-
-
-```
-1) Drupal\Tests\tdd_dublin\Functional\PageListTest::testListingPageExists
-Behat\Mink\Exception\ExpectationException: Current response status code is 404, but 200 expected.
-
-FAILURES!
-Tests: 1, Assertions: 1, Errors: 1.
-```
-
-Because the route does not yet exist, the response code returned is 404, so the
-test fails.
-
-Now we can make it pass by adding the page. For this, I will use the Views
-module, though you could achieve the same result with a custom route and a
-Controller.
-
-### Building the View
-
-To begin with, I will create a view showing all types of content with a default
-sort order of newest first. We will use further tests to ensure that only the
-correct content is returned and that it is ordered correctly.
-
- { .with-border }
-
-The only addition I will make to the view is to add a path at `pages`, as per
-the acceptance criteria.
-
- { .with-border }
-
-### Exporting the View
-
-With the first version of the view built, it needs to be incldued within the
-module so that it can be enabled when the test is run. To do this, we need to
-export the configuration for the view, and place it within the module’s
-`config/install` directory. This can be done using the `drush config-export`
-command or from within the Drupal UI. In either case, the `uid` line at the top
-of the file needs to be removed so the configuration can be installed.
-
-Here is the exported view configuration:
-
-```yaml
-langcode: en
-status: true
-dependencies:
- module:
- - node
- - user
-id: pages
-label: pages
-module: views
-excerpt: ''
-tag: ''
-base_table: node_field_data
-base_field: nid
-core: 8.x
-display:
- default:
- display_plugin: default
- id: default
- display_title: Master
- position: 0
- display_options:
- access:
- type: perm
- options:
- perm: 'access content'
- cache:
- type: tag
- options: { }
- query:
- type: views_query
- options:
- disable_sql_rewrite: false
- distinct: false
- replica: false
- query_comment: ''
- query_tags: { }
- exposed_form:
- type: basic
- options:
- submit_button: Apply
- reset_button: false
- reset_button_label: Reset
- exposed_sorts_label: 'Sort by'
- expose_sort_order: true
- sort_asc_label: Asc
- sort_desc_label: Desc
- pager:
- type: mini
- options:
- items_per_page: 10
- offset: 0
- id: 0
- total_pages: null
- expose:
- items_per_page: false
- items_per_page_label: 'Items per page'
- items_per_page_options: '5, 10, 25, 50'
- items_per_page_options_all: false
- items_per_page_options_all_label: '- All -'
- offset: false
- offset_label: Offset
- tags:
- previous: ‹‹
- next: ››
- style:
- type: default
- options:
- grouping: { }
- row_class: ''
- default_row_class: true
- uses_fields: false
- row:
- type: fields
- options:
- inline: { }
- separator: ''
- hide_empty: false
- default_field_elements: true
- fields:
- title:
- id: title
- table: node_field_data
- field: title
- entity_type: node
- entity_field: title
- label: ''
- alter:
- alter_text: false
- make_link: false
- absolute: false
- trim: false
- word_boundary: false
- ellipsis: false
- strip_tags: false
- html: false
- hide_empty: false
- empty_zero: false
- settings:
- link_to_entity: true
- plugin_id: field
- relationship: none
- group_type: group
- admin_label: ''
- exclude: false
- element_type: ''
- element_class: ''
- element_label_type: ''
- element_label_class: ''
- element_label_colon: true
- element_wrapper_type: ''
- element_wrapper_class: ''
- element_default_classes: true
- empty: ''
- hide_alter_empty: true
- click_sort_column: value
- type: string
- group_column: value
- group_columns: { }
- group_rows: true
- delta_limit: 0
- delta_offset: 0
- delta_reversed: false
- delta_first_last: false
- multi_type: separator
- separator: ', '
- field_api_classes: false
- filters:
- status:
- value: '1'
- table: node_field_data
- field: status
- plugin_id: boolean
- entity_type: node
- entity_field: status
- id: status
- expose:
- operator: ''
- group: 1
- sorts:
- created:
- id: created
- table: node_field_data
- field: created
- order: DESC
- entity_type: node
- entity_field: created
- plugin_id: date
- relationship: none
- group_type: group
- admin_label: ''
- exposed: false
- expose:
- label: ''
- granularity: second
- header: { }
- footer: { }
- empty: { }
- relationships: { }
- arguments: { }
- display_extenders: { }
- cache_metadata:
- max-age: -1
- contexts:
- - 'languages:language_content'
- - 'languages:language_interface'
- - url.query_args
- - 'user.node_grants:view'
- - user.permissions
- tags: { }
- page_1:
- display_plugin: page
- id: page_1
- display_title: Page
- position: 1
- display_options:
- display_extenders: { }
- path: pages
- cache_metadata:
- max-age: -1
- contexts:
- - 'languages:language_content'
- - 'languages:language_interface'
- - url.query_args
- - 'user.node_grants:view'
- - user.permissions
- tags: { }
-```
-
-When the test is run again, we see a different error that leads us to the next
-step.
-
-```
-1) Drupal\Tests\tdd_dublin\Functional\PageListTest::testListingPageExists
-Drupal\Core\Config\UnmetDependenciesException: Configuration objects provided by tdd_dublin have unmet dependencies: node.type.page (node), views.view.pages (node, views)
-
-FAILURES!
-Tests: 1, Assertions: 0, Errors: 1.
-```
-
-This error is identifying unmet dependencies within the module’s configuration.
-In this case, the view that we’ve added depends on the node and views modules,
-but these aren’t enabled. To fix this, we can add the extra modules as
-dependencies of tdd_dublin so they will be enabled too.
-
-```yaml
-# tdd_dublin.info.yml
-
-dependencies:
- - drupal:node
- - drupal:views
-```
-
-```
-1) Drupal\Tests\tdd_dublin\Functional\PageListTest::testListingPageExists
-Drupal\Core\Config\UnmetDependenciesException: Configuration objects provided by tdd_dublin have unmet dependencies: views.view.pages (node.type.page)
-
-FAILURES!
-Tests: 1, Assertions: 0, Errors: 1.
-```
-
-With the modules enabled, we can see one more unmet dependency for
-`node.type.page`. This means that we need a page content type to be able to
-install the view. We can fix this in the same way as before, by exporting the
-configuration and copying it into the `config/install` directory.
-
-With this in place, the test should now pass - and it does.
-
-```
-Time: 26.04 seconds, Memory: 6.00MB
-
-OK (1 test, 1 assertion)
-```
-
-We now have a test to ensure that the listing page exists.
-
-## Ensure that only Published Pages are Shown
-
-### Writing the Test
-
-Now that we have a working page, we can now move on to checking that the correct
-content is returned. Again, I’ll start by writing comments and then translate
-that into code.
-
-The objectives of this test are:
-
-- To ensure that only page nodes are returned.
-- To ensure that only published nodes are returned.
-
-```php
-public function testOnlyPublishedPagesAreShown() {
- // Given that a have a mixture of published and unpublished pages, as well
- // as other types of content.
-
- // When I view the page.
-
- // Then I should only see the published pages.
-}
-```
-
-In order to test the different scenarios, I will create an additional "article"
-content type, create a node of this type as well as one published and one
-unpublished page. From this combination, I only expect one node to be visible.
-
-```php
-public function testOnlyPublishedPagesAreShown() {
- $this->drupalCreateContentType(['type' => 'article']);
-
- $this->drupalCreateNode(['type' => 'page', 'status' => TRUE]);
- $this->drupalCreateNode(['type' => 'article']);
- $this->drupalCreateNode(['type' => 'page', 'status' => FALSE]);
-
- // When I view the page.
-
- // Then I should only see the published pages.
-}
-```
-
-We could use `drupalGet()` again to browse to the page and write assertions
-based on the rendered HTML, though I’d rather do this against the data returned
-from the view itself. This is so that the test isn’t too tightly coupled to the
-presentation logic, and we won’t be in a situation where at a later date the
-test fails because of changes made to how the data is displayed.
-
-Rather, I’m going to use `views_get_view_result()` to programmatically get the
-result of the view. This returns an array of `Drupal\views\ResultRow` objects,
-which contain the nodes. I can use `array_column` to extract the node IDs from
-the view result into an array.
-
-```php
-public function testOnlyPublishedPagesAreShown() {
- $this->drupalCreateContentType(['type' => 'article']);
-
- $this->drupalCreateNode(['type' => 'page', 'status' => TRUE]);
- $this->drupalCreateNode(['type' => 'article']);
- $this->drupalCreateNode(['type' => 'page', 'status' => FALSE]);
-
- $result = views_get_view_result('pages');
- $nids = array_column($result, 'nid');
-
- // Then I should only see the published pages.
-}
-```
-
-From the generated nodes, I can use `assertEquals()` to compare the returned
-node IDs from the view against an array of expected node IDs - in this case, I
-expect only node 1 to be returned.
-
-```php
-public function testOnlyPublishedPagesAreShown() {
- $this->drupalCreateContentType(['type' => 'article']);
-
- $this->drupalCreateNode(['type' => 'page', 'status' => TRUE]);
- $this->drupalCreateNode(['type' => 'article']);
- $this->drupalCreateNode(['type' => 'page', 'status' => FALSE]);
-
- $result = views_get_view_result('pages');
- $nids = array_column($result, 'nid');
-
- $this->assertEquals([1], $nids);
-}
-```
-
-### Running the Test
-
-The test fails as no extra conditions have been added to the view, though the
-default "Content: Published" filter is already excluding one of the page nodes.
-We can see from the output from the test that node 1 (a page) and node 2 (the
-article) are both being returned.
-
-```
-1) Drupal\Tests\tdd_dublin\Functional\PageListTest::testOnlyPublishedPagesAreShown
-Failed asserting that two arrays are equal.
---- Expected
-+++ Actual
-@@ @@
- Array (
-- 0 => 1
-+ 0 => '2'
-+ 1 => '1'
- )
-
-FAILURES!
-Tests: 1, Assertions: 3, Failures: 1.
-```
-
-### Updating the Test
-
-We can fix this by adding another condition to the view, to only show content
-based on the node type - i.e. only return page nodes.
-
- { .with-border }
-
-Once the view is updated and the configuration is updated within the module, the
-test should then pass - and it does.
-
-```
-Time: 24.76 seconds, Memory: 6.00MB
-
-OK (1 test, 3 assertions)
-```
-
-## Ensure that the Pages are in the Correct Order
-
-### Writing the Test
-
-As we know that the correct content is being returned, we can now focus on
-displaying it in the correct order. We’ll start again by adding a new test
-method and filling out the comments.
-
-```php
-public function testResultsAreOrderedAlphabetically() {
- // Given I have multiple nodes with different titles.
-
- // When I view the pages list.
-
- // Then I should see pages in the correct order.
-}
-```
-
-To begin with this time, I’ll create a number of different nodes and specify the
-title for each. These are intentionally in the incorrect order alphabetically so
-that we can see the test fail initially and then see it pass after making a
-change so we know that the change worked.
-
-```php
-public function testResultsAreOrderedAlphabetically() {
- $this->drupalCreateNode(['title' => 'Page A']);
- $this->drupalCreateNode(['title' => 'Page D']);
- $this->drupalCreateNode(['title' => 'Page C']);
- $this->drupalCreateNode(['title' => 'Page B']);
-
- // When I view the pages list.
-
- // Then I should see pages in the correct order.
-}
-```
-
-We can use the same method as the previous test to get the returned IDs, using
-`views_get_view_result()` and `array_column()`, and assert that the returned
-node IDs match the expected node IDs in the specified order. Based on the
-defined titles, the order should be 1, 4, 3, 2.
-
-```php
-public function testResultsAreOrderedAlphabetically() {
- $this->drupalCreateNode(['title' => 'Page A']);
- $this->drupalCreateNode(['title' => 'Page D']);
- $this->drupalCreateNode(['title' => 'Page C']);
- $this->drupalCreateNode(['title' => 'Page B']);
-
- $nids = array_column(views_get_view_result('pages'), 'nid');
-
- $this->assertEquals([1, 4, 3, 2], $nids);
-}
-```
-
-### Running the Test
-
-As expected the test fails, as the default sort criteria in the view orders the
-results by their created date.
-
-In the test output, we can see the returned results are in sequential order so
-the results array does not match the expected one.
-
-This would be particularly more complicated to test if I was using `drupalGet()`
-and having to parse the HTML, compared to getting the results as an array from
-the view programmatically.
-
-```
-1) Drupal\Tests\tdd_dublin\Functional\PageListTest::testResultsAreOrderedAlphabetically
-Failed asserting that two arrays are equal.
---- Expected
-+++ Actual
-@@ @@
- Array (
-- 0 => 1
-- 1 => 4
-- 2 => 3
-- 3 => 2
-+ 0 => '1'
-+ 1 => '2'
-+ 2 => '3'
-+ 3 => '4'
- )
-
-FAILURES!
-Tests: 1, Assertions: 2, Failures: 1.
-```
-
-### Updating the Test
-
-This can be fixed by removing the default sort criteria and adding a new one
-based on "Content: Title".
-
- { .with-border }
-
-Again, once the view has been updated and exported, the test should pass - and
-it does.
-
-```
-Time: 27.55 seconds, Memory: 6.00MB
-
-OK (1 test, 2 assertions)
-```
-
-## Ensure all Tests Still Pass
-
-Now we know that all the tests pass individually, all of the module tests should
-now be run to ensure that they all still pass and that there have been no
-regressions due to any of the changes.
-
-```
-docker@cli:/var/www$ vendor/bin/phpunit -c core modules/custom/tdd_dublin/tests
-
-Testing modules/custom/tdd_dublin/tests
-...
-
-Time: 1.27 minutes, Memory: 6.00MB
-
-OK (3 tests, 6 assertions)
-```
-
-They all pass, so we be confident that the code works as expected, we can
-continue to refactor if needed, and if any changes are made to this module at a
-later date, we have the tests to ensure that any regressions are caught and
-fixed before deployment.
-
-## Next Steps
-
-I’ve started looking into whether some of the tests can be rewritten as kernel
-tests, which should result in quicker test execution. I will post any updated
-code to the [GitHub repository][3], and will also do another blog post
-highlighting the differences between functional and kernel tests and the steps
-taken to do the conversion.
-
-[0]: {{site.url}}/talks/tdd-test-driven-drupal
-[1]: http://2017.drupal.ie
-[2]: https://github.com/opdavies/tdd_dublin
-[3]: https://packagist.org/packages/tightenco/collect
-[4]: http://php.net/manual/en/function.array-column.php
-[5]: https://gist.github.com/opdavies/dc5f0cea46ccd349b34a9f3a463c14bb
diff --git a/astro/src/content/blog/zenophile.md b/astro/src/content/blog/zenophile.md
deleted file mode 100644
index b18e3114..00000000
--- a/astro/src/content/blog/zenophile.md
+++ /dev/null
@@ -1,24 +0,0 @@
----
-title: Quickly Create Zen Subthemes Using Zenophile
-date: 2010-05-10
-excerpt: How to use the Zenophile module to create a Zen subtheme.
-tags:
- - drupal-planet
- - drupal-6
- - drupal-modules
- - drupal-theming
- - zen
- - zenophile
----
-
-If you use the [Zen](http://drupal.org/project/zen) theme, then you should also
-be using the [Zenophile](http://drupal.org/project/zenophile) module!
-
-The Zenophile module allows you to very quickly create Zen subthemes from within
-your web browser, as well as editing options such as the site directory where it
-should be placed, the layout type (fixed or fluid), page wrapper and sidebar
-widths, and the placement of the sidebars.
-
-For more information about the Zenophile module, check out
-[this video](http://blip.tv/file/2427703) by
-[Elliott Rothman](http://elliottrothman.com).
diff --git a/astro/src/content/config.ts b/astro/src/content/config.ts
deleted file mode 100644
index b3f1084f..00000000
--- a/astro/src/content/config.ts
+++ /dev/null
@@ -1,84 +0,0 @@
-import { defineCollection, z } from "astro:content";
-
-const blogCollection = defineCollection({
- schema: z.object({
- date: z.date().or(z.null()),
- draft: z.boolean().optional(),
- excerpt: z.string().or(z.null()).optional(),
- promoted: z.boolean().optional(),
- title: z.string(),
- tweets: z.boolean().optional(),
- }),
-});
-
-const dailyEmailCollection = defineCollection({
- schema: z.object({
- snippet: z.string().optional(),
- pubDate: z.date(),
- permalink: z.string(),
- tags: z.array(z.string()).optional(),
- title: z.string(),
- }),
-});
-
-const podcastEpisodeCollection = defineCollection({
- schema: z.object({
- date: z.date(),
- draft: z.boolean().optional(),
- guests: z.array(z.string()),
- links: z.array(z.array(z.string())),
- topic: z.string(),
- transistor: z.object({ id: z.string() }).optional(),
- }),
-});
-
-const talkCollection = defineCollection({
- schema: z.object({
- description: z.string(),
- events: z.array(
- z.object({
- date: z.string().or(z.date()),
- location: z.string().optional(),
- name: z.string(),
- online: z.boolean().optional(),
- url: z.string().or(z.null()).optional(),
- })
- ),
- speakerdeck: z
- .object({
- id: z.string(),
- ratio: z.string(),
- url: z.string(),
- })
- .optional().or(z.null()),
- title: z.string(),
- video: z
- .object({
- id: z.string(),
- type: z.enum(["vimeo", "youtube"]),
- })
- .or(z.null())
- .optional(),
- }),
-});
-
-const testimonialCollection = defineCollection({
- type: 'data',
- schema: z.object({
- date: z.string().optional(),
- image: z.string().or(z.null()),
- name: z.string(),
- tagline: z.string().or(z.null()),
- text: z.string(),
- url: z.string().or(z.null()),
- }),
-});
-
-
-export const collections = {
- "daily-email": dailyEmailCollection,
- "podcast-episode": podcastEpisodeCollection,
- blog: blogCollection,
- talk: talkCollection,
- testimonial: testimonialCollection,
-};
diff --git a/astro/src/content/daily-email/2022-08-12.md b/astro/src/content/daily-email/2022-08-12.md
deleted file mode 100644
index c235f8b2..00000000
--- a/astro/src/content/daily-email/2022-08-12.md
+++ /dev/null
@@ -1,75 +0,0 @@
----
-permalink: archive/2022/08/12/git-worktrees-docker-compose
-title: Git Worktrees and Docker Compose
-pubDate: 2022-08-12
----
-
-I've recently started trialing Git worktrees again as part of my development workflow.
-
-If you are unfamiliar with Git worktrees, they allow you to have muliple branches of a repository checked out at the same time in different directories.
-
-For example, this is what I see within my local checkout of my website repository:
-
-```
-.
-├── config
-├── HEAD
-├── main
-│ ├── ansible
-│ ├── nginx
-│ ├── README.md
-│ └── website
-├── new-post
-│ ├── ansible
-│ ├── nginx
-│ ├── README.md
-│ └── website
-├── objects
-│ ├── info
-│ └── pack
-├── packed-refs
-├── refs
-│ ├── heads
-│ └── tags
-└── worktrees
- ├── main
- └── new-post
-```
-
-The first thing that you'll notice is, because it's a bare clone, it looks a little different to a what you usually see in a Git repository.
-
-Each worktree has it's own directory, so my "main" branch inside the `main` directory.
-
-If I need to work on a different branch, such as `new-post`, then I can create a new worktree, move into that directory and start working. I don't need to commit or stash any in-progress work and switch branches.
-
-## Complications with Docker Compose
-
-I use Docker and Docker Compose for my projects, and this caused some issues for me the last time that I tried using worktrees.
-
-By default, Docker Compose will use the name of the directory that the Compose file is in to name its containers. If the directory name is "oliverdavies-uk", then the containers will be `oliverdavies-uk-web_1`, `oliverdavies-uk-db_1` etc.
-
-This doesn't work so well if the directory is a worktree called "main" or "master" as you'll have containers called `main_web_1` or `master_db_1`.
-
-The way to solve this is to use the `COMPOSE_PROJECT_NAME` environment variable.
-
-If you prefix Docker Compose commands with `COMPOSE_PROJECT_NAME=your-project`, or add it to an `.env` file (Docker Compose will load this automatically), then this will override the prefix in the container names to be `your-project-{service}`.
-
-## Container names per worktree
-
-Whilst you could use the same Compose project name within all of your worktrees, I prefer to include the worktree name as a suffix - something like `my-project-main` or `my-project-staging` - and keep these stored in an `.env` file in each worktree's directory.
-
-As each worktree now has unique container names, I can have multiple instances of a project running at the same time, and each worktree will have it's own separate data - meaning that I can make changes and test something in one worktree without affecting any others.
-
-You can also use the `COMPOSE_PROJECT_NAME` variable inside Docker Compose files.
-
-For example, if you use Traefik and needed to override the host URL for a service, the string will be interpolated and the project name would be injected as you'd expect.
-
-```yaml
-labels:
- - "traefik.http.routers.${COMPOSE_PROJECT_NAME}.rule=Host(
- `${COMPOSE_PROJECT_NAME}.docker.localhost`,
- `admin.${COMPOSE_PROJECT_NAME}.docker.localhost`
- )"
-```
-
-This means that Traefik would continue to use a different URL for each worktree without you needing to make any changes to your Docker Compose file.
diff --git a/astro/src/content/daily-email/2022-08-13.md b/astro/src/content/daily-email/2022-08-13.md
deleted file mode 100644
index f8456457..00000000
--- a/astro/src/content/daily-email/2022-08-13.md
+++ /dev/null
@@ -1,47 +0,0 @@
----
-permalink: archive/2022/08/13/i-wrote-a-neovim-plugin
-pubDate: 2022-08-13
-title: I wrote a Neovim plugin
-tags:
- - neovim
- - open-source
----
-
-I enjoy writing and working with open-source software, starting back to when I started working with PHP and Drupal in 2007.
-
-Since then, I've written and maintained a number of Drupal modules and themes, PHP libraries, npm packages, Ansible roles and Docker images - all of which are available on my GitHub and Drupal.org pages.
-
-Just over a year ago, [I switched to using Neovim full-time](/blog/going-full-vim) for my development and DevOps work, and last week, I wrote my first Neovim plugin, written in Lua.
-
-I've used Lua to configure Neovim but this is the first time that I've written and open-sourced a standalone Neovim plugin.
-
-It's called [toggle-checkbox.nvim](https://github.com/opdavies/toggle-checkbox.nvim) and is used toggle checkboxes in Markdown files - something that I use frequently for to-do lists.
-
-For example, this a simple list containing both checked and unchecked checkboxes:
-
-```markdown
-- [x] A completed task
-- [ ] An incomplete task
-```
-
-To toggle a checkbox, the `x` character needs to be either added or removed, depending on whether we're checking or unchecking it.
-
-This is done by calling the `toggle()` function within the plugin.
-
-In my Neovim configuration, I've added a keymap to do this:
-
-```lua
-vim.keymap.set(
- "n",
- "tt",
- "require('toggle-checkbox').toggle()"
-)
-```
-
-This means that I can use the same keymap by running `tt` to check or uncheck a checkbox. I could use Vim's replace mode to do this, but I really wanted to have one keymap that I could use for both.
-
-As it's my first Neovim plugin, I decided to keep it simple.
-
-The main `toggle-checkbox.lua` file is currently only 41 lines of code, and whilst there is an existing Vim plugin that I could have used, I was excited to write my own plugin for Neovim, to start contributing to the Neovim ecosystem, and add a Neovim plugin to my portfolio of open-source projects.
-
-You can view the plugin at , as well as my Neovim configuration (which is also written in Lua) as part of [my Dotfiles repository](https://github.com/opdavies/dotfiles/tree/main/roles/neovim/files).
diff --git a/astro/src/content/daily-email/2022-08-14.md b/astro/src/content/daily-email/2022-08-14.md
deleted file mode 100644
index 3347a630..00000000
--- a/astro/src/content/daily-email/2022-08-14.md
+++ /dev/null
@@ -1,36 +0,0 @@
----
-permalink: archive/2022/08/14/why-i-write-tests
-pubDate: 2022-08-14
-title: "Why I write automated tests"
-tags: [testing]
----
-
-In February 2012, I saw a tweet from Tim Millwood asking if anyone wanted to maintain or co-maintain a Drupal module called [Override Node Options](https://www.drupal.org/project/override_node_options).
-
-It had more than 9,200 active installations at that time, with versions for Drupal 5, 6 and 7.
-
-I said yes and became the module’s maintainer.
-
-The module now has versions for Drupal 7, 8 and 9, with (at the latest count, according to Drupal.org) 32,292 active installations - which makes it currently the 197th most installed module.
-
-There have been two main things that come to mind with this module, related to automated testing.
-
-Before I become the maintainer, a feature request had been created, along with a large patch file, to add some new permissions to the module. There were some large merge conflicts that stopped me from just committing the changes but I was able to fix them manually and, because the tests still passed, ensure that the original functionality still worked. There weren’t tests for the new permissions but I committed the patch and added the tests later.
-
-Without the tests to ensure that the original functionality still worked, I probably wouldn’t have committed the patch and would have just closed the issue.
-
-More recently, a friend and ex-colleague and I decided to refactor some of the module's code.
-
-We wanted to split the `override_node_options.module` file so that each override was in its own file and its own class. This would make them easier to edit and maintain, and if anyone wanted to add a new one, they’d just need to create a new file for it and add it to the list of overrides.
-
-Without the tests ensuring that the module still worked after the refactor, we probably wouldn’t have done it as it was used on over 30,000 sites that I didn't want to break.
-
-When I was learning about testing, I was working on projects where I was writing the code during the day and the tests in the evening on my own time.
-
-I remember once when my manual testing had been fine, but when writing the test, I found that I’d used an incorrect permission name in the code that was causing the test to fail. This was a bug that, rather than waiting for a QA Engineer or the client to discover and report, I was able to fix it locally before I'd even committed the code.
-
-I also worked on an event booking and management website, where we had code responsible for calculating the number of available spaces for an event based on orders, determining the correct price based on the customer's status and the time until the event, creating voucher codes for new members and event leaders, and bulk messaging event attendees. All of the custom functionality was covered by automated tests.
-
-The great thing about testing is that it gives you confidence that everything still works how you expect - not only when you wrote the code, but also in the future.
-
-I've talked about this, and how to get started with automated testing in Drupal, in a presentation called [TDD - Test-Driven Drupal]({{site.url}}/talks/tdd-test-driven-drupal). If you want to find out more, the slides and a video recording are embedded there.
diff --git a/astro/src/content/daily-email/2022-08-15.md b/astro/src/content/daily-email/2022-08-15.md
deleted file mode 100644
index 6d2435d3..00000000
--- a/astro/src/content/daily-email/2022-08-15.md
+++ /dev/null
@@ -1,84 +0,0 @@
----
-permalink: archive/2022/08/15/using-run-file-simplify-project-tasks
-pubDate: 2022-08-15
-title: Using a "run" file to simplify project tasks
-tags: ["php"]
----
-
-Every project has its own set of commands that need to be run regularly.
-
-From starting a local server or the project's containers with Docker or Docker Compose, running tests or clearing a cache, or generating the CSS and JavaScript assets, these commands can get quite complicated and time-consuming and error-prone to type over and over again.
-
-One common way to simplify these commands is using a `Makefile`.
-
-A Makefile contains a number of named targets that you can reference, and each has one or more commands that it executes.
-
-For example:
-
-```yaml
-# Start the project.
-start:
- docker-compose up -d
-
-# Stop the project.
-stop:
- docker-compose down
-
-# Run a Drush command.
-drush:
- docker-compose exec php-fpm drush $(ARGS)
-```
-
-With this Makefile, I can run `make start` to start the project, and `make stop` to stop it.
-
-Makefiles work well, but I don't use the full functionality that they offer, such as dependencies for targets, and passing arguments to a command - like arguments for a Drush, Symfony Console, or Artisan command, doesn't work as I originally expected.
-
-In the example, to pass arguments to the `drush` command, I'd have to type `ARGS="cache:rebuild" make drush` for them to get added and the command to work as expected.
-
-An agency that I worked for created and open-sourced their own Makefile-like tool, written in PHP and built on Symfony Console. I gave a talk on it called [Working with Workspace]({{site.url}}/talks/working-with-workspace) and used it on some of my own personal and client projects.
-
-## What I'm using now
-
-The solution that I'm using now is a `run` file, which is something that I learned from Nick Janetakis' blog and YouTube channel.
-
-It's a simple Bash file where you define your commands (or tasks) as functions, and then execute them by typing `./run test` or `./run composer require something`.
-
-Here's the Makefile example, but as a `run` script:
-
-```bash
-#!/usr/bin/env bash
-
-function help() {
- # Display some default help text.
- # See examples on GitHub of how to list the available tasks.
-}
-
-function start {
- # Start the project.
- docker-compose up -d
-}
-
-function stop {
- # Stop the project.
- docker-compose down
-}
-
-function drush {
- # Run a Drush command with any additional arguments.
- # e.g. "./run drush cache:rebuild"
- docker-compose exec php-fpm drush "${@}"
-}
-
-# Execute the command, or run "help".
-eval "${@:-help}"
-```
-
-As it's Bash, I can just use `$1`, `$2` etc to get specific arguments, or `$@` to get them all, so `./run drush cache:rebuild` works as expected and any additional arguments are included.
-
-You can group tasks by having functions like `test:unit` and `test:commit`, and tasks can run other tasks. I use this for running groups of commands within a CI pipeline, and to extract helper functions for tasks like running `docker-compose exec` within the PHP container that other commands like `drush`, `console` or `composer` could re-use.
-
-As well as running ad-hoc commands during development, I also use the run file to create functions that run Git pre-commit or pre-push hooks, deploy code with Ansible, or build, push or pull the project's latest Docker images.
-
-I also use one within my Talks repository to generate PDF files using rst2pdf, present them using phdpc, and generate thumbnail images.
-
-For examples of `run` files that I use in my open-source code, [you can look in my public GitHub repositories](https://github.com/search?l=Shell&q=user%3Aopdavies+filename%3Arun&type=Code), and for more information, here is [Nick's blog post where I first found the idea](https://nickjanetakis.com/blog/replacing-make-with-a-shell-script-for-running-your-projects-tasks).
diff --git a/astro/src/content/daily-email/2022-08-16.md b/astro/src/content/daily-email/2022-08-16.md
deleted file mode 100644
index c94c05d5..00000000
--- a/astro/src/content/daily-email/2022-08-16.md
+++ /dev/null
@@ -1,42 +0,0 @@
----
-permalink: archive/2022/08/16/what-are-git-hooks-why-are-they-useful
-pubDate: 2022-08-16
-title: "What are Git hooks and why are they useful?"
-tags: ["git"]
----
-
-In yesterday's email, I mentioned Git hooks but didn't go into any detail. So, what are they?
-
-Git hooks are Bash scripts that you add to your repository that are executed when certain events happen, such as before a commit is made or before a push to a remote.
-
-By default, the script files need to be within the `.git/hooks` directory, have executable permissions, and be named to exactly match the name of the hook - e.g. `pre-push` - with no file extension.
-
-If it returns an error exit code then the process is stopped and the action doesn't complete.
-
-This is useful if, for example, you or your team use a specified format for commit messages and you want to prevent the commit if the message doesn't match the requirements.
-
-But, the main benefit that I get from Git hooks if from the `pre-push` hook.
-
-I use it to run a subset of the checks that are run within project's CI pipeline to limit failures in the CI tool and fix simple errors before I push the code.
-
-Typically, these are the quicker tasks such as ensuring the Docker image builds, running linting and static analysis, validating lock files, and some of the automated tests if they don't take too long to run.
-
-If a build is going to fail because of something simply like a linting error, then I'd rather find that out and fix it locally rather than waiting for a CI tool to fail.
-
-Also, if you're utilising trunk-based development and continuous integration where team members are pushing changes regularly, then you want to keep the pipeline in a passing, deployable state as much as possible and prevent disruption.
-
-But what have Git hooks got to do with the "run" file?
-
-Firstly, I like to keep the scripts as minimal as possible and move the majority of the code into functions within the `run` file. This means that the scripts are only responsible for running functions like `./run test:commit` and returning the appropriate exit code, but also means that it's easy to iterate and test them locally without making fake commits or trying to push them to your actual remote repository (and hoping that they don't get pushed).
-
-Secondly, I like to simplify the setup of Git hooks with their own functions.
-
-For security reasons, the `.git/hooks` directory cannot be committed and pushed to your remote so they need to be enabled per user within their own clone of the repository.
-
-A common workaround is to put the scripts in a directory like `.githooks` and either symlink them to where Git expects them to be, or to use the `core.hooksPath` configuration option and change where Git is going to look.
-
-I like to lower the barrier for any team members by creating `git-hooks:on` and `git-hooks:off` functions which either set or unset the `core.hooksPath`. If someone wants to enable the Git hooks then they only need to run one of those commands rather than having to remember the name of the configuration option or manually creating or removing symlinks.
-
-There are other Git hooks that can be used but just using `pre-commit` and `pre-push` has saved me and teams that I've worked on both Developer time and build minutes, provides quicker feedback and fewer disruptions in our build pipelines, and I like how simple it can be by creating custom functions in a `run` file.
-
-Lastly, I've created as an example with a minimal `run` file and some example hooks.
diff --git a/astro/src/content/daily-email/2022-08-17.md b/astro/src/content/daily-email/2022-08-17.md
deleted file mode 100644
index e0474f33..00000000
--- a/astro/src/content/daily-email/2022-08-17.md
+++ /dev/null
@@ -1,39 +0,0 @@
----
-permalink: archive/2022/08/17/one-more-run-command-git-worktrees
-pubDate: 2022-08-17
-title: One more "run" command, for Git worktrees
-tags: ["drupal", "git"]
----
-
-Here's another `run` file example, this time relating to Git worktrees...
-
-One project that I work on is a multilingual Drupal application that needs to work in both English and Welsh. As I'm cloning a fresh version today, I'm doing it as a bare repository so I can use worktrees.
-
-To work on it locally, just like in production, I need to use a different URL for each language so that Drupal can identify it and load the correct content and configuration.
-
-For fixed environments like production or staging, the URLs are set in configuration files, but for ad-hoc environments such as local worktrees, I thought that the best approach was to override them as needed per worktree using Drush (a Drupal CLI tool).
-
-I could do this manually each time or I could automate it in a `run` command. :)
-
-Here's the function that I came up with:
-
-```bash
-function drupal:set-urls-for-worktree {
- # Set the site URLs based on the current Git worktree name.
- local worktree_name="$(basename $PWD)"
-
- local cy_url="cy-projectname-${worktree_name}.docker.localhost"
- local en_url="projectname-${worktree_name}.docker.localhost"
-
- # Update the URLs.
- drush config:set language.negotiation url.domains.cy -y $cy_url
- drush config:set language.negotiation url.domains.en -y $en_url
-
- # Display the domains configuration to ensure that they were set correctly.
- drush config:get language.negotiation url.domains
-}
-```
-
-It builds the worktree URL for each language based on the directory name, executes the configuration change, and finally displays the updated configuration so I can confirm that it's been set correctly.
-
-This is a good example of why I like using `run` files and how I use them to automate and simplify parts of my workflow.
diff --git a/astro/src/content/daily-email/2022-08-18.md b/astro/src/content/daily-email/2022-08-18.md
deleted file mode 100644
index c3d004b0..00000000
--- a/astro/src/content/daily-email/2022-08-18.md
+++ /dev/null
@@ -1,27 +0,0 @@
----
-permalink: archive/2022/08/18/talking-drupal-tailwind-css
-pubDate: 2022-08-18
-title: "'Talking Drupal' and Tailwind CSS"
-tags:
- - css
- - tailwind-css
- - twig
----
-
-In March, I was a guest again on the Talking Drupal podcast. This time I was talking about utility CSS and, in particular, the Tailwind CSS framework.
-
-I've become a big fan of this approach to styling websites and was an early adopter of Tailwind, and have released [a starter-kit theme](https://www.drupal.org/project/tailwindcss) for building custom Drupal themes with Tailwind CSS based on what I was using for my own client projects.
-
-## Rebuilding Talking Drupal with Tailwind
-
-Usually when I give a Tailwind CSS talk at a conference or user group, I rebuild something familiar - maybe a page of their website - as an example and to explain some of the concepts and anything that was particularly interesting during the build. (I have [a blog post]({{site.url}}/blog/uis-ive-rebuilt-tailwind-css) that lists the ones that I've done before).
-
-After this podcast episode, I built a [Tailwind version of the Talking Drupal homepage](https://talking-drupal-tailwindcss.oliverdavies.uk).
-
-But, given that Drupal uses Twig and that we'd talked about best practices around using a templating engine to use loops and extract components to organise code and reduce duplication, I definitely wanted to build this example using Twig templates.
-
-Drupal seemed like too much for a single page example, and Symfony or Sculpin could distract from the main focus of the demo, so I decided to start from scratch with an empty PHP file and add Twig and any other dependencies myself.
-
-[The code repository](https://github.com/opdavies/talking-drupal-tailwindcss) is publicly viewable on my GitHub profile so people can look at the code and see some of the things that I talked about during the episode in practice and not just the resulting HTML a browser.
-
-You can [listen to the episode](https://talkingdrupal.com/338), and if you want any more information, the slides and video from my [Taking Flight with Tailwind CSS talk]({{site.url}}/talks/taking-flight-with-tailwind-css) are on my website.
diff --git a/astro/src/content/daily-email/2022-08-19.md b/astro/src/content/daily-email/2022-08-19.md
deleted file mode 100644
index dcda3afc..00000000
--- a/astro/src/content/daily-email/2022-08-19.md
+++ /dev/null
@@ -1,25 +0,0 @@
----
-permalink: archive/2022/08/19/pair-programming-or-code-reviews
-pubDate: 2022-08-19
-title: Pair programming or code reviews?
----
-
-It's been almost a year and a half since I last pushed a feature branch, created a pull request, and waited for it to be reviewed and (hopefully) merged and deployed.
-
-On the majority of teams and projects that I've worked on, this was how things were done.
-
-Tasks would be worked on in separate branches which would need to be reviewed by one or more other Developers before being merged.
-
-I'm an advocate for continuous integration and trunk-based development (both I plan on writing about in more depth) in which there is no formal code review step, but instead, I encourage people to pair program as much as possible.
-
-Pair or mob (group) programming, for me, is like a real-time code review where you can discuss and make changes instantly, rather than waiting until the work is complete and someone reviewing it after the fact. If a bug is spotted as you're typing it or something could be named better, you can update it there and then.
-
-But there are other benefits too.
-
-Instead of one person writing some code, and others reviewing it after the fact, multiple people have written it together and the knowledge is shared amongst those people.
-
-As you've worked together, you don't need to ask or wait for someone to set time aside to review your changes, so it's quicker for them to be merged and deployed. It's already been reviewed, so as long as any automated checks pass, the code can be merged.
-
-I've worked in pairs where I've taught someone how to write automated tests and do test-driven development, which I suspect wouldn't have been quite the same if they'd just read the finished code afterwards.
-
-Of course, some Developers and teams will prefer the typical code review process - it's worked well for me and projects that I've worked on in the past - but personally, I like the speed, agility, mentoring and learning, and social benefits that I can get more easily from pair programming.
diff --git a/astro/src/content/daily-email/2022-08-20.md b/astro/src/content/daily-email/2022-08-20.md
deleted file mode 100644
index f5b7dcc3..00000000
--- a/astro/src/content/daily-email/2022-08-20.md
+++ /dev/null
@@ -1,22 +0,0 @@
----
-pubDate: 2022-08-20
-title: "A return to offline meetups and conferences"
-permalink: "archive/2022/08/20/return-to-offline-meetups-conferences"
-tags: ["community"]
----
-
-Yesterday, I dusted off our Meetup page and posted our next [PHP South Wales meetup](https://www.meetup.com/php-south-wales) event.
-
-We've had online meetups and code practice sessions throughout the pandemic and during lockdowns, but this will be our first offline/in person/IRL meetup since February 2020.
-
-As well as organising our online meetups during COVID, I attended a lot of other online events, [usually giving various talks or workshops]({{site.url}}/blog/speaking-remotely-during-covid-19), and whilst they were good for a while, I eventually started to get burned out by them.
-
-I've been an organiser of various meetups and conferences for a long time, and attending events has been a very large part of my career so far - providing opportunities to learn, to network and socialise with other attendees, and pass knowledge on through talks, workshops and mentoring.
-
-It's been great to see some offline events returning, from local user groups to conferences such as DevOpsDays, DrupalCon and SymfonyLive.
-
-I've given one talk this year - a lot less than this time last year - but it was in front of an audience instead of a screen, and whilst it seemed strange, I'm sure that it's something that will feel normal again in time.
-
-I'm thinking of attending a conference next month, I've submitted some talk suggestions to some other conferences which I'm waiting to hear from, and am considering travelling to some of the other UK user groups as they restart - some of which I joined or spoke at online but it would be great to meet them in person.
-
-For next week, I'll be glad to have PHP South Wales events running again and to see our community back together in person, and then do it again and start getting ready for next month's event.
diff --git a/astro/src/content/daily-email/2022-08-21.md b/astro/src/content/daily-email/2022-08-21.md
deleted file mode 100644
index a1916fbe..00000000
--- a/astro/src/content/daily-email/2022-08-21.md
+++ /dev/null
@@ -1,29 +0,0 @@
----
-permalink: archive/2022/08/21/2022-08-21
-pubDate: 2022-08-21
-title: "Why I use Docker and Docker Compose for my projects"
-tags:
- - docker
----
-
-For the last few years, I've used Docker and Docker Compose exclusively on all of my projects. When I start a new project or onboard a new client, usually one of the first things that I need to do is get an application running in Docker so that I can work on it.
-
-
-
-I've inherited projects with no environment configuration or documentation at all and I need to start from scratch to get it running. Ideally, each project would have it's local environment configuration in the same Git repository as the application code.
-
-For my own projects, these days I prefer to use Docker and Docker Compose - creating my own Dockerfiles for each project so that the correct dependencies are present and the required build steps are executed, as well as acting as documentation.
-
-It's lean as the environment is built specifically for each project, and easy to configure using Docker and Docker Compose directly using native patterns such as override files, environment variables and interpolation, and multi-stage builds.
-
-The configuration can be as simple or complicated as it needs to be for each project rather than using "a one size fits all" approach. If I'm working with Drupal, Fractal, Vue.js, a PHP library, a Go command line tool, or something else entirely, I can use the most appropriate starting point.
-
-As well as local developments, it's easy to use Docker and Docker Compose in CI environments with tools like GitHub Actions and Bitbucket Pipelines. They will either be present by default or will be easy to install, and it's simple to run a `docker-compose build` or `docker-compose run` command within a pipeline to check that the project builds correctly and to execute tasks such as automated tests or static analysis.
-
-As well as using it for projects, Docker has been useful for me in other situations where I need to run small tools such as rst2pdf for generating presentation slides, and ADR Tools for working with architectural decision records.
-
-For some situations like an open-source contribution day, using an off-the-shelf solution would probably be a better option, and some teams will have their own preferences, but I prefer to use Docker and Docker Compose when I can.
-
-Personally, I like to invest time into learning tools that provide reusable knowledge, such as Docker and Docker Compose. I'd prefer to spend time learning something, even if it may take longer compared to other tools, if it's going to give me a return on that investment in the medium- to long-term.
-
-For some examples of how I work with Docker and Docker Compose, you can [see my public GitHub repositories](https://github.com/opdavies?tab=repositories&q=docker) and how things are put together there.
diff --git a/astro/src/content/daily-email/2022-08-22.md b/astro/src/content/daily-email/2022-08-22.md
deleted file mode 100644
index 45af8ed7..00000000
--- a/astro/src/content/daily-email/2022-08-22.md
+++ /dev/null
@@ -1,25 +0,0 @@
----
-permalink: archive/2022/08/22/2022-08-22
-pubDate: 2022-08-22
-title: "Being a T-shaped Developer"
----
-
-A blog post appeared on my feed this morning, titled [How to be T-Shaped](https://www.nomensa.com/blog/how-to-be-t-shaped).
-
-"T-shaped Developers" is a term that I've also used before. Being T-shaped means that you have a deep knowledge in one particular area and a breadth of knowledge in other areas.
-
-I would say that I'm T-shaped.
-
-My main area of knowledge is PHP and Drupal software development - they're the programming language and content management system that I've used throughout most of my career so far, since I started in 2007.
-
-As I worked on my own personal and client projects, I needed to learn more complementary skills.
-
-I needed to learn how to style websites and build themes so I started to learn front-end development with CSS and frameworks like Bootstrap, Bulma and Tailwind CSS, and JavaScript frameworks like Angular, Vue.js and Alpine, as well as TypeScript.
-
-I also needed to host these projects somewhere, which introduced me to Linux servers, virtual hosts, (S)FTP and SSL, web servers like Apache, Nginx and Caddy, MySQL and MariaDB databases, and as projects got more complicated, I started using tools like Vagrant and Puppet, Ansible, and Docker for configuring environments to work in.
-
-I don't use Drupal for every project. I've used static site generators and frameworks like Symfony based on the project's requirements, and have projects that use several different technologies at the same time.
-
-The main benefits are that I can either deliver entire projects or projects with more complicated architectures, or work across different teams - mentoring a team of Front-End Developers in Drupal theming, or working with System Administrators to start hosting PHP applications. Having these additional skills is definitely valuable to employers and clients.
-
-I've said that one of the best and worst things about software development is that there's always something new to learn!
diff --git a/astro/src/content/daily-email/2022-08-23.md b/astro/src/content/daily-email/2022-08-23.md
deleted file mode 100644
index 7b546f53..00000000
--- a/astro/src/content/daily-email/2022-08-23.md
+++ /dev/null
@@ -1,31 +0,0 @@
----
-pubDate: 2022-08-23
-title: "Git: GUI or command-line?"
-permalink: "archive/2022/08/23/git-gui-command-line"
-tags:
- - "git"
----
-
-I’ve been using Git for a long time. My first full-time Developer role in 2010 was working on an in-house team and that project used Git as it’s version control system.
-
-I remember typing commands into an Ubuntu terminal and trying to wrap my head around the process of adding and staging files, (sometimes) pulling, and then pushing to a remote. I think the remote was a simple bare repository on a server, so there was no UI like there is in GitHub and similar tools today.
-
-In fact, GitHub only started two years earlier in 2008, and GitLab wasn’t around until 2014.
-
-Looking back, my introduction to Git as a Junior Developer wasn't easy and I remember starting to get frustrated until it eventually "clicked" and made sense.
-
-I don't remember if there were GUIs at that time (I remember using gitk but I can't think when), but having a tool like GitHub where I could see the code, branches and commits, would probably have been helpful with my initial learning.
-
-Whilst working locally, I've tried some of the desktop GUI tools like Sourcetree, gitkraken and Tower, but I always come back to using Git on the command line.
-
-While a Git GUI tool may make it easier to learn Git initially as a Junior Developer, I'd recommend trying to learn the command line too.
-
-In my opinion, understanding what’s happening "under the hood" when is important working with a GUI - just in case you find yourself unexpectedly having to use the command line. I’ve seen an error in a Git GUI that suggests running commands in the terminal to debug or fix the issue. If you aren't familiar with the terminal commands or what they do, then I'd expect this to be intimidating and confusing.
-
-If you're working as part of a team or contributing to an open-source project then the consistency that the command line provides will make it easier when working with colleagues or getting help from project maintainers. You're also learning Git itself rather than a tool that may add it's own terminology or change how Git itself works, also causing confusion.
-
-There's a lot of Git functionality and concepts that I wouldn't have explored if I wasn't using the command line and relying on a GUI, such as adding and removing code in chunks using patch mode, using bisect to find when a bug was introduced, worktrees for local code organisation, and understanding merging vs rebasing, interactive and non-interactive rebases, and merge commits and fast-forward merges.
-
-Of course, if you prefer to use a GUI and it works for you, then that's fine. Personally, I like to dig deep when learning tools, to know them inside-out and understand how to use them well, and I think that the time that I've spent learning Git and optimising my workflow paid for itself a long time ago.
-
-How do you like to use Git? Do you prefer to use the command line or a GUI tool? Reply to this email and let me know.
diff --git a/astro/src/content/daily-email/2022-08-24.md b/astro/src/content/daily-email/2022-08-24.md
deleted file mode 100644
index 3790c2a2..00000000
--- a/astro/src/content/daily-email/2022-08-24.md
+++ /dev/null
@@ -1,51 +0,0 @@
----
-permalink: archive/2022/08/24/2022-08-24
-pubDate: 2022-08-24
-title: "How I've configured Git"
-tags:
- - "git"
----
-
-After yesterday's post on why I prefer using Git on the command line rather than using a GUI tool, today I thought that I'd post about how I've configured Git.
-
-First, I rarely ever run the `git` command - I usually run a `g` function that I've created within my zsh configuration.
-
-Rather than being an simple alias, it's a shell function that will run `git status -sb` to show the current status of the repository if there are no additional arguments. If there are, such as when running `g add`, then this is executed as a normal Git command. (This is something that I first saw from Thoughtbot, if I remember correctly).
-
-## Using .gitconfig
-
-The main part of my configuration is within Git's `~/.gitconfig` file, where I can configure Git to work how I want.
-
-For example, I like to avoid merge conflicts, so I always want to use fast-forward merges whilst pulling and also to rebase by default. I can do this by adding `ff = only` and `rebase = true` to the `[pull]` section of my `~/.gitconfig` file.
-
-I can do this manually, or running `git config --global pull.rebase true` will set the option but also update the file automatically.
-
-Some of the tweaks that I've made are to only allow fast-forward merges by adding `merge.ff = only`, automatically squash commits when rebasing by setting `rebase.autosquash = true`, and automatically pruning branches by adding `fetch.prune = true`.
-
-### Simple aliases
-
-Another way that I configure Git is using aliases, which are also within the `~/.gitconfig` file.
-
-For example, if I ran `git config --global alias.b "branch"`, then running `git b` would just run `git branch` which shortens the command and saves some time and keystrokes.
-
-I have similar one- or two letter "short" aliases for pushing and pulling code, and some that also set some additional arguments such as `aa` for `add --all` and `worktrees` for `worktree list`.
-
-### More complicated aliases
-
-Aliases can be more complex if needed by prefixing it with a `!`, meaning that it executes it as a shell command.
-
-This means that I can have `repush = !git pull --rebase && git push` to chain two separate Git commands and combine them into one, and `ureset = !git reset --hard $(git upstream)` which executes the full command, including another alias as part of it.
-
-I also have `issues = !gh issue list --web` and `pulls = !gh pr list --web` to open the current repository's GitHub issues or pull requests respectively, which can be done as it's not limited to just running `git` commands.
-
-### Custom functions
-
-Finally, if an alias is getting too long or complex, then it can extracted to it's own file.
-
-Any executable file within your `$PATH` that starts with `git-` will automatically become a Git command.
-
-One example that I have is [git-cm](https://github.com/opdavies/dotfiles/blob/2b20cd1e59ae3b1fa81074077e855cbdfa02f146/bin/bin/git-cm) which, similar to the `g` function`, is a bash script that checks for any arguments passed to it and runs a slightly different command. It achieves the same thing as if it were an alias, but it does make it easier to write and maintain as it's in a separate file.
-
-These are just some examples. If you want to see my entire configuration, then check out [my dotfiles repository on GitHub](https://github.com/opdavies/dotfiles/tree/2b20cd1e59ae3b1fa81074077e855cbdfa02f146/roles/git/files).
-
-How have you configured Git for your workflow? Reply to this email and let me know.
diff --git a/astro/src/content/daily-email/2022-08-25.md b/astro/src/content/daily-email/2022-08-25.md
deleted file mode 100644
index 304e1a53..00000000
--- a/astro/src/content/daily-email/2022-08-25.md
+++ /dev/null
@@ -1,24 +0,0 @@
----
-pubDate: 2022-08-25
-title: "Why I work in Neovim"
-tags: ["vim", "neovim"]
-permalink: "archive/2022/08/25/why-i-work-in-neovim"
----
-
-Over a year ago, I posted that I was [switching to using Neovim full-time]({{site.url}}/blog/going-full-vim) for my development work.
-
-I'd used Vim one file at a time on remote servers, and added Vim plugins in other IDEs and editors, so I was already familiar with a lot of the key bindings and motions before I decided to use it full-time.
-
-Still, it was tough to begin with, but once I'd learned how to configure Neovim, I also learned that being able to customise and extend it as much as you need to is one of its main advantages compared to other IDEs and code editors.
-
-TJ DeVries - a Neovim core team member - has recently coined the term "PDE" (a personalised development environment) which, for me, describes Neovim perfectly.
-
-Currently, I have a fuzzy-finder to quickly open files (as well as many other things), an LSP client to add code intelesense, auto-completion, refactoring tools, custom snippets, and very recently, a database client and a HTTP client.
-
-Just as important to me, I've found a growing community of other Neovim users who stream on Twitch, post YouTube videos, write blog posts, or publish their dotfiles for others to see and reference.
-
-I've learned Lua. Not just for my own Neovim configuration, but I recently wrote and open-sourced my own simple plugin.
-
-Like Git, I enjoy and prefer using tools that I can configure and adapt to my workflow.
-
-Given Neovim's flexibility and configurability, its expanding feature set both in core and community plugins, and the growing community, I think that Neovim is going to be something that I continue to use and adapt for a long time.
diff --git a/astro/src/content/daily-email/2022-08-26.md b/astro/src/content/daily-email/2022-08-26.md
deleted file mode 100644
index d6cb695f..00000000
--- a/astro/src/content/daily-email/2022-08-26.md
+++ /dev/null
@@ -1,19 +0,0 @@
----
-pubDate: 2022-08-26
-title: "Always be learning"
-permalink: "archive/2022/08/26/always-be-learning"
----
-
-I've been a Developer for 15 years and one thing that I've always focussed on is to always keep learning.
-
-From starting as a self-taught Developer, initially learning HTML and CSS, to later learning PHP and Drupal as well as other languages, frameworks and tools.
-
-For the last couple of days, I've been experimenting with Next.js - a React-based web framework. I hadn't used React before and have typically reached for Vue.js or sometimes Alpine.js based on what I needed to do. However, I'm always looking for opportunities to learn and implement new things, and see how I can use them in any of my projects.
-
-This afternoon, I started a new Next.js and TypeScript project, and refactored a small codebase that used a static site generator to create a small number of landing pages from Markdown files.
-
-It took me a short time to set up a Docker environment for it based on some of my Vue.js projects, ported across the application to recreate the pages, and finally, updated the CI pipeline that generated the static pages and uploaded them to an S3 bucket.
-
-The end result is the same - the same HTML pages are generated and uploaded - but, for me, trying and experimenting with new things keeps my work interesting and my knowledge fresh, which benefits me as well as my colleagues and clients.
-
-As I said in a previous email, one of the great things about software development is that there's always something new to learn.
diff --git a/astro/src/content/daily-email/2022-08-27.md b/astro/src/content/daily-email/2022-08-27.md
deleted file mode 100644
index 3e6950ec..00000000
--- a/astro/src/content/daily-email/2022-08-27.md
+++ /dev/null
@@ -1,15 +0,0 @@
----
-pubDate: 2022-08-27
-title: "Giving back"
-permalink: "archive/2022/08/27/giving-back"
----
-
-Today, I've been at an event run by a local animal rescue charity. It's one that we attend often as my children like to enter the dog show, but this year, I've also sponsored one of the categories.
-
-As well as organising the PHP South Wales user group, I'm also now a sponsor - donating books and elePHPant plushies for raffle prizes and paying the group's Meetup.com subscription costs.
-
-Giving back and supporting open-source maintainers and content creators is a big priority of mine. If I use some open-source software or find that someone's Twitch or YouTube channel is useful, if that person or organisation is on GitHub or Patron, then I'll sponsor them, or I'll subscribe to their channel.
-
-If I find a useful blog post or video, I'll add a comment or link to it on Twitter, thanking them and letting them know that it helped me.
-
-Especially if it's something that I've used within my projects, it makes sense to support it and it's maintainers, so that they keep working on and improving the software, continue streaming, and keep writing blog posts and recording videos for me to learn from.
diff --git a/astro/src/content/daily-email/2022-08-28.md b/astro/src/content/daily-email/2022-08-28.md
deleted file mode 100644
index c531f4e4..00000000
--- a/astro/src/content/daily-email/2022-08-28.md
+++ /dev/null
@@ -1,27 +0,0 @@
----
-pubDate: 2022-08-28
-title: "How I started programming"
-permalink: "archive/2022-08-28/how-started-programming"
----
-
-In 2007, I was working in the IT sector in a Desktop Support role but hadn't done any coding professionally.
-
-In my spare time, I was a black belt in Tae Kwon-Do and enjoyed training at a few different schools. Because of my IT experience, I was asked if I could create a website for one of the schools - somewhere that we could post information and class times for new starters, as well as news articles and competition results.
-
-This would be my introduction to programming.
-
-I started learning what I needed to know, starting with HTML and CSS - experimenting with a template that I found online and was able to tweak to match the school's colours.
-
-I was able to complete the first version of the website with static HTML pages and CSS but had to manually create a new HTML page for every new news article and edit existing pages manually.
-
-I wanted to make it more dynamic, and started to learn about PHP and MySQL from video courses and online forums.
-
-After posting a question about some PHP code that I'd written, someone suggested that I look at content management systems - namely Drupal, which was used for that forum (I have [a screenshot of the reply](https://twitter.com/opdavies/status/1185456825103241216)). This was a new concept to me as until that point, I'd written everything so far myself whilst learning it.
-
-I remember evaluating Drupal alongside some others - rebuilding the same website a few different times, but stuck with Drupal and relaunched it on Drupal 6 and a custom theme that I'd created from the original templates.
-
-I signed up for a Drupal.org account, started to do some freelance work for a local web design agency, and built a new website for a local cattery.
-
-I started blogging, attending meetups, and when an opportunity to switch careers to software development came along, I applied for and got the job.
-
-That job was also using Drupal and, in another email, I'll write more about why I still like and use Drupal years later.
diff --git a/astro/src/content/daily-email/2022-08-29.md b/astro/src/content/daily-email/2022-08-29.md
deleted file mode 100644
index 78ba11f0..00000000
--- a/astro/src/content/daily-email/2022-08-29.md
+++ /dev/null
@@ -1,22 +0,0 @@
----
-pubDate: 2022-08-29
-title: "Why I like Drupal"
-permalink: "archive/2022/08/29/why-like-drupal"
-tags: ["drupal"]
----
-
-As I said in yesterday's email, I developed my first website project on Drupal. It allowed me to take a static HTML and CSS website and convert it into something that was much easier and quicker for me to update, and allowed me to create more users with permissions to do those tasks too.
-
-I worked on various Drupal projects, and my first full-time job was on an in-house team where we maintained and enhanced a Drupal 6 website.
-
-I've since used Drupal for projects of all shapes and sizes with different levels of complexity. Everything from a simple brochure website to large and complex, multilingual, API-driven projects.
-
-I've been able to build eCommerce websites with Drupal using Ubercart and Drupal Commerce. I've built traditional stores where customers purchase physical products, a photography competition website with custom judging functionality, a site for purchasing commercial and residential property and land searches, and a fully-fledged events booking and management platform.
-
-Whatever the size and complexity of the project, Drupal is flexible enough to fit it.
-
-I've loved some of the ecosystem improvements within the last few years. Moving to object-orientated code by default, integrating code from other projects like Symfony, shipping new features every six months as part of the new release cycle, and embracing tools like Composer, PHPStan and Rector.
-
-I also love being part of the Drupal community. Collaborating on tasks, speaking on Slack, and attending events like DrupalCon where I've been lucky enough to attend, speak and mentor.
-
-Although Drupal is my specialty and the tool that I've used the most, I don't use it exclusively. I'll talk more about this in tomorrow's email.
diff --git a/astro/src/content/daily-email/2022-08-30.md b/astro/src/content/daily-email/2022-08-30.md
deleted file mode 100644
index 7b1a3577..00000000
--- a/astro/src/content/daily-email/2022-08-30.md
+++ /dev/null
@@ -1,24 +0,0 @@
----
-pubDate: 2022-08-30
-title: "Why I don't only use Drupal"
-permalink: "archive/2022/08/30/why-dont-only-use-drupal"
-tags: ["drupal"]
----
-
-Yesterday, [I shared some of the reasons]({{site.url}}/archive/2022/08/29/why-like-drupal) why I like Drupal and why I use it for the majority of my projects. But, as I said, I don't use it exclusively and for some projects I used various different tools.
-
-Essentially, I always try to recommend and use the best tool for the job.
-
-I previously interviewed for a job and was asked to complete a coding test. The role was mostly Drupal-focussed, but as the test asked for a command-line application, I completed it using Symfony and Symfony Console, and was able to discuss why I'd made that decision. In my opinion, it was the best choice based on the requirements.
-
-This is the same approach that I use when making recommendations for a new project.
-
-I've delivered projects using other tools like the Symfony framework or a static site generator, as long as it fitted the requirements.
-
-If there's a SaaS solution that can be used instead, or an off-the-shelf tool that can be integrated instead of writing a custom solution, then that should be evaluated.
-
-There may be other constraints like budgets or deadlines to consider - maybe something can be delivered faster or cheaper using a particular technology, even if it's not the final solution.
-
-There are situations though where a tool may be the best choice even though it's not the ideal fit based purely on the technical requirements. Maybe the client is already familiar with publishing content in Drupal, or an in-house development team is used to working with a certain tool or language. In that case, those things should be considered too.
-
-Also, for me, having a chance to evaluate other technologies and explore what's happening outside of the Drupal ecosystem is a good opportunity. A lot of what I've learned about automated testing, for example, is from the wider PHP and JavaScript communities, as well as tools like [Tailwind CSS]({{site.url}}/talks/taking-flight-with-tailwind-css) and [Illuminate Collections]({{site.url}}//talks/using-illuminate-collections-outside-laravel) that I've been able to bring back into my other Drupal projects.
diff --git a/astro/src/content/daily-email/2022-08-31.md b/astro/src/content/daily-email/2022-08-31.md
deleted file mode 100644
index fdefa4a2..00000000
--- a/astro/src/content/daily-email/2022-08-31.md
+++ /dev/null
@@ -1,24 +0,0 @@
----
-title: "To monorepo, or not to monorepo?"
-permalink: "archive/2022/08/31/monorepo-or-not"
-pubDate: 2022-08-31
-tags: ["git"]
----
-
-I listened to a podcast episode recently which talked about monorepos - i.e. code repositories that contain multiple project codebases rather than a single repository for each codebase - and this got me thinking about whether I should be using these more.
-
-It's something that I've been trialling recently in my [Docker examples](https://github.com/opdavies/docker-examples) and [Docker images](https://github.com/OliverDaviesLtd/docker-images) repositories, where one repository contains and builds multiple Docker images.
-
-I'm not suggesting that I put all of my client projects into one repository, but at least combining the different parts of the same project into the same repository.
-
-For example, I'm working for one client on their current Drupal 7 websites whilst developing the new Drupal 9 versions, which are currently in two separate repositories. I'm also developing an embeddable Vue.js application as part of the Drupal 9 website, and using Fractal as a component library. These are also in their own repositories.
-
-Using a monorepo approach, all of these projects would be in the same repository.
-
-I can see advantages to being able to see cross-project changes in the same place - such as an API change in Drupal that needs a update to be made in Vue.js, or vice-versa - rather than needing to look at separate repositories. This could also make versioning easier as everything will be stored and tagged inside the same repository.
-
-Each project has it's own CI pipeline, so it would require some changes where I set a specific pipeline to run only when a directory is changed.
-
-I see how deployments may be tricker if I need to push an update within a directory to another Git repository, which makes me wonder if I'll need to look into using subtree splits to create separate deployment repositories - similar to how the Symfony project has one main repository and then each component split into its own repository.
-
-I'll keep trialling it in my open-source projects and maybe test it with some client projects, but if you have experience with monorepos that you'd like to share, then please reply to this email - I'd love to hear about it.
diff --git a/astro/src/content/daily-email/2022-09-01.md b/astro/src/content/daily-email/2022-09-01.md
deleted file mode 100644
index 638335fb..00000000
--- a/astro/src/content/daily-email/2022-09-01.md
+++ /dev/null
@@ -1,40 +0,0 @@
----
-pubDate: 2022-09-01
-title: "Conventional commits and CHANGELOGs"
-tags: []
-permalink: "archive/2022/09/01/conventional-commits-changelogs"
----
-
-One of the things that I've done since joining my current team is to implement a standard approach for our commit messages.
-
-We're using the [Conventional Commits specification](https://www.conventionalcommits.org), which gives some additional rules to follow when writing commit messages.
-
-For example:
-
-```
-build(deps): update Drupal to 9.4.5
-
-Updated Drupal's `drupal/core-*` packages to 9.4.5.
-
-See https://www.drupal.org/project/drupal/releases/9.4.5.
-
-Refs: #123
-```
-
-We can see that this is a `build` task that relates to our project dependencies, in this example, we're updating Drupal core. We can also see this in the subject line.
-
-In the commit body, I add as much information as possible to do with the change and include any relevant links, just in case I need to refer to them again, and the list the names of anyone else who worked with me. I also typically include any ticket numbers or links in the commit footer.
-
-So far, I've mostly used the `build`, `chore`, `ci`, `docs` and `refactor` commit types, which are types that are recommended and used by [the Angular convention](https://github.com/angular/angular/blob/22b96b9/CONTRIBUTING.md#-commit-message-guidelines).
-
-Following this standard means that it's very easy to look at the Git log and see what type of changes are going to be included within a release and, if you're using scopes, which part of the application are affected.
-
-Conventional commits also works nicely with something else that we've introduced, which is a CHANGELOG file.
-
-There are tools that can generate and update CHANGELOGs automatically from conventional commits, but so far, we've been following the [Keep a Changelog](https://keepachangelog.com) format.
-
-It's easy to match the commits to the `Added`, `Changed` or `Fixed` types, and although it needs to be updated manually, it's easy to add to the `Unreleased` section of the file and re-organise everything within the appropriate headings as needed as part of a release.
-
-What I like about this format is that it's more human-friendly and gives a higher level overview of the changes rather than a reformatted Git log.
-
-As we do trunk-based development and continuous integration on our projects, there can be numerous commits related to the same change, so I'd rather only see a single line in the CHANGELOG for each change. This also makes it easier to share the CHANGELOG file with others, and we can still view and grep the Git log to see the individual commits if we need to.
diff --git a/astro/src/content/daily-email/2022-09-02.md b/astro/src/content/daily-email/2022-09-02.md
deleted file mode 100644
index 7857b916..00000000
--- a/astro/src/content/daily-email/2022-09-02.md
+++ /dev/null
@@ -1,22 +0,0 @@
----
-title: "Automating all the things with Ansible"
-pubDate: 2022-09-02
-permalink: "archive/2022/09/02/automating-all-the-things-with-ansible"
-tags: ["ansible"]
----
-
-Ansible is a tool for automating IT tasks. It's one of my preferred tools to use, and one that I've written about and [presented talks on]({{site.url}}/talks/deploying-php-ansible-ansistrano) previously.
-
-It's typically thought of as a tool for managing configuration on servers. For example. you have a new VPS that you want to use as a web server, so it needs Nginx, MySQL, PHP, etc to be installed - or whatever your application uses. You define the desired state and run Ansible, which will perform whatever tasks are needed to get to that state.
-
-Ansible though does include modules for interacting with services like Amazon AWS and DigitalOcean to create the servers and resources, and not just configure them.
-
-It also doesn't just work on servers. I use Ansible to configure my local development environment, to ensure that dependencies and tools are installed, and requirements like my SSH keys and configuration are present and correct.
-
-Lastly, I use Ansible to deploy application code onto servers and automatically run any required steps, ensuring that deployments are simple, robust and repeatable.
-
-In the next few emails, I'll explain how I've been able to utilise Ansible for each of these situations.
-
----
-
-Want to learn more about how I use Ansible? [Register for my upcoming free email course]({{site.url}}/ansible-course).
diff --git a/astro/src/content/daily-email/2022-09-03.md b/astro/src/content/daily-email/2022-09-03.md
deleted file mode 100644
index 479cec25..00000000
--- a/astro/src/content/daily-email/2022-09-03.md
+++ /dev/null
@@ -1,57 +0,0 @@
----
-pubDate: 2022-09-03
-title: Creating infrastructure with Ansible
-permalink: archives/2022/09/03/creating-infrastructure-with-ansible
-tags: ["ansible"]
----
-
-Let's start at the beginning.
-
-If we want to automate our infrastructure then we first need to create it. This could be done manually or we can automate it.
-
-Popular tools for this include Terraform and Pulumi, but Ansible also includes modules to interface with hosting providers such as Amazon Web Services, Microsoft Azure, DigitalOcean, and Linode.
-
-By using one of these tools, you can programatically provision a new, blank server that is ready for you to be configered.
-
-For example, to [create a DigitalOcean droplet](https://docs.ansible.com/ansible/latest/collections/community/digitalocean/digital_ocean_module.htm):
-
-```yaml
----
-- community.digitalocean.digital_ocean_droplet:
- image: ubuntu-20-04-x64
- name: mydroplet
- oauth_token: "..."
- region: sfo3
- size: s-1vcpu-1gb
- ssh_keys: [ .... ]
- state: present
- wait_timeout: 500
- register: my_droplet
-```
-
-Running this playbook will create a new Droplet with the specified name, size, and operating system, and within the specified region.
-
-If you needed to create a separate database server or another server for a new environment, then the file can be updated and re-run.
-
-[Creating an Amazon EC2 instance](https://docs.ansible.com/ansible/latest/collections/amazon/aws/ec2_instance_module.html#ansible-collections-amazon-aws-ec2-instance-module) looks very similar:
-
-```yaml
----
-- amazon.aws.ec2_instance:
- image_id: ami-123456
- instance_type: c5.large
- key_name: "prod-ssh-key"
- name: "public-compute-instance"
- network:
- assign_public_ip: true
- security_group: default
- vpc_subnet_id: subnet-5ca1ab1e
-```
-
-This doesn't apply just to servers - you can also use Ansible to create security groups and S3 buckets, manage SSH keys, firewalls, and load balancers.
-
-Once we have our infrastructure in place, we can start using Ansible to set and manage its configuration, which we'll do in tomorrow's email.
-
----
-
-Want to learn more about how I use Ansible? [Register for my upcoming free email course]({{site.url}}/ansible-course).
diff --git a/astro/src/content/daily-email/2022-09-04.md b/astro/src/content/daily-email/2022-09-04.md
deleted file mode 100644
index c20427e2..00000000
--- a/astro/src/content/daily-email/2022-09-04.md
+++ /dev/null
@@ -1,23 +0,0 @@
----
-title: "Using Ansible for server configuration"
-pubDate: 2022-09-04
-permalink: "archive/2022/09/04/using-ansible-for-server-configuration"
----
-
-[In yesterday's email]({{site.url}}/archives/2022/09/03/creating-infrastructure-with-ansible), I described how to set up a blank server with Ansible.
-
-Now that we've done that, it needs to be configured.
-
-Once the server’s IP address or hostname has been added to a `hosts.ini` file, you can run ad-hoc commands against it - such as `ansible all -i hosts.ini -m ping` to run Ansible's `ping` module on all of the hosts in your inventory and check that you can connect to them.
-
-Another useful one that you can use is the `shell` module, that runs ad-hoc run commands on each host. If you need to check the uptime of each of your servers, run `ansible all -i hosts.ini -m shell -a uptime`. You can replace the last argument with any other shell command that you need to run, like `df` or `free`.
-
-Running commands in this way is great for getting started, for routine maintenance, or an emergency free disk space check, but for more complex tasks like configuration management, using playbooks is the better option. They are YAML files that contain lists of tasks that Ansible will run through and execute in order.
-
-If you have a group of related tasks, such as for installing a piece of software, then you can combine them into roles. In fact, Ansible Galaxy has thousands of pre-built collections and roles that you can download, include in your playbooks, configure, and run.
-
-Very quickly, you can get a full stack installed and configured - ready to serve your application.
-
----
-
-Want to learn more about how I use Ansible? [Register for my upcoming free email course]({{site.url}}/ansible-course).
diff --git a/astro/src/content/daily-email/2022-09-05.md b/astro/src/content/daily-email/2022-09-05.md
deleted file mode 100644
index c1f22cc1..00000000
--- a/astro/src/content/daily-email/2022-09-05.md
+++ /dev/null
@@ -1,25 +0,0 @@
----
-title: "Using Ansible for local environment configuration"
-pubDate: 2022-09-05
-permalink: "archive/2022/09/05/using-ansible-for-local-configuration"
----
-
-As well as [configuring servers]({{site.url}}/archive/2022/09/04/using-ansible-for-server-configuration), you can use Ansible to configure your own local machine and development environment.
-
-The change that you need to make is within the `hosts.ini` file:
-
-```
-127.0.0.1 ansible_connection=local
-```
-
-Instead of the server's IP address or hostname, use the localhost IP address and set `ansible_connection` to `local` to tell Ansible to run locally instead of using an SSH connection.
-
-Another way to do this is to set `hosts: 127.0.0.1` and `connection: true` in your playbook.
-
-Once this is done, you can run tasks, roles, and collections to automate tasks such as installing software, adding your SSH keys, configuring your project directories, and anything else that you need to do.
-
-For an example of this, you can see [my dotfiles repository on GitHub](https://github.com/opdavies/dotfiles).
-
----
-
-Want to learn more about how I use Ansible? [Register for my upcoming free email course]({{site.url}}/ansible-course).
diff --git a/astro/src/content/daily-email/2022-09-06.md b/astro/src/content/daily-email/2022-09-06.md
deleted file mode 100644
index 149f6bb8..00000000
--- a/astro/src/content/daily-email/2022-09-06.md
+++ /dev/null
@@ -1,26 +0,0 @@
----
-title: "Deploying applications with Ansible"
-pubDate: 2022-09-06
-permalink: "archive/2022/09/06/deploying-applications-with-ansible"
----
-
-The last few days' emails have been about using Ansible to create and configure infrastructure, but it can also be used to deploy application code.
-
-The simplest way being that an artifact is built locally - e.g. a directory of static HTML pages from a static site generator - and uploaded onto the server, and for this you could use Ansible's `synchronize` module.
-
-It's a wrapper around the `rsync` command and makes it as simple as specifying `src` and `dest` values for the local and remote paths.
-
-For more complicated deployments, I like to use a tool called Ansistrano - an Ansible port of a deployment tool called Capistrano.
-
-It creates a new directory for each release and updates a `current` symlink to identify and serve the current release, and can share files and directories between releases.
-
-As well as being able to configure settings such as the deployment strategy, how many old releases to keep, and even the directory and symlink names, there are a number of hooks that you can listen for an add your own steps as playbooks so you can install dependencies, generate assets, run migrations, or rebuild a cache as part of each deployment.
-
-If you're running your applications in Docker, you could use Ansible to pull the latest images and restart your applications.
-
-For more information and examples, I've given a talk on Ansible at various PHP events, which covers some Ansible basics before moving on to [deploying applications with Ansistrano]({{site.url}}/talks/deploying-php-ansible-ansistrano).
-
----
-
-Want to learn more about how I use Ansible? [Register for my upcoming free email course]({{site.url}}/ansible-course).
-
diff --git a/astro/src/content/daily-email/2022-09-07.md b/astro/src/content/daily-email/2022-09-07.md
deleted file mode 100644
index ac0dd714..00000000
--- a/astro/src/content/daily-email/2022-09-07.md
+++ /dev/null
@@ -1,30 +0,0 @@
----
-title: "My Tailwind CSS origin story"
-pubDate: 2022-09-07
-permalink: "archive/2022/09/07/my-tailwind-css-origin-story"
-tags: ["tailwind-css"]
----
-
-Tomorrow night, I'm attending one of Simon Vrachliotis (simonswiss)'s Pro Tailwind workshops, so I thought that it would be a good time, as Simon has done himself recently on the Navbar podcast, to describe how I started using Tailwind CSS.
-
-I remember watching a lot of Adam Wathan's live streams on YouTube before Tailwind CSS, and I remember when he started a new project - a SaaS product called KiteTail.
-
-It was a Laravel and Vue.js project, and although I'm not a Laravel Developer primarily, I got a lot of other information from Adam's streams about automated testing, test-driven development, and Vue.js as I was learning Vue at the time.
-
-One of the episodes was about styling a card component using some styles that Adam was copying between projects - which would eventually be the starting point for Tailwind CSS.
-
-In fact, I think I watched some of the episode and stopped as I was happy with the Sass and BEM or SMACSS approach that I was using at the time, and didn't initially see the value of the utility CSS approach that I was seeing for the first time (everyone has a similar reaction initially).
-
-After a while, I did re-visit it but because Tailwind CSS wasn't released as it's own project yet, I (like Simon) started to experiment with Tachyons - another utility CSS library.
-
-I rebuilt a particularly tricky component that I'd just finished working on and had caused me some issues, and managed to re-do it in only a few minutes.
-
-I started to use Tachyons on some personal and client projects as a layer on other frameworks like Bootstrap and Bulma, and later moved on to Tailwind CSS once it has been released.
-
-I was working in this way on a project when I released that I could use Tailwind for all of the styling instead of just adding small sprinklings of utilities here and there. I refactored everything and removed the other framework that I'd been using - leaving just Tailwind CSS.
-
-With the exception of some legacy projects, now I use Tailwind CSS exclusively and have used it for a number of projects. I've given lunch and learn sessions to teams that I've worked on, [presented a Tailwind CSS talk]({{site.url}}/talks/taking-flight-tailwind-css) at a number of PHP, Drupal, WordPress, and JavaScript events, and maintain [a starter-kit theme](https://www.drupal.org/project/tailwindcss) for using Tailwind in custom Drupal themes.
-
-I've also rebuilt a [number of existing sites]({{site.url}}/blog/uis-ive-rebuilt-tailwind-css) as examples and written some [Tailwind CSS related blog posts]({{site.url}}/blog/tags/tailwind-css).
-
-I'm looking forward to attending Simon's workshop tomorrow and quickly putting that knowledge to use in the next phase of a project that I'm currently working on.
diff --git a/astro/src/content/daily-email/2022-09-08.md b/astro/src/content/daily-email/2022-09-08.md
deleted file mode 100644
index 6b5b933e..00000000
--- a/astro/src/content/daily-email/2022-09-08.md
+++ /dev/null
@@ -1,34 +0,0 @@
----
-title: "Keeping secrets with Ansible Vault"
-pubDate: 2022-09-08
-permalink: "archive/2022/09/08/keeping-secrets-with-ansible-vault"
-tags: ["ansible"]
----
-
-In the last few posts, I've talked about using Ansible for configuring servers and local environments, during both of which, you're likely to have some sensitive or secret values. These could be database credentials within your application and on your server, and your SSH private keys within your local environment.
-
-Rather than committing these to a code repository in plain text, Ansible includes the `ansible-vault` command to encrypt values.
-
-To see this working, run `ansible-vault encrypt_string my-secret-password`, enter a password, and then you should see something like this:
-
-```
-!vault |
- $ANSIBLE_VAULT;1.1;AES256
- 33353031663366313132333831343930643830346531666564363562666136383838343235646661
- 6336326637333230396133393936646636346230623932650a333035303265383437633032326566
- 38616262653933353033376161633961323666366132633033633933653763373539613434333039
- 6132623630643261300a346438636332613963623231623161626133393464643634663735303664
- 66306433633363643561316362663464646139626533323363663337363361633333
-```
-
-This is the encrypted version of that password, and this could be committed and pushed to a code repository.
-
-You can use it within a playbook, and you'll be prompted to re-enter the password so that Ansible can decrypt and use it.
-
-Rather than a single string, you could have a file of variables that you want to encrypt. You can do this by running `ansible-vault encrypt vault.yml` and include it as before. Again, you'll be prompted by Ansible so that it can decrypt and use the values.
-
-For an example of how I'm using Ansible Vault, see [the Dransible repository](https://github.com/opdavies/dransible/tree/986ba5097d62ff4cd0e637d40181bab2c4417f2e/tools/ansible) on GitHub or my [ Deploying PHP applications with Ansible, Ansible Vault and Ansistrano]({{site.url}}/talks/deploying-php-ansible-ansistrano) talk.
-
----
-
-Want to learn more about how I use Ansible? [Register for my upcoming free email course]({{site.url}}/ansible-course).
diff --git a/astro/src/content/daily-email/2022-09-09.md b/astro/src/content/daily-email/2022-09-09.md
deleted file mode 100644
index 9e0c6990..00000000
--- a/astro/src/content/daily-email/2022-09-09.md
+++ /dev/null
@@ -1,20 +0,0 @@
----
-title: "Refactoring a Tailwind CSS component"
-pubDate: 2022-09-09
-permalink: "archive/2022/09/09/refactoring-tailwind-component"
-tags: ["tailwind-css"]
----
-
-After last night's Pro Tailwind theming workshop, I decided to revisit and refactor some similar code that I'd worked on before.
-
-It was a demo for a presentation on utility-first CSS and Tailwind whilst I was at Inviqa.
-
-I'd taken one of the components from the website that we'd lauched and rebuilt it - in particular to show how Tailwind could be used for responsive and themeable components.
-
-[The original version](https://play.tailwindcss.com/Yfmw8O5UNN) was written in Tailwind 1 and used custom CSS with `@apply` rules to include text or background colours to elements based on the theme being used on that page or component.
-
-As well as moving it into a Next.js application, [the new version](https://github.com/opdavies/inviqa-tailwindcss-example) uses techniques covered in Simon's workshop - using CSS custom properties (aka variables) to override the colours, and writing custom plugins to generate the required styles. It doesn't include everything from the workshop, but enough for this refactor.
-
-I also moved the `flex-basis` classes into their own standalone plugin and might release that as it's own open-source plugin.
-
-I'm working on a client project at the moment which will need switchable themes so I'm looking forward to putting these techniques to use again in the near future.
diff --git a/astro/src/content/daily-email/2022-09-10.md b/astro/src/content/daily-email/2022-09-10.md
deleted file mode 100644
index 83740c06..00000000
--- a/astro/src/content/daily-email/2022-09-10.md
+++ /dev/null
@@ -1,38 +0,0 @@
----
-title: "Automating Ansible deployments in CI"
-pubDate: 2022-09-10
-permalink: "archive/2022/09/10/automating-ansible-deployments-ci"
-tags: ["ansible"]
----
-
-Once you have a deployment that's run using Ansible, rather than running it manually, it's easy to automate it as part of a continuous integration pipeline and have your changes pushed automatically by tools like GitHub Actions and GitLab CI.
-
-You'll need to configure SSH by adding a known hosts file and a private key so the tool can connect to your server, but after that, it's just running the same Ansible commands.
-
-If you're using Ansistrano or other roles, you can install dependencies by using `ansible-galaxy`, and `ansible-vault` to decrypt and use any encrypted variables - securely storing the Vault password and any other secrets as environment variables within your pipeline.
-
-Here's an example using GitHub Actions:
-
-```
-- name: Download Ansible roles
- run: ansible-galaxy install -r requirements.yml
-
-- name: Export the Ansible Vault password
- run: echo $ANSIBLE_VAULT_PASS > .vault-pass.txt
- env:
- ANSIBLE_VAULT_PASS: ${{ secrets.ANSIBLE_VAULT_PASS }}
-
-- name: Deploy the code
- run: >
- ansible-playbook deploy.yml
- -i inventories/$INVENTORY_FILE.ini
- -e "project_git_branch=$GITHUB_SHA"
- --vault-password-file=.vault-pass.txt
-
-- name: Remove the Ansible Vault password file
- run: rm .vault-pass.txt
-```
-
-Before these steps, I've added the SSH key and determined which inventory file to use by the updated branch. The Vault password is exported and then removed once it has been used.
-
-Automated tests and other code quality checks can be run in prior job, ensuring that the deployment only happens if those checks pass, but assuming that all is good, the playbook will be run and the changes will be deployed automatically.
diff --git a/astro/src/content/daily-email/2022-09-11.md b/astro/src/content/daily-email/2022-09-11.md
deleted file mode 100644
index 81a502ef..00000000
--- a/astro/src/content/daily-email/2022-09-11.md
+++ /dev/null
@@ -1,62 +0,0 @@
----
-title: "Custom styles in Tailwind CSS: `@apply`, `theme` or custom plugins"
-pubDate: 2022-09-11
-permalink: "archive/2022/09/11/custom-styles-tailwind-css-apply-theme-custom-plugins"
-tags: ["tailwind-css"]
----
-
-There are three ways to add custom styles to a Tailwind CSS project. As there have been [some recent tweets](https://twitter.com/adamwathan/status/1559250403547652097) around one of them - the `@apply` directive - I'd like to look at and give examples for each.
-
-## What is `@apply`?
-
-`@apply` is a PostCSS directive, provided by Tailwind, to allow re-using it's classes - either when extracting components or overriding third-party styles.
-
-The CSS file is the same as if you were writing traditional CSS, but rather than adding declarations to a ruleset, you use the `@apply` directive and specify the Tailwind CSS class names that you want to apply.
-
-For example:
-
-```css
-fieldset {
- @apply bg-primary-dark;
-}
-```
-
-This is a simple example but it's easy to see how this could be used in ways that weren't intended and how edge-cases can be found.
-
-Adam said in a another tweet:
-
-> I estimate that we spend at least $10,000/month trying to debug extremely edge-case issues people run into by using `@apply` in weird ways.
-
-## Using the `theme` function
-
-As well as `@apply`, Tailwind also provides a `theme` function that you can use in your CSS file. This removes the abstraction of using the class names and adds the ability to retrieve values from the `theme` section of your tailwind.config.js file.
-
-```css
-fieldset {
- backgroundColor: theme('colors.primary.dark');
-}
-```
-
-This seems to be the preferred approach over using `@apply`.
-
-## Creating a custom plugin
-
-The `theme` function is also available if you write a custom Tailwind CSS plugin:
-
-```javascript
-const plugin = require('tailwindcss/plugin')
-
-plugin(({ addBase, theme }) => {
- addBase({
- fieldset: {
- backgroundColor: theme('colors.primary.dark'),
- }
- })
-})
-```
-
-This is an approach that I've used for [generic, open-source plugins](https://github.com/opdavies?tab=repositories&q=%23tailwindcss-plugin) but for project-specific styling, I've mostly used `@apply` or the `theme` function.
-
-That said, I like the modular architecture of having different custom plugins - especially if they're separated into their own files - and being able to easily toggle plugins by simply adding to or removing from the `plugins` array.
-
-I usually don't write many custom styles in a Tailwind project but I think that I'll focus on using the `theme` function going forward, either in a stylesheet or a custom plugin.
diff --git a/astro/src/content/daily-email/2022-09-12.md b/astro/src/content/daily-email/2022-09-12.md
deleted file mode 100644
index b6a5c8e3..00000000
--- a/astro/src/content/daily-email/2022-09-12.md
+++ /dev/null
@@ -1,15 +0,0 @@
----
-title: "A month of daily emails"
-pubDate: 2022-09-12
-permalink: "archive/2022/09/12/month-daily-emails"
----
-
-It’s already been a month since I started my email list and writing daily emails.
-
-Since then, I’ve written emails on various development and workflow-based topics, including Drupal, Git, Docker, Neovim, Ansible and Tailwind CSS.
-
-The first email was written on Thursday the 12th of August and after initially wondering whether I should start on the upcoming Monday, or how often to post, I decided to jump in with both feet and wrote the first daily post that day. The first few weren't actually emailed as I waited to see if I could sustain writing a daily post (I was just posting them to my website), but after a few days, I set up the email list and started sending the posts.
-
-I can confirm what [Jonathan Stark](https://jonathanstark.com) and [Jonathan Hall](https://jhall.io) have said - that it's easier to write daily and that you start to see topic ideas everywhere. I started with a list of between 20 and 25 ideas and still have most of them as I've pivoted on a day's topic based on an article or tweet that I saw, some code that I'd written, or some approach that I took.
-
-If you're considering starting a daily email list, I'd recommend it.
diff --git a/astro/src/content/daily-email/2022-09-14.md b/astro/src/content/daily-email/2022-09-14.md
deleted file mode 100644
index 617b9cb8..00000000
--- a/astro/src/content/daily-email/2022-09-14.md
+++ /dev/null
@@ -1,67 +0,0 @@
----
-title: "The simplest Drupal test"
-pubDate: 2022-09-14
-permalink: "archive/2022/09/14/simpletest-drupal-test"
----
-
-Most of my work uses the Drupal framework, and I've given talks and workshops on automated testing and building custom Drupal modules with test-driven development. Today, I wanted to see how quickly I could get a working test suite on a new Drupal project.
-
-I cloned a fresh version of my [Docker Examples repository](https://github.com/opdavies/docker-examples) and started the Drupal example.
-
-I ran `mkdir -p web/modules/custom/example/tests/src/Functional` to create the directory structure that I needed, and then `touch web/modules/custom/example/tests/src/Functional/ExampleTest.php` to create a new test file and populated it with some initial code:
-
-```php
-drupalGet('');
-
- $this->assertSession()->statusCodeEquals(Response::HTTP_OK);
-}
-```
-
-To execute the test, I ran `SIMPLETEST_DB=sqlite://localhost//dev/shm/test.sqlite SIMPLETEST_BASE_URL=http://web phpunit -c web/core web/modules/custom`. The environment variables could be added to a `phpunit.xml.dist` file but I decided to add them to the command and use Drupal core's PHPUnit configuration file.
-
-As this is existing functionalty, the test passes. I can change either the path or the response code to ensure it also fails when expected.
-
-With the first test working, it's easy to add more for other functionality, such as whether different users should be able to access administration pages:
-
-```php
-/** @test */
-public function the_admin_page_is_not_accessible_to_anonymous_users() {
- $this->drupalGet('admin');
-
- $this->assertSession()->statusCodeEquals(Response::HTTP_FORBIDDEN);
-}
-
-/** @test */
-public function the_admin_page_is_accessible_by_admin_users() {
- $adminUser = $this->createUser([
- 'access administration pages',
- ]);
-
- $this->drupalLogin($adminUser);
-
- $this->drupalGet('admin');
-
- $this->assertSession()->statusCodeEquals(Response::HTTP_OK);
-}
-```
-
-Hopefully, this shows how quickly you can get tests running for a Drupal module. If you'd like to see more, the slides and video recording of my [Test-Driven Drupal talk]({{site.url}}/talks/tdd-test-driven-drupal) are online.
diff --git a/astro/src/content/daily-email/2022-09-16.md b/astro/src/content/daily-email/2022-09-16.md
deleted file mode 100644
index 4048b26a..00000000
--- a/astro/src/content/daily-email/2022-09-16.md
+++ /dev/null
@@ -1,111 +0,0 @@
----
-title: "Why I mostly write functional and integration tests"
-pubDate: 2022-09-16
-permalink: "archive/2022/09/16/why-mostly-write-functional-and-integration-tests"
-tags: ["drupal"]
----
-
-In [Wednesday's email]({{site.url}}/archive/2022/09/14/simpletest-drupal-test), I showed how quick it is to get started writing automated tests for a new Drupal module, starting with a functional test.
-
-I prefer the outside-in style (or London approach) of test-driven development, where I start with a the highest-level test that I can for a task. If the task needs me to make a HTTP request, then I’ll use a functional test. If not, I’ll use a kernel (or integration) test.
-
-I find that these higher-level types of tests are easier and quicker to set up compared to starting with lower-level unit tests, cover more functionality, and make it easier to refactor.
-
-## An example
-
-For example, this `Device` class which is a data transfer object around Drupal's `NodeInterface`. It ensures that the correct type of node is provided, and includes a named constructor and a helper method to retrieve a device's asset ID from a field:
-
-```php
-final class Device {
-
- private NodeInterface $node;
-
- public function __construct(NodeInterface $node) {
- if ($node->bundle() != 'device') {
- throw new \InvalidArgumentException();
- }
-
- $this->node = $node;
- }
-
- public function getAssetId(): string {
- return $this->node->get('field_asset_id')->getString();
- }
-
- public static function fromNode(NodeInterface $node): self {
- return new self($node);
- }
-
-}
-```
-
-## Testing getting the asset ID using a unit test
-
-As the `Node::create()` method (what I'd normally use to create a node) interacts with the database, I need to create a mock node to wrap with my DTO.
-
-I need to specify what value is returned from the `bundle()` method as well as getting the asset ID field value.
-
-I need to mock the `get()` method and specify the field name that I'm getting the value for, which also returns it's own mock for `FieldItemListInterface` with a value set for the `getString()` method.
-
-```php
-/** @test */
-public function should_return_an_asset_id(): void {
- // Arrange.
- $fieldItemList = $this->createMock(FieldItemListInterface::class);
-
- $fieldItemList
- ->method('getString')
- ->willReturn('ABC');
-
- $deviceNode = $this->createMock(NodeInterface::class);
-
- $deviceNode
- ->method('bundle')
- ->willReturn('device');
-
- $deviceNode
- ->method('get')
- ->with('field_asset_id')
- ->willReturn($fieldItemList);
-
- // Act.
- $device = Device::fromNode($deviceNode);
-
- // Assert.
- self::assertSame('ABC', $device->getAssetId());
-}
-```
-
-This is quite a long 'arrange' section for this test, and just be confusing for those new to automated testing.
-
-If I was to refactor from using the `get()` and `getString()` methods to a different implementation, it's likely that the test would fail.
-
-## Refactoring to a kernel test
-
-This is how I could write the same test using a kernel (integration) test:
-
-```php
-/** @test */
-public function should_return_an_asset_id(): void {
- // Arrange.
- $node = Node::create([
- 'field_asset_id' => 'ABC',
- 'type' => 'device'
- ]);
-
- // Assert.
- self::assertSame('ABC', Device::fromNode($node)->getAssetId());
-}
-```
-
-I can create a real `Node` object, pass that to the `Device` DTO, and call the `getAssetId()` method.
-
-As I can interact with the database, there's no need to create mocks or define return values.
-
-The 'arrange' step is much smaller, and I think that this is easier to read and understand.
-
-### Trade-offs
-
-Even though the test is cleaner, because there are no mocks there's other setup to do, including having the required configuration available, enabling modules, and installing schemas and configuration as part of the test - and having test-specific modules to store the needed configuration files.
-
-Because of this, functional and kernel tests will take more time to run than unit tests, but an outside-in approach could be worth considering, depending on your project and team.
diff --git a/astro/src/content/daily-email/2022-09-17.md b/astro/src/content/daily-email/2022-09-17.md
deleted file mode 100644
index beb78de0..00000000
--- a/astro/src/content/daily-email/2022-09-17.md
+++ /dev/null
@@ -1,21 +0,0 @@
----
-title: "Thoughts on automated code formatting"
-pubDate: 2022-09-17
-permalink: "archive/2022/09/17/thoughts-automated-code-formatting"
----
-
-For a long time, I've been focused on writing code that complies with defined coding standards, either to pass an automated check from a tool like PHP Code Sniffer (PHPCS) or eslint, or a code review from a team member.
-
-Complying with the standards though is something that I've done manually.
-
-As well as automated tools for linting the code, there are tools like PHP Code Beautifier and Fixer, and Prettier for formatting the code based on the same standards, which I've started to use more recently.
-
-These tools can be run on the command line, VS Code has a "Format on save" option, and I can do the same in Neovim using an auto-command that runs after writing a file if an LSP is attached. I typically use a key mapping for this though so I can run it when I need, rather than it running automatically every time a file is saved.
-
-One of my concerns with automated code formatting is what to do when working with existing code that doesn't already follow the standards. If I need to make a change to a file, with automated formatting, the rest of the file can change due to formatting being applied when I save my change.
-
-I recently introduced a PHPCS step to a CI pipeline for an existing project. I knew that it was going to fail initially, but I was able to see the list of errors. I ran the code formatter on each of the files to fix the errors, committed and pushed the changes, and watched the pipeline run successfully.
-
-This meant that I had a commit reformatting all of the affected files, but it was good to combine these together rather than having them separate, and not mixed with any other changes like a new feature or a bug fix.
-
-Since doing this, it's been nice when working in this codebase to not have to worry about code style violations, and I can focus on writing the code that I need to, knowing that I can rely on the automated formatting to fix any issues before I commit them.
diff --git a/astro/src/content/daily-email/2022-09-19.md b/astro/src/content/daily-email/2022-09-19.md
deleted file mode 100644
index 5ffa47a1..00000000
--- a/astro/src/content/daily-email/2022-09-19.md
+++ /dev/null
@@ -1,26 +0,0 @@
----
-title: "Useful Git configuration"
-pubDate: 2022-09-19
-permalink: "archive/2022/09/19/useful-git-configuration"
-tags: ["git"]
----
-
-Here are some snippets from my Git configuration file.
-
-These days, I use a much simpler workflow and configuration since doing more trunk-based development, but in general, I rebase instead of merging by default, and prefer to use fast-forward merges that doesn't create a merge commit.
-
-`branch.autosetuprebase = always` and `pull.rebase = true` configure Git to always rebase instead of pull. It does this for all branches, though I might override this for `main` branches.
-
-`pull.ff = only` and `merge.ff = only` prevents creating a merge commit and will prevent the merge if it would create one. If I needed to override this, I could by using the `--no-ff` option on the command line.
-
-I use `checkout.defaultRemote = origin` to ensure that the `origin` remote is used if I have multiple remotes configured, and `push.default = upstream` to set the default remote to push to.
-
-`merge.autoStash` allows for running merges on a dirty worktree by automatically creating and re-applying a stash of the changes, and `fetch.prune` will automatically prune branches on fetch - keeping things tidy.
-
-I also have and use a number of aliases.
-
-Some like `pl = pull` and `ps = push` are shorter versions of existing commands, and some like `aa = add --all`, `fixup = commit --fixup` and some additional arguments to commands.
-
-I also have some like `current-branch = rev-parse --abbrev-ref HEAD` and `worktrees = worktree list` which add simple additional commands, and some like `repush = !git pull --rebase && git push` which use execute shell commands to execute more complex commands or combine multiple commands.
-
-This is a snapshot of my Git configuration. The [full version is on GitHub](https://github.com/opdavies/dotfiles/blob/7e935b12c09358adad480a566988b9cbfaf5999e/roles/git/files/.gitconfig).
diff --git a/astro/src/content/daily-email/2022-09-20.md b/astro/src/content/daily-email/2022-09-20.md
deleted file mode 100644
index 035b9672..00000000
--- a/astro/src/content/daily-email/2022-09-20.md
+++ /dev/null
@@ -1,26 +0,0 @@
----
-title: "Why I like trunk-based development"
-pubDate: 2022-09-20
-permalink: "archive/2022/09/20/why-like-trunk-based-development"
-tags: ["git"]
----
-
-For the majority of my software development career, I've worked with version control in a very similar way.
-
-There are one or two long-lived branches, usually a combination of `develop`, `master` or `main`, that contain the production version of the code. When starting work on a new feature or bug fix, a new branch is created where the changes are made in isolation, and is submitted for review once complete. This is typically referred to as "Git Flow" or "GitHub Flow".
-
-Whilst those changes are awaiting review, a new task is started and the process is repeated.
-
-## Trunk-based development
-
-Something that I've been practicing and advocating for lately is trunk-based development, where there's only one branch that everyone works on, and commits and pushes to instead of creating separate per-task branches.
-
-Even on a client project where I was the only Developer, I was used to creating per-task branches and I can recall when trying to demo two features to a client and the application broke when switching between branches.
-
-The vast majority of the time, whether working individually or on a team, I've found that the per-task branches weren't needed and working on a single branch was easier and simpler.
-
-There are still occassions when a temporary branch is needed, but in general, all changes are made to the single branch.
-
-Trunk-based development ties in nicely with the continuous integration approach, where everyone commits and pushes their work at least once a day - ideally, multiple times a day. This eliminates long-running feature or bug fix branches that get out of sync with the main branch as well as conflicting with each other.
-
-It seemed scary to begin with, having been used to per-task branches and asynchronous peer reviews via pull or merge requests, but trunk-based development has made things simpler and encourages other best practices such as pair and mob programming. having a good CI pipeline to identify regressions, using feature flags to separate code deployments from feature releases, and frequent code integration and deployment via continuous commits and pushes.
diff --git a/astro/src/content/daily-email/2022-09-21.md b/astro/src/content/daily-email/2022-09-21.md
deleted file mode 100644
index 2dae3e4e..00000000
--- a/astro/src/content/daily-email/2022-09-21.md
+++ /dev/null
@@ -1,34 +0,0 @@
----
-title: "Being a Drupal contribution mentor"
-pubDate: 2022-09-21
-permalink: "archive/2022/09/21/being-drupal-contribution-mentor"
-tags: ["drupal"]
----
-
-This week is DrupalCon Prague, and although I'm not at this event, I'd like to write about some my experiences at DrupalCon - in particular about being a contribution mentor.
-
-## My first DrupalCon
-
-The first DrupalCon that I attended was in 2013, also in Prague.
-
-I was enjoying the session days when I stopped at the mentoring table to find out more about the contribution sprints that were happening on the Friday.
-
-I didn't have any commits in Drupal core but had already worked on and released some of my own contributed modules, so I was familiar with the tools and the Drupal.org contribution workflow. In short, I was signed up to be a mentor during the sprints.
-
-I remember being involved in the preparation too, sitting in a hotel lobby, identifying potential issues for new contributors to work on, alongside people who I'd previously interacted with in the issue queues on Drupal.org.
-
-On the day, I helped new contributors get their local environments up and running, select issues to work on, and perform tasks like creating and re-rolling patch files and submitting them for review.
-
-One of my highlights at the end of the day was the live commit, when a patch that a new contributor had worked on that day was committed to Drupal core live on stage!
-
-Whenever I've attended DrupalCon events since, I've always volunteered to be a contribution mentor, as well as mentoring and organising sprints at other Drupal events.
-
-## The Five Year Issue
-
-One of the most memorable times mentoring was whilst working with a group of contributors at DrupalCon in May 2015.
-
-Someone was working on a Drupal core issue that was very similar to [one that I'd looked at](https://www.drupal.org/project/drupal/issues/753898) a few years before.
-
-We focused on the original issue that I'd commented on, reviewed, tested, and re-rolled the patch, fixed a failing test, and marked it as "reviewed and tested by the community".
-
-A few days after the conference, and just over five years after my original comment, the patch was committed - giving my contributors their first commits to Drupal 8 core, and also [one of mine](https://git.drupalcode.org/project/drupal/-/commits/9.5.x?search=opdavies).
diff --git a/astro/src/content/daily-email/2022-09-22.md b/astro/src/content/daily-email/2022-09-22.md
deleted file mode 100644
index 83a0df2e..00000000
--- a/astro/src/content/daily-email/2022-09-22.md
+++ /dev/null
@@ -1,20 +0,0 @@
----
-title: "Releasing a Drupal module template"
-pubDate: 2022-09-22
-permalink: "archive/2022/09/22/releasing-drupal-module-template"
-tags: ["drupal"]
----
-
-Today, I an the idea to create a reusable template for new Drupal modules, based on how I like to build modules and how I've shown others to do so in my Drupal testing workshop.
-
-So I did, and released it for free [on my GitHub account](https://github.com/opdavies/drupal-module-template).
-
-Like my Tailwind CSS starter theme on Drupal.org, it's not intended to be added as a module directly, but something that can be cloned and used as a base for people's own modules.
-
-It includes an example route and Controller that load a basic page, and has a test to ensure that the page exists and loads correctly.
-
-The Controller is defined as a service and uses autowiring to automatically inject the its dependencies, the same as in my workshop example code.
-
-It's the initial release so it's rough around the edges still. I'll use it tomorrow to create a new module and document the steps to add to the README as well as other pieces of documentation.
-
-If you're creating a new Drupal module and try it out, start a discussion on the GitHub repository or [let me know on Twitter](https://twitter.com/opdavies). If you have questions, create a discussion or just reply to this email and I'll get back to you.
diff --git a/astro/src/content/daily-email/2022-09-23.md b/astro/src/content/daily-email/2022-09-23.md
deleted file mode 100644
index e490fd24..00000000
--- a/astro/src/content/daily-email/2022-09-23.md
+++ /dev/null
@@ -1,44 +0,0 @@
----
-title: "ADRs and Technical Design Documents"
-pubDate: 2022-09-23
-permalink: "archive/2022/09/23/adrs-technical-design-documents"
-tags: []
----
-
-## Architectural Decision Records
-
-Architectural Decision Records (ADRs) are documents to record software design choices. They could be saved in your code repository as plain-text or Markdown files, or stored in Confluence or a wiki - wherever your team stores its documentation.
-
-They usually consist of the sections:
-
-* Status - is it proposed, accepted, rejected, deprecated, superseded, etc.?
-* Context - what is the issue that is causing the decision or change?
-* Decision - what is the change that's being done or proposed?
-* Consequences - what becomes easier or more difficult to do?
-
-Any change that is architecturally significant should require an ADR to be written, after which it can be reviewed and potentially actioned.
-
-These will remain in place to form a decision log, with specific ADRs being marked as superseded if a newer ADR replaces it.
-
-## Technical Design Documents
-
-A similar type of document are Technical Design Documents (TDDs), that I first saw on TheAltF4Stream. I like to think of these as lightweight ADRs.
-
-The first heading is always "What problem are we trying to solve?", or sometimes just "The problem".
-
-Similar to the Context heading in an ADR, this should include a short paragraph describing the issue.
-
-Unlike ADRs, there are no other set headings but these are some suggested ones:
-
-- What is the current process?
-- What are any requirements?
-- How do we solve this problem?
-- Alternative approaches
-
-I like after describing the problem, being able to move straight into describing what's appropriate and relevant for this task and ignore sections that aren't needed.
-
-When I started writing ADRs, they all had the 'Accepted' status as I was either writing them for myself or in a pair or mob. As wasn't adding any value, I've removed it since switching to writing TDDs.
-
-Whether you use ADRs, TDDs or another approach, it's very useful to have a log of all of your architectural design decisions, both looking back in the future to remember why something was done in a certain way, or before you start implementing a solution to review the problem, evaluate the requirements and all potential solutions and document the selected one any why it was selected.
-
-[Find our more about ADRs](https://adr.github.io) or [find out more about TDDs](https://altf4.wiki/t/how-do-i-write-a-tdd/21).
diff --git a/astro/src/content/daily-email/2022-09-25.md b/astro/src/content/daily-email/2022-09-25.md
deleted file mode 100644
index 50cc987d..00000000
--- a/astro/src/content/daily-email/2022-09-25.md
+++ /dev/null
@@ -1,28 +0,0 @@
----
-title: "Using a component library for front-end development"
-pubDate: 2022-09-25
-permalink: "archive/2022/09/25/using-component-library-for-front-end-development"
-tags: []
----
-
-On a current project, I've decided to use a component library as the first place to do front-end development.
-
-I'm using [Fractal](https://fractal.build) as I can use Twig for templates. As Drupal also uses Twig templates, I have more reusabilty between the components in Fractal and Drupal compared to converting them from a different templating language like Handlebars or Nunjucks.
-
-Rather than developing directly within the custom Drupal theme, I've been creating new components and pages initially within Fractal.
-
-I have been able to create new components quickly and easily with the views uing Twig templates and inject data to it using a context file - a YAML file for each component that contains data that is injected automatically into the view.
-
-This meant that I've been able to develop new components from scratch without needing to set up content types or paragraphs within Drupal, validate and confirm my data model, and present the templates to the client for review in Fractal. If a change is needed, it's quick to do.
-
-I've also moved my asset generation step into Fractal. No CSS or JavaScript is being compiled within the Drupal theme, it is created within Fractal and copied over with the Twig templates.
-
-In most cases, I've been able to copy the Twig templates into Drupal and replace the static context data with dynamic data from Drupal without needing to make any further changes.
-
-In a couple of situations, I've needed to change my implementation slightly when moving a template into Drupal, so in this workflow, I've made the changes in Fractal and re-exported them to keep things in sync between the two systems.
-
-In situations where there is existing markup and/or styles from the Drupal side, I've copied those into Fractal so that they match before adding the additional styling and any markup changes.
-
-In general, I like the approach as it gives me more flexibility upfront to make changes before needing to configure Drupal. I can see how things could get out of sync between the two systems, but hopefully having the assets compiled in Fractal and needing to copy them into Drupal will keep things synced up.
-
-I don't think that I'd use this approach for all projects, but for this one, where I'm working with multiple themes and will need to later add different variants of pages and components, it's worked well so far.
diff --git a/astro/src/content/daily-email/2022-09-26.md b/astro/src/content/daily-email/2022-09-26.md
deleted file mode 100644
index 894a31cb..00000000
--- a/astro/src/content/daily-email/2022-09-26.md
+++ /dev/null
@@ -1,20 +0,0 @@
----
-title: "Experimenting with the Nix package manager"
-pubDate: 2022-09-26
-permalink: "archive/2022/09/26/experimenting-with-the-nix-package-manager"
-tags: ["nix"]
----
-
-After seeing it on some recent live streams and YouTube videos, I've recently been trying out the Nix package manager and looking into how I might use it for my local environment setup - potentially replacing some of my current Ansible configuration.
-
-Separate from the NixOS operating system, Nix is a cross-platform package manager, so instead of using `apt` on Ubuntu and `brew` on macOS, you could run Nix on both and install from the 80,000 packages listed on https://search.nixos.org/packages.
-
-There is a community project called Home Manager which can be installed alongside Nix which, similar to Stow or what I'm doing with Ansible, can manage your dotfiles or even create them from your Home Manager configuration, and can manage plugins for other tools such as ZSH and tmux.
-
-There's also a Nix feature called "Flakes" which allow you to separate configuration for different operating systems. I currently have a flake for Pop!\_OS which installs all of my packages and a minimal flake for my WSL2 environment as some of the packages are installed in Windows instead of Linux.
-
-I can see Ansible still being used to set up my post-setup tasks such as cloning my initial projects, but the majority of my current Ansible setup where I'm installing and configuring packages I think could be moved to Nix.
-
-I have a work-in-progress Nix-based version [in my dotfiles repository](https://github.com/opdavies/dotfiles/tree/7c3436c553f8b81f99031e6bcddf385d47b7e785) where you can also see [how I've configured Git with Home Manager](https://github.com/opdavies/dotfiles/blob/7c3436c553f8b81f99031e6bcddf385d47b7e785/home-manager/modules/git.nix).
-
-I may install NixOS on an old laptop to test that out too.
diff --git a/astro/src/content/daily-email/2022-09-27.md b/astro/src/content/daily-email/2022-09-27.md
deleted file mode 100644
index 6dc063fa..00000000
--- a/astro/src/content/daily-email/2022-09-27.md
+++ /dev/null
@@ -1,16 +0,0 @@
----
-title: "Mentoring with Drupal Career Online"
-pubDate: 2022-09-27
-permalink: "archive/2022/09/27/mentoring-with-drupal-career-online"
-tags: ["drupal"]
----
-
-Today, I met my new mentee from the Drupal Career Online program.
-
-[As well as mentoring at events like DrupalCamps and DrupalCons]({{site.url}}/archive/2022/09/21/being-drupal-contribution-mentor), I enjoy mentoring and working with new Developers going through bootcamps and training programmes like Drupal Career Online, some who are experienced Developers who are learning a new skill, and some who are learning how to code and are taking their first steps into programming.
-
-I've talked about [how I got started programming]({{site.url}}/archive/2022-08-28/how-started-programming), but as self-taught Developer, it would have been great to have had a mentor to ask questions of, to help me get me started, and to make sure that I was going down the right track and learning the correct things.
-
-Maybe this is more applicable these days with more people learning and working from home since COVID-19?
-
-Similar to helping mentees at a contribution sprint work towards their first commits to Drupal, it's great to be able to introduce new Developers to a open-source project and community such as Drupal, help develop their skills, and hopefully enable them to get the new job and career that they want.
diff --git a/astro/src/content/daily-email/2022-09-28.md b/astro/src/content/daily-email/2022-09-28.md
deleted file mode 100644
index dfe1dbe0..00000000
--- a/astro/src/content/daily-email/2022-09-28.md
+++ /dev/null
@@ -1,20 +0,0 @@
----
-title: "Mob programming at PHP South Wales"
-pubDate: 2022-09-28
-permalink: "archive/2022/09/28/mob-programming-php-south-wales"
-tags: []
----
-
-Tonight was our September meetup for the PHP South Wales user group, where I ran a hands-on session on mob programming.
-
-I created [a small slide deck](https://speakerdeck.com/opdavies/an-introduction-to-mob-programming) before we started a mob session with the group.
-
-We worked on the FizzBuzz kata in PHP, using Pest for our automated tests.
-
-We followed the Driver and Navigator model, with one person responsible for the typing and interpreting the instructions from the Navigators, and switched roles every ten minutes.
-
-You can [see the code that we wrote](https://github.com/opdavies/code-katas/blob/1da5dd5a79bc7ca083c0c4216fc3b4b0854f623d/php/tests/FizzBuzzTest.php) on my code katas GitHub repository.
-
-It was a fun experience and nice to code with some people who I hadn't coded with before.
-
-We did some code kata sessions during our online meetups which also seemed to go well, so coding nights on katas or personal or open-source projects might be something that we do more of in the future.
diff --git a/astro/src/content/daily-email/2022-09-30.md b/astro/src/content/daily-email/2022-09-30.md
deleted file mode 100644
index 85ccb115..00000000
--- a/astro/src/content/daily-email/2022-09-30.md
+++ /dev/null
@@ -1,83 +0,0 @@
----
-title: "Store Wars: different state management in Vue.js"
-pubDate: 2022-09-30
-permalink: "archive/2022/09/30/store-wars-vuejs"
-tags: ["vue"]
----
-
-I'm currently working on a Vue.js application that I started building in Vue 2 before starting to use the Composition API, and then moved it to Vue 3.
-
-In the original version, I was using Vuex for state management within the application, and interacting with Vuex directly within my Vue components - calling `getters` and `dispatch` to retrieve and update data.
-
-As part of moving to Vue 3, I wanted to evaluate any new options, like Pinia which is now the default state management library for Vue.
-
-But because I was integrating with Vuex directly, switching to an alternative would mean changing code within my components.
-
-## Defining a Store interface
-
-This is a situation that often occurs in back-end development - where you may need to switch to a different type of database or a different payment provider in an eCommerce application.
-
-In that situation, you need a generic interface that can be used by different implementations. Because they have consistent methods, one implementation can be replaced with another or multiple can be added at the same time. This is called the Strategy design pattern, and related to the open-closed principle in SOLID.
-
-This is what I did by adding a `Store` interface:
-
-```javascript
-export default interface Store {
- actions: {
- addRow(): void;
- init(): void;
- removeRow(index: Number): void;
- };
-
- state: {
- isLoading: boolean;
- selection: {
- items: [];
- };
- };
-}
-```
-
-Any store that I want to work with needs to have these defined actions and state values, so I can use them within my components knowing that they will always be available.
-
-## Creating a native Vue store
-
-This is one implementation of the `Store` interface, using just Vue's `reactive` function from the Composition API:
-
-```javascript
-let state = reactive({
- isLoading: false,
- selection: {
- items: [],
- },
-});
-
-let actions = {
- addRow(): void {
- state.selection.items.push({
- // ...
- });
- },
-
- init(): void {
- state.isLoading = true;
-
- // ...
- },
-
- removeRow(index: number): void {
- state.selection.items.splice(index, 1);
- },
-};
-
-const vueStore: Store = {
- actions,
- state: readonly(state),
-};
-
-export default vueStore;
-```
-
-If I needed to add a Pinia version or another library, I can create another implementation that complies with same interface.
-
-Each implementation being responsible for any specifics for that library - extracting that logic from the component code making it more flexible and reusable.
diff --git a/astro/src/content/daily-email/2022-10-01.md b/astro/src/content/daily-email/2022-10-01.md
deleted file mode 100644
index da21b82e..00000000
--- a/astro/src/content/daily-email/2022-10-01.md
+++ /dev/null
@@ -1,34 +0,0 @@
----
-title: Why do code katas?
-pubDate: 2022-10-01
-permalink: archive/2022/10/01/code-katas
-tags: []
----
-
-## What are code katas?
-
-Code katas are programming exercises which, like katas in martial arts, use practice and repetition to improve your skills.
-
-Common katas are Fizzbuzz, the Bowling score calculator, and the Gilded Rose.
-
-Each gives you the criteria of what the kata should do before it can be considered complete along with any specific information, and some websites will also give you a suite of failing tests to make pass - though I prefer to write my own and follow a test-driven development approach.
-
-Once you have completed the solution and the criteria is satisfied, the kata is complete.
-
-## Why I do code katas
-
-As I said, doing code katas improves your skills by solving problems and identifying patterns that you may see when working in your project code.
-
-Different katas focus on different patterns. For example, the Fibonacci Number kata focuses on recursion, whereas the Gilded Rose kata is all about refactoring complex legacy code.
-
-Doing code katas keeps your skills sharp and gives you a different perspectives as you work through different katas. You can then use and apply these within your main projects.
-
-If you want to learn a new programming language then working on a kata that you've already solved in a language that you're familiar with allows you to focus on the syntax and features of the new language. I've been working on some code katas in TypeScript as I've been working with that recently, and would like to do some in Go.
-
-If you work as part of a team or a part of a meetup, code katas can be worked on as a group and can introduce new skills like automated testing and test-driven development as well as providing some opportunities for team-building and socialising. If you're trying to introduce pair or mob programming, then working on code katas could be a good first step.
-
-If you're just getting started with programming, working on code katas will help you learn the fundamentals and problem solving, but I'd also encourage you to put the code on GitHub and blog about each kata that you complete. Doing so will help and encourage others and also look good when applying for roles.
-
-P.S. There are lists of code katas at https://github.com/gamontal/awesome-katas and https://codingdojo.org/kata, and online versions at https://www.codewars.com/join and https://exercism.org/tracks. There are many others - if you have a favourite, reply to this email and let me know.
-
-I have [some GitHub repositories for my code kata solutions](https://github.com/opdavies?tab=repositories&q=katas) and will continue to build these as I do more.
diff --git a/astro/src/content/daily-email/2022-10-02.md b/astro/src/content/daily-email/2022-10-02.md
deleted file mode 100644
index e24f3050..00000000
--- a/astro/src/content/daily-email/2022-10-02.md
+++ /dev/null
@@ -1,32 +0,0 @@
----
-title: Minimum viable CI pipelines
-pubDate: 2022-10-02
-permalink: archive/2022/10/02/minimum-viable-pipelines
-tags: []
----
-
-When I start a new project, and sometimes when I join an existing project, there are no CI (continuous integration) pipelines, no automated tests, and sometimes no local environment configuration.
-
-In that case, where should you start when adding a CI pipeline?
-
-I like to start with the simplest solution to get a passing build and to prove the concept - even if it's a "Hello, world" message. I know that the pipeline is configured correctly and runs when expected, and gives the output that I expect.
-
-I like to use Docker for my development environments, partly because it's very easy to reuse the same set up within a CI pipeline just by running `docker image build` or `docker compose build`.
-
-Having a task that ensures the project builds correctly is a great next step.
-
-Within a Dockerfile, I run commands to validate my lock files, download and install dependencies from public and private repositories, and often apply patch files to third-party code. If a lock file is no longer in sync with its composer.json or package.json file, or a patch no longer applies, this would cause Docker and the CI pipeline to fail and the error can be caught and fixed within the pipeline.
-
-Next, I'd look to run the automated tests. If there aren't any tests, I'd create an example test that will pass to prove the concept, and expect to see the number of tests grow as new features are added and as bugs are fixed.
-
-The big reason to have automated tests running in a pipeline is that all the tests are run every time, ensuring that the test suite is always passing and preventing regressions across the codebase. If any test fails, the pipeline fails. This is knows as continuous delivery - ensuring that code is always in a releasable state.
-
-From there, I'd look to add additional tasks such as static analysis and code linting, as well as anything else to validate, build or deploy the code and grow confidence that a passing CI pipeline means that the code is releasable.
-
-As more tasks are added to the pipeline, and the more of the code the tasks cover (e.g. test coverage) the more it can be replied upon.
-
-If there is a failure that wasn't caught in the CI pipeline, then the pipeline itself should be iterated on and improved.
-
-Having a CI pipeline allows you to identify issues sooner and fix them quicker, encourages best practices like automated testing and test-driven development, and enables continuous deployment where code is automatically deployed after a passing build.
-
-If you have a project without a CI pipeline, I'd encourage you to add one, to start small, and continuously iterate on it over time - adding tasks that are useful and valuable, and that build confidence that you can safely release when you need to.
diff --git a/astro/src/content/daily-email/2022-10-03.md b/astro/src/content/daily-email/2022-10-03.md
deleted file mode 100644
index 82be5b65..00000000
--- a/astro/src/content/daily-email/2022-10-03.md
+++ /dev/null
@@ -1,75 +0,0 @@
----
-title: Refactoring to value objects
-pubDate: 2022-10-03
-permalink: archive/2022/10/03/refactoring-value-objects
-tags: [php]
----
-
-
-Here's a snippet of some Drupal code that I wrote last week. It's responsible for converting an array of nodes into a Collection of one of it's field values.
-
-```php
-return Collection::make($stationNodes)
- ->map(fn (NodeInterface $station): string => $station->get('field_station_code')->getString())
- ->values();
-```
-
-There are two issues with this code.
-
-First, whilst I'm implicitly saying that it accepts a certain type of node, because of the `NodeInterface` typehint this could accept any type of node. If that node doesn't have the required field, the code will error - but I'd like to know sooner if an incorrect type of node is passed and make it explicit that only a certain type of node can be used.
-
-Second, the code for getting the field values is quite verbose and is potentially repeated in other places within the codebase. I'd like to have a simple way to access these field values that I can reuse anywhere else. If the logic for getting these particular field values changes, then I'd only need to change it in one place.
-
-## Introducing a value object
-
-This is the value object that I created.
-
-It accepts the original node but checks to ensure that the node is the correct type. If not, an Exception is thrown.
-
-I've added a helper method to get the field value, encapsulating that logic in a reusable function whilst making the code easier to read and its intent clearer.
-
-```php
-namespace Drupal\mymodule\ValueObject;
-
-use Drupal\node\NodeInterface;
-
-final class Station implements StationInterface {
-
- private NodeInterface $node;
-
- private function __construct(NodeInterface $node) {
- if ($node->bundle() != 'station') {
- throw new \InvalidArgumentException();
- }
-
- $this->node = $node;
- }
-
- public function getStationCode(): string {
- return $this->node->get('field_station_code')->getString();
- }
-
- public static function fromNode(NodeInterface $node): self {
- return new self($node);
- }
-
-}
-```
-
-## Refactoring to use the value object
-
-This is what my code now looks like:
-
-```php
-return Collection::make($stationNodes)
- ->map(fn (NodeInterface $node): StationInterface => Station::fromNode($node))
- ->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.
diff --git a/astro/src/content/daily-email/2022-10-08.md b/astro/src/content/daily-email/2022-10-08.md
deleted file mode 100644
index a74f15bf..00000000
--- a/astro/src/content/daily-email/2022-10-08.md
+++ /dev/null
@@ -1,20 +0,0 @@
----
-title: First impressions of Astro
-pubDate: 2022-10-08
-permalink: archive/2022/10/08/first-impressions-astro
-tags: [astro]
----
-
-This week I attended another of Simon Vrachliotis' Pro Tailwind workshops.
-
-The workshop again was great, teaching us about multi-style Tailwind components, such as a button that has props for variants like size, shape and impact, and how to create them in a flexible and maintainable way as well as making use of Headless UI.
-
-For this workshop though, the examples and challenges used a tool that I wasn't familiar with - the Astro web framework.
-
-I've seen a lot of blog posts and streams mentioning it but I hadn't tried it out for myself until the workshop.
-
-What I find interesting is that it comes with a number of available integrations - from Tailwind CSS, to Vue, React, and Alpine.js, and you can use the all within the same project, or even on the same page. Installing an integration is as simple as `yarn astro add tailwindcss`.
-
-The templates feel familiar and make use of front matter within Astro components, and regular YAML front matter works within Markdown files - which are supported out of the box.
-
-I've been thinking of redoing my personal website and evaluating options, but I think that Astro might be a new one to add to the list.
diff --git a/astro/src/content/daily-email/2022-10-09.md b/astro/src/content/daily-email/2022-10-09.md
deleted file mode 100644
index 8be3f91d..00000000
--- a/astro/src/content/daily-email/2022-10-09.md
+++ /dev/null
@@ -1,52 +0,0 @@
----
-title: Coding defensively, and Implicit vs explicit coding
-pubDate: 2022-10-09
-permalink: archive/2022/10/09/coding-defensively-implicit-explicit
-tags: [tailwindcss, php]
----
-
-As well as [being introduced to Astro](https://www.oliverdavies.uk/archive/2022/10/08/first-impressions-astro) in Simon's most recent Pro Tailwind workshop, something else that we discussed was implicit vs explicit coding, and coding defensively.
-
-For example, if you had this code:
-
-```javascript
-const sizeClasses = {
- small: 'px-3 py-1 text-sm',
- medium: 'px-5 py-2',
- large: 'px-7 py-2.5 text-lg',
-}
-
-const shapeClasses = {
- square: '',
- rounded: 'rounded',
- pill: 'rounded-full',
-}
-```
-
-Both the `medium` size and `square` shape have an implicit value.
-
-The `small` size has a text size class of `text-sm` and the `large` size has `text-lg`. As there isn't a text size added for `medium`, it is implicitly `text-base` - the default text size.
-
-Likewise, the `rounded` shape has a class of `rounded` and the `pill` shape has `rounded-full`. As a square button doesn't have any rounding, it has an empty string but it is implicitly `rounded-none` - the default border radius value.
-
-If we were to code this explicitly, `text-base` and `rounded-none` would be added to their respective size and shape classes.
-
-It's mostly personal preference, but explicitly adding the additional classes could potentially future-proof the components if there was a situation where the text size or border radius was being overridden.
-
-It also makes it more obvious to anyone reading the code that these values are being set, rather than them needing to make that assumption - assuming that they're aware of the default values at all.
-
-It's similar to having this example PHP code:
-
-```php
-function __invoke(string $type, int $limit): void {};
-```
-
-Whilst I'm using type hints for the parameters to ensure that the values are a string and an integer respectively, it's also safe to assume that the type shouldn't be an empty string, so do we check for that?
-
-I'd also suggest that the limit shouldn't be a negative integer, so we'd want to check that the value is not less than zero, or if zero isn't being used as an "all" value, then we'd want to check that the limit is greater than one.
-
-In this case, the type hints add some explicitness to the parameters, but checking for these additional conditions adds another defensive layer to the code - forcing it to return earlier with an explicit error message rather than causing a vaguer error and elsewhere in the application.
-
-Personally, I like to be explicit and code defensively, making sure that I try and cover as many edge cases as possible and writing test cases for them.
-
-Coming back to the Tailwind example, the majority of us decided to add in extra classes after the exercise and it was an interesting discussion and part of the workshop.
diff --git a/astro/src/content/daily-email/2022-10-10.md b/astro/src/content/daily-email/2022-10-10.md
deleted file mode 100644
index 064ba84a..00000000
--- a/astro/src/content/daily-email/2022-10-10.md
+++ /dev/null
@@ -1,14 +0,0 @@
----
-title: Contributing to open-source software, one small change at a time
-pubDate: 2022-10-10
-permalink: archive/2022/10/10/contributing-open-source-software-one-small-change-time
-tags: [open-source]
----
-
-Since looking more into Astro, I was looking through the GitHub repository - specifically within the examples - and spotted a typo within the title of one of the examples.
-
-Rather than leaving it, I decided to follow the "boy-scout rule" and submit a fix and leave the code in a better state than I found it.
-
-The Astro repository is hosted on GitHub so I was able to fork the repository, fix the typo and create a pull request with a few clicks in the GitHub UI.
-
-Contributing to open-source software - particularly if you're new to it - doesn't mean that you need to always add large and complex changes. Small changes such as fixing a typo, updating documentation, fixing a small bug, or adding additional tests are all valid contributions that improve open-source projects.
diff --git a/astro/src/content/daily-email/2022-10-11.md b/astro/src/content/daily-email/2022-10-11.md
deleted file mode 100644
index 2c6a4e17..00000000
--- a/astro/src/content/daily-email/2022-10-11.md
+++ /dev/null
@@ -1,18 +0,0 @@
----
-title: Not long until Drupal 10
-pubDate: 2022-10-11
-permalink: archive/2022/10/11/not-long-until-drupal-10
-tags: [drupal, php]
----
-
-I was surprised to see this week that it’s only two months until Drupal 10 is released (14th December 2022).
-
-I’m starting a new Drupal development project in December so will be looking to get that on Drupal 10 as soon as possible.
-
-From the client’s perspective, getting their new project on Drupal 10 and them not needing to upgrade from D9 in the future is a big plus, even if the code differences between D9 and D10 are not that big - similar to Drupal 8 and 9.
-
-As a module maintainer, it’s been great to again see issues being created with automated Drupal 10 compatibility patches - thanks to Rector.
-
-It’s great to see these regular updates and new versions of Drupal, but also for the PHP language, with PHP 7 being end-of-life next month.
-
-It’s a big difference compared to the long-term releases that we had for Drupal 6 and 7, and PHP 5, but one that I definitely prefer.
diff --git a/astro/src/content/daily-email/2022-10-12.md b/astro/src/content/daily-email/2022-10-12.md
deleted file mode 100644
index ce969150..00000000
--- a/astro/src/content/daily-email/2022-10-12.md
+++ /dev/null
@@ -1,28 +0,0 @@
----
-title: Overcoming deployment anxiety
-pubDate: 2022-10-12
-permalink: 'archive/2022/10/12/overcoming-deployment-anxiety'
----
-
-As a Developer with 15 years of experience, I still sometimes get "deployment anxiety" - when I've backed up the database and tagged a release, but even though the CI pipelines are passing and the staging site is working, I'm holding off on pushing the latest code to be released to production - trying to think of any potential issues that could arise from this deployment and avoid any downtime.
-
-When I thought about this further, the releases that I've felt anxious or nervous about have usually been in at one or both of the following categories:
-
-* The release includes a lot of changes, and maybe a combination of different types of changes such as framework or CMS updates, bug fixes, or new features.
-* It's been a long time, maybe weeks or months, since the last production release.
-
-The best way to resolve both of these issues, I think, is to break down the large releases into smaller ones, and to deploy them more frequently.
-
-In the opposite scenario, the releases where the changes are small and it's been a short time since the previous release - ideally minutes or hours - have been the ones where I've been the least nervous.
-
-If a single commit is being released, then I can be confident that if there is a failure, I can either revert it and put things back the way they were or quickly identify the issue and push a fix. This isn't the case for large changes as the potential source of the failure is larger and it will take longer to find and fix.
-
-If a bug fix or a feature needs to be reverted, I'm happy knowing that I can do that easily without also reverting the CMS update that was deployed separately - rather than them all being released together.
-
-There are other advantages too - clients or product owners are generally happier if the new feature or fix that they requested is on production within hours or days rather than weeks or months, and having your latest code deployed to production rather than on a staging branch makes it a lot easier if you need to deploy an urgent fix or security update.
-
-If you're familiar with the DevOps Research and Assessment (DORA) team, three of their key metrics are deployment frequency, lead time for changes, and time to restore service. All of these are improved by small and frequent releases.
-
-In my [Deployments with Ansible and Ansistrano talk](https://www.oliverdavies.uk/talks/deploying-php-ansible-ansistrano), I mention that there is a separate rollback role, but I don't think that I've ever used it.
-
-Because I'm deploying small changes often, it's usually much easier to fix forward than it is to rollback, and knowing this makes me a lot less anxious when deploying changes.
diff --git a/astro/src/content/daily-email/2022-10-17.md b/astro/src/content/daily-email/2022-10-17.md
deleted file mode 100644
index 33c12d6c..00000000
--- a/astro/src/content/daily-email/2022-10-17.md
+++ /dev/null
@@ -1,17 +0,0 @@
----
-title: 14 years on Drupal.org and working with PHP and Drupal
-pubDate: 2022-10-17
-permalink: 'archive/2022/10/17/14-years-drupalorg'
----
-
-Today I saw that my Drupal.org profile is showing that I’ve been on that website for 14 years.
-
-
-
-Drupal.org is the online home of the open-source Drupal CMS project, and where I registered to ask questions on the forums as I started to learn Drupal. More recently, it’s been where I’ve uploaded and maintain my own contributed projects and contribute patches to others, including Drupal core.
-
-I even spent time working for the Drupal Association on Drupal.org itself.
-
-I've talked about T-shaped Developers in a previous email, and whilst I've added complementary skills to my toolkit over the years, Drupal has been my main specialism and what I focused on when I started freelancing and later switched careers into software development.
-
-With Drupal 10 just around the corner, I'm looking forward to seeing how Drupal continues to evolve and develop.
diff --git a/astro/src/content/daily-email/2022-10-18.md b/astro/src/content/daily-email/2022-10-18.md
deleted file mode 100644
index b25da30f..00000000
--- a/astro/src/content/daily-email/2022-10-18.md
+++ /dev/null
@@ -1,19 +0,0 @@
----
-title: Pair and mob programming
-pubDate: 2022-10-18
-permalink: 'archive/2022/10/18/pair-mob-programming'
----
-
-As well as my recent session at PHP South Wales, I've also been involved with a lot more mob programming recently with members of my team.
-
-We recently added a new feature to our codebase that we completed over a couple of mob sessions - starting by describing the problem and some potential solutions within a [technical design document](https://www.oliverdavies.uk/archive/2022/09/23/adrs-technical-design-documents) before moving on to the implementation.
-
-I was already familiar with the existing code that we needed to extend, so had some ideas of how to approach parts of the solution which we discussed - but there were other parts that I hadn't thought of.
-
-What was very interesting was that an approach was suggested that I probably wouldn't have thought of myself, which become part of the final solution. This is an advantage of pair programming and is multiplied when working in groups - that you get to include everyone's thoughts, experience and perspective, and collectively decide on the best approach to take in real-time.
-
-As a side effect, we had continuous code review from members of the group, and if we need to work on this code again in the future, everyone will already be familiar with it.
-
-As it was already reviewed, we didn't need to wait before pushing the feature to production so it was delivered quickly and providing value by fixing an issue that someone was experiencing.
-
-We're already working on the next feature as a group, and if you haven't tried pair or mob programming before, I'd recommend that you give it a try.
diff --git a/astro/src/content/daily-email/2022-10-19.md b/astro/src/content/daily-email/2022-10-19.md
deleted file mode 100644
index 785a3b42..00000000
--- a/astro/src/content/daily-email/2022-10-19.md
+++ /dev/null
@@ -1,23 +0,0 @@
----
-title: run file vs task runners
-pubDate: 2022-10-19
-permalink: archive/2022/10/19/run-vs-task-runners
-# tags:
-# -
----
-
-[I've written a few earlier emails](https://www.oliverdavies.uk/archive/2022/08/15/using-run-file-simplify-project-tasks) about `run` files - a simple bash file that I add to my projects to simplify or combine common commands that I need to run often.
-
-Recently, I've looked at a couple of alternatives to see how they compare.
-
-One is very YAML based where all commands are written within a YAML file, and one is very Makefile-like and it does fix some of the confusion and issues that I've made with Makefiles in the past - such as passing arguments to commands, and dealing with `.PHONY`.
-
-Whilst I like both of these approaches and that they offer small additional features like auto-completion of task names, after using one of them in a project for a short while, I think that I'm going to stick with the `run` file.
-
-The main reason for this is that I like the simplicity of the `run` file, and that it's just a Bash file that contains functions.
-
-There were a couple of things that I couldn't quite get to work in one of the other tools, such as setting the TTY value in a Docker Command - which is something that I was able to do with bash within the `run` file. The fact that I can write regular bash and reuse existing knowledge is a big plus rather than having to try to learn another syntax or DSL for another tool.
-
-The main reason though is because bash is already installed everywhere. There's no additional tool for Developers to download and install so it keeps the barrier to entry low, and there's no additional dependencies to add to my CI pipeline for it to work.
-
-I was able to use one of these other tools in GitHub Actions as someone had already written a workflow for it, and although I could possibly install it via a package manager, just being able to run a bash file in any CI tool was probably the deciding factor to stick with `run` files.
diff --git a/astro/src/content/daily-email/2022-10-20.md b/astro/src/content/daily-email/2022-10-20.md
deleted file mode 100644
index ef2147f1..00000000
--- a/astro/src/content/daily-email/2022-10-20.md
+++ /dev/null
@@ -1,27 +0,0 @@
----
-title: >
- Cherry picking commits is an anti-pattern
-pubDate: 2022-10-20
-permalink: >
- archive/2022/10/20/cherry-picking-commits-is-an-anti-pattern
-tags:
- - git
----
-
-`git cherry-pick` is a command that allows you to re-apply changes from existing commits - typically moving commits from one branch to another. Whilst it's good for some use-cases, I believe that it's generally an anti-pattern.
-
-As I mostly do trunk-based development so only have a single branch, it's not a command that I'd run often - but I have seen it used in a Git Flow-type scenario where there are multiple long-lived branches and various other short-lived ones. Commits can be cherry-picked between a long-term branch like `develop` onto a feature branch rather than merging or rebasing, or to re-apply a hotfix from the `main` branch.
-
-The main issue that I've seen with `cherry-pick` is where a number of changes have been merged into a branch which is being used for user acceptance testing by a client or product owner. They decide to approve some of the changes but not all, and the approved commits are cherry-picked onto a production branch and deployed.
-
-In my opinion, this is very risky as there's no guarantee that the cherry-picked changes will work without the others, and as the artifact that's pushed to production is different to what was tested against, it arguably affects the value of doing the testing at all. Ideally, once the release has been tested and approved, the same artifact will be deployed - ensuring consistency and reducing the risk of any errors.
-
-Potentially, the cherry-picked changes could be moved onto a release branch and tested again together without the other changes, but this would increase the testing overhead and the time for the changes to release production.
-
-A good automated test suite would help, ensuring that the tests still pass once the cherry picking is done.
-
-In this situation, I'd rather use feature flags (also known as "feature toggles"). This would mean that the code between the two environments would be the same, and allow for functionality to be enabled or disabled as needed. If a feature wasn't selected to be released, then it's feature flag would be disabled until it's approved.
-
-A feature flag would also allow a feature to be switched off if it was causing errors without the need for a code deployment. If a change did need a code change, if you're following continuous integration and delivery, it would be easy to apply and push a fix.
-
-These are the use-cases that I can think of or have seen for `git cherry-pick`. If you know of any others or use `cherry-pick` in your workflow in another way, reply to the email and let me know.
diff --git a/astro/src/content/daily-email/2022-10-21.md b/astro/src/content/daily-email/2022-10-21.md
deleted file mode 100644
index 28d38e69..00000000
--- a/astro/src/content/daily-email/2022-10-21.md
+++ /dev/null
@@ -1,23 +0,0 @@
----
-title: >
- Automated testing and test-driven development are not the same
-pubDate: 2022-10-21
-permalink: >
- archive/2022/10/21/automated-testing-and-test-driven-development-are-not-the-same
-tags:
- - testing
----
-
-Automated testing is where you write tests to ensure that your code works as expected, which can be re-run as needed and executed automatically without user input.
-
-Test-driven development (TDD) is when you write the tests before the production code. You see the tests fail and write code until they pass, and then repeat the process. However, TDD is not just about the tests - it's about the design of the code.
-
-By writing the tests first, you guarantee that the code that you write will be testable, which isn't something that you can't do if the production code is written first.
-
-You may need to refactor your initial working implementation before it can be tested - which means that you could also break it during that time and need to spend time debugging and fixing any regressions. Ideally, you want the tests in place first before any refactoring, so if something breaks, you'll know because of the failing test.
-
-TDD keeps your code cleaner and simpler, as you only write enough code to make the tests pass. Once a test is passing, you stop writing code, so you'll end up with less, simpler code as it's easy to know when to stop.
-
-If you don't write the tests first, you may be tempted to skip writing them completely, leaving untested code or adding `TODO: add test` comments that may never get reviewed.
-
-Also, where's the fun in writing tests for code that you've already written, that you know are going to pass?
diff --git a/astro/src/content/daily-email/2022-10-24.md b/astro/src/content/daily-email/2022-10-24.md
deleted file mode 100644
index 58bdf71c..00000000
--- a/astro/src/content/daily-email/2022-10-24.md
+++ /dev/null
@@ -1,21 +0,0 @@
----
-title: >
- Looking at LocalGov Drupal
-pubDate: 2022-10-24
-permalink: >
- archive/2022/10/24/looking-at-localgov-drupal
-tags:
- - drupal
----
-
-Today, I've been looking at [LocalGov](https://localgovdrupal.org) - a Drupal distribution for building council websites, with a focus on code reuse and collaboration.
-
-After a few small changes, I was able to get it running based on my [Docker Examples](https://github.com/opdavies/docker-examples) repository.
-
-As someone who has worked with one of the Councils who are now using the platform, and was involved in early similar discussions around code reuse and collaboration between Councils, this has been something that I've been keen to try for a while.
-
-I was able to get a basic site running after a fresh installation, and was interested to explore how some of the functionality was built. I've recently been looking at implementing similar functionality to LocalGov's alert banners onto a project and will be able to gain some inspiration from that or will look into the LocalGov version could be used.
-
-I was happy to find some initial ways to contribute back. I had an error during the installation which I was able to fix and assist with in the [LocalGov issue queue on Drupal.org](https://www.drupal.org/project/localgov/issues/3307516#comment-14759989) by answering a support request, and after spotting a potential issue within the alert banner styling, [submitted a pull request with a fix](https://github.com/localgovdrupal/localgov_alert_banner/pull/225).
-
-I like what the project is doing and agree with its goals, so hopefully I'll get an opportunity to use and contribute more in the future.
diff --git a/astro/src/content/daily-email/2022-10-25.md b/astro/src/content/daily-email/2022-10-25.md
deleted file mode 100644
index a7b573ad..00000000
--- a/astro/src/content/daily-email/2022-10-25.md
+++ /dev/null
@@ -1,25 +0,0 @@
----
-title: >
- What are Drupal distributions?
-pubDate: 2022-10-25
-permalink: >
- archive/2022/10/25/what-are-drupal-distributions
-tags:
- - drupal
----
-
-Yesterday's email was about the LocalGov Drupal distribution that I've been looking at, but I glossed over what a Drupal distribution is.
-
-It's an interesting topic for me, having [written an article for Linux Journal](https://www.linuxjournal.com/content/speed-your-drupal-development-using-installations-and-distributions) about it in 2012.
-
-Distributions are pre-configured versions of Drupal that include additional modules, themes, or configuration than you'd get if you installed a standard version of Drupal core.
-
-By default, LocalGov includes content types for service pages, service landing pages and sub-pages, and additional menus and taxonomies, a different administration theme and a base theme to use for custom themes, and multiple additional modules that add alert banners, events, content reviews, search, media types, and sub-sites. This is all in addition to what Drupal core itself provides, and can be extended further with additional contrib or custom modules.
-
-Commerce Kickstart was a distribution for Drupal 7 that added eCommerce functionality such as product and order types, shipping and payment methods, stock levels and discounts. Again, this could be extended further by adding more contrib or custom modules.
-
-A few months ago, I started developing a distribution for managing meetup group websites, like PHP South Wales.
-
-If you're starting a new Drupal website, there could be a distribution that exists that could provide some or all of the functionality that you need, and if new features or fixes are added, then they benefit everyone who uses it.
-
-There are 1,430 distributions listed on https://www.drupal.org/project/project_distribution so take a look there and see if anything matches your needs.
diff --git a/astro/src/content/daily-email/2022-10-26.md b/astro/src/content/daily-email/2022-10-26.md
deleted file mode 100644
index 8ae6cf45..00000000
--- a/astro/src/content/daily-email/2022-10-26.md
+++ /dev/null
@@ -1,26 +0,0 @@
----
-title: >
- Neovim as a Personalised Development Environment
-pubDate: 2022-10-26
-permalink: >
- archive/2022/10/26/neovim-as-a-personalised-development-environment
-tags:
- - neovim
----
-
-A few months ago, TJ DeVries (a Neovim core team member) coined the phrase "Personalised Development Environment" or PDE.
-
-[I've been using Neovim full-time](https://www.oliverdavies.uk/blog/going-full-vim) since July 2021 - starting with no configuration to configuring it with Vimscript and later with Lua - setting options like line numbers and relative numbers, tabs and spaces, and indent and fold levels.
-
-
-I evaluated and installed some initial plugins to add functionality that I needed. Some of them I still use, and some I've replaced with alternative plugins or built-in solutions that have been included in newer versions of Neovim.
-
-I added my own keymaps that made sense to me that either, in my opinion, improved on default keymaps or created new ones that made sense to me or configured a plugin that I'd added.
-
-Recently, I found and added plugins that added a [HTTP client](https://github.com/rest-nvim/rest.nvim) and a [database connection manager](https://github.com/kristijanhusak/vim-dadbod-ui) to Neovim - two pieces of functionality that I'd used in other IDEs or separate applications.
-
-I also [wrote my own Neovim plugin](https://github.com/opdavies/toggle-checkbox.nvim) for toggling checkboxes within Markdown lists.
-
-Like Drupal and other open-source solutions that I use, I love being able to add or edit functionality as needed.
-
-In the last year or so, I've definitely been able to personalise my Neovim setup to meet my needs, and have it work as a fully-fledged solution for PHP and JavaScript development, DevOps work, and technical writing (including this email).
diff --git a/astro/src/content/daily-email/2022-10-27.md b/astro/src/content/daily-email/2022-10-27.md
deleted file mode 100644
index 34530aa9..00000000
--- a/astro/src/content/daily-email/2022-10-27.md
+++ /dev/null
@@ -1,17 +0,0 @@
----
-title: >
- Getting back into live streaming
-pubDate: 2022-10-27
-permalink: >
- archive/2022/10/27/getting-back-into-live-streaming
----
-
-Surprisingly, it's been two and a half years since I last did a live coding stream.
-
-As well as talk recordings and demos, I did a few live streams back then, working on the "Test-Driven Drupal" project and submitting a merge request to Drupal core.
-
-It's been something that I'd like to get back into and pick up again, and I plan on doing that within the next few weeks.
-
-I have a new freelance project due to start in December but getting back into streaming seems like a good way to make sure that I put aside time for open-source and side projects, as well as for writing longer form blog posts and hopefully starting to prepare more meetup and conference talks again.
-
-I'll be streaming again on my YouTube channel, so if you'd like to be notified when I do, [please subscribe](https://www.youtube.com/channel/UCkeK0qF9HHUPQH_fvn4ghqQ?sub_confirmation=1).
diff --git a/astro/src/content/daily-email/2022-10-28.md b/astro/src/content/daily-email/2022-10-28.md
deleted file mode 100644
index 12ea0150..00000000
--- a/astro/src/content/daily-email/2022-10-28.md
+++ /dev/null
@@ -1,25 +0,0 @@
----
-title: >
- Why write framework agnostic packages?
-pubDate: 2022-10-28
-permalink: >
- archive/2022/10/28/why-write-framework-agnostic-packages
-tags:
- - php
----
-
-A couple of years ago, I wrote an integration for a client's Drupal Commerce website with an online eBook service as they wanted to sell eBook variations of their products.
-
-They provided me with some example code for different PHP frameworks, each were separate and tightly-coupled to each framework, so there was no code shared between them. Because of this, and because there was no Drupal Commerce example, I wrote my own version.
-
-However, I decided to make my version as reusable and loosely-coupled as possible. This meant that I'd be able to potentially reuse it for other clients and the same code could be used for different implementations.
-
-Reusable code such as the configuration, different types of Requests, value objects for Customers, Orders and OrderItems, were all written within a separate, reusable PHP library. It contains it's own tests, has it's own CI pipeline, and it's own static analysis - ensuring that things work as expected.
-
-With this code separated, the Drupal module was much smaller and responsible only for bridging the library's code with Drupal Commerce and adding any other Drupal-specific code.
-
-The client is currently considering an upgrade from Drupal 7 to Drupal 9, which would also mean upgrading this module. But, with this approach, there's a lot less to upgrade. The library code can still be used, and I can focus on any Drupal-specific changes within the Drupal module.
-
-I recently had an enquiry from someone who needs an integration with the same service. Whilst their requirements may be different, I could still re-use the reusable library code, and write any client-specific code within a custom module.
-
-Finally, if I wanted to reuse this code within a different PHP eCommerce framework then I could by installing the library with Composer. This means that I'd get the same code without needing to manually copy it, keeping a single source that can be maintained separately upstream. I'd get the same code that I'm already familiar with, so I could focus only on how to integrate the library with that framework - again meaning less framework-specific code and a much lower development effort.
diff --git a/astro/src/content/daily-email/2022-10-29.md b/astro/src/content/daily-email/2022-10-29.md
deleted file mode 100644
index f7c60b6f..00000000
--- a/astro/src/content/daily-email/2022-10-29.md
+++ /dev/null
@@ -1,25 +0,0 @@
----
-title: >
- The open-source-first development workflow
-pubDate: 2022-10-29
-permalink: >
- archive/2022/10/29/the-open-source-first-development-workflow
-tags:
- - open-source
----
-
-Yesterday's email talked about [writing reusable, framework-agnostic packages](https://www.oliverdavies.uk/archive/2022/10/28/why-write-framework-agnostic-packages) but didn't mention where those packages could be located.
-
-They could be kept within a private repository and still have the same benefits, such as re-usability for internal projects, but I like to open-source code as often as I can and make it available publicly to see and use.
-
-My preference is to follow an open-source-first workflow, identify which parts of a solution can be open-sourced and create them as open-source libraries or modules from the beginning rather than planning to extract them later. They can then be included within the main project using a dependency manager tool like Composer, npm or Yarn.
-
-The eBook integration project that I mentioned was an example of this. I identified which pieces could be open-sourced, set up a public repository and put together an MVP based on that project's requirements. Issues were created for nice-to-have additions that could be added later, and the working version was installed with Composer.
-
-There was no need to extract the code from the main project, no need to "clean it up" or check that it contained no client information, and I had the full Git history for the project - not just a new history from the point when the code was extracted and open-sourced.
-
-I've worked on projects that contained a number of potential open-source components that would be released after project completion, but this didn't always happen - I assume due to time pressures to move on to the next project, a focus on adding new features or avoiding the risk of introducing breakages into the code. If the code had been open-sourced from the beginning, these things wouldn't have been an issue.
-
-I've also worked on projects where I've followed an open-source-first approach and released a number of PHP libraries and Drupal modules, including [Private Message Queue](https://www.drupal.org/project/private_message_queue), [System User](https://www.drupal.org/project/system_user), and [Null User](https://www.drupal.org/project/null_user) modules. I've also been working on some legacy code recently and started to replace it with a library that I've already open-sourced, even though I'm in the early stages of developing it.
-
-As someone who enjoys creating and working on open-source software, I would encourage you to open-source your code if you can and to do so sooner rather than later and not wait until the end of your project.
diff --git a/astro/src/content/daily-email/2022-10-30.md b/astro/src/content/daily-email/2022-10-30.md
deleted file mode 100644
index 03197e61..00000000
--- a/astro/src/content/daily-email/2022-10-30.md
+++ /dev/null
@@ -1,45 +0,0 @@
----
-title: >
- Refactoring one large test into multiple smaller tests
-pubDate: 2022-10-30
-permalink: >
- archive/2022/10/30/refactoring-one-large-test-into-multiple-smaller-tests
-tags:
- - php
- - phpunit
----
-
-Today I spent some time refactoring a large test within a client project, splitting it into several smaller tests. The commit removed 169 lines but added 233 lines.
-
-So, why did I do this?
-
-This test is responsible for testing the creation of products and product variants within Drupal Commerce from a custom CSV file and originally had a very generic name - "Should create a product and product variations from an array of data".
-
-But it did much more than that:
-
-1. It asserted that there are no initial existing products or product variations.
-1. It ran a product import using some stub data.
-1. It asserted that there are two products, each with two variations.
-1. It asserted that each product has the correct title.
-1. It asserted that each product variation has the correct title.
-1. It asserted that each variation has the correct SKU.
-1. It asserted that each variation has the correct price.
-1. It asserted that each variation has the correct value for 10 product attributes.
-
-All of this was hidden within a single test.
-
-Whilst it was great as the original test name (I usually start with a vague name whilst I'm spiking the first test and until it's clearer to me what it's testing and what the correct name is), what I actually want this test to do is to check that the correct number of products and variations are created.
-
-This refactoring task was to split the remaining assertions into their own named tests, after which I had six different tests.
-
-This means that each piece of functionality and related assertions are now contained within their own named tests. I can read the test file and see the expected functionality within the test names rather than everything being grouped and hidden within a single vaguely-named test.
-
-If an assertion fails, I can easily see in which test the failure occurred.
-
-Each test is very simple and only a few lines long - it runs the product import, loads the created variation, and runs the appropriate assertions.
-
-It'll be much easier to add new functionality to the importer by adding a new separate test rather than continuously adding to the large original one.
-
-Even though there are more lines in the file after the refactoring, most of those are just because of adding the additional test functions. There are only 72 lines of actual test methods, and the reusable steps, such as running the product import as well as custom assertions, are defined as private methods to avoid duplication.
-
-In my opinion, this was a good refactor to do, and now was a good time to do it before we get started on the next phase of the project.
diff --git a/astro/src/content/daily-email/2022-11-08.md b/astro/src/content/daily-email/2022-11-08.md
deleted file mode 100644
index c7c2fb49..00000000
--- a/astro/src/content/daily-email/2022-11-08.md
+++ /dev/null
@@ -1,26 +0,0 @@
----
-title: >
- Are sprints incompatible with Continuous Deployment?
-pubDate: 2022-11-08
-permalink: >
- archive/2022/11/08/are-sprints-incompatible-with-continuous-deployment
-# tags:
-# - a
-# - b
----
-
-It's been common for me whilst working on software projects to have work organised into sprints or cycles - a period, usually between 1 and 3 weeks, where the team is working on stories and tasks for that project.
-
-In my experience, those changes are usually released at the end of that cycle. But it seems that's not always the case; see [release sprints](https://scrumdictionary.com/term/release-sprint):
-
-> A specialised sprint whose purpose is to release deliverable results; it contains stories specific to release activities and finishing undone work. A release sprint usually contains no additional development.
-
-If we worked in two-week cycles and released at the end of each one, it would be at least two weeks before a change could be deployed to production. But what if we wanted to follow continuous deployment and release more frequently? Maybe daily or hourly?
-
-Instead of waiting for a release sprint, if we released multiple times within a single sprint, how would this fit into or affect the process?
-
-Does the release cycle need to be tightly coupled to the sprint cycle or can they be separate and independent of each other?
-
-I've worked on projects - including a current one - where I've done multiple releases in a sprint, so of course, it can be done from a technical perspective, but how do we get the best from both processes - whether they work together or separately?
-
-This is something that I'm going to continue to experiment with, iterate on, and learn more about going forward.
diff --git a/astro/src/content/daily-email/2022-11-09.md b/astro/src/content/daily-email/2022-11-09.md
deleted file mode 100644
index 4ff0d3da..00000000
--- a/astro/src/content/daily-email/2022-11-09.md
+++ /dev/null
@@ -1,15 +0,0 @@
----
-title: >
- Your conference talk has been accepted
-pubDate: 2022-11-09
-permalink: >
- archive/2022/11/09/your-conference-talk-has-been-accepted
----
-
-I’m happy to have had a conference talk proposal accepted for what will be my first in-person conference since DrupalCamp London in February 2020.
-
-I’ll be giving my "[Taking Flight with Tailwind CSS](https://www.oliverdavies.uk/talks/taking-flight-with-tailwind-css)" talk for the first time since February 2021, and in front of an in-person audience since June 2019.
-
-The talk itself will need some updating. The last time I gave it, Tailwind CSS was on version 2.0.3. It’s now on version 3.2.2 and includes features like the just-in-time engine, arbitrary values and variants, container queries, and a load of new utility classes.
-
-I gave a lot of talks at online events in 2020, so after taking a bit of a break last year, it will be nice to speak in front of an in-person conference audience again.
diff --git a/astro/src/content/daily-email/2022-11-11.md b/astro/src/content/daily-email/2022-11-11.md
deleted file mode 100644
index 85b5a03f..00000000
--- a/astro/src/content/daily-email/2022-11-11.md
+++ /dev/null
@@ -1,28 +0,0 @@
----
-title: >
- Creating a small proof-of-concept application in an afternoon
-pubDate: 2022-11-11
-permalink: >
- archive/2022/11/12/creating-small-proof-of-concept-application-afternoon
-# tags:
-# - a
-# - b
----
-
-This morning, I was asked a “Could you build…” question.
-
-It was an idea mentioned a short while ago and involves a simple, interactive form on the front end that sends requests to a public API, filters the results from the response and displays them to the user.
-
-I’d probably want to hide the API request behind a service responsible for interacting with the API and filtering the results - ensuring that the API could be switched with something else later if needed.
-
-This afternoon, I built a small proof-of-concept application with Vue.js and TypeScript.
-
-There’s no API, or service retrieving real-time results. All of the data is hard-coded within the App component, as well as the code that filters, sorts and returns the results.
-
-The results are shown by adding a `
{{ results }}
` to the page, with a `
{{ state.selection }}
` to show the input data.
-
-There isn’t even any styling, with just some basic horizontal rules to split the page - similar to [these screenshots from Taylor Otwell](https://twitter.com/taylorotwell/status/1203356860818087944) of some work-in-progress versions of Vapor and Nova.
-
-A working proof of concept, or a "spike", answers the initial "Can we build..." question. It can be shown to a client or other stakeholders, act as a starting point for discussions and requirements gathering and then be turned into user stories. It also allows the Developers to validate their initial thoughts and experiment with different approaches.
-
-If the spike is successful, the idea can then be moved forward and implemented in a full way, otherwise, it can be stopped with a minimal amount of effort and time.
diff --git a/astro/src/content/daily-email/2022-11-12.md b/astro/src/content/daily-email/2022-11-12.md
deleted file mode 100644
index 82f71a56..00000000
--- a/astro/src/content/daily-email/2022-11-12.md
+++ /dev/null
@@ -1,26 +0,0 @@
----
-title: >
- Building a minimum viable product and managing technical debt
-pubDate: 2022-11-12
-permalink: >
- archive/2022/11/12/building-a-minimum-viable-product-and-managing-technical-debt
-# tags:
-# - a
-# - b
----
-
-Yesterday's email was about a proof-of-concept application that I’d quickly built to validate an idea and explore some initial approaches.
-
-Today, I’ve been working on a client project that I’ve improved and maintained for a few years.
-
-When I started working with this client, they had one website, built with Drupal 7 and Drupal Commerce. Now, there are x websites using the same codebase due to Drupal’s multi-site functionality.
-
-My main task for the last few months has been to get one of their sites onto Drupal 9 (which I did, it went live in October).
-
-This first site was the "minimum viable product" (MVP) - the least amount of functionality required to make it releasable to customers. This is different to a proof of concept which is to validate the idea and start a conversation about requirements and scope - where we define the MVP.
-
-For example, there is the ability to create products and product variations from a CSV file. It loads the file from disk and creates the products, but it doesn't update a product variation if a row with an existing SKU is changed, or disable the variation if a row is removed from the file. There is no admin UI for the client to upload a file - the only file that it'll use is the one that's path is hard-coded within the module.
-
-There are user stories for this, but we decided that we didn't need it for the initial launch and that we were happy to take on some technical debt, knowing that we can address it later when the original solutions are no longer sufficient.
-
-Now the minimum viable solution has been released, we can continue to iterate and enhance it based on customers' feedback, add more functionality, and address the technical debt as needed and as requirements require us to do so.
diff --git a/astro/src/content/daily-email/2022-11-13.md b/astro/src/content/daily-email/2022-11-13.md
deleted file mode 100644
index 8465214f..00000000
--- a/astro/src/content/daily-email/2022-11-13.md
+++ /dev/null
@@ -1,23 +0,0 @@
----
-title: >
- How I manage multiple Drupal websites using the same codebase
-pubDate: 2022-11-13
-permalink: >
- archive/2022/11/13/how-i-manage-multiple-drupal-websites-using-the-same-codebase
-tags:
- - drupal
----
-
-In my last email, I mentioned that I maintain several Drupal websites for a client using the same codebase, but how do I do that?
-
-The sites use Drupal's multisite functionality to have a separate directory for each site, each with its own settings file and files, and potentially modules and themes. Whilst there are some downsides to this approach, and we did evaluate alternatives, this approach allows us to keep one hosting account and save the client money compared to hosting each site separately.
-
-Each site has a separate database and configuration files, so out of the box, I can customise what functionality is needed on each site by turning modules on and off. Whilst this is fine for larger pieces of functionality, for smaller pieces I like to use feature flags.
-
-I use feature flags on single-site projects to separate deploying code from releasing a change, but I can also use them here to toggle something per-site. This could be using a module like [Feature toggle](https://www.drupal.org/project/feature_toggle) or another way like a checkbox on a settings form. Anything that I can use to say "Do this if that is enabled".
-
-Settings such as setting an endpoint URL or storing some API credentials would be set in an admin form and stored as configuration per site.
-
-I've tried various iterations of this - initially duplicating the custom code and having several near-identical versions of the same modules (this wasn't good for maintenance). We also used environment variables. However, this didn't scale as I added more sites and needed to create a new set of environment variables every time.
-
-This approach has worked well for the last few years on their original websites and should continue to work well as I upgrade and migrate them to their next versions.
diff --git a/astro/src/content/daily-email/2022-11-14.md b/astro/src/content/daily-email/2022-11-14.md
deleted file mode 100644
index a8ecb027..00000000
--- a/astro/src/content/daily-email/2022-11-14.md
+++ /dev/null
@@ -1,43 +0,0 @@
----
-title: >
- Camel-case or snake-case for test methods?
-pubDate: 2022-11-14
-permalink: >
- archive/2022/11/14/camel-case-or-snake-case-for-test-methods
-tags:
- - testing
----
-
-When writing object-orientated code, particularly in PHP, you usually write method names using camel-case letters - such as:
-
-```php
-public function doSomething(): void {
- // ...
-}
-```
-
-This is also true when writing methods within a test class - only that the method name is prefixed with the word `test`:
-
-```php
-public function testSomething(): void {
-}
-```
-
-This is probably expected and complies with the PSR code style standards like PSR-12.
-
-Something that I've seen some PHP developers and some frameworks prefer is to write their test methods using snake-case letters and commonly removing the `test` prefix in favour of using an annotation:
-
-```php
-/** @test */
-public function the_api_should_return_a_200_response_code_if_everything_is_ok(): void {
- // ...
-}
-```
-
-This is something that I've done myself for a while, but now I'm starting to reconsider both options.
-
-Whilst it's more readable, especially for longer test names (which I like to write), it's not consistent with method names in non-test files or non-test methods in test files; it looks odd if I need to add another annotation (do I keep a single annotation on one line, or just those with multiple annotations on the separate lines), and to do this, I need to disable some code sniffer rules for code to pass the PHPCS checks.
-
-If I used camel-cased names, I wouldn't need the PHPCS overrides, the annotations would be simpler, and the code would be more consistent - so I think I'll try that way again in the next tests that I write and see how it feels.
-
-Which do you prefer, and which would you expect to see in your project?
diff --git a/astro/src/content/daily-email/2022-11-15.md b/astro/src/content/daily-email/2022-11-15.md
deleted file mode 100644
index a16b211a..00000000
--- a/astro/src/content/daily-email/2022-11-15.md
+++ /dev/null
@@ -1,21 +0,0 @@
----
-title: >
- Writing good automated test names
-pubDate: 2022-11-15
-permalink: >
- archive/2022/11/15/writing-good-automated-test-names
-tags:
- - testing
----
-
-Something that I often see in code examples or tutorials are test methods like `testGet` or `testAdd`, or `testSubtract`. Short method names that don't describe the scenario that they're testing in much detail.
-
-What if a `get` method returns different types of value based on the input or a string is passed into a calculator method like `add` or `subtract`?
-
-I'd assume that the result of the calculation returns the total, but the test method doesn't say this.
-
-I'd rather be overly descriptive and write methods like `should_add_two_or_more_numbers_and_return_the_total()` rather than `testAdd`. It's a lot more readable and easier to see what the intention of the test is, and it's much better to use longer descriptive names when using options like `--testdox` with PHPUnit, which converts the method name into a sentence, which is what I do when running tests in CI pipelines.
-
-Something that I've picked up and recommend is to start each test case with the word "It" or "Should". This gives it a more behavioural feel and puts you in the mindset of what you're testing and not the methods that you're executing.
-
-A method like 'testAdd' might make sense within a unit test focusing on a single class and method, but as I usually do outside-in testing - which mostly uses functional and integration tests - this approach works well for me.
diff --git a/astro/src/content/daily-email/2022-11-16.md b/astro/src/content/daily-email/2022-11-16.md
deleted file mode 100644
index 61cc95fc..00000000
--- a/astro/src/content/daily-email/2022-11-16.md
+++ /dev/null
@@ -1,17 +0,0 @@
----
-title: >
- Why don't you write automated tests?
-pubDate: 2022-11-16
-permalink: >
- archive/2022/11/16/why-don't-you-write-automated-tests
-tags:
- - testing
----
-
-Many projects I’ve worked on in the past haven’t had an automated test suite.
-
-If you don't or can't write tests for your project for some reason, I'd love it if you could reply to this email or [let me know on Twitter](https://twitter.com/opdavies) and let me know why.
-
-I know some of the classic reasons, like "I don't have time" and "My clients won't pay for me to write them", but I'd like to get some more real-world examples.
-
-Then I'll do some follow-up posts to look into and address them.
diff --git a/astro/src/content/daily-email/2022-11-17.md b/astro/src/content/daily-email/2022-11-17.md
deleted file mode 100644
index 375b4652..00000000
--- a/astro/src/content/daily-email/2022-11-17.md
+++ /dev/null
@@ -1,17 +0,0 @@
----
-title: >
- Agnostic CI pipelines with run files
-pubDate: 2022-11-17
-permalink: >
- archive/2022/11/17/agnostic-ci-pipelines-with-run-files
----
-
-As I work on various projects, I use several different CI tools, such as GitHub Actions, Bitbucket Pipelines, and GitLab CI, as well as hosting providers that have build and deploy steps.
-
-Some only run continuous integration checks, like automated tests and static analysis, some build and push Docker images, and some use Ansible and Ansistrano to deploy the changes to production.
-
-Each tool has its configuration file with different settings and formats.
-
-Rather than being too tightly coupled to a particular tool, I like to keep things as agnostic as possible and [use a run file](https://www.oliverdavies.uk/archive/2022/08/15/using-run-file-simplify-project-tasks) with separate `ci:build` and `ci:deploy` tasks.
-
-This means that all the logic is within the run file rather than the CI tool-specific configuration file, so the file is shorter and cleaner; I can make changes to the CI tasks locally and quickly test changes and iterate, and also, as the logic is within the run file, I can easily switch to a different CI tool if needed without making changes to the tasks themselves.
diff --git a/astro/src/content/daily-email/2022-11-18.md b/astro/src/content/daily-email/2022-11-18.md
deleted file mode 100644
index b0410da8..00000000
--- a/astro/src/content/daily-email/2022-11-18.md
+++ /dev/null
@@ -1,19 +0,0 @@
----
-title: >
- One test a day keeps bugs away
-pubDate: 2022-11-18
-permalink: >
- archive/2022/11/18/one-test-a-day-keeps-bugs-away
-tags:
- - testing
----
-
-This is a quote from a presentation by Diego Aguiar at SymfonyCon that I saw from [a tweet from SymfonyCasts](https://twitter.com/SymfonyCasts/status/1593551105471938560?t=A8wnRUa0tLbb2q5qLhcQnA).
-
-I haven't seen the rest of the presentation, but I liked this quote and the idea of continuously improving a codebase using automated tests.
-
-The talk was titled "Advanced Test Driven Development" so I assume that it was focused on ensuring that new functionality also has accompanying tests but it could also apply to existing code.
-
-A lot of existing code that I've worked on wasn't covered by tests, so going back and writing tests for that code would be beneficial too - even if it's only one test a day. It would help to prevent and uncover existing bugs, enable the code to be refactored and changed without introducing regressions, and make the codebase more maintainable.
-
-Small changes over time add up.
diff --git a/astro/src/content/daily-email/2022-11-19.md b/astro/src/content/daily-email/2022-11-19.md
deleted file mode 100644
index 8cc1ff5b..00000000
--- a/astro/src/content/daily-email/2022-11-19.md
+++ /dev/null
@@ -1,17 +0,0 @@
----
-title: >
- Are missing tests a blocker to refactoring?
-pubDate: 2022-11-19
-permalink: >
- archive/2022/11/19/are-missing-tests-a-blocker-to-refactoring
----
-
-Is having automated tests a prerequisite for refactoring a piece of code?
-
-Without passing tests for that code, any changes made could introduce a regression, and bugs can be accidentally introduced.
-
-When refactoring with tests, you run them before making any changes to ensure they pass. The tests are rerun after every change to ensure that they still pass and that the change didn't introduce a regression that caused the test to fail. If a test fails, the change is reverted and re-attempted.
-
-If I need to refactor some code without tests, the first thing that I'll do is add some initial tests before the main work.
-
-Whilst nothing is stopping me from refactoring without the tests, the risk isn't something that I'd want to take on, and I'd much prefer to have some tests in place - just in case!
diff --git a/astro/src/content/daily-email/2022-11-20.md b/astro/src/content/daily-email/2022-11-20.md
deleted file mode 100644
index 4d88bbea..00000000
--- a/astro/src/content/daily-email/2022-11-20.md
+++ /dev/null
@@ -1,25 +0,0 @@
----
-title: >
- Version-controlled commented-out code
-pubDate: 2022-11-20
-permalink: >
- archive/2022/11/20/version-controlled-commented-out-code
-tags:
- - git
----
-
-Today, whilst debugging some legacy code within an application, I found several blocks of commented-out code.
-
-Some were previous debugging code which had been commented out, and some were old components or previous implementations - but instead of being removed when they were no longer needed, they remained in the codebase as commented-out lines - inactive but adding noise and complexity around the code that I was trying to understand and debug.
-
-To make it easier for me to figure out this code, I'd like it to be as clean to read and as simple to understand as possible.
-
-The codebase is version-controlled, so why would there be a need to comment out and keep the lines?
-
-Version control systems have a log of each change, so if you need to see previous changes, you can view the log and see what changed, when, and by who.
-
-You can also see any other files that were changed in the same commit, and usually, there will be a reference to the issue or ticket that required that change.
-
-If you need to re-add a change that had been removed, you can either do this manually or by reverting the commit.
-
-Should there be commented-out code within a codebase if it's version controlled? I'd say no unless there's a good reason for it to be there and it's providing some additional context or for a specific purpose. If it's an outdated implementation, some old debugging code, or a component that's no longer needed, I think that it should be removed, and people can use version control tools to find or re-introduce those changes if needed.
diff --git a/astro/src/content/daily-email/2022-11-21.md b/astro/src/content/daily-email/2022-11-21.md
deleted file mode 100644
index 9c782c08..00000000
--- a/astro/src/content/daily-email/2022-11-21.md
+++ /dev/null
@@ -1,21 +0,0 @@
----
-title: >
- Git tricks to avoid committing commented-out and other unneeded code
-pubDate: 2022-11-21
-permalink: >
- archive/2022/11/21/git-tricks-to-avoid-committing-commented-out-and-other-unneeded-code
-tags:
- - git
----
-
-[Yesterday's email](https://www.oliverdavies.uk/archive/2022/11/20/version-controlled-commented-out-code) talked about whether commented-out code should be present if your code is version-controlled, but how do you avoid committing it in the first place?
-
-You could make sure that you remove everything manually before you stage and commit your changes, or I like to use `git add --patch` (or `git add -p`) to interactively stage my changes, allowing me to select which parts of files I want to include in my commit and ignore anything else. The `--patch` option also works for other commands, including `checkout` and `reset`.
-
-If you've already committed something like some debug code, you can use `git commit --amend` to amend the previous commit before pushing it, or if you have a separate clean-up commit, you can use `git rebase --interactive` and either the squash or fixup options to amend the original commit.
-
-If some old code has been removed and you want to find it, you can use `git log -S` with a string to search for, and Git will show a list of commits where the specified string was changed.
-
-If instead, you wanted to search for text within the commit message, you can use `git log --grep` with a string like an issue number to see a list of commits with that text in the commit message subject line or body.
-
-I hope these tips help keep unwanted code out of your version-control repository.
diff --git a/astro/src/content/daily-email/2022-11-22.md b/astro/src/content/daily-email/2022-11-22.md
deleted file mode 100644
index 79c84530..00000000
--- a/astro/src/content/daily-email/2022-11-22.md
+++ /dev/null
@@ -1,26 +0,0 @@
----
-title: >
- tldr
-pubDate: 2022-11-22
-permalink: >
- archive/2022/11/22/tldr
-# tags:
-# - a
-# - b
----
-
-`tldr` is a command-line tool that I've been using a lot recently.
-
-Usually, on the command line, you'd use the `man` command to show a manual page for a certain command - like `man ls`.
-
-`tldr` is "a collection of simplified and community-driven man pages".
-
-After installing it, run `man tldr` or even `tldr tldr` to learn more about it.
-
-Then, run a command like `tldr ls` to get output for a specific command.
-
-I like that it shows a short description of what the command does, followed by a link to find out more information and then several valuable examples demonstrating the various options, flags, and arguments the command takes.
-
-For `ls`, it shows how to list one file per line, list hidden files, use a long format list, show human-readable size units, long format sorted by size or modification date, and only show directories.
-
-For commands like `tar`, `rsync`, and `scp` that I don't use that often or can't remember all of the different options, I like being able to see these examples and figure out what I need at that time.
diff --git a/astro/src/content/daily-email/2022-11-23.md b/astro/src/content/daily-email/2022-11-23.md
deleted file mode 100644
index 1a5ab735..00000000
--- a/astro/src/content/daily-email/2022-11-23.md
+++ /dev/null
@@ -1,33 +0,0 @@
----
-title: >
- Do you need to branch if you're the only one working on a project?
-pubDate: 2022-11-23
-permalink: >
- archive/2022/11/23/do-you-need-to-branch
-tags:
- - git
----
-
-Yesterday, I [saw a tweet](https://twitter.com/scottkeckwarren/status/1594752744165847040) where the writer said they were “falling into the branch, pull request, and merge after actions pass I use at work even though I'm the only one working on it”.
-
-After reading this, my question is, "Should you, or do you need to, create branches if you're the only person working on a project?".
-
-These days, I use trunk-based development as much as possible, so I hardly ever create new branches, whether working on a project myself or with a team.
-
-[I used to use Git Flow](https://www.oliverdavies.uk/talks/git-flow) and create branches for every new feature and bug fix, but I remember, whilst demonstrating two work-in-progress features to a client, switching between the different branches caused my local site to break. Whilst it wasn’t a major issue, it wouldn't have seemed professional.
-
-In a team environment, feature branches are intended to keep different changes and different people's work separate.
-
-But is this needed if you’re the only in the team?
-
-Assumingly, you're only working on one change at a time, so what's the benefit of creating a separate branch?
-
-If you need to switch to a different task, another approach could be to revert your work-in-progress commits, move them onto another local branch temporarily, or wrap them within a feature flag so that the changes are committed but not active.
-
-The other part of the tweet said, “I like the little integrations to make sure the tests pass”.
-
-I’m comfortable working on a single branch and committing and pushing small changes often.
-
-My CI pipelines run for every change that I push, and if one fails, I’ll either push a small fix to get it passing again or revert the failing change and investigate further.
-
-For me, working on a single branch keeps my workflow simple and lean, allowing me to focus on the changes and the tasks that I need to work on and not worry about which branch I’m working on.
diff --git a/astro/src/content/daily-email/2022-11-24.md b/astro/src/content/daily-email/2022-11-24.md
deleted file mode 100644
index 5ce18efe..00000000
--- a/astro/src/content/daily-email/2022-11-24.md
+++ /dev/null
@@ -1,29 +0,0 @@
----
-title: >
- Doing the simplest possible thing
-pubDate: 2022-11-24
-permalink: >
- archive/2022/11/24/doing-the-simplest-possible-thing
----
-
-I spent most of today working on some code I wrote for the first phase of a client project a few months ago.
-
-The previous version used hard-coded data within a Vue.js application, which was sufficient for the previous criteria and in line with the lean approach we decided to take.
-
-It was the simplest thing that worked.
-
-A new requirement means that the hard-coded data no longer works, so I need to refactor and enhance the code to work with different configurations. I have a proof of concept of this working using JSON from an API endpoint, but I would also like to use a static JSON file when needed for local development.
-
-I experimented with a few different ways to approach this before asking myself, "What's the simplest possible thing I can do to get this working?".
-
-I already knew that I needed to make a change to the structure of the data, which I was able to do quickly with the hard-coded data that I already had, and whilst a static JSON file would be a nice-to-have, I could quickly move the hard-coded data into the API endpoint that I'd already created and continue building on my proof of concept.
-
-The idea of "What's the simplest thing?" is something that I use regularly.
-
-When teaching or coaching test-driven development, I want to write the smallest failing test and then find the quickest and simplest way to get it to pass - even if it means returning a hard-coded value for now.
-
-When working on development tasks, I like to break things down as much as possible and find the smallest thing I can do, commit, and push. This gets the ball rolling, and then I repeat the process.
-
-Even when writing an email or blog post, once I start writing, it's much easier to continue once I'm in the flow.
-
-Taking the simplest approach and not making assumptions about future requirements or scope means less and more maintainable code, as well as being a productivity hack.
diff --git a/astro/src/content/daily-email/2022-11-25.md b/astro/src/content/daily-email/2022-11-25.md
deleted file mode 100644
index 35e0bfdc..00000000
--- a/astro/src/content/daily-email/2022-11-25.md
+++ /dev/null
@@ -1,19 +0,0 @@
----
-title: >
- Plan, then code
-pubDate: 2022-11-25
-permalink: >
- archive/2022/11/25/plan-then-code
----
-
-Recently I [saw this tweet](https://twitter.com/OneJKMolina/status/1303047499238776832) in a screenshot on a LinkedIn post.
-
-The post was about improving business writing, but the original tweet was about software engineering.
-
-For me, the main sentence within the tweet is, "Resist the urge to do something before having a plan." - or as the LinkedIn post said, "Resist the urge to start typing before having a plan.".
-
-This is something that I've focused on a lot over the last few years, always asking, "What problem are we trying to solve?" and using flow charts and ADRs or technical design documents to come up with a plan before starting to write any code.
-
-Doing this makes me think of and answer as much as possible upfront - what we need, how things should work, the required steps, and what edge cases and pitfalls there might be. I'll usually have two or three solutions I'll consider and document, as well as which I decided to use and why.
-
-Once I've planned the solution, coding is usually very fast and straightforward, as most or all questions should already have been answered. I don't need to stop and answer questions whilst writing the code, and the code should be cleaner as I'm coding to the plan rather than figuring it out as I go.
diff --git a/astro/src/content/daily-email/2022-11-30.md b/astro/src/content/daily-email/2022-11-30.md
deleted file mode 100644
index 9d7af9b8..00000000
--- a/astro/src/content/daily-email/2022-11-30.md
+++ /dev/null
@@ -1,43 +0,0 @@
----
-title: >
- Ship, Show or Ask
-pubDate: 2022-11-30
-permalink: >
- archive/2022/11/30/ship-show-or-ask
-tags:
- - git
----
-
-"Ship / Show / Ask" describes itself as a self-described modern branching strategy that combines the features of pull or merge requests with the ability to keep shipping changes.
-
-Each change is either a "Ship", "Show", or "Ask".
-
-## Ship
-
-"Ship" changes are what I most commonly do with continuous integration and trunk-based development projects. Changes are committed directly to the main branch and shipped - assuming that the CI pipeline and any other automated checks pass. There is no blocking code review or pull request for "Ship" changes.
-
-## Show
-
-"Show" changes are made on a temporary branch instead of the mainline. This branch is then used to create a pull request which is closed once the CI checks pass without any code review.
-
-Once the pull request is merged, the change is deployed, but the pull request is still available as somewhere to have feedback and conversation about the change.
-
-This is something that I did today after starting to write a new feature by implementing the Decorator design pattern, and wanted others to be aware of this approach and ask any questions.
-
-Another reason for this approach is if someone wants to ensure that the CI checks will pass before merging to mainline. Some Developers worry about breaking the CI pipeline with a trunk-based approach and blocking others, so want to know that the pipeline will continue to work and they aren't disrupting other team members.
-
-## Ask
-
-This is how I've worked on most projects before, and still with some clients where they want to review changes before merging, or maybe I want to have a discussion and review a change beforehand.
-
-This is also common when new Developers join a project or need to change some code they haven't worked on before.
-
-## Conclusion
-
-I like the flexibility and balance of this approach. I prefer to work on "mostly ship" projects, and most of the show and ask conversations happen during pair or mob programming sessions.
-
-Some of my clients where I work with teams are "mostly ask" and work in a more Git Flow-type way and want to review any changes before they're merged and deployed.
-
-But if you're working on a "mostly ask" project and want to move to "mostly ship", then aiming to move to "mostly show" is a good intermediate step and a way to reduce shipping time or develop and build confidence in the CI pipeline before moving to trunk-based development and removing the manual review step.
-
-The full article with more information is at https://martinfowler.com/articles/ship-show-ask.html.
diff --git a/astro/src/content/daily-email/2022-12-01.md b/astro/src/content/daily-email/2022-12-01.md
deleted file mode 100644
index 0cc94339..00000000
--- a/astro/src/content/daily-email/2022-12-01.md
+++ /dev/null
@@ -1,33 +0,0 @@
----
-title: >
- Writing readable code
-pubDate: 2022-12-01
-permalink: >
- archive/2022/12/01/writing-readable-code
----
-
-This week, I needed to investigate and fix a bug within some existing code.
-
-It's code written some time ago and not by anyone working on the team.
-
-The code wasn't very readable, so before I could fix the bug, I needed to figure out what the code was supposed to be doing.
-
-I started to write a list of things that would make the code easier to read and understand - no single-letter variable names, reduced levels of indentation and splitting some nested ternary operators to use separate return statements.
-
-I also watched a video of a conference talk titled "Writing code you won't hate tomorrow", which re-introduced me to Object Callisthenics.
-
-They are from "The ThoughtWorks Anthology" book and are some steps that include some of the points that I had written:
-
-1. Use only one level of indentation per method.
-1. Don’t use the else keyword.
-1. Wrap all primitives and strings.
-1. Use only one dot per line.
-1. Don’t abbreviate.
-1. Keep all entities small.
-1. Don’t use any classes with more than two instance variables.
-1. Use first-class collections.
-1. Don’t use any getters/setters/properties
-
-As well as the original book, there are numerous blog posts and videos on this topic.
-
-Why try some of them on the next code you write and see if it's easier to read and understand?
diff --git a/astro/src/content/daily-email/2022-12-02.md b/astro/src/content/daily-email/2022-12-02.md
deleted file mode 100644
index 0613a2e1..00000000
--- a/astro/src/content/daily-email/2022-12-02.md
+++ /dev/null
@@ -1,27 +0,0 @@
----
-title: >
- Commit and push something every day
-pubDate: 2022-12-02
-permalink: >
- archive/2022/12/02/commit-and-push-something-every-day
----
-
-One of the significant changes that I've found and that's benefitted me whilst developing is to commit and push something every day.
-
-It doesn't need to be a whole feature. It could be a new class with its passing tests, but it isn't used anywhere yet, so it won't affect the existing functionality, or it could be a new test for some existing functionality that was missing previously.
-
-It could be a small refactor - renaming a variable or class name that makes some code easier to read or removing some commented-out code that isn't doing anything other than adding visual clutter.
-
-It could be updating some documentation or [writing a technical document](https://www.oliverdavies.uk/archive/2022/09/23/adrs-technical-design-documents); if you keep those in your version control repository, that would help you implement the following change or to make the documentation clearer for the next reader - whether that's you or someone else.
-
-Committing something at least once a day creates a different mindset to "I'll write everything and push it when it's done".
-
-It makes you break up large tasks into multiple smaller ones and set mini-deadlines for yourself. I used to do the same when I commuted to work on a train and had a task for a freelance project to complete before I arrived. I used to think, "What can I start, finish and commit before I get there?" instead of leaving something incomplete.
-
-You don't need to push your change to mainline. If you use the ["Ship, Show, Ask" approach](https://www.oliverdavies.uk/archive/2022/11/30/ship-show-or-ask) then you could commit to a temporary branch that you either merge yourself once you know it passes the checks, or to show or get feedback from other team members.
-
-Practicing this becomes a habit, and if you're doing test-driven development and committing after every passing test or refactor, you'll find yourself pushing numerous changes a day.
-
-This became my normal approach instead of having long-lived feature branches or lots of unpushed local commits.
-
-I much prefer making as small charges as possible and pushing them as often as I can.
diff --git a/astro/src/content/daily-email/2022-12-03.md b/astro/src/content/daily-email/2022-12-03.md
deleted file mode 100644
index 5574079f..00000000
--- a/astro/src/content/daily-email/2022-12-03.md
+++ /dev/null
@@ -1,23 +0,0 @@
----
-title: >
- What to do with TODO comments
-pubDate: 2022-12-03
-permalink: >
- archive/2022/12/03/what-to-do-with-todo-comments
----
-
-[In a previous email](https://www.oliverdavies.uk/archive/2022/11/20/version-controlled-commented-out-code), I wrote about commented-out code and whether it should remain in a codebase - especially if it's version controlled and there's a commit log of all changes.
-
-But what about TODO comments that remind you to do something?
-
-When I think of TODO comments, I think of times when I've found them left in codebases from a long time ago by Developers who no longer work on it - never to be looked at again.
-
-I recently removed a small number from a codebase I added while working on the first MVP.
-
-They were comments like "Move this to a repository" or "Remove this hard-coded value and make this configurable".
-
-These weren't things that would affect the functionality of the code - but nice-to-haves, things that could be done differently, or reminders of things where hard-coded values were fine but would need to be replaced in the future.
-
-Instead of being code comments that only I was aware of, I moved them into the issue-tracking system I'm using. This allows the client to have visibility of them and that they can be scheduled and prioritised alongside other work, providing a truer reflection of the current tasks.
-
-Some have since been addressed, but some will remain and be actioned in the future. If they were still code comments, they might not have been addressed at all, so the issue tracker seems like the better place for them to be.
diff --git a/astro/src/content/daily-email/2022-12-04.md b/astro/src/content/daily-email/2022-12-04.md
deleted file mode 100644
index ae3355e2..00000000
--- a/astro/src/content/daily-email/2022-12-04.md
+++ /dev/null
@@ -1,25 +0,0 @@
----
-title: >
- Writing "Why first" user stories
-pubDate: 2022-12-04
-permalink: >
- archive/2022/12/04/writing-why-first-user-stories
----
-
-I've usually written user stories that follow this format:
-
-As a...
-I want...
-So that...
-
-You focus on the person who needs the task first, followed by what they want, and why they want it.
-
-Lately, I've been re-ordering stories to follow this order:
-
-So that...
-As a...
-I want...
-
-What I like about this is that it focuses on capturing the "why" of the story first rather than at the end or maybe even forgetting it altogether.
-
-What's needed and who needs it doesn't matter unless you also capture why it's needed.
diff --git a/astro/src/content/daily-email/2022-12-05.md b/astro/src/content/daily-email/2022-12-05.md
deleted file mode 100644
index 44750906..00000000
--- a/astro/src/content/daily-email/2022-12-05.md
+++ /dev/null
@@ -1,27 +0,0 @@
----
-title: >
- Outcomes or output
-pubDate: 2022-12-05
-permalink: >
- archive/2022/12/05/outcomes-or-output
----
-
-I was reading a Twitter thread recently that [started with this tweet](https://twitter.com/allenholub/status/1594786089994067969).
-
-TL;DR:
-
-> "Measuring output (e.g. velocity) is a waste of time. It's outcomes you care about - customer happiness."
-
-This is definitely something that I agree with.
-
-I can't remember the last time I looked at an output burndown chart or a velocity score.
-
-I'd rather focus on what outcomes have been delivered and adding value to clients and customers.
-
-What features did we release, what bugs did we fix, and what impact and value did that provide?
-
-What increased revenue or improved a customer's experience?
-
-I may have a sprint or cycle where I only deliver one or two large tasks, but those are major features that have been requested, a bug affecting a user's experience, or a task that unblocks future tasks.
-
-In that situation, my velocity may not be good and could be improved by working on multiple smaller tasks, but which outcomes provide the most value?
diff --git a/astro/src/content/daily-email/2022-12-06.md b/astro/src/content/daily-email/2022-12-06.md
deleted file mode 100644
index 53e23f21..00000000
--- a/astro/src/content/daily-email/2022-12-06.md
+++ /dev/null
@@ -1,33 +0,0 @@
----
-title: >
- Should you comment your code?
-pubDate: 2022-12-06
-permalink: >
- archive/2022/12/06/should-you-comment-your-code
----
-
-Something that I hear often is "self-documenting code", and that code should be easy to understand without comments.
-
-If you need to write a comment explaining what something does, move the code into a new class or function and have its name describe what it does.
-
-I agree with this, but I still think there is a place for comments within the code as long as they add value.
-
-## What comments shouldn't be
-
-Comments shouldn't just repeat what the code says.
-
-If the comment says "Returns false", and I can read that from the code, the comment isn't adding any value.
-
-I use types a lot in PHP and TypeScript, and if docblocks are just repeating the native types, I'd rather not include them and keep the code minimal.
-
-Comments like "Constructor" and "This shouldn't happen" add no context.
-
-## What comments should be
-
-Comments need to add value by adding extra information or explaining why the code does what it does.
-
-I will add comments like "This class decorates ... so that ..." and "This returns ... if ...". These comments add value and make the code easier to read and understand. The downside is that you then need to maintain the comments, make sure they remain correct, and if the functionality changes the comment is also changed.
-
-If a static analysis tool requires me to provide more information in a docblock that describes some parameters or a return type, I'll do that. It makes the code quality better, reduces bugs, and makes the Developer experience better. As I'm improving the native types by providing more information, I'm not just repeating them so this is OK with me.
-
-Comments should make the code easier to read, understand, and work with for yourself and other team members.
diff --git a/astro/src/content/daily-email/2022-12-07.md b/astro/src/content/daily-email/2022-12-07.md
deleted file mode 100644
index 7df23fc6..00000000
--- a/astro/src/content/daily-email/2022-12-07.md
+++ /dev/null
@@ -1,23 +0,0 @@
----
-title: >
- Separating releases from deployments with feature flags
-pubDate: 2022-12-07
-permalink: >
- archive/2022/12/07/separating-releases-from-deployments-with-feature-flags
----
-
-In a typical feature release process, a feature is released when you merge the code and push it to production.
-
-If a bug is found after the release, the code needs to be reverted (and any conflicts or issues dealt with) and deployed again.
-
-Also, features can only be merged once they are complete, which may take hours, days or weeks, depending on the size of the feature.
-
-These are some reasons I like to use feature flags (aka feature toggles) and separate the code deployment from releasing the feature. The code is deployed as before, but the feature isn't released, and the code isn't executed until a feature flag is enabled.
-
-If there is a bug, the feature flag can be disabled, and the feature is turned off until a fix can be pushed - without needing another code deployment.
-
-If my feature is incomplete, if it's feature flagged, I can commit and deploy it without users seeing it or affecting the running application, resulting in smaller and more manageable commits and deployments.
-
-If you wanted, you could enable a feature flag for a subset or a certain subsection of your users - allowing them to test it before making it available to everyone.
-
-Another way I use feature flags is within a [multi-site Drupal application](https://www.oliverdavies.uk/archive/2022/11/13/how-i-manage-multiple-drupal-websites-using-the-same-codebase) to enable a different feature set per site and allow me to keep one version of the code for all sites to keep this easy to manage and maintain.
diff --git a/astro/src/content/daily-email/2022-12-08.md b/astro/src/content/daily-email/2022-12-08.md
deleted file mode 100644
index c77c78ed..00000000
--- a/astro/src/content/daily-email/2022-12-08.md
+++ /dev/null
@@ -1,64 +0,0 @@
----
-title: >
- The Decorator design pattern
-pubDate: 2022-12-08
-permalink: >
- archive/2022/12/08/the-decorator-design-pattern
-tags:
- - design-patterns
----
-
-Decorator is a structural design pattern that allows you to add extra functionality, such as if you want to add caching or logging to a service, without changing the original class.
-
-As long as a class implements an Interface, it can be decorated.
-
-For example, if I have this PHP interface:
-
-```php
-interface DoesSomething
-{
- public function doSomething(): void;
-}
-```
-
-I could have this class that does something:
-
-```php
-final class FirstClass implements DoesSomething
-{
- public function doSomething(): void
- {
- // Does something.
- }
-}
-```
-
-If I need to do something else, like caching or logging the result, I can decorate it.
-
-To do this, I need another class that implements the same interface and inject the original version.
-
-```php
-final class SecondClass implements DoesSomething
-{
- public function __constuct(
- private DoesSomething $originalClass
- ) {}
-
- public function doSomething()
- {
- // Do something else before.
-
- $this->originalClass->doSomething();
-
- // Do something else afterwards.
- }
-}
-```
-
-Within the new class, the methods can be overridden, extra functionality can be added, and the original method can be run to execute the original functionality.
-
-As the two classes implement the same interface, I can swap between different versions and decorate multiple times if needed.
-
-This a pattern that I used recently to extend a service that retrieved some data from an API and saved it to a file, to change some arguments and do more work with it.
-
-The original class was unchanged, the new class was minimal and easy to understand as it only had a single responsibility, and if I needed to switch back to the original version, I could easily do that.
diff --git a/astro/src/content/daily-email/2022-12-09.md b/astro/src/content/daily-email/2022-12-09.md
deleted file mode 100644
index 05127984..00000000
--- a/astro/src/content/daily-email/2022-12-09.md
+++ /dev/null
@@ -1,28 +0,0 @@
----
-title: >
- How and why I started using PostCSS
-pubDate: 2022-12-09
-permalink: >
- archive/2022/12/09/how-and-why-i-started-using-postcss
-tags:
- - css
- - front-end
----
-
-I assume that, like many other Developers, when I started learning front-end development, I wrote normal, plain CSS and later discovered and adopted pre-processors like Less and Sass that added features such as variables and nesting to my stylesheets.
-
-This was the case when I first saw what became Tailwind CSS, which were some stylesheets written in Less and ported manually between projects.
-
-I remember watching one of those streams, and a fellow viewer suggested PostCSS, which Tailwind CSS would later be written in.
-
-PostCSS, a CSS post-processor rather than a pre-processor, has become my preferred way of writing CSS because of Tailwind.
-
-When I started using Tailwind in my projects, I was layering it on top of another CSS framework or styles that were written using Less or Sass, so I needed to pre-process them into CSS first and then run PostCSS - essentially running two build steps and adding to the build time.
-
-I moved to use PostCSS by default - removing one of the build steps.
-
-What I liked about it, as well as the quicker build times, was that I could start with plain CSS and add the extra features I needed. I didn't use all of Sass and Less' features, and now, if I needed nesting or real-time imports, I could add it via a PostCSS plugin or write my own.
-
-It's also quick and easy to use, using the PostCSS CLI tool and without more complex tools like Webpack.
-
-If you haven't tried PostCSS, I recommend taking a look.
diff --git a/astro/src/content/daily-email/2022-12-10.md b/astro/src/content/daily-email/2022-12-10.md
deleted file mode 100644
index 8933f1e0..00000000
--- a/astro/src/content/daily-email/2022-12-10.md
+++ /dev/null
@@ -1,53 +0,0 @@
----
-title: >
- Managing databases with Neovim and Docker
-pubDate: 2022-12-10
-permalink: >
- archive/2022/12/10/managing-databases-with-neovim-and-docker
-tags:
- - docker
- - neovim
----
-
-If you work on software projects that use a database, you need a convenient way to connect, inspect, and query them.
-
-Some IDEs like PhpStorm have an integrated database client, which I've recently added to my Neovim setup and working with Docker and Docker Compose.
-
-## Configuring Docker Compose
-
-A local port needs to be exposed from the database container that Neovim can connect to.
-
-I usually do this with a `docker-compose.override.yaml` file:
-
-```yaml
-services:
- database:
- ports:
- - 3307:3306
-```
-
-Docker Compose recognises this by default, extends the normal `docker-compose.yaml` file and adds a port forwarding to the `database` service.
-
-## Configuring Neovim
-
-The two plugins I'm using are tpope/vim-dadbod and kristijanhusak/vim-dadbod-ui, and should work with Vim and Neovim. Thanks to both of these project maintainers.
-
-Once installed, run `:DBUIAddconnection` to add a database connection.
-
-Here is an example connection string:
-
-```
-mysql://drupal:drupal@localhost:3307/drupal?protocol=tcp
-```
-
-Using the local port mapping, this connects to a MySQL database within the `database` service.
-
-Then run `:DBUI` to toggle the UI and see a list of databases in the left-hand sidebar.
-
-You can enter `R` to refresh databases or `r` to rename or update connection details for a specific database.
-
-Once connected, you can enter and save queries, using table and column name completion, which are executed every time the query is saved.
-
-I like not needing to switch contexts and leave my editor in order to query a database, and feel a lot more productive being able to write, execute and save queries within this UI.
-
-If you're a Vim or Neovim user, I'd suggest trying this setup and seeing if it works for you.
diff --git a/astro/src/content/daily-email/2022-12-15.md b/astro/src/content/daily-email/2022-12-15.md
deleted file mode 100644
index c0707463..00000000
--- a/astro/src/content/daily-email/2022-12-15.md
+++ /dev/null
@@ -1,24 +0,0 @@
----
-title: >
- Happy Drupal 10 release day!
-pubDate: 2022-12-15
-permalink: >
- archive/2022/12/15/happy-drupal-10-release-day
-tags:
- - drupal
- - php
----
-
-Today, Drupal 10 was released alongside Drupal 9.5.
-
-This means that, as of today, Drupal 9.3 is no longer supported, so people should update to 9.4, 9.5, or 10.
-
-As things stand, Drupal 7 is still supported until November 2023.
-
-I haven't tried upgrading any existing websites from Drupal 9 to 10 yet, but I have already started a new client project with Drupal 10.
-
-It's a project for a new client that we've been discussing for a few months, and we wanted to wait until Drupal 10 was released before starting. My preparation work has been on the release candidate version of Drupal 10, so I can't foresee any issues updating to the stable 10.0.0 version.
-
-As an open-source Drupal project maintainer, I'll soon release Drupal 10 compatible versions of my maintained modules and themes, such as Override Node Options and the Tailwind CSS starter kit theme.
-
-If your company has a Drupal module that needs to be upgraded to be Drupal 10 compatible, or needs a module to integrate your service with Drupal 10, reply to this email and let's arrange a call and see if we can work together.
diff --git a/astro/src/content/daily-email/2022-12-20.md b/astro/src/content/daily-email/2022-12-20.md
deleted file mode 100644
index 3a53630d..00000000
--- a/astro/src/content/daily-email/2022-12-20.md
+++ /dev/null
@@ -1,26 +0,0 @@
----
-title: >
- Automating all the things, including infrastructure
-pubDate: 2022-12-20
-permalink: >
- archive/2022/12/20/automating-all-the-things,-including-infrastructure
-tags:
- - automation
- - devops
----
-
-I'm a big advocate for automation, from having a reproducible Docker and Docker Compose environment, automated tests, static analysis, and code linting in my projects to running them automatically on every push to a remote repository using a CI pipeline.
-
-I've written scripts to simplify common complex tasks and automated my local development environment setup before using tools like Ansible and, recently, the Nix package manager, NixOS and Home Manager.
-
-Another main piece of automation I use is to create and manage the infrastructure my applications run in.
-
-I've talked about it in my [Deploying PHP applications with Ansible and Ansistrano talk](https://www.oliverdavies.uk/talks/deploying-php-ansible-ansistrano), that before you can deploy an application, you need a server with the required packages installed to run it. You may also need a CDN endpoint, SSL certificate, DNS records, CORS policy, database server, container registry, object storage bucket or a number of various other things.
-
-Using automation tools like Terraform, Pulumi or Ansible, you can run a single command to create, update or destroy resources or your entire stack.
-
-The automation code acts as living documentation, can be version-controlled, stored alongside the code, and read by the Developers or anyone else involved with the project.
-
-If you need to hand over the hosting requirements to a client or create their own version, you can do that with the same automation code.
-
-And if a disaster scenario was to happen and you needed to recreate your infrastructure from scratch or move to a different cloud provider, you could do that quickly using automation tools, knowing that the new infrastructure would be consistent with the original, all of the pieces would be in place, and without needing to recreate everything manually from scratch.
diff --git a/astro/src/content/daily-email/2022-12-21.md b/astro/src/content/daily-email/2022-12-21.md
deleted file mode 100644
index 50202ce3..00000000
--- a/astro/src/content/daily-email/2022-12-21.md
+++ /dev/null
@@ -1,19 +0,0 @@
----
-title: >
- Duck typing
-pubDate: 2022-12-21
-permalink: >
- archive/2022/12/21/duck-typing
----
-
-If it looks like a duck, walks like a duck, and quacks like a duck, it must be a duck.
-
-If I pass a parameter into a function, as long as it works with the code within the function - it is of the correct type and has the expected properties and methods - it will work, although nothing is enforcing that the correct thing is passed in.
-
-If not, you'd get an error that the method or property doesn't exist when trying to invoke or access it.
-
-This is the opposite of strict typing, where you'd get a Type error if you passed the wrong thing.
-
-Both are valid approaches, though I prefer to use types and get specific error messages and leverage tools like static analysis, which work better the more it understands your code.
-
-In particular when writing and using open-source code that anyone can use however they like, I'd suggest leveraging types and type-checking, but it depends on what you, your team or your community prefer.
diff --git a/astro/src/content/daily-email/2022-12-22.md b/astro/src/content/daily-email/2022-12-22.md
deleted file mode 100644
index 2cfe1771..00000000
--- a/astro/src/content/daily-email/2022-12-22.md
+++ /dev/null
@@ -1,17 +0,0 @@
----
-title: >
- The Boy Scout rule
-pubDate: 2022-12-22
-permalink: >
- archive/2022/12/22/the-boy-scout-rule
----
-
-The Boy Scout rule is "Always leave the campground cleaner than you found it".
-
-From a programming perspective, "Always leave the code better than you find it".
-
-If you're working on some code and see some commented-out lines or unused variables, once you've finished with your changes, remove them too.
-
-If there's a variable that could have a more descriptive name, change it.
-
-If there are any other refactors you can do, do them and leave the code better than before and easier for the next Developer (whether it's you or someone else) to work with.
diff --git a/astro/src/content/daily-email/2022-12-23.md b/astro/src/content/daily-email/2022-12-23.md
deleted file mode 100644
index 0df8ff82..00000000
--- a/astro/src/content/daily-email/2022-12-23.md
+++ /dev/null
@@ -1,23 +0,0 @@
----
-title: >
- Speaking at PHP Stoke and nor(DEV):con
-pubDate: 2022-12-23
-permalink: >
- archive/2022/12/23/speaking-at-php-stoke-and-nordevcon
-tags:
- - public-speaking
----
-
-I had some early presents this month and have been accepted to present talks at the new PHP Stoke meetup and the Norfolk Developers Conference.
-
-## PHP Stoke
-
-The first PHP Stoke meetup will be held at Genr8 Smithfield Works on the 12th of January. I'll be presenting "[Things you should know about PHP](https://www.oliverdavies.uk/talks/things-you-should-know-about-php)". It'll be great to be the first speaker at this new meetup.
-
-## nor(DEV):con
-
-The Norfolk Developers conference is in Norwich on the 23rd and 24th of February.
-
-I'll be presenting "[Taking Flight about Tailwind CSS](https://www.oliverdavies.uk/talks/taking-flight-with-tailwind-css)". It's been a while since I last gave this talk so I'm looking forward to updating it with the latest changes and new features in Tailwind CSS.
-
-It'll be great to be speaking at these events and hopefully others in 2023.
diff --git a/astro/src/content/daily-email/2022-12-28.md b/astro/src/content/daily-email/2022-12-28.md
deleted file mode 100644
index 5f08cd7c..00000000
--- a/astro/src/content/daily-email/2022-12-28.md
+++ /dev/null
@@ -1,19 +0,0 @@
----
-title: >
- Debugging gitignore rules
-pubDate: 2022-12-28
-permalink: >
- archive/2022/12/28/debugging-gitignore-rules
-tags:
- - git
----
-
-Have you wondered why a file or directory is being ignored in your Git repository and isn't appearing when you run `git status`?
-
-Maybe you have multiple `.gitignore` files and you don't know which is causing the issue, or you ignore everything and explicitly unignore the files that you want to add.
-
-## `check-ignore` to the rescue
-
-`git check-ignore` accepts a list of paths and checks if each is ignored.
-
-There's also a `--verbose` option that will tell you which `.gitignore` file is causing it to be ignored as well as the line number and the pattern - great information for debugging, and no more force adding files.
diff --git a/astro/src/content/daily-email/2022-12-29.md b/astro/src/content/daily-email/2022-12-29.md
deleted file mode 100644
index e949ca86..00000000
--- a/astro/src/content/daily-email/2022-12-29.md
+++ /dev/null
@@ -1,45 +0,0 @@
----
-title: >
- What is the cost of a bug?
-pubDate: 2022-12-29
-permalink: >
- archive/2022/12/29/what-is-the-cost-of-a-bug
----
-
-All software has bugs, but each has a different cost depending on when and where it's found.
-
-## In production
-
-If a bug was found in production, it was probably found by a user, will time to replicate, diagnose and fix, and could have caused some reputational or financial damage.
-
-You'd need to create a ticket and schedule the work, meaning you're not working on something else.
-
-Cost: High
-
-## In a pre-production environment
-
-It's likely found by a test analyst or product owner but hidden from the end users and customers.
-
-It will still take time to replicate, diagnose and fix, and you'd still need to create a ticket and schedule the work, as well as the bug potentially blocking releases to production until it's resolved.
-
-Cost: High
-
-## In a CI pipeline
-
-This is likely to be a static analysis or a test failure. It should be quicker to fix though it will need to be done quickly or reverted if you're doing trunk-based development to unblock other Developers.
-
-If you're doing code reviews, you'll need to ensure that the pipeline passes before the review and continues to pass after making any changes.
-
-Cost: Medium
-
-## Locally
-
-If an automated check fails in CI, why not run it locally before you commit and push the change?
-
-If it's a coding standards issue or static analysis failure, you could configure your text editor or IDE to show you issues in real time. Then they can be fixed immediately and not even committed and pushed to a CI pipeline.
-
-If you were working in a pair or mob, could someone else have spotted the issue and suggested a fix?
-
-Cost: Low
-
-The sooner you can find a bug, the less time and cheaper it is to fix, and we can use tools like automated tests and static analysis to help us write fewer bugs and to fix them sooner and faster.
diff --git a/astro/src/content/daily-email/2022-12-30.md b/astro/src/content/daily-email/2022-12-30.md
deleted file mode 100644
index ab79f75d..00000000
--- a/astro/src/content/daily-email/2022-12-30.md
+++ /dev/null
@@ -1,35 +0,0 @@
----
-title: >
- Tests are living documentation
-pubDate: 2022-12-30
-permalink: >
- archive/2022/12/30/tests-are-living-documentation
-tags:
- - testing
----
-
-Today I was working on a project and made a one-line change that updated a single value within an API response.
-
-Unexpectedly, it caused a test to fail. The API response returned a 500 status code instead of the expected 201 code.
-
-I reverted the change locally and ensured that the test passed again, so I knew it was causing the failure.
-
-## Fixing the failure
-
-The change was removing a hard-coded part of a URL to a dynamic one, using Drupal's `Settings` class.
-
-I was retrieving a value from it, but as there was no value being set within the test, it was returning a null value and causing the 500 error code.
-
-## How does the Settings class work?
-
-To fix the test failure, I needed to learn how to set a Settings value within a test.
-
-To do this, I looked for and found the test for the Settings class itself. I saw how it was being set there, did the same in my test, fixed the failure and got my test passing again.
-
-## Tests are living documentation
-
-As well as verifying things work when they are written, tests also act as long-term documentation. They can be run at any point to ensure that they still pass and are a reference to other developers on how the code should work.
-
-Rather than a Confluence page, a README file or code comments which can become out of date, if a test becomes outdated, it will fail and make developers aware, as well as break any CI pipeline that it runs in.
-
-By writing tests, you're ensuring that your code works as expected and documenting it at the same time.
diff --git a/astro/src/content/daily-email/2022-12-31.md b/astro/src/content/daily-email/2022-12-31.md
deleted file mode 100644
index bfff792a..00000000
--- a/astro/src/content/daily-email/2022-12-31.md
+++ /dev/null
@@ -1,23 +0,0 @@
----
-title: >
- Just start writing
-pubDate: 2022-12-31
-permalink: >
- archive/2022/12/31/just-start-writing
-tags:
- - productivity
----
-
-Whether it's writing code or a technical design document, diagnosing an issue, or working on a blog post or a presentation deck, sometimes, the hardest part for me is getting started.
-
-When this happens, I try to find the smallest thing I can do to start the task and get the ball rolling.
-
-This could be just opening Neovim or Notion and finding the smallest task I can do to get going.
-
-In code, it could be making the smallest change to start on the task or committing a small refactoring on another part of the code to get into the flow.
-
-With a technical design document, once I've written the first heading, "What problem are we trying to solve?" and started to describe the problem, it's easy to continue writing the rest of the document.
-
-For a blog post or presentation, I've found that writing the headings first is a good starting point, adds structure and makes it easier to add the main content.
-
-Things are great once the ball is rolling; the question sometimes is, "what is the simplest thing I can do to start it?".
diff --git a/astro/src/content/daily-email/2023-01-01.md b/astro/src/content/daily-email/2023-01-01.md
deleted file mode 100644
index 2d12a8df..00000000
--- a/astro/src/content/daily-email/2023-01-01.md
+++ /dev/null
@@ -1,20 +0,0 @@
----
-title: >
- Types and static analysis saved me today
-pubDate: 2023-01-01
-permalink: >
- archive/2023/01/01/types-and-static-analysis-saved-me-today
-tags:
- - static-analysis
- - types
----
-
-Today I was writing Pulumi code in Typescript, and I although I have autocompletion, I mistyped the name of a property.
-
-But, because of the types that I'd declared and how I have Neovim configured, the error was immediately shown, and I was able to fix the typo and what would have been a compilation error if I'd tried to run it.
-
-It only took a second or two for me to make and fix the mistake.
-
-I didn't need to run the code or commit it and push it to a CI pipeline to find out that there was a bug.
-
-I found out and fixed it immediately, and moved on as if I hadn't written the typo at all. This is why I like types and static analysis.
diff --git a/astro/src/content/daily-email/2023-01-02.md b/astro/src/content/daily-email/2023-01-02.md
deleted file mode 100644
index 165e6f9e..00000000
--- a/astro/src/content/daily-email/2023-01-02.md
+++ /dev/null
@@ -1,25 +0,0 @@
----
-title: >
- Don't use arbitrary values in Tailwind CSS
-pubDate: 2023-01-02
-permalink: >
- archive/2023/01/02/dont-use-arbitrary-values-in-tailwind-css
-tags:
- - tailwind-css
----
-
-It's been almost five years since I gave the first version of my "[Taking Flight with Tailwind CSS](https://www.oliverdavies.uk/talks/taking-flight-with-tailwind-css)" talk at the Drupal Bristol meetup in January 2018.
-
-It's a talk that I've updated every time I've given it, showing new rebuilt example UIs and the new features in the framework, as well as tweaking content like installation steps for different audiences.
-
-As I prepare for the Norfolk Developers Conference (nordevcon) next month, I'm updating the talk again.
-
-One feature that wasn't in the last version of the talk is arbitrary values in class names. This, I think, is an antipattern and something that I avoid using.
-
-Whilst you could always add arbitrary values in custom CSS, one of my original reasons for liking and adopting Tailwind CSS was that there was a predefined list of classes to choose from.
-
-A set list of colours, text sizes, margins and padding, for example, meant that UIs looked more consistent and the generated CSS was smaller.
-
-If you need an additional value or to replace the existing values, you can do so within your `tailwind.config.js` file, and Tailwind will generate classes accordingly.
-
-Whilst writing custom CSS, inline styles, and arbitrary values are all possible, I'd suggest using the configuration file, generating the classes that you need, and sticking to them as much as you can and enjoying the consistency and benefits that brings.
diff --git a/astro/src/content/daily-email/2023-01-03.md b/astro/src/content/daily-email/2023-01-03.md
deleted file mode 100644
index 54d69de2..00000000
--- a/astro/src/content/daily-email/2023-01-03.md
+++ /dev/null
@@ -1,33 +0,0 @@
----
-title: >
- Tailwind CSS' extensibility is one of its best features
-pubDate: 2023-01-03
-permalink: >
- archive/2023/01/03/tailwind-css-extensibility-is-one-of-its-best-features
-tags:
- - tailwind-css
----
-
-As well as the library of utility CSS classes that Tailwind provides, the ability to easily add your own has been one of my main advantages of using it.
-
-You can add your own CSS to a stylesheet within a specific layer, customise the theme settings within a `tailwind.config.js` file, and write your own custom plugins that you can reuse and even release as separate open-source projects.
-
-Here is a complete plugin that I've added to some projects recently:
-
-```js
-const plugin = require('tailwindcss/plugin');
-
-plugin(function({ addVariant }) {
- addVariant('hocus', ['&:hover', '&:focus'])
-});
-```
-
-By adding these lines of JavaScript, Tailwind will generate a new set of utility classes that apply styles to both hover and focus states for an element - reducing the number of classes that need to be added and making it more maintainable.
-
-Other plugins that I've written recently include creating different variants of buttons, styling elements within an HTML table (similar to the Tailwind typography plugin), and adding multi-theme support to make components themable with different colours.
-
-I've also released some [as open-source projects on GitHub](https://github.com/opdavies?tab=repositories&q=tailwind-plugin).
-
-The interesting thing is that the plugin API is how Tailwind itself generates its own classes, and I like the stability that provides.
-
-However you extend Tailwind, the fact you can tweak and extend it for each project is great and something that you can't always do or do easily with other tools or frameworks.
diff --git a/astro/src/content/daily-email/2023-01-04.md b/astro/src/content/daily-email/2023-01-04.md
deleted file mode 100644
index c8e72da7..00000000
--- a/astro/src/content/daily-email/2023-01-04.md
+++ /dev/null
@@ -1,63 +0,0 @@
----
-title: >
- Testable Tailwind CSS plugins
-pubDate: 2023-01-04
-permalink: >
- archive/2023/01/04/testable-tailwind-css-plugins
-tags:
- - tailwind-css
----
-
-A great thing about [Tailwind CSS plugins](https://www.oliverdavies.uk/archive/2023/01/03/tailwind-css-extensibility-is-one-of-its-best-features) being written in JavaScript is that they can be tested using tools like Jest.
-
-Here's an example from https://github.com/opdavies/tailwindcss-plugin-jest-example (it may need updating to work with the latest Tailwind versions or to use the latest best practices):
-
-```javascript
-function run(options = {}) {
- return postcss(
- tailwindcss({
- corePlugins: false,
- plugins: [plugin(options)]
- })
- )
- .process('@tailwind utilities;', {
- from: undefined
- })
-}
-
-expect.extend({
- toMatchCss: cssMatcher
-})
-
-test('it generates the correct classes with no variants', () => {
- const output = `
- .test {
- display: block
- }
- `
-
- run().then(result => {
- expect(result.css).toMatchCss(output)
- })
-})
-
-test('it generates the correct classes with variants', () => {
- const output = `
- .test {
- display: block
- }
- .hover\\:test:hover {
- display: block
- }
- .focus\\:test:focus {
- display: block
- }
- `
-
- run({ variants: ['hover', 'focus'] }).then(result => {
- expect(result.css).toMatchCss(output)
- })
-});
-```
-
-Within the test, Tailwind can be run using PostCSS and generates styles based on a provided configuration, which is then checked against some expected output. If the generated styles match what was expected, the tests pass and the plugin is working as expected.
diff --git a/astro/src/content/daily-email/2023-01-05.md b/astro/src/content/daily-email/2023-01-05.md
deleted file mode 100644
index ed75d718..00000000
--- a/astro/src/content/daily-email/2023-01-05.md
+++ /dev/null
@@ -1,21 +0,0 @@
----
-title: >
- Adding Tailwind CSS to an existing project
-pubDate: 2023-01-05
-permalink: >
- archive/2023/01/05/adding-tailwind-to-an-existing-project
-tags:
- - tailwind-css
----
-
-Tailwind's configuration file also makes it easy to add it to an existing codebase, whether it uses custom CSS or another CSS framework.
-
-You can opt-out of Tailwind's CSS reset and normalisation by adding `corePlugins: { preflight: false }` to tailwind.config.js, and if you have duplicate classes with existing classes and Tailwind-generated ones, you can add `prefix: 'tw-'` to prefix all of Tailwind's class names and avoid the conflicts.
-
-If you need to deal with specificity, you can mark Tailwind-generated classes as important by adding `important: true` so that they can override any existing styling. You can do the same in HTML code by prefixing a class name with an exclamation mark - e.g. `!flex`.
-
-Or, if you know that your Tailwind styles will only be used within a certain element, like `#app`, instead of making all classes important, by adding `important: "#app"` to the configuration, Tailwind classes will be prefixed with that selector - making them more specific.
-
-Once these options are set, you can start using Tailwind without affecting the existing styles.
-
-Doing this, and starting small by using a small number of utilities can be a good step towards migrating an existing codebase to use Tailwind and removing the existing styles at a later date.
diff --git a/astro/src/content/daily-email/2023-01-06.md b/astro/src/content/daily-email/2023-01-06.md
deleted file mode 100644
index 745e3853..00000000
--- a/astro/src/content/daily-email/2023-01-06.md
+++ /dev/null
@@ -1,23 +0,0 @@
----
-title: >
- Utility-first or utility-last?
-pubDate: 2023-01-06
-permalink: >
- archive/2023/01/06/utility-first-or-utility-last
-tags:
- - tailwind-css
----
-
-Tailwind CSS is based on the "utility-first" approach, where the majority of styling is done using utility CSS classes. You can still add additional custom styles if needed if there is something that can't be achieved with utilities or would be better placed in a custom CSS stylesheet.
-
-Utility-last is the opposite approach, where a small number of utilities are used alongside other CSS styles or another framework. This is common when [adding a utility-based framework like Tailwind CSS](https://www.oliverdavies.uk/archive/2023/01/05/adding-tailwind-to-an-existing-project) to an existing project and you want to use it for a new page or component whilst keeping the existing styles.
-
-This is what I did when I started learning Tachyons, and later Tailwind CSS. My project already had styling from another CSS framework, I started using utility classes and over time refactored until only utilities were used and the other styles could be removed.
-
-You could do the opposite too, and refactor groups of utilities into a CSS component, either by using Tailwind's `@apply` directive or [writing a plugin](https://www.oliverdavies.uk/archive/2023/01/03/tailwind-css-extensibility-is-one-of-its-best-features).
-
-If you did want to use Tailwind for a small number of utilities, by default, it will only generate classes that are used within HTML or template files, but it can also be configured to only use the core modules that you specify - preventing Developers from using unwanted utility based on the rules for that project.
-
-You could, of course, write your own utilities, or they're becoming common in other frameworks now too for things like padding, margin and colours.
-
-Do you typically do styling utility-first or utility-last, or are you transitioning from one to the other?
diff --git a/astro/src/content/daily-email/2023-01-07.md b/astro/src/content/daily-email/2023-01-07.md
deleted file mode 100644
index f963c293..00000000
--- a/astro/src/content/daily-email/2023-01-07.md
+++ /dev/null
@@ -1,132 +0,0 @@
----
-title: >
- Reducing utility class duplication
-pubDate: 2023-01-07
-permalink: >
- archive/2023/01/07/reducing-utility-class-duplication
-tags:
- - tailwind-css
----
-
-
-
-One of the main concerns for Developers evaluating or starting with a utility-first approach to styling is maintainability due to the number and duplication of classes.
-
-For example, with this component, as I duplicate it to add more links, I also duplicate the classes applied to the link - making it harder to maintain:
-
-```html
-
-```
-
-There are some solutions to this, which you can also see in an example Astro project at https://github.com/opdavies/reducing-utility-class-duplication.
-
-## Extracting a variable of class names
-
-The simplest way to remove the duplication is to create a variable that holds the class names which can be reused. For example, Astro allows variables to be created within the frontmatter section and used within the template. Creating variables can be done in other templating engines too.
-
-```astro
----
-const linkClasses = "py-2 block border-b-2 border-transparent hover:border-blue-500 hover:text-blue-500 focus:outline-none focus:bg-yellow-400 focus:border-current";
----
-
-
-```
-
-## Extracting CSS components
-
-Instead of extracting a variable, you could also extract a CSS component. With Tailwind, the `@apply` directive within a stylesheet will create a reusable CSS component:
-
-```astro
-
-
-
-
-
-```
-
-The `link` class can be added to any link items, and whilst the approach works, I prefer to use template-based solutions and keep the classes within the HTML markup.
-
-## Loops and maps
-
-Templating engines will have a way to loop over a list of items. This can be used to remove the duplication and only have a single list of classes whilst keeping the benefits of keeping them in the HTML code.
-
-For example, in Astro:
-
-```astro
----
-const links = [
- { name: "About" },
- { name: "Blog" },
- { name: "Talks" },
- { name: "Daily list" },
- { name: "Search" },
-];
----
-
-{links.map(link => (
-
-))}
-```
-
-## Extracting HTML components
-
-Finally, if the component needs to be reused, it can be extracted into its own file and re-imported where needed.
-
-This is the extracted component:
-
-```astro
----
-const { name } = Astro.props;
----
-
-
- {name}
-
-```
-
-And the original file:
-
-```astro
----
-import Layout from "~/layouts/Layout.astro";
-import Link from "~/components/Link.astro";
----
-
-
-
-
-
-
-
-
-
-
-```
-
-This can now be used anywhere within this project and could be combined with the loop approach, passing the appropriate value to the `name` prop.
-
-## Summary
-
-All of these approaches remove duplication, either using features provided by Tailwind CSS or a templating engine, to make the code more maintainable.
-
-I've shown [Astro](https://astro.build) in these examples but the same can be done with PHP, Twig, Blade, Vue, React, etc.
-
-The examples are public on GitHub at https://github.com/opdavies/reducing-utility-class-duplication/tree/main/src/pages.
diff --git a/astro/src/content/daily-email/2023-01-16.md b/astro/src/content/daily-email/2023-01-16.md
deleted file mode 100644
index 09fd54a2..00000000
--- a/astro/src/content/daily-email/2023-01-16.md
+++ /dev/null
@@ -1,20 +0,0 @@
----
-title: >
- Back after PHP Stoke
-pubDate: 2023-01-16
-permalink: >
- archive/2023/01/16/back-after-php-stoke
-# tags:
-# - a
-# - b
----
-
-I took a bit of time off from these emails whilst I was preparing for the first PHP Stoke event which happened last week in Stoke-on-Trent.
-
-It was a great event with around 35 attendees and two other speakers as well as myself.
-
-The [latest version of my slides are online](https://www.oliverdavies.uk/talks/things-you-should-know-about-php) as well [some updated resources](https://www.oliverdavies.uk/things-about-php).
-
-My next talk will be at the Norfolk Developers conference next month where I'll be presenting an updated version of [Taking Flight with Tailwind CSS](https://www.oliverdavies.uk/talks/taking-flight-with-tailwind-css).
-
-If you have a topic idea for a talk or would like me to speak at your meetup or conference, please get in touch.
diff --git a/astro/src/content/daily-email/2023-01-17.md b/astro/src/content/daily-email/2023-01-17.md
deleted file mode 100644
index d677d326..00000000
--- a/astro/src/content/daily-email/2023-01-17.md
+++ /dev/null
@@ -1,23 +0,0 @@
----
-title: >
- Things to know about PHP
-pubDate: 2023-01-17
-permalink: >
- archive/2023/01/17/things-to-know-about-php
-tags:
- - php
----
-
-The talk that I gave last week at PHP Stoke was [Things to know about PHP](https://www.oliverdavies.uk/talks/things-you-should-know-about-php) - a talk that I was originally asked to give at the Swansea Software Development Meetup (SSDC) in January 2019, and this was the second time that I've been asked to give this talk at a PHP meetup.
-
-Originally to give a group of various Software Developers an introduction to PHP, I didn't want the talk to be focused just on the language itself and be a walkthough the PHP manual.
-
-Whilst there is some code in the talk so demonstrate what it can do, the other half of the talk is about the other parts of the PHP ecosystem such as tooling and the community. I talk about tools like Composer, PHPStan, Xdebug, PHPUnit and Pest, the CMSes and frameworks that are available, and the various online learning tools like SymfonyCasts and Laracasts as well as certification programs that are available.
-
-It's great to give this talk at meetups as that's where the community starts, where people come to share and learn, and what larger conferences like PHP UK, php[tek] and others are built on. I love attending meetups and events and meeting other members of the PHP community.
-
-Oh, and elePHPants!
-
-The latest versions of the slides are on the Talks section of my website (the link is at the top of the email).
-
-If you'd like me to come and speak at your meetup or conference, please get in touch!
diff --git a/astro/src/content/daily-email/2023-01-18.md b/astro/src/content/daily-email/2023-01-18.md
deleted file mode 100644
index 509a08a6..00000000
--- a/astro/src/content/daily-email/2023-01-18.md
+++ /dev/null
@@ -1,23 +0,0 @@
----
-title: >
- Drupal turns 22!
-pubDate: 2023-01-18
-permalink: >
- archive/2023/01/18/drupal-turns-22
-tags:
- - php
----
-
-On Sunday, the Drupal project turned 22 years old.
-
-I've personally been working with Drupal primarily for almost 15 years [according to my Drupal.org profile](https://www.drupal.org/u/opdavies), self teaching and working on personal and freelance projects since 2007, and in full-time roles since 2010 when I started at Horse and Country TV to work on their Drupal 6 website.
-
-Last month, I started my first Drupal 10 project for a client.
-
-I'm proud that over a year of that time was spent working for the Drupal Association where I improved the Drupal.org websites and resolved issues that would have blocked the Drupal 8 release in 2015.
-
-I'm also happy to have [presented talks and workshops](https://www.oliverdavies.uk/talks) at events like DrupalCamps, Drupal Developer Days and twice at DrupalCon. I've also organised Drupal events such as the Drupal Bristol meetup and DrupalCamp Bristol conference.
-
-I've had opportunities to contribute to open-source by having patches committed to Drupal core and maintaining modules and themes like [Override Node Options](https://www.drupal.org/project/override_node_options) and the [Tailwind CSS starter kit](https://www.drupal.org/project/tailwindcss). I've also mentored and helped others to get their first commits to Drupal core and open-source.
-
-I plan to continue working with Drupal and being part of the community for a long time, hopefully for at least another 22 years.
diff --git a/astro/src/content/daily-email/2023-01-19.md b/astro/src/content/daily-email/2023-01-19.md
deleted file mode 100644
index 4c8ee173..00000000
--- a/astro/src/content/daily-email/2023-01-19.md
+++ /dev/null
@@ -1,28 +0,0 @@
----
-title: >
- Long-term maintainability with utility classes and Tailwind CSS
-pubDate: 2023-01-19
-permalink: >
- archive/2023/01/19/long-term-maintainability-with-utility-classes-and-tailwind-css
-tags:
- - css
- - tailwind-css
----
-
-One of the common initial concerns of utility classes and Tailwind CSS is its maintainability.
-
-How you manage all the classes within the HTML and how easy is it to make changes?
-
-Today, [I saw this tweet](https://twitter.com/mauro_codes/status/1615726036737576960):
-
-> You can say whatever you want about @tailwindcss, but I just opened a legacy project with tailwind 0.7 that I didn't touch for almost three years... and I was able to update the whole branding in 30 minutes.
-
- One of my earliest Tailwind projects was the [PHP South West website](https://phpsw.uk). We [worked on this in November 2017](https://twitter.com/opdavies/status/934488762276564993) and it still uses Tailwind CSS 0.5.
-
-These are the classes used on the main menu:
-
-`bg-grey-lightest hidden absolute z-20 w-full border border-grey-lighter sm:flex sm:relative sm:w-auto sm:border-none`
-
-Even though Tailwind CSS is now on version 3.2.4, I can still read this and know exactly what the classes do, and I'm confident that I could easily make changes to this or any other element on the website.
-
-That probably isn't something that I could say for other projects that use different approaches to styling, and definitely an advantage of styling with small, reusable utility classes.
diff --git a/astro/src/content/daily-email/2023-01-20.md b/astro/src/content/daily-email/2023-01-20.md
deleted file mode 100644
index 120dc05d..00000000
--- a/astro/src/content/daily-email/2023-01-20.md
+++ /dev/null
@@ -1,18 +0,0 @@
----
-title: >
- Tailwind's classes are your classes
-pubDate: 2023-01-20
-permalink: >
- archive/2023/01/20/tailwinds-classes-are-your-classes
-tags:
- - css
- - tailwind-css
----
-
-In my [Taking Flight with Tailwind CSS talk](https://www.oliverdavies.uk/talks/taking-flight-with-tailwind-css), I've described Tailwind as a CSS utility class generator. You write a configuration file that Tailwind reads and generates the appropriate classes.
-
-Yesterday I mentioned the [PHP South West user group](https://phpsw.uk) website. It's a project that [I worked on in November 2017](https://twitter.com/opdavies/status/934488762276564993) and uses Tailwind 0.5.
-
-For me, a big advantage of Tailwind was that once it generates the classes, they are ours. They aren't hidden within the framework or an npm package. We can see them, commit them to version control and keep them for as long as we need.
-
-Even if the Tailwind CSS framework disappeared tomorrow (I hope it doesn't), I'd be able to continue using the styles that it generated, and my projects would continue to work and look the same.
diff --git a/astro/src/content/daily-email/2023-01-21.md b/astro/src/content/daily-email/2023-01-21.md
deleted file mode 100644
index e9fa86a8..00000000
--- a/astro/src/content/daily-email/2023-01-21.md
+++ /dev/null
@@ -1,20 +0,0 @@
----
-title: >
- Tailwind: Not just translating CSS to utility classes
-pubDate: 2023-01-21
-permalink: >
- archive/2023/01/21/tailwind-not-just-translating-css-to-utility-classes
-tags:
- - css
- - tailwind-css
----
-
-Whilst a number of classes that Tailwind CSS generates are single-value utility classes such as `.block { display: block; }` and `.relative { position: relative; }`, it also includes additional things such as [setting a default line height with a font size](https://tailwindcss.com/docs/font-size#setting-the-font-size), adding variants for [group-hover](https://tailwindcss.com/docs/hover-focus-and-other-states#styling-based-on-parent-state) and [focus-within](https://tailwindcss.com/docs/hover-focus-and-other-states#focus-within) (as well as various other pseudo states).
-
-It includes utilities for adding [horizontal or vertical space](https://tailwindcss.com/docs/space#add-horizontal-space-between-children) or [styling dividers between elements](https://tailwindcss.com/docs/divide-style).
-
-As well prefixing a class using a screen modifier, such as `md:flex`, you can stack them and set a maximum screen value. For example, `md:max-lg:flex` will only flex between the `md` and `lg` breakpoints.
-
-If has official plugins for typography styles, forms, line-clamp (truncating text) and aspect ratios, as well as numerous community plugins and supports arbitrary values if you need them.
-
-If you take a look at the [Tailwind CSS documentation](https://tailwindcss.com/docs), you'll definitely find some interesting and useful things.
diff --git a/astro/src/content/daily-email/2023-01-22.md b/astro/src/content/daily-email/2023-01-22.md
deleted file mode 100644
index 5c8994f6..00000000
--- a/astro/src/content/daily-email/2023-01-22.md
+++ /dev/null
@@ -1,18 +0,0 @@
----
-title: >
- Building Bootstrap CSS examples with Tailwind
-pubDate: 2023-01-22
-permalink: >
- archive/2023/01/22/building-bootstrap-css-examples-with-tailwind
-tags:
- - css
- - tailwind-css
----
-
-Previously when I gave my [Taking Flight with Tailwind CSS](https://www.oliverdavies.uk/talks/taking-flight-with-tailwind-css) talk, I created examples that relate to the event such as something related to that technology or event.
-
-The nor(DEV):con website already uses Tailwind CSS so I've been looking for other examples and have started to build some of the [Bootstrap CSS components](https://getbootstrap.com/docs/4.0/examples) with Tailwind CSS.
-
-I've created the [Album](http://bootstrap-with-tailwind.s3-website.eu-west-2.amazonaws.com/album) and [Pricing](http://bootstrap-with-tailwind.s3-website.eu-west-2.amazonaws.com/pricing) components so far but will likely do more before the conference as I think they're good examples.
-
-[The source code](https://github.com/opdavies/bootstrap-with-tailwind) is on my GitHub profile, uses Astro and its Tailwind CSS integration, the default Tailwind configuration with some slight colour and font tweaks, the official Typography plugin and a small custom plugin that adds a "hocus" variant for both hover and focus styles.
diff --git a/astro/src/content/daily-email/2023-01-23.md b/astro/src/content/daily-email/2023-01-23.md
deleted file mode 100644
index 1d2c35c3..00000000
--- a/astro/src/content/daily-email/2023-01-23.md
+++ /dev/null
@@ -1,27 +0,0 @@
----
-title: >
- Debugging with git bisect
-pubDate: 2023-01-23
-permalink: >
- archive/2023/01/23/debugging-with-git-bisect
-tags:
- - git
----
-
-Last week, I had to debug a regression in a codebase.
-
-Something was working at the last release but is now broken.
-
-There have been around 20 commits to the mainline branch since the last release, and the first step to fixing the issue is to determine which commit caused the regression.
-
-Git has a great tool for this - `git bisect`.
-
-You tell Git what the last known working commit was, such as the tag of the last release, and it will start to split the commits and prompt you to tell it whether the commit is good or bad.
-
-If there are 20 commits, it may pick commit number 10, and based on whether the commit is good or bad, it may pick commit 5 or 15.
-
-Based on your answers, Git will then tell you which the first bad commit is.
-
-Even better, if it's something that you can script or is covered with an automated test, `git bisect` can run a command for you and find the failure automatically rather than a human needing to check manually.
-
-Once you've found the commit that breaks, you can view it and find and fix the bug.
diff --git a/astro/src/content/daily-email/2023-01-24.md b/astro/src/content/daily-email/2023-01-24.md
deleted file mode 100644
index 6cd65f93..00000000
--- a/astro/src/content/daily-email/2023-01-24.md
+++ /dev/null
@@ -1,23 +0,0 @@
----
-title: >
- Small commits and good commit messges
-pubDate: 2023-01-24
-permalink: >
- archive/2023/01/24/small-commits-and-good-commit-messges
-tags:
- - git
----
-
-An important thing when using a tool like [git bisect](https://www.oliverdavies.uk/archive/2023/01/23/debugging-with-git-bisect) as well as reviewing pull/merge requests and commits is to have small (aka "atomic") commits.
-
-Commits with small changes make them easier to review and, if needed, to revert and debug with bisect. If a commit has ten new or changed lines, it's much easier to see and fix a bug than if the commit had a hundred lines.
-
-If you're doing code reviews or "Showing" in a Ship/Show/Ask format, you'll likely get better and more valuable feedback if the commits are smaller and only doing one thing.
-
-If you're submitting a change for review, commit a failing test first so that it can be seen failing before committing the code to make it pass. This makes it easier to see that the code is actually making the test pass.
-
-Also take some time to write good, informative commit messages.
-
-As well as the short one-line subject, you can add as much detail as you need to the body of the message about the change that's being committed, why it's needed, what other approaches were considered or tried, as well as links to supporting documentation such as ADRs, technical design documents or diagrams.
-
-Having as much information as possible makes it much easier when someone needs to review or fix a specific commit. I like to use the [conventional commits specification](https://www.oliverdavies.uk/archive/2022/09/01/conventional-commits-changelogs), though the main objective is to have all of the information documented so it's available in the future.
diff --git a/astro/src/content/daily-email/2023-01-25.md b/astro/src/content/daily-email/2023-01-25.md
deleted file mode 100644
index eb571e9d..00000000
--- a/astro/src/content/daily-email/2023-01-25.md
+++ /dev/null
@@ -1,25 +0,0 @@
----
-title: >
- To squash or not to squash
-pubDate: 2023-01-25
-permalink: >
- archive/2023/01/25/to-squash-or-not-to-squash
-tags:
- - git
----
-
-When reviewing a pull or merge request, tools like GitHub and GitHub offer the option to squash the commits before merging.
-
-If the request had twenty commits, they'd be combined into a single commit before being merged.
-
-But should you do it?
-
-The answer will be "it depends" based on the project or team, but I'm personally not a fan of squashing commits.
-
-Even though I commit small changes often, I put quite a bit of effort into [crafting commits and writing detailed commit messages](https://www.oliverdavies.uk/archive/2023/01/24/small-commits-and-good-commit-messges) that capture the reason for each change. If the commits are squashed, either the messages will be combined into one extra-long commit message or I've seen them be deleted completely.
-
-One large commit message would be very difficult to read and connect specific messages with their changes, and deleting the commit body would lose the history completely and waste the time it took to write the messages and craft the commits. It may be available within the pull or merge request page but there's no guarantee that you'll continue to use the same repository hosting service in the future.
-
-One large commit would also be difficult to debug if there was an error. If the whole feature was added in a single commit, tools like [git bisect](https://www.oliverdavies.uk/archive/2023/01/23/debugging-with-git-bisect) would no longer work and a single commit couldn't be simply reverted if it contained a bug.
-
-I prefer to keep the original small commits and instead prefer to use rebasing and only fast-forward merges to avoid merge commits and keep a simple, linear history in my Git log, and be able to easily read, find and, if needed, fix the code that's been committed.
diff --git a/astro/src/content/daily-email/2023-02-07.md b/astro/src/content/daily-email/2023-02-07.md
deleted file mode 100644
index 834f77c5..00000000
--- a/astro/src/content/daily-email/2023-02-07.md
+++ /dev/null
@@ -1,19 +0,0 @@
----
-title: >
- Astro as a static site generator
-pubDate: 2023-02-07
-permalink: >
- archive/2023/02/07/astro-as-a-static-site-generator
-tags:
- - astro
----
-
-Since first setting it first during Simon Vrachliotis' workshops, I've started evaluating [Astro](https://astro.build) as an option for building static websites alongside PHP options like Sculpin and Jigsaw, and used it to rebuild [my personal website](https://www.oliverdavies.uk).
-
-As well as being a good opportunity to get more experience with JavaScript, TypeScript and JSX templating, Astro includes a number of features that were useful for my website, such as code syntax highlighting and markdown support out of the box, as well as integrations to set up Tailwind CSS, sitemaps and images that I needed.
-
-Its file-based routing is very familiar to what I'd been working with in Next.js, including dynamic and nested routes such as my Blog, Talks, and email archive pages.
-
-A static HTML version of the site can be generated which can be uploaded to a web server - like with other static site generators - with the advantage that Astro includes no JavaScript by default.
-
-As well as my personal website, I've been using Astro for some other mini-projects including [building Bootstrap components with Tailwind](https://www.oliverdavies.uk/archive/2023/01/22/building-bootstrap-css-examples-with-tailwind), and I'm using it for the updated examples for my Tailwind CSS talk at nor(DEV):con in a couple of weeks time.
diff --git a/astro/src/content/daily-email/2023-02-08.md b/astro/src/content/daily-email/2023-02-08.md
deleted file mode 100644
index 36d3b199..00000000
--- a/astro/src/content/daily-email/2023-02-08.md
+++ /dev/null
@@ -1,15 +0,0 @@
----
-title: >
- Fetching external API data with Astro
-pubDate: 2023-02-08
-permalink: >
- archive/2023/02/08/fetching-api-data-with-astro
-tags:
- - astro
----
-
-As well as using static data like Astro components and Markdown files, Astro allows you to pull in data from external APIs even if you're generating a static website.
-
-Astro's [Data Fetching documentation](https://docs.astro.build/en/guides/data-fetching) shows how to do this using the global `fetch` function. This is the same approach that I've been using to build [a page of my open-source projects](https://github.com/opdavies/oliverdavies.uk/blob/39314de34ce22b14cf85f816e4469cc4d6fb822c/website/src/pages/open-source.astro). I'm still working on it, but it fetches project information from both Drupal.org and GitHub and displays them on a page.
-
-This is also makes Astro a good option to be used as a front-end for decoupled projects that use a separate back-end CMS like Drupal to store and manage the content which it fetches and uses when generating the site.
diff --git a/astro/src/content/daily-email/2023-02-09.md b/astro/src/content/daily-email/2023-02-09.md
deleted file mode 100644
index b7c37696..00000000
--- a/astro/src/content/daily-email/2023-02-09.md
+++ /dev/null
@@ -1,35 +0,0 @@
----
-title: >
- Creating API endpoints with Astro
-pubDate: 2023-02-09
-permalink: >
- archive/2023/02/09/creating-api-endpoints-with-astro
-tags:
- - astro
----
-
-As well as [fetching API data](https://www.oliverdavies.uk/archive/2023/02/08/fetching-api-data-with-astro), you can also use Astro to generate your own API endpoints.
-
-This is an example of an endpoint that I recently created as part of a demo application:
-
-```javascript
-// trains.json.ts
-
-import data from "@/data.json";
-import type { APIRoute } from "astro";
-import type { Train } from "@/types";
-
-export const get: APIRoute = () => {
- return {
- body: JSON.stringify(data.trains as Train[]),
- };
-};
-```
-
-The train data is imported from a JSON file, and Astro's `APIRoute` is responsible for setting the appropriate response headers.
-
-For server-side rendered applications, you can also have endpoints for `post`, `del` and `all`, though for this example, I only needed to support GET requests.
-
-This is something that I've used a db-json library for previously, but being able to do this in Astro seemed like a good fit as I can easily manage lists of stations as well as a single station from one JSON file but I can just take the static HTML that Astro generates and upload it to a static hosting solution which simplifies the hosting side of things a lot.
-
-And, as the example application that consumes the data is also written with Astro, having them both using the same solution has advantages too.
diff --git a/astro/src/content/daily-email/2023-02-16.md b/astro/src/content/daily-email/2023-02-16.md
deleted file mode 100644
index 9fd85815..00000000
--- a/astro/src/content/daily-email/2023-02-16.md
+++ /dev/null
@@ -1,20 +0,0 @@
----
-title: >
- Tailwind CSS at the Bristol Software Development Meetup
-pubDate: 2023-02-16
-permalink: >
- archive/2023/02/16/tailwind-css-at-the-bristol-software-development-meetup
-tags:
- - public-speaking
- - tailwind-css
----
-
-Tonight I was lucky to speak at the first [Bristol Software Development Meetup event](https://www.meetup.com/south-wales-tech/events/291092930), organised by South Wales Tech.
-
-Following a great talk from Tom Vaughan, I gave an updated version of my [Taking Flight with Tailwind CSS](https://www.oliverdavies.uk/talks/taking-flight-with-tailwind-css) talk.
-
-It's a talk that I first gave in January 2018 and one that I need to continuously update so that it's up to date with the latest version of the framework. The last time I gave this talk was in February 2021 so there was quite a lot of new things to cover.
-
-I was also able to show my recent [Tailwind versions of Bootstrap components](https://bootstrap-with-tailwind.oliverdavies.uk) as a demonstration at the end of the talk.
-
-I'm glad to have had the opportunity to test out the updated version before [Norfolk Developers conference](https://nordevcon.com) next week and I'm looking forward to attending more South Wales Tech events in Swansea and Bristol in the future.
diff --git a/astro/src/content/daily-email/2023-02-17.md b/astro/src/content/daily-email/2023-02-17.md
deleted file mode 100644
index 87c4dd6b..00000000
--- a/astro/src/content/daily-email/2023-02-17.md
+++ /dev/null
@@ -1,19 +0,0 @@
----
-title: >
- Upgrading my Drupal example project to Drupal 10
-pubDate: 2023-02-17
-permalink: >
- archive/2023/02/17/upgrading-my-drupal-example-project-to-drupal-10
-tags:
- - docker
- - drupal
- - open-source
----
-
-Today I upgraded my [Drupal Docker example](https://github.com/opdavies/docker-examples/tree/main/drupal) to Drupal 10.
-
-Admittedly, it's a simple project, but upgrading from Drupal 9 to 10 was a straightforward process.
-
-I had to remove the Examples module as there's no Drupal 10 compatible version yet, but updating to Drupal 10 only needed me to change the version constraints in the `composer.json` file and run the `composer update` command.
-
-After completing a number of Drupal 7 upgrade projects which involve migrating content, rewriting custom modules, and rebuilding themes, it's great to be able to upgrade between major modern versions with a few simple commands.
diff --git a/astro/src/content/daily-email/2023-02-18.md b/astro/src/content/daily-email/2023-02-18.md
deleted file mode 100644
index 001f6f14..00000000
--- a/astro/src/content/daily-email/2023-02-18.md
+++ /dev/null
@@ -1,18 +0,0 @@
----
-title: >
- Creating a Drupal 10 compatible version of Override Node Options
-pubDate: 2023-02-18
-permalink: >
- archive/2023/02/18/drupal-10-version-of-override-node-options
-tags:
- - drupal
- - open-source
----
-
-Today, I reviewed [the issue and merge request](https://www.drupal.org/project/override_node_options/issues/3269901) to make the [Override Node Options](https://www.drupal.org/project/override_node_options) module compatible with Drupal 10.
-
-It's a small patch that mainly affects the module's test suite so has a low risk of breaking the functionality of the module.
-
-As well as the automated tests, I've done some manual testing with the patch applied on both Drupal 9.5 and 10.
-
-The project page shows the module is currently used on over 34,000 sites including 18,565 Drupal 8 and 9 websites on the 8.x-2.x branch. Hopefully this number will continue to increase once the Drupal 10 version is released.
diff --git a/astro/src/content/daily-email/2023-02-19.md b/astro/src/content/daily-email/2023-02-19.md
deleted file mode 100644
index 675fb9c8..00000000
--- a/astro/src/content/daily-email/2023-02-19.md
+++ /dev/null
@@ -1,17 +0,0 @@
----
-title: >
- Clients dont care which design pattern you use
-pubDate: 2023-02-19
-permalink: >
- archive/2023/02/19/clients-dont-care-which-design-pattern-you-use
----
-
-In most cases, clients don't care which CMS, framework, CSS library or design patterns you use. Clients are focused on the business value that those tools can provide, such as increasing traffic or conversion rate to increase revenue or awareness.
-
-Improving the load speed of a page is good, but what business value does that offer? Are customers more likely to make a purchase if the page is faster?
-
-If you can build the same page with different CMSes or frameworks, and style it in the same way with different CSS libraries, is there a business case for one over the other, such as better maintainability or a quicker time to launch the application?
-
-Can you ship a simple MVP sooner, and refactor to use design patterns later?
-
-Instead of focusing on technologies, tools and strategies, focus on the benefits and business value they can offer.
diff --git a/astro/src/content/daily-email/2023-02-20.md b/astro/src/content/daily-email/2023-02-20.md
deleted file mode 100644
index 70d4619a..00000000
--- a/astro/src/content/daily-email/2023-02-20.md
+++ /dev/null
@@ -1,56 +0,0 @@
----
-title: >
- Tailwind: why I prefer to extract HTML components
-pubDate: 2023-02-20
-permalink: >
- archive/2023/02/20/tailwind-why-i-prefer-to-extract-html-components
-tags:
- - tailwind-css
----
-
-Tailwind offers the @apply directive that you can use to extract components in your CSS by applying the styles the classes would have added.
-
-For example:
-
-```css
-/* Input */
-
-.btn {
- @apply inline-block rounded-3xl bg-blue-500 px-8 py-3 text-lg text-white hover:bg-blue-800 focus:bg-blue-800;
-}
-
-/* Output */
-
-.btn {
- --tw-bg-opacity: 1;
- --tw-text-opacity: 1;
- background-color: rgb(59 130 246 / var(--tw-bg-opacity));
- border-radius: 1.5rem;
- color: rgb(255 255 255 / var(--tw-text-opacity));
- display: inline-block;
- font-size: 1.125rem;
- line-height: 1.75rem;
- padding-bottom: 0.75rem;
- padding-left: 2rem;
- padding-right: 2rem;
- padding-top: 0.75rem;
-}
-
-.btn:hover {
- --tw-bg-opacity: 1;
- background-color: rgb(30 64 175 / var(--tw-bg-opacity));
-}
-
-.btn:focus {
- --tw-bg-opacity: 1;
- background-color: rgb(30 64 175 / var(--tw-bg-opacity));
-}
-```
-
-Whilst this works and reduced duplication, I prefer to handle this within my HTML instead.
-
-All templating engines I've used have ways to loop over or map through items and including separate files such as separate partials or different components.
-
-The main benefit of this is that you get the HTML structure of the component and not just the styling. If you extract a .btn component, it may depend on a span or other element within it to display correctly but as this isn't obvious, it may be missed when writing an implementation of it in HTML - this can't happen when working inside a loop or importing a canonical version.
-
-Also, by working just in the HTML markup, we continue to get the lower cognitive load and speed benefits that we're used to when styling with utility classes rather than switching between multiple files.
diff --git a/astro/src/content/daily-email/2023-03-01.md b/astro/src/content/daily-email/2023-03-01.md
deleted file mode 100644
index a580582b..00000000
--- a/astro/src/content/daily-email/2023-03-01.md
+++ /dev/null
@@ -1,18 +0,0 @@
----
-title: >
- Tailwind CSS at the Norfolk Developer Conference
-pubDate: 2023-03-01
-permalink: >
- archive/2023/03/01/tailwind-css-at-the-norfolk-developer-conference
-tags:
- - speaking
- - tailwind-css
----
-
-Last week, I was at the Norfolk Developer's Conference, aka `nor(DEV):con` - my first in-person conference since DrupalCamp London in February 2020.
-
-I've been excited about this conference since I received the acceptance email in November, inviting me to give my [Taking Flight with Tailwind CSS](https://www.oliverdavies.uk/talks/taking-flight-with-tailwind-css) talk.
-
-The talk itself went well and included some changes following the Bristol Software Development meetup last month. The last time I gave this talk prior to that was remotely for Nashville PHP in February 2021 and a lot of new things have been added to Tailwind CSS since then for me to include.
-
-My next talk will be at the PHP London meetup next month (subject TBC) as I continue working towards my hundredth presentation.
diff --git a/astro/src/content/daily-email/2023-03-02.md b/astro/src/content/daily-email/2023-03-02.md
deleted file mode 100644
index 0d7c4243..00000000
--- a/astro/src/content/daily-email/2023-03-02.md
+++ /dev/null
@@ -1,14 +0,0 @@
----
-title: >
- Busy working on client projects
-pubDate: 2023-03-02
-permalink: >
- archive/2023/03/02/busy-working-on-client-projects
-tags: []
----
-
-As well as starting to speak again at conferences and meetups, I've been very busy lately with various client projects. I've been working on completing the next phase and launch of the next website for a long-term client and handed over some other completed projects.
-
-This has affected me sending out these emails every day and I missed a few days last month.
-
-I'll do better!
diff --git a/astro/src/content/daily-email/2023-03-03.md b/astro/src/content/daily-email/2023-03-03.md
deleted file mode 100644
index 591fc8b5..00000000
--- a/astro/src/content/daily-email/2023-03-03.md
+++ /dev/null
@@ -1,20 +0,0 @@
----
-title: >
- Adding a LocalGov Drupal example
-pubDate: 2023-03-03
-permalink: >
- archive/2023/03/03/adding-a-localgov-drupal-example
-tags:
- - drupal
- - localgov-drupal
----
-
-After [previously looking at the LocalGov Drupal distribution](https://www.oliverdavies.uk/archive/2022/10/24/looking-at-localgov-drupal), today I added a LocalGov Drupal example to my [Docker Examples repository](https://github.com/opdavies/docker-examples/tree/main/drupal-localgov).
-
-Based on the Drupal 10 example, the LocalGov Drupal example used Composer's `create-project` command to scaffold the project plus some additional configuration files such as the `Dockerfile`, `docker-compose.yaml` and a `justfile`.
-
-A feature on my list is to add to both examples is to install Drupal automatically instead of opening the installation screen or having to run an install command. Once that's in place, it'll remove a manual step and allow people to see the application more quickly.
-
-I have some issues for examples and enhancements to add within [the repository's issue queue](https://github.com/opdavies/docker-examples/issues) and would welcome any suggestions or questions.
-
-For LocalGov itself, I hope to find more opportunities to use and contribute to it in the future.
diff --git a/astro/src/content/daily-email/2023-03-04.md b/astro/src/content/daily-email/2023-03-04.md
deleted file mode 100644
index 2a82e477..00000000
--- a/astro/src/content/daily-email/2023-03-04.md
+++ /dev/null
@@ -1,19 +0,0 @@
----
-title: >
- Why I built a tool to generate configuration files
-pubDate: 2023-03-04
-permalink: >
- archive/2023/03/04/why-i-built-a-tool-to-generate-configuration-files
----
-
-I'm always working on various personal and client projects, and they contain a lot of the same configuration files. I exclusively use Docker and Docker Compose on all projects, I use a `justfile` for running tasks, and for PHP projects, I need configuration files for tools like PHPStan, PHPCS and PHPUnit.
-
-The majority of those files are the same with some slight configuration for each project - such as whether it uses `web` or `docroot`, or which paths are checked with static analysis or for coding standards issues.
-
-I've given a talk called [Working with Workspace](https://www.oliverdavies.uk/talks/working-with-workspace) - a tool that we used at an agency I worked at. It had two functions - to execute project tasks and to generate configuration files from templates.
-
-I use a `justfile` to execute tasks and commands but needed to write my own tool to generate the configuration files.
-
-The result is that I can add one YAML file to a project, enter the values that it needs and when I run the CLI tool, it will generate all of the files the project needs.
-
-As well as being faster to set up a project, like a [LocalGov Drupal Docker example](https://github.com/opdavies/docker-examples/tree/main/drupal-localgov), having a canonical set of templated configuration files I can enhance and maintain by adding new features and fixes and they'll be added to every project when I next generate its files.
diff --git a/astro/src/content/daily-email/2023-03-05.md b/astro/src/content/daily-email/2023-03-05.md
deleted file mode 100644
index e9948515..00000000
--- a/astro/src/content/daily-email/2023-03-05.md
+++ /dev/null
@@ -1,18 +0,0 @@
----
-title: >
- Mentoring for School of Code
-pubDate: 2023-03-05
-permalink: >
- archive/2023/03/05/mentoring-for-school-of-code
-tags: []
----
-
-I've been a Mentor for students on a coding bootcamp a few times before, and I'm looking forward to doing this again - this time with [School of Code](https://www.schoolofcode.co.uk).
-
-After hearing about them at a PHP meetup last year, I was keen to get involved after the previous bootcamp I was involved with closed its doors.
-
-I've always been impressed to see people with little, or usually no prior coding experience, on these bootcamps and what they can learn and achieve in a short amount of time - and one of the things that drew me to School of Code is that the bootcamp is free for learners.
-
-This week is the mentor kick-off session, with the new cohort starting next week.
-
-I'm looking forward to seeing who I'm paired up with, and helping them take their first steps into a career in software development.
diff --git a/astro/src/content/daily-email/2023-03-08.md b/astro/src/content/daily-email/2023-03-08.md
deleted file mode 100644
index 7b07f451..00000000
--- a/astro/src/content/daily-email/2023-03-08.md
+++ /dev/null
@@ -1,19 +0,0 @@
----
-title: >
- Automating infrastructure with IaC
-pubDate: 2023-03-08
-permalink: >
- archive/2023/03/08/automating-infrastructure-with-iac
-tags:
- - devops
----
-
-Are you responsible for creating and maintaining resources like GitHub repositories, DigitalOcean servers, Amazon S3 buckets and Cloudfront distributions or DNS records in Cloudflare?
-
-Do you do that through the various web UIs?
-
-I'd recommend looking into infrastructure as code tools such as Ansible, Terraform and Pulumi.
-
-You can create, manage and destroy these resources by writing text files rather than clicking around in web UIs, which you can store and share using version control tools.
-
-Infrastructure as code (IaC) tools are something that I use when working with infrastructure, whether it's for a client project or [a talk demo](https://github.com/opdavies/rebuilding-acquia/blob/4efe94398f4d8715d22ca677756beb36017d4e74/main.tf) (this uses Terraform to create an Amazon S3 bucket and Cloudflare distribution, link it to an SSL certificate and create my DNS records - all automatically).
diff --git a/astro/src/content/daily-email/2023-03-09.md b/astro/src/content/daily-email/2023-03-09.md
deleted file mode 100644
index 5d042484..00000000
--- a/astro/src/content/daily-email/2023-03-09.md
+++ /dev/null
@@ -1,18 +0,0 @@
----
-title: >
- In what language should I write my automation?
-pubDate: 2023-03-09
-permalink: >
- archive/2023/03/09/in-what-language-should-i-write-my-automation
-# tags:
-# - a
-# - b
----
-
-Of the three tools I mentioned in yesterday's email - Ansible, Terraform and Pulumi - I mostly use Pulumi these days for writing automation code.
-
-Why? As someone who is already familiar with writing code in certain programming languages, I like that I can use those languages to also write automation, avoid learning a domain-specific language, and those existing approaches like functions and classes to make reusable components and resources.
-
-I like that it supports a number of languages. I started with TypeScript but since watching a recent episode of the AltF4Stream, I'm looking at Python too. I've written Python before with Fabric and what you can achieve in Pulumi with a small amount of Python code is very impressive compared to other languages like Go and TypeScript.
-
-If you prefer those other languages, why not give Pulumi a try with it?
diff --git a/astro/src/content/daily-email/2023-03-13.md b/astro/src/content/daily-email/2023-03-13.md
deleted file mode 100644
index f8e53bd7..00000000
--- a/astro/src/content/daily-email/2023-03-13.md
+++ /dev/null
@@ -1,16 +0,0 @@
----
-title: >
- What problem are we trying to solve?
-pubDate: 2023-03-13
-permalink: >
- archive/2023/03/13/what-problem-am-i-trying-to-solve
-tags: []
----
-
-This is a question that I always ask before starting any development task, and I was very happy to see a slide in one of the keynote sessions at nor(DEV):con asking this question.
-
-I'd much rather have a collegue or client come to me with a problem that needs solving rather than a self-diagnosis and a decided solution.
-
-Depending what on the problem is, and other factors like timescales, I may suggest a different solution or approach. This happened recently when I suggested a different approach using Drupal's built-in maintenance mode feature.
-
-If there's no problem to solve, what's the reason for doing the work?
diff --git a/astro/src/content/daily-email/2023-03-14.md b/astro/src/content/daily-email/2023-03-14.md
deleted file mode 100644
index 1e674433..00000000
--- a/astro/src/content/daily-email/2023-03-14.md
+++ /dev/null
@@ -1,23 +0,0 @@
----
-title: >
- Automating all the things
-pubDate: 2023-03-14
-permalink: >
- archive/2023/03/14/automating-all-the-things
-tags:
- - automation
----
-
-As a solo Developer and Consultant, I rely a lot on automation to get my tasks done.
-
-I use tools like [Pulumi, Ansible and Terraform](https://www.oliverdavies.uk/archive/2023/03/09/in-what-language-should-i-write-my-automation) to automate creating and configuring infrastructure - recently creating new client GitHub repositories using a standard configuration with Pulumi.
-
-I use Nix and Home Manager to automate my local development environment, install packages I need and create files like `.gitconfig` for my needs. These are reusable and stored in my [dotfiles](https://github.com/opdavies/dotfiles) repository.
-
-For projects, I use tools like Docker, Docker Compose and Nix flakes for consistency.
-
-[I wrote a tool for generating configuration files for each project](https://www.oliverdavies.uk/archive/2023/03/04/why-i-built-a-tool-to-generate-configuration-files) - reducing the time it takes me to set up, configure and maintain standard files for tools like Docker and Docker Compose that I always use. If I need to add a new feature or fix a bug in a configuration file, I can do that in my templated version and re-generate each project's files rather than making the same change manually.
-
-Today, I wrote a script that loops over all projects where I commit those files to GitHub, clones a fresh version of it, re-generates the files and pushes any new files or changes back to the repository. This means that any changes will be automatically applied and all of my projects will remain in sync.
-
-Automating all of these things reduces the time that I need to spend on them - allowing me to focus on delivering value and solving problems for my clients.
diff --git a/astro/src/content/daily-email/2023-03-15.md b/astro/src/content/daily-email/2023-03-15.md
deleted file mode 100644
index 7c6ee434..00000000
--- a/astro/src/content/daily-email/2023-03-15.md
+++ /dev/null
@@ -1,19 +0,0 @@
----
-title: >
- The benefits of automation
-pubDate: 2023-03-15
-permalink: >
- archive/2023/03/15/the-benefits-of-automation
-tags:
- - automation
----
-
-I've been working on a project with a client, using [Fractal](https://fractal.build) for our component library. I've been working on it locally but yesterday I needed to make it public for the client to review the work I've done.
-
-I recently added `node` support to my [build configuration file generator](https://www.oliverdavies.uk/archive/2023/03/04/why-i-built-a-tool-to-generate-configuration-files) and used that to generate and use a consistent set of configuration files for a Fractal project.
-
-I've used Terraform in [some codebases](https://github.com/opdavies/rebuilding-acquia) to create and configure AWS resources like S3 buckets and Cloudfront distributions, so I was able to use that to create what I needed as well as adding the DNS record for a new subdomain to access Cloudfront.
-
-I use a `justfile` to automate tasks such as generating production assets from Fractal and uploading it to the S3 bucket, so I can do this in a single command instead of multiple and in a consistent and reproducible way.
-
-I started with a standalone project on my laptop and finished with a consistent cloud-based environment for my client and their project to review their component library, and because of the automation that I've built and used, this only took a few minutes to do.
diff --git a/astro/src/content/daily-email/2023-03-21.md b/astro/src/content/daily-email/2023-03-21.md
deleted file mode 100644
index 9567c250..00000000
--- a/astro/src/content/daily-email/2023-03-21.md
+++ /dev/null
@@ -1,19 +0,0 @@
----
-title: >
- There isn't a standard "Tailwind-looking" site
-pubDate: 2023-03-21
-permalink: >
- archive/2023/03/21/there-isnt-a-tailwind-looking-site
-tags:
- - tailwind-css
----
-
-When looking at some websites, you can tell that it was built using a certain CSS framework.
-
-Whether it's using a standard component like a navbar or card, or it's using the default colour palette, you can confidently know that website uses ___.
-
-As Tailwind includes no components (other than the `container`) and only has low-level utility classes for things like spacing and colours (amongst many other things), you can build radically different-looking websites with the same classes.
-
-There are some [examples of UIs that I've rebuilt](https://www.oliverdavies.uk/blog/uis-ive-rebuilt-tailwind-css) and some websites that I show in my [Taking Flight with Tailwind CSS talk](https://www.oliverdavies.uk/talks/taking-flight-with-tailwind-css).
-
-If you take a look, you'll see what I mean.
diff --git a/astro/src/content/daily-email/2023-03-22.md b/astro/src/content/daily-email/2023-03-22.md
deleted file mode 100644
index d57c4ea0..00000000
--- a/astro/src/content/daily-email/2023-03-22.md
+++ /dev/null
@@ -1,20 +0,0 @@
----
-title: >
- With utility styles, your CSS stops growing
-pubDate: 2023-03-22
-permalink: >
- archive/2023/03/22/with-utility-styles-your-css-stops-growing
-tags:
- - css
- - tailwind-css
----
-
-When working with traditional CSS, the first thing you do when you need to style a new page or component is to open a stylesheet and start writing new CSS.
-
-Also when editing existing styles, sometimes you'll write new styles to avoid breaking the existing pages in unexpected ways in other parts of the page. This is why I've not seen many projects where the styling is maintained or refactored over time - only added to.
-
-By writing new CSS for every new page or component, the size of your stylesheets will continue to grow and be less performant and harder to maintain over time.
-
-With utility styles and frameworks like Tailwind CSS, this happens a lot less or sometimes not at all.
-
-If you need to use a class like `flex` or `grid` and you already use that in your project, there's no new CSS to add and the stylesheet doesn't grow. Because these type of classes are so specific, they're much more reusable which means less duplication of CSS rules and less CSS in total.
diff --git a/astro/src/content/daily-email/2023-03-27.md b/astro/src/content/daily-email/2023-03-27.md
deleted file mode 100644
index b9b688bc..00000000
--- a/astro/src/content/daily-email/2023-03-27.md
+++ /dev/null
@@ -1,20 +0,0 @@
----
-title: >
- Software development is about solving problems and adding value
-pubDate: 2023-03-27
-permalink: >
- archive/2023/03/27/software-development-solving-problems-and-adding-value
-# tags:
-# - a
-# - b
----
-
-I've recently started as a Mentor for the School of Code, working with a student on their cohort that started last week. Whilst the Bootcamp is focussed on JavaScript and node, and is currently looking at front-end development and using APIs, we've already started talking about different back-end technologies and frameworks.
-
-Something that I've believed for a while is that software development is about solving problems and different languages and frameworks are tools to use to solve the problem and achieve the desired result. The programming fundamentals that he's learning now can be applied to different languages and some may be better depending on the problem that needs to be solved.
-
-I've also said when speaking with a client this week that development is about adding business value.
-
-Whilst there is some value to doing security updates and maintenance to keep an application running and secure, I'd much rather be working on tasks that directly add value for the client like some of the tasks I've done for them recently like improving eCommerce conversions and adding new payment methods or revenue streams.
-
-It's easier for the client to justify and see the results of the work, it improves the experience for their customers or users, and it's more interesting and fulfilling for me.
diff --git a/astro/src/content/daily-email/2023-04-07.md b/astro/src/content/daily-email/2023-04-07.md
deleted file mode 100644
index f27fc4cb..00000000
--- a/astro/src/content/daily-email/2023-04-07.md
+++ /dev/null
@@ -1,17 +0,0 @@
----
-title: >
- Speaking at PHP London
-pubDate: 2023-04-07
-permalink: >
- archive/2023/04/07/speaking-at-php-london
-tags:
- - speaking
----
-
-After a trip away with the family earlier this week, I was happy to speak at the PHP London meetup yesterday evening.
-
-Following on from my previous "Working from Workspace" talk, I spoke about my current development setup for my personal and work laptops with Nix and NixOS, Linux, Neovim, tmux, just, Docker and more!
-
-Of course, I spoke about PHP, Drupal, and Symfony too as well as some of the work that we're doing at Transport for Wales.
-
-I learned that the call for papers for the PHP UK conference 2024 is already open so I'll definitely be submitting some proposals for next year's conference. Hopefully, I'll be back in London again before that.
diff --git a/astro/src/content/daily-email/2023-04-08.md b/astro/src/content/daily-email/2023-04-08.md
deleted file mode 100644
index 56e56061..00000000
--- a/astro/src/content/daily-email/2023-04-08.md
+++ /dev/null
@@ -1,21 +0,0 @@
----
-title: >
- Why I use tmux
-pubDate: 2023-04-08
-permalink: >
- archive/2023/04/08/why-i-use-tmux
-tags:
- - tmux
----
-
-tmux is a "terminal multiplexer" - a program that makes one terminal window into many.
-
-I use the terminal a lot and am often switching between codebase so this is very useful for me.
-
-I use a different session for each codebase. If I'm working on one and need to switch to another, I can detatch from one session and attach to another. Later, when I'm ready to switch back, I do the same again.
-
-I usually have multiple windows inside a session. Neovim will be in the main one, and I can run separate commands - especially long-running ones like watchers - with their own windows.
-
-If I need to split a window and have Neovim on the left and a terminal for running tests on the right, I can do this with different panes.
-
-Being able to organise my workspace in this way has become a big part blogof my development workflow and my productivity.
diff --git a/astro/src/content/daily-email/2023-04-09.md b/astro/src/content/daily-email/2023-04-09.md
deleted file mode 100644
index ccf93e04..00000000
--- a/astro/src/content/daily-email/2023-04-09.md
+++ /dev/null
@@ -1,22 +0,0 @@
----
-title: >
- Nix, NixOS, Home Manager, and WSL2
-pubDate: 2023-04-09
-permalink: >
- archive/2023/04/09/nix-nixos-home-manager-and-wsl2
-tags:
- - linux
- - nix
- - nixos
- - wsl2
----
-
-Although I've been using Linux for work computers for a lot longer, a few years ago, I switched from macOS and an Apple MacBook Pro to using Linux full-time on my personal computers.
-
-My current daily driver laptop is a Tuxedo InfinityBook that I've installed NixOS on.
-
-NixOS, as the name suggests, is a Linux operating system based on the Nix package manager. It has access to the 80,000+ packages in the `nixpkgs` repository and can still install and manage them, but also does a lot more including managing hardware.
-
-For user-level configuration, I use Home Manager. I can configure my home directory including user-specific packages and manage my dotfiles, creating files like `.gitconfig` and linking them to the required destination.
-
-Home Manager can be a NixOS module or a standalone tool - it can be added to NixOS or installed on any Linux distribution, even in WSL2, so I have the same packages that I need installed on every machine as well as having my dotfiles in the correct place and ready to be used.
diff --git a/astro/src/content/daily-email/2023-04-10.md b/astro/src/content/daily-email/2023-04-10.md
deleted file mode 100644
index ef5723f4..00000000
--- a/astro/src/content/daily-email/2023-04-10.md
+++ /dev/null
@@ -1,23 +0,0 @@
----
-title: >
- How I use Neovim for writing PHP
-pubDate: 2023-04-10
-permalink: >
- archive/2023/04/10/how-i-use-neovim-for-writing-php
-tags:
- - neovim
- - php
- - vim
----
-
-Since [July 2021](https://www.oliverdavies.uk/blog/going-full-vim), I've used Neovim full-time for my development work and writing.
-
-Whilst Vim and Neovim are minimal by default, its functionality can be extended by adding plugins.
-
-I use nvim-lspconfig along with Intelephpense and Phpactor to add code actions and functionality like "go to definition" for PHP code.
-
-I use null-ls to apply code formatting and add diagnostic messages for PHPCS and PHPStan so I can see them on the appropriate lines.
-
-I use nvim-dap and nvim-dap-ui to leverage the debug adapter protocol to do step debugging with Xdebug.
-
-Along with others like dadbod.vim for databases, rest.nvim for making HTTP requests, Gitsigns and Fugitive for Git, and Telescope for fuzzy searching, I have all of the functionality that I've previously had in other browsers with the benefit that it's open source and I can add more plugins or write my own if I need to add anything else.
diff --git a/astro/src/content/daily-email/2023-04-11.md b/astro/src/content/daily-email/2023-04-11.md
deleted file mode 100644
index 092330f2..00000000
--- a/astro/src/content/daily-email/2023-04-11.md
+++ /dev/null
@@ -1,57 +0,0 @@
----
-title: >
- just vs make
-pubDate: 2023-04-11
-permalink: >
- archive/2023/04/11/just-vs-make
-tags:
- - devops
- - just
- - make
- - linux
----
-
-`just` compared to `make` is something that was asked during my PHP London talk, and whilst they are similar, `just` has differences for me that explains why I use it:
-
-## Tabs or spaces
-
-A Makefile needs to use tabs. Justfiles are more flexible and work with tabs or any number of spaces.
-
-## .PHONY
-
-With a Makefile, you need to declare some targets as "phony". I believe that this is for targets that don't generate artifact files with that name, so as I'm not compiling and building files with `make`, this is redundant and adds visual noise.
-
-## Passing arguments
-
-This is how a `composer` target looks like in a Makefile:
-
-```make
-composer:
- docker compose exec php composer
-```
-
-With this, I'd expect to be able to pass arguments to it - e.g. `make composer info drupal/core`.
-
-But, instead of seeing the expected output, I get an error: `make: *** No rule to make target 'info'. Stop.`.
-
-This is what I'd need to do to pass arguments to the `composer` target:
-
-```make
-composer:
- docker compose exec php composer $(COMPOSER_ARGS)
-```
-
-Now I can run `make composer COMPOSER_ARGS="info drupal/core"` and see what I was expecting but the syntax isn't what I'd want.
-
-`just`, on the other hand, allows for defining parameters to its recipes:
-
-```yaml
-composer *args:
- docker compose exec php composer {{ args }}
-```
-
-Here, I can create as many named parameters as needed and use them in the recipe with the syntax that I wanted - `just composer info drupal/core`.
-
-I can think of a few others but this is is the main reason why I moved from `make` and later adopted `just`.
-
-`just`, for me, gives the flexibilty that I need whilst using a simple and familiar syntax but without some of the confusing and complicated behaviours of `make`.
diff --git a/astro/src/content/daily-email/2023-04-12.md b/astro/src/content/daily-email/2023-04-12.md
deleted file mode 100644
index 854625c4..00000000
--- a/astro/src/content/daily-email/2023-04-12.md
+++ /dev/null
@@ -1,48 +0,0 @@
----
-title: >
- Cleaner PHP code with promoted constructor properties
-pubDate: 2023-04-12
-permalink: >
- archive/2023/04/12/cleaner-php-code-with-promoted-constructor-properties
-tags:
- - php
----
-
-One of my favorite features that was introducted in PHP 8 was promoted constructor properties.
-
-If I'm passing arguments into a constructor, I can declare a visibility and it will be promoted to a property on the class.
-
-Here's an example of a value of a data transfer object that accepts a sort code and account number as strings:
-
-```php
-class AccountDetails {
-
- public function __construct(
- public string $accountNumber,
- public string $sortCode,
- ) {}
-
-}
-```
-
-Without promoted constructor properties, I'd need to create the properties and assign them manually, and I'd have this:
-
-```php
-class AccountDetails {
-
- public string $accountNumber;
-
- public string $sortCode;
-
- public function __construct(
- string $accountNumber,
- string $sortCode,
- ) {
- $this->accountNumber = $accountNumber;
- $this->sortCode = $sortCode;
- }
-
-}
-```
-
-Whilst text editors and IDEs can create the properties automatically, I prefer this as it's less code, more readable and easier to understand.
diff --git a/astro/src/content/daily-email/2023-04-13.md b/astro/src/content/daily-email/2023-04-13.md
deleted file mode 100644
index f4e01db6..00000000
--- a/astro/src/content/daily-email/2023-04-13.md
+++ /dev/null
@@ -1,35 +0,0 @@
----
-title: >
- Immutable read-only properties in PHP 8.1
-pubDate: 2023-04-13
-permalink: >
- archive/2023/04/13/immutable-read-only-properties-in-php-8-1
-tags:
- - php
----
-
-Continuing with yesterday's data transfer object (DTO) example, something that can be done since PHP 8.1 is to make properties read-only:
-
-```php
-class AccountDetails {
-
- public function __construct(
- public readonly string $accountNumber,
- public readonly string $sortCode,
- ) {}
-
-}
-```
-
-This means the public properties can be read and used without the need for getter methods, but cannot be overridden - making the DTO immutable.
-
-Without `readonly`, a DTO can be created and the property values can be changed:
-
-```php
-$accountDetails = new AccountDetails('12345678', '00-00-00');
-$accountDetails->accountNumber = 'banana';
-```
-
-With `readonly` set, you'd get a fatal error instead:
-
-> Fatal error: Uncaught Error: Cannot modify readonly property AccountDetails::$accountNumber in /home/opdavies/tmp/example.php:13
diff --git a/astro/src/content/daily-email/2023-04-14.md b/astro/src/content/daily-email/2023-04-14.md
deleted file mode 100644
index f5ff6901..00000000
--- a/astro/src/content/daily-email/2023-04-14.md
+++ /dev/null
@@ -1,37 +0,0 @@
----
-title: >
- Data transfer objects and value objects
-pubDate: 2023-04-14
-permalink: >
- archive/2023/04/14/data-transfer-objects-and-value-objects
-tags: []
----
-
-In the last few emails, we've seen a data transfer object called `AccountDetails` that stores the account number and sort code for a bank account.
-
-A data transfer object only stores data but we could also use a value object that can do more tasks, like validating the values.
-
-For example, we could validate that the account number is the correct length and the sort code is the correct format:
-
-```php
-class AccountDetails {
-
- public function __construct(
- public readonly string $accountNumber,
- public readonly string $sortCode,
- ) {
- // Validate the account number.
- if (!preg_match('/^\d{8}$/', $accountNumber)) {
- throw new \InvalidArgumentException('Account number must be an 8-digit number');
- }
-
- // Validate the sort code.
- if (!preg_match('/^\d{2}-\d{2}-\d{2}$/', $sortCode)) {
- throw new \InvalidArgumentException('Sort code must be in the format 00-00-00');
- }
- }
-
-}
-```
-
-Helper methods can also be added to a value object as long as they don't modify the state of the object, such as getting the raw sort code without the separating dashes or performing further checks on the input values.
diff --git a/astro/src/content/daily-email/2023-04-15.md b/astro/src/content/daily-email/2023-04-15.md
deleted file mode 100644
index a0dfb6f1..00000000
--- a/astro/src/content/daily-email/2023-04-15.md
+++ /dev/null
@@ -1,27 +0,0 @@
----
-title: >
- Automatically running commands with nodemon
-pubDate: 2023-04-15
-permalink: >
- archive/2023/04/15/automatically-running-commands-with-nodemon
-tags: []
----
-
-Instead of running the same commands over and over again, some of the command-line tools that I use have a `watch` mode and will automatically re-run when files are changed, however, not all do.
-
-Instead of doing this manually, I can achieve the same thing though using a tool called `nodemon` - a script monitor for node projects, but it can work with non-node projects too.
-
-Here's an example where I'm automatically re-running my PHPUnit tests using a `just test` recipe each time a file within my custom modules directory changes:
-
-```
-nodemon \
- --watch web/modules/custom \
- --ext '*' \
- --exec "just test --stop-on-failure --colors=always"
-```
-
-I specify the files or directories I want to watch, which file extensions should trigger a restart (in this case, I've enabled all extensions), and the command to execute.
-
-This watches all files and run all of the tests, but I can filter either if I need to.
-
-As well as PHP tools like PHPUnit and PHPStan, I also use this for other things such as when creating presentation slides with rst2pdf where I can automatically re-generate the PDF whenever I update the rst file.
diff --git a/astro/src/content/daily-email/2023-04-16.md b/astro/src/content/daily-email/2023-04-16.md
deleted file mode 100644
index e3fbab46..00000000
--- a/astro/src/content/daily-email/2023-04-16.md
+++ /dev/null
@@ -1,39 +0,0 @@
----
-title: >
- Refactoring with readonly classes in PHP 8.2
-pubDate: 2023-04-16
-permalink: >
- archive/2023/04/16/refactoring-with-readonly-classes-in-php-8-2
-tags:
- - php
----
-
-Marian Kostadinov ([stochnagara on Twitter](https://twitter.com/stochnagara)) replied to Friday's email about DTOs and value objects to tell me about `readonly` classes, which can be done in PHP 8.2.
-
-Looking at the previous class:
-
-```php
-class AccountDetails {
-
- public function __construct(
- public readonly string $accountNumber,
- public readonly string $sortCode,
- ) {}
-
-}
-```
-
-Instead of setting each property as `readonly`, the whole class can instead be marked as `readonly`:
-
-```php
-readonly class AccountDetails {
-
- public function __construct(
- public string $accountNumber,
- public string $sortCode,
- ) {}
-
-}
-```
-
-Thanks for the suggestion, Marian!
diff --git a/astro/src/content/daily-email/2023-04-17.md b/astro/src/content/daily-email/2023-04-17.md
deleted file mode 100644
index a2856bf5..00000000
--- a/astro/src/content/daily-email/2023-04-17.md
+++ /dev/null
@@ -1,26 +0,0 @@
----
-title: >
- Introducing feature flags to "build-configs"
-pubDate: 2023-04-17
-permalink: >
- archive/2023/04/17/introducing-feature-flags-to-build-configs
-tags: []
----
-
-Yesterday, I wanted to make a breaking change to my [build-configs project](https://www.oliverdavies.uk/archive/2023/03/04/why-i-built-a-tool-to-generate-configuration-files) - changing the default database credentials that are used by Docker Compose.
-
-As I have several projects based on generated files by the tool, changing the values could cause issues in those projects in the future and this is something that I wanted to avoid.
-
-## What did I do?
-
-To avoid this issue and needing to update all of my projects at once, I added a feature flag to the `build.yaml` file so I can opt-in to this feature on a per-project basis.
-
-If a project, like my [Drupal](https://github.com/opdavies/docker-example-drupal) and [LocalGov Drupal](https://github.com/opdavies/docker-example-drupal-localgov) Docker examples, are opted in, its files will get the new credentials. If not, it will continue to use the original ones.
-
-[In this commit](https://github.com/opdavies/docker-example-drupal/commit/3f496168d5c32f9706970519023b431ee02c4b19), you'll see where I enabled the feature flag and committed the resulting change.
-
-## What does this achieve?
-
-I can continue to work on existing projects without them breaking, and migrate projects one at a time by using the feature flag instead of needing to do them all once.
-
-Once all active projects have been migrated or completed, the feature flag can be removed and I can refactor and simplify the code - removing the feature flag and the legacy values.
diff --git a/astro/src/content/daily-email/2023-04-18.md b/astro/src/content/daily-email/2023-04-18.md
deleted file mode 100644
index 1c203094..00000000
--- a/astro/src/content/daily-email/2023-04-18.md
+++ /dev/null
@@ -1,23 +0,0 @@
----
-title: >
- Consistency is key
-pubDate: 2023-04-18
-permalink: >
- archive/2023/04/18/consistency-is-key
-tags:
- - automation
- - devops
- - docker
----
-
-A side effect of [using a tool to generate build configuration files](https://www.oliverdavies.uk/archive/2023/03/04/why-i-built-a-tool-to-generate-configuration-files) with templates is the consistency that it introduces.
-
-The majority of my projects use a PHP-FPM or PHP CLI container. In my Docker Compose file, the service was mostly named `php` but sometimes it was `php-fpm`. In the templated file, it's always named `php`.
-
-Some projects would use `mysql` or `mariadb` for the database service and `nginx` or `caddy` depending on which server was being used. These are now always `database` and `web` respectively.
-
-As well as being easier to switch between projects and not having to think about which names are used in each codebase, it's also much easier to write tools and automation when the names are consistent.
-
-For example, I'd always write a long-ish command to import a database file - reading and unzipping it, and importing it by connecting to the database running in its container. The command would essentially be the same with slight changes based on that project - such as the database service name.
-
-Now the command is the same for all projects, and I can automate it by writing a script that works on any project meaning I no longer need to write the long command at all.
diff --git a/astro/src/content/daily-email/2023-04-19.md b/astro/src/content/daily-email/2023-04-19.md
deleted file mode 100644
index fa79de28..00000000
--- a/astro/src/content/daily-email/2023-04-19.md
+++ /dev/null
@@ -1,40 +0,0 @@
----
-title: >
- Camel-case or snake-case for Drupal code?
-pubDate: 2023-04-19
-permalink: >
- archive/2023/04/19/camel-case-or-snake-case-for-drupal-code
-tags:
- - drupal
- - php
----
-
-For some time, [Drupal's PHP coding standards](https://www.drupal.org/docs/develop/standards/php/php-coding-standards#s-functions-and-variables) allows for writing variables in either snake-case (e.g. `$my_variable`) or lower camel-case (`e.g. $myVariable`).
-
-It originally only allowed for snake-case variable names but once it accepted both, I switched to camel-case as my default.
-
-Why? I didn't like the inconsistency of using one approach for variable names and one for method and property names in PHP classes (which were always camel-case).
-
-I'd have had code like this with a mixture of both:
-
-```php
-class MyClass {
-
- private EntityTypeManagerInterface $entityTypeManager;
-
- public function __construct(EntityTypeManagerInterface $entity_type_manager) {
- $this->entityTypeManager = $entity_type_manager;
- }
-
-}
-```
-
-Or even more simply:
-
-```php
-$entity_type_manager = \Drupal::entityTypeManager();
-```
-
-I prefer not to have to consistently think about which to use and, if possible, like to use standard approaches in different codebases whether I'm working on a Drupal project, a Symfony project, or a PHP library.
-
-Plus, I get to use new PHP features like [promoted constructor properties](https://www.oliverdavies.uk/archive/2023/04/12/cleaner-php-code-with-promoted-constructor-properties) if everything is named in the same format.
diff --git a/astro/src/content/daily-email/2023-04-20.md b/astro/src/content/daily-email/2023-04-20.md
deleted file mode 100644
index 212c69ae..00000000
--- a/astro/src/content/daily-email/2023-04-20.md
+++ /dev/null
@@ -1,35 +0,0 @@
----
-title: >
- Micro-refactorings
-pubDate: 2023-04-20
-permalink: >
- archive/2023/04/20/micro-refactorings
-tags:
- - refactoring
- - technical-debt
- - programming
----
-
-Today, I saw a [LinkedIn post by Peter Morlion](https://www.linkedin.com/posts/petermorlion_refactoring-technicaldebt-softwaredevelopment-activity-7054378097051095040-I545), in which he describes micro-refactoring - very small and safe refactors like renaming a variable, moving a method in a file to a more logical place, or adding a comment.
-
-He says that micro-refactors are safer than big refactors and have less chance of introducing a regression, are easy to do, improve the code quality over time, make larger refactorings easier later, increase the readability of your code, and reduce technical debt bit by bit.
-
-## What's the issue?
-
-I agree with what Peter says and also encourage people to make small refactors to the code they're working on and follow the "[Boy Scout rule](https://www.oliverdavies.uk/archive/2022/12/22/the-boy-scout-rule)".
-
-The main blocker to this I've seen is Git workflows that require people to work in separate branches that need to be reviewed before being merged, as this slows down the process.
-
-As Peter also says, micro-refactorings can be done anytime while working on other tasks. This is hard to do if each refactor requires its own branch and pull request, and the number of pull requests would quickly become unmanageable and take time to review.
-
-If I know that a micro-refactor like renaming a variable is going to take hours, days or weeks to be reviewed and merged, I'd probably be less likely to do the refactor in the first place. Not to mention having to update my working code once it's been merged.
-
-## What do I prefer to do?
-
-I prefer to follow trunk-based development where everyone commits to a single branch and continuous integration where everyone is committing, pushing and pulling changes often - removing the need for merging branches and merge conflicts.
-
-Instead of asynchronous code review, I prefer to pair- or mob-program or to rely on automation with CI/CD pipelines.
-
-If the commit before my change is passing the pipeline checks, and they're still passing after my change, they're good to deploy.
-
-Making the process as frictionless as possible encourages people to make small changes and micro-refactors, and to make codebases better a small piece at a time.
diff --git a/astro/src/content/daily-email/2023-04-21.md b/astro/src/content/daily-email/2023-04-21.md
deleted file mode 100644
index 35bd5c65..00000000
--- a/astro/src/content/daily-email/2023-04-21.md
+++ /dev/null
@@ -1,20 +0,0 @@
----
-title: >
- Making my Drupal module template Drupal 10 compatible
-pubDate: 2023-04-21
-permalink: >
- archive/2023/04/21/making-my-drupal-module-template-drupal-10-compatible
-tags:
- - drupal
- - php
----
-
-Today, I made my [Drupal module template](https://github.com/opdavies/drupal-module-template) compatible with Drupal 10.
-
-Because Drupal 10 is developed from Drupal 9, the changes between the two and the changes required are minimal.
-
-In this case, I only needed to change the `core_version_requirement` in `drupal_module_template.info.yml` from `^9` to `^9 || ^10` - meaning the template works for both Drupal 9 and 10, so there's no need for different versions.
-
-If it used any deprecated code that was removed before Drupal 10, I'd have needed to update it to use the Drupal 10-compliant code.
-
-Updating to new major Drupal versions is much easier than it used to be!
diff --git a/astro/src/content/daily-email/2023-04-22.md b/astro/src/content/daily-email/2023-04-22.md
deleted file mode 100644
index 74085bc4..00000000
--- a/astro/src/content/daily-email/2023-04-22.md
+++ /dev/null
@@ -1,20 +0,0 @@
----
-title: >
- Configuration files as a service
-pubDate: 2023-04-22
-permalink: >
- archive/2023/04/22/build-configs-as-a-service
-tags:
- - development
- - devops
- - drupal
- - php
----
-
-After using my "build-configs" tool to generate and manage configuration files for several personal and client Drupal projects for the past few months, I'm offering it as a product to purchase.
-
-I can provide an initial Drupal project skeleton built using `build-configs`, and for a recurring monthly amount, ongoing updates and unlimited support via Slack.
-
-I can retrofit it to an existing codebase, but as this will be different every time, I'll need more information to give a price.
-
-See https://www.oliverdavies.uk/build-configs for more information and, as a list subscriber, use the code `dailyconfigs` to get an early-bird discount.
diff --git a/astro/src/content/daily-email/2023-04-23.md b/astro/src/content/daily-email/2023-04-23.md
deleted file mode 100644
index a5ad7d2b..00000000
--- a/astro/src/content/daily-email/2023-04-23.md
+++ /dev/null
@@ -1,28 +0,0 @@
----
-title: >
- Laravel Pipelines
-pubDate: 2023-04-23
-permalink: >
- archive/2023/04/23/laravel-pipelines
-tags:
- - php
- - laravel
----
-
-I've seen a lot on social media and posts and videos recently about Laravel Pipelines - functionality that's been present in Laravel and used within the framework for some time - but there was only documentation added for it last month as part of the Laravel 10 release.
-
-This is an example from the new documentation:
-
-```php
-$user = Pipeline::send($user)
- ->through([
- GenerateProfilePhoto::class,
- ActivateSubscription::class,
- SendWelcomeEmail::class,
- ])
- ->then(fn (User $user) => $user);
-```
-
-Once a user has registered, it is passed through different classes - each performing a task and calling the next class in the list, similar to middleware. Once finished, a final action is performed or a value is returned.
-
-As someone who doesn't use Laravel often but does use standalone components - like `illuminate/collections` - in other PHP projects, I'm interested to see how I can use this via `illuminate/pipeline` to refactor some of my existing code.
diff --git a/astro/src/content/daily-email/2023-04-24.md b/astro/src/content/daily-email/2023-04-24.md
deleted file mode 100644
index ed370799..00000000
--- a/astro/src/content/daily-email/2023-04-24.md
+++ /dev/null
@@ -1,33 +0,0 @@
----
-title: >
- CI pipelines should start locally
-pubDate: 2023-04-24
-permalink: >
- archive/2023/04/24/ci-pipelines-should-start-locally
-tags:
- - development
- - devops
- - git
----
-
-This week, Solomon Hykes (@solomonstre on Twitter) said:
-
-> Your CI/CD pipeline should start on the developer's laptop. If it only starts after a git push, you're slowing your team down and throwing money down the drain.
-
-## What does this mean?
-
-My interpretation of this is that if a pipeline is going to fail, and fail for something that could been easily tested locally, then it should have been tested and fixed locally rather than waiting to push the changes to a CI pipeline, watch it fail there, and then need to push a fix and go through the process again.
-
-In PHP projects, a common CI pipeline failure after working on a change is that PHPCS (code style) or PHPStan (static analysis) checks will fail - even though the feature, fix or refactor is working. If those checks can be run locally to shorten the feedback loop and allow the error to be fixed before the pipeline runs, it would be better to do so.
-
-## My preferred solution
-
-My approach for this is using Git hooks - specifically on a pre-push event.
-
-These are scripts that run automatically before the commits are pushed, and if it fails, it prevents the push and allows you to fix the issue.
-
-They're easy to enable using a command like `git config core.hooksPath .githooks` (assuming the scripts are in a directory called `.githooks`), and whilst I wouldn't run everything that I would in a CI pipeline, I would run tasks like PHPCS and PHPStan checks, and maybe the unit and integration tests if they're fast to run.
-
-Anything that would take a longer time to run, like functional or behavioural tests, would only be executed within the pipeline, but for common failures like PHPCS and PHPStan errors, these can be quickly fixed locally and not pushed to a CI pipeline at all.
-
-[Here is Solomon's original tweet](https://twitter.com/solomonstre/status/1649118014594502656).
diff --git a/astro/src/content/daily-email/2023-04-25.md b/astro/src/content/daily-email/2023-04-25.md
deleted file mode 100644
index 01e8549b..00000000
--- a/astro/src/content/daily-email/2023-04-25.md
+++ /dev/null
@@ -1,21 +0,0 @@
----
-title: >
- Shortening the feedback loop even more
-pubDate: 2023-04-25
-permalink: >
- archive/2023/04/25/shortening-the-feedback-loop-even-more
-tags:
- - development
- - devops
- - neovim
----
-
-Yesterday's email was about shortening the feedback loop of a CI pipeline by running some of the checks like PHPCS and PHPStan locally and dealing with any errors before they get pushed to the code repository.
-
-What's even better than writing and committing code and then waiting until just before pushing it to test it? Seeing the errors in real-time and being able to fix them immediately.
-
-In my Neovim setup (I talked about this at the PHP London meetup recently), I have the Intelephense language server configured to add IDE-like features such as code completion, go-to definition, symbol renaming, etc.
-
-I also have another plugin - `null-ls.nvim` - that adds errors from command-line tools to Neovim's diagnostics list.
-
-So, if I try to do something that would cause a PHPStan failure, such as using an unknown variable or missing a return type, I can see that and fix it immediately and not even wait for a Git hook to run.
diff --git a/astro/src/content/daily-email/2023-04-26.md b/astro/src/content/daily-email/2023-04-26.md
deleted file mode 100644
index 2b8e338e..00000000
--- a/astro/src/content/daily-email/2023-04-26.md
+++ /dev/null
@@ -1,56 +0,0 @@
----
-title: >
- Structure a new test by writing comments first
-pubDate: 2023-04-26
-permalink: >
- archive/2023/04/26/tdd-structure-a-new-test-by-writing-comments-first
-tags:
- - automated-testing
- - test-driven-development
----
-
-Test cases are usually split into two or three sections - "Arrange, Act, Assert" or "Given, When, Then".
-
-If the test has a prerequisite, such as some users or content to be created or in a given state, you create the required environment for the test. With unit tests, this would include mocking any dependencies you need to use.
-
-Then you perform an action on the subject under test and, finally, assert that the system is in the desired state.
-
-Maybe a user was pending initially, and they're active after running a command or a cron task. You can assert the initial state of the user as well as the final state to ensure the action did what it was supposed to do.
-
-## Option 1
-
-To help me get started, I'll sometimes write a test like this with placeholders to separate the test into its separate stages:
-
-```php
-/** @test */
-function should_activate_a_pending_user(): void {
- // Arrange.
-
- // Act.
-
- // Assert.
-}
-```
-
-This makes me think about the different stages and what each might need to contain.
-
-## Option 2
-
-Or I might write it out in the "Given, When, Then" format:
-
-```php
-/** @test */
-function should_activate_a_pending_user(): void {
- // Given I have a user.
- // And the user is pending.
-
- // When I run the user update command.
-
- // Then the user should no longer be 'pending'.
- // And the user status should be 'active'.
-}
-```
-
-This takes a little longer to write but feels more familiar if you're used to a behavioural testing framework like Behat.
-
-Either way, sometimes, I'll remove the comments once I've written the code around them or leave them to provide additional context.
diff --git a/astro/src/content/daily-email/2023-04-27.md b/astro/src/content/daily-email/2023-04-27.md
deleted file mode 100644
index 28f7627d..00000000
--- a/astro/src/content/daily-email/2023-04-27.md
+++ /dev/null
@@ -1,22 +0,0 @@
----
-title: >
- Write the test backwards
-pubDate: 2023-04-27
-permalink: >
- archive/2023/04/27/tdd-write-the-test-backwards
-tags:
- - automated-testing
- - test-driven-development
----
-
-When writing a test, something that I like to do is start by writing the first assertion first, and then work backwards.
-
-My first assertion might be `self::assertTrue($result)`.
-
-If I ran this test, it would fail because of the undefined `$result` variable - but it's clear to me what I need next by asking, "Where does `$result` come from?".
-
-If I need to call a method on another class and get the result, I'll add it before the assertion. Then I repeat the process and ask, "What do I need for this to work?".
-
-Maybe I need to create some users or content in the application for the class to query and return a result based on it, so I'll create those.
-
-With this approach, I'm not making any assumptions about the test's prerequisites, and I usually find that I end up with cleaner and more focused tests.
diff --git a/astro/src/content/daily-email/2023-04-30.md b/astro/src/content/daily-email/2023-04-30.md
deleted file mode 100644
index 07afdf01..00000000
--- a/astro/src/content/daily-email/2023-04-30.md
+++ /dev/null
@@ -1,15 +0,0 @@
----
-title: >
- Will we see Drupal 7.100?
-pubDate: 2023-04-30
-permalink: >
- archive/2023/04/30/will-we-see-drupal-7-100
-tags:
- - drupal
----
-
-Drupal 7, first released in January 2011, is now on version 7.97.
-
-As things stand, it's supported until November 2023, which makes me wonder whether we'll see the first version of Drupal to get 100 releases.
-
-It was originally supposed to be end-of-life in November 2022, I also wonder if it'll be extended again and whether it should be.
diff --git a/astro/src/content/daily-email/2023-05-01.md b/astro/src/content/daily-email/2023-05-01.md
deleted file mode 100644
index 22a76eed..00000000
--- a/astro/src/content/daily-email/2023-05-01.md
+++ /dev/null
@@ -1,31 +0,0 @@
----
-title: >
- Should Drupal 7 support be extended again?
-pubDate: 2023-05-01
-permalink: >
- archive/2023/05/01/should-drupal-7-support-be-extended-again
-tags:
- - drupal
- - php
- - phpc
----
-
-Drupal 7, which was released in 2011, was originally supposed to be end-of-life in November 2022.
-
-This would mean there would be no more Drupal 7 versions and there would be no further support or bug fixes from the core Developer team.
-
-However, in February 2022, support was extended until November 2023 with a potential for it to be extended by another 12 months, which would be announced by July 2023.
-
-There are still over 425,000 active Drupal 7 websites according to - almost 100,000 fewer than Feburary 2022. That's still a lot of websites!
-
-Should support be extended again or should Drupal 7 be marked as end-of-life and unsupported?
-
-If so, those websites will continue to work, and an argument could be made that there's been enough time to upgrade projects since Drupal 8's first release in 2015.
-
-That said, it's a tricky upgrade - migrating data into a new Drupal website and re-writing custom modules and themes to make them compatible.
-
-It's definitely work upgrading, in my opinion, as the updates between Drupal 8, 9 and 10 are much simpler and quicker, and don't involve large rewrites or data migrations.
-
-Hit reply and let me know what you think.
-
-P.S. Are you still using Drupal 7 and don’t know what’s involved to upgrade to Drupal 10? Book a [Drupal 7 upgrade consultation call](https://www.oliverdavies.uk/call).
diff --git a/astro/src/content/daily-email/2023-05-02.md b/astro/src/content/daily-email/2023-05-02.md
deleted file mode 100644
index 16b67e25..00000000
--- a/astro/src/content/daily-email/2023-05-02.md
+++ /dev/null
@@ -1,25 +0,0 @@
----
-title: >
- Does it depend on who you ask?
-pubDate: 2023-05-02
-permalink: >
- archive/2023/05/02/does-it-depend-on-who-you-ask
-tags:
- - drupal
- - php
- - phpc
----
-
-The answer to "[Should Drupal 7 support be extended again?](https://www.oliverdavies.uk/archive/2023/05/01/should-drupal-7-support-be-extended-again)" might depend on who you ask.
-
-If you ask a Developer or agency, the answer would likely be that it shouldn't be extended again, and D7 should be sunsetted.
-
-Clients and end-users who haven't yet upgraded would likely say it should be extended.
-
-But if it's extended - and maybe again next year and the next - where's the incentive to upgrade?
-
-Some people won't upgrade regardless and will continue until their site breaks.
-
-That would be messy (and costly) to fix, though!
-
-P.S. Are you still using Drupal 7 and don’t know what’s involved to upgrade to Drupal 10? Book a [Drupal 7 upgrade consultation call](https://www.oliverdavies.uk/call).
diff --git a/astro/src/content/daily-email/2023-05-03.md b/astro/src/content/daily-email/2023-05-03.md
deleted file mode 100644
index 243190c6..00000000
--- a/astro/src/content/daily-email/2023-05-03.md
+++ /dev/null
@@ -1,25 +0,0 @@
----
-title: >
- Just because core is supported...
-pubDate: 2023-05-03
-permalink: >
- archive/2023/05/03/just-because-core-is-supported
-tags:
- - drupal
- - php
- - phpc
----
-
-Just because Drupal core is supported, it doesn't mean that all of the other modules your project uses are still also supported or actively worked on.
-
-Since the Drupal 8 release in 2015, I've seen numerous examples of modules that haven't been updated for some time as maintainers focus on writing and maintaining the versions for Drupal 8 and now 9 and 10.
-
-Whilst it isn't marked as unsupported, it isn't being updated either.
-
-I recently explained to a client that their site uses a module last released in 2014. It’s buggy, but there’s no newer version to use and issues in the queue are no longer being fixed or triaged.
-
-Override Node Options - a popular module I maintain - is in a similar situation. The most recent Drupal 9/10 version was in February 2023, whereas the last Drupal 7 release was in March 2018.
-
-I don't have any official figures to support this, but feel the contribution rate for Drupal 7 projects (as in modules, themes and distributions) has been slowing for some time.
-
-Meanwhile, Drupal 7 core is still supported, at least for now.
diff --git a/astro/src/content/daily-email/2023-05-04.md b/astro/src/content/daily-email/2023-05-04.md
deleted file mode 100644
index 5214039e..00000000
--- a/astro/src/content/daily-email/2023-05-04.md
+++ /dev/null
@@ -1,21 +0,0 @@
----
-title: >
- Speaking at the Symfony UK meetup in London
-pubDate: 2023-05-04
-permalink: >
- archive/2023/05/04/speaking-at-the-symfony-uk-meetup-london
-tags:
- - speaking
- - mob-programming
- - php
- - phpc
- - symfony
----
-
-After registering as an attendee, I've been upgraded to a speaker for next week's event and the first in-person Symfony UK meetup in two years.
-
-I'll be speaking about my experiences so far with mob programming - something that I spoke about at a PHP South Wales meetup last year.
-
-If you're interested and in London on the 11th of May, [find out more and register](https://www.meetup.com/symfony/events/293153957).
-
-Also, Happy Star Wars Day!
diff --git a/astro/src/content/daily-email/2023-05-05.md b/astro/src/content/daily-email/2023-05-05.md
deleted file mode 100644
index 6438b89c..00000000
--- a/astro/src/content/daily-email/2023-05-05.md
+++ /dev/null
@@ -1,19 +0,0 @@
----
-title: >
- Getting to green
-pubDate: 2023-05-05
-permalink: >
- archive/2023/05/05/getting-to-green
-tags:
- - automated-testing
- - testing
- - test-driven development
----
-
-When doing test-driven development, once you've written a failing (a.k.a. red) test, the main objective is to get to a green (a.k.a. passing) test as quickly as possible via the simplest method.
-
-Even if that means returning a hard-coded value.
-
-Once the test passes, it or the code it's testing can be refactored.
-
-Or you can move on to the next test and, if you need to change the hard-coded value to get both tests to pass, then it is the right time to do so.
diff --git a/astro/src/content/daily-email/2023-05-06.md b/astro/src/content/daily-email/2023-05-06.md
deleted file mode 100644
index 60381e7e..00000000
--- a/astro/src/content/daily-email/2023-05-06.md
+++ /dev/null
@@ -1,21 +0,0 @@
----
-title: >
- Why it's important to see the test fail
-pubDate: 2023-05-06
-permalink: >
- archive/2023/05/06/why-its-important-to-see-the-test-fail
-tags:
- - automated-testing
- - test-driven-development
----
-
-With automated testing and test-driven development, it's important to see a test fail.
-If a test passes straight away, how do you know that you're testing the right thing? You could be accidentally testing a different piece of functionality, or it could be a false positive.
-
-If the functionality already exists, do you need another test for it?
-
-When you see a test fail, you know that the functionality hasn't been implemented, that you're testing the correct thing, and you have a clear goal to work towards.
-
-If you're fixing a bug, writing a test and seeing it fail verifies the bug exists and that, once the bug is fixed, the test will pass.
-
-Usually, you can anticipate why a test will fail as it evolves and know when it will pass. If a test passes before I expect, I'm immediately sceptical and will look into why rather than assuming it passed for the right reasons.
diff --git a/astro/src/content/daily-email/2023-05-07.md b/astro/src/content/daily-email/2023-05-07.md
deleted file mode 100644
index bd89c688..00000000
--- a/astro/src/content/daily-email/2023-05-07.md
+++ /dev/null
@@ -1,20 +0,0 @@
----
-title: >
- You don't need to think about what to do next
-pubDate: 2023-05-07
-permalink: >
- archive/2023/05/07/you-dont-need-to-think-about-what-to-do-next
-tags:
- - automated-testing
- - test-driven-development
----
-
-When practising test-driven development, you don't need to think about what to do next.
-
-If you have a failing test, the objective is to get that test to pass as quickly and simply as possible, and you rely on the error from the failing test to tell you the next step.
-
-It could be a failing assertion, an undefined variable or function, or a yet-to-be-implemented service.
-
-Once you've fixed that error, the test will either pass or fail. If it fails, you'll have a new error and know the next step.
-
-When working in this way, it's like being on autopilot. You can focus only on fixing each error until the feature or fix is complete and the test is passing.
diff --git a/astro/src/content/daily-email/2023-05-08.md b/astro/src/content/daily-email/2023-05-08.md
deleted file mode 100644
index 7693ba59..00000000
--- a/astro/src/content/daily-email/2023-05-08.md
+++ /dev/null
@@ -1,16 +0,0 @@
----
-title: >
- Only write enough code to get a failing test
-pubDate: 2023-05-08
-permalink: >
- archive/2023/05/08/only-write-enough-code-to-get-a-failing-test
-tags:
- - automated-testing
- - test-driven-development
----
-
-Instead of writing a whole test and then attempting to make it pass, only write enough code to get the test to fail.
-
-This could be by starting with a failing assertion that is fixed with a hard-coded value and then iterating on the test to introduce the next failure before repeating the process.
-
-This allows you to keep the feedback loop small and not write more code than is needed, to focus on the objective of the test, and not code yourself into a corner.
diff --git a/astro/src/content/daily-email/2023-05-09.md b/astro/src/content/daily-email/2023-05-09.md
deleted file mode 100644
index f8c54c04..00000000
--- a/astro/src/content/daily-email/2023-05-09.md
+++ /dev/null
@@ -1,20 +0,0 @@
----
-title: >
- The single responsibility principle
-pubDate: 2023-05-09
-permalink: >
- archive/2023/05/09/the-single-responsibility-principle
-tags: []
----
-
-Today, I added a new feature to a project that allows a member to search for a node based on either its title or a specified field on that node, select a result from an autocomplete list and then be redirected to their selected node.
-
-I've already implemented this for other node types but needed to do the same for this node type.
-
-There are some differences, such as the node type to query for; the additional field depends on which node type as does the text shown in the autocomplete list.
-
-To do this, I needed to add a custom block and form, update the `AutocompleteController`, create a new instance of a `NodeQuery` class (a custom class within the custom module), register it as a service and update the `SearchQueryFactory` class.
-
-A principle that I follow as much as possible is the single responsibility principle, or SRP (the 'S' in SOLID), where each function or class only has one responsibility - such as returning a response for the autocomplete list, determining the correct node query to use based on the search being run or building the query itself - these are separated and split into their own files.
-
-Although more files and functions are created when coding in this way, though they are smaller and more straightforward to work with - which makes them easier to read, debug and maintain. It also makes code like the node query classes reusable as they aren't embedded within a larger class and are easier to test.
diff --git a/astro/src/content/daily-email/2023-05-10.md b/astro/src/content/daily-email/2023-05-10.md
deleted file mode 100644
index d3bf49a1..00000000
--- a/astro/src/content/daily-email/2023-05-10.md
+++ /dev/null
@@ -1,18 +0,0 @@
----
-title: >
- Tailwind CSS makes change easier
-pubDate: 2023-05-10
-permalink: >
- archive/2023/05/10/tailwind-css-makes-change-easier
-tags:
- - css
- - tailwind-css
----
-
-CSS usually has a global scope which can make change risky.
-
-How do you know that changing CSS in a global stylesheet to fix a bug won't cause more elsewhere?
-
-Tailwind CSS and utility classes change CSS to a local scope.
-
-You can see what styling is applied to an element by looking at its classes and easily make changes without worrying that it will cause unexpected issues elsewhere.
diff --git a/astro/src/content/daily-email/2023-05-11.md b/astro/src/content/daily-email/2023-05-11.md
deleted file mode 100644
index 2096d56e..00000000
--- a/astro/src/content/daily-email/2023-05-11.md
+++ /dev/null
@@ -1,18 +0,0 @@
----
-title: >
- Why I like pair and mob programming
-pubDate: 2023-05-11
-permalink: >
- archive/2023/05/11/why-i-like-pair-and-mob-programming
-tags:
- - pair-programming
- - mob-programming
----
-
-When working as part of a team, I like to do pair or mob programming as much as possible.
-
-I like being able to give and receive feedback in real-time; everyone can contribute to the solution and more shared knowledge, so there's less siloing, and it's much harder to block multiple people than a single person.
-
-Working in pairs or a mob is a great opportunity to onboard new team members, train and mentor, and share tips and tricks.
-
-It's usually more productive than working separately, and it's nice to speak and socialise with other team members whilst working on a task.
diff --git a/astro/src/content/daily-email/2023-05-12.md b/astro/src/content/daily-email/2023-05-12.md
deleted file mode 100644
index 5330fb34..00000000
--- a/astro/src/content/daily-email/2023-05-12.md
+++ /dev/null
@@ -1,18 +0,0 @@
----
-title: >
- Always listen to the mob
-pubDate: 2023-05-12
-permalink: >
- archive/2023/05/12/always-listen-to-the-mob
-tags:
- - pair-programming
- - mob-programming
----
-
-Something I'm aware of when working in a pair or mob is to always listen to input from other team members.
-
-A pair or mob session isn't just focused on one person's ideas or solution. It's a collaborative effort based on everyone's input, experience and ideas.
-
-If there are conflicting or different ideas or approaches, they can be discussed, and everyone can agree on the way forward. Approaches may also change as you learn more together during the session.
-
-Together, you will come up with the best solution - even if it's different from what you had in mind to begin with.
diff --git a/astro/src/content/daily-email/2023-05-13.md b/astro/src/content/daily-email/2023-05-13.md
deleted file mode 100644
index 7ef3433f..00000000
--- a/astro/src/content/daily-email/2023-05-13.md
+++ /dev/null
@@ -1,19 +0,0 @@
----
-title: >
- When You Do Things Right, People Won't Be Sure You've Done Anything at All
-pubDate: 2023-05-13
-permalink: >
- archive/2023/05/13/when-you-do-things-right
-tags:
- - software-development
----
-
-I think this quote from Futurama also applies well to software development:
-
-> When You Do Things Right, People Won’t Be Sure You’ve Done Anything at All
-
-Today I did multiple releases to production websites. There were no outages or downtime, or messages from clients or colleagues.
-
-Processes were followed, and everything worked as it should. As far as everyone's concerned, everything still "just works".
-
-So, did I do anything at all?
diff --git a/astro/src/content/daily-email/2023-05-14.md b/astro/src/content/daily-email/2023-05-14.md
deleted file mode 100644
index 7defa779..00000000
--- a/astro/src/content/daily-email/2023-05-14.md
+++ /dev/null
@@ -1,17 +0,0 @@
----
-title: >
- Releasing small changes often is less risky
-pubDate: 2023-05-14
-permalink: >
- archive/2023/05/14/releasing-small-changes-often-is-less-risky
-tags:
- - software-development
----
-
-Contrary to what many think (at least to begin with), releasing small, incremental changes often - maybe daily or weekly - is less risky than larger releases containing weeks or months of changes.
-
-If there is an issue after a large release, diagnosing and fixing it can take longer than a smaller release with fewer changes.
-
-You might have to revert and roll back to the previous release instead of being able to push a fix for a small change.
-
-With a small change, the risk of an issue is much lower as it has less chance to impact any other part of the application and is much easier for others to read, understand and debug.
diff --git a/astro/src/content/daily-email/2023-05-15.md b/astro/src/content/daily-email/2023-05-15.md
deleted file mode 100644
index a3f53e85..00000000
--- a/astro/src/content/daily-email/2023-05-15.md
+++ /dev/null
@@ -1,29 +0,0 @@
----
-title: >
- Is the Drupal release cycle too fast?
-pubDate: 2023-05-15
-permalink: >
- archive/2023/05/15/is-the-drupal-release-cycle-too-fast
-tags:
- - drupal
- - php
- - phpc
----
-
-Compared to Drupal 7, [which is almost at version 100](https://oliverdavies.dev/archive/2023/04/30/will-we-see-drupal-7-100), the release cycle from Drupal 9 onwards has been quite different.
-
-We've adopted semantic versioning with new feature releases every six months, and we've already sunsetted Drupal 8 and moved on to Drupal 9 and 10.
-
-Major versions are released more quickly, with Drupal 9 support ending in November 2023 and Drupal 11 potentially being released in May or November 2024.
-
-But is it too quick, as someone asked on Twitter?
-
-The main reason I'm aware of is to keep in sync with major versions of projects that Drupal uses, such as the components used by Symfony. As they update and release new major versions, we also need to do so.
-
-As a module and theme maintainer, I don't think it's too fast and have been happy with the number of changes to upgrade them and make them Drupal 10 compatible. In most cases, I only had to change the `core_version_requirement` key to include the new version.
-
-It depends on how well the project is maintained during the earlier versions. If you keep up to date with changes in minor versions and remove any deprecated code, there will be less to do in the future.
-
-The same applies to any custom code within website projects, not just contributed modules and themes.
-
-The more often you maintain and update what you have; the easier it will be.
diff --git a/astro/src/content/daily-email/2023-05-16.md b/astro/src/content/daily-email/2023-05-16.md
deleted file mode 100644
index 0528b4a0..00000000
--- a/astro/src/content/daily-email/2023-05-16.md
+++ /dev/null
@@ -1,19 +0,0 @@
----
-title: >
- Mastering your tools improves productivity
-pubDate: 2023-05-16
-permalink: >
- archive/2023/05/16/mastering-your-tools-improves-productivity
-tags:
- - software-development
----
-
-Spending time to learn and master your tools, whether it's your IDE or text editor, CMS or framework, or something else that you use regularly like Git, spending time to expand on the basics and learn it more thoroughly is an investment in your future.
-
-I try to keep up to date with the latest additions and changes to Drupal and the PHP language so that I can be more productive and write better and cleaner code.
-
-I invest time to make my development environment and tools work as effectively and efficiently as possible. If I can make it easier and quicker to perform simple tasks like navigating to and creating files, and scaffolding new content within them, that time will be paid back in future time saved.
-
-If I find a new plugin, module, theme or tool that will make future tasks easier - even something as easy as commenting out a line or block of code - putting aside some time to investigate and evaluate it and decide if I want to use it is time well spent.
-
-As someone said in a video recently, "you invest time now to buy back time later".
diff --git a/astro/src/content/daily-email/2023-05-17.md b/astro/src/content/daily-email/2023-05-17.md
deleted file mode 100644
index 08b25f59..00000000
--- a/astro/src/content/daily-email/2023-05-17.md
+++ /dev/null
@@ -1,34 +0,0 @@
----
-title: >
- What is deprecated code?
-pubDate: 2023-05-17
-permalink: >
- archive/2023/05/17/what-is-deprecated-code
-tags:
- - php
- - drupal
- - software-development
----
-
-Deprecating code is a way of identifying code that will be removed in a future major version.
-
-For example, the `drupal_set_message()` function was deprecated in Drupal 8.5 and removed in Drupal 9 as the `messenger` service replaced it.
-
-Once it was deprecated, the function was changed to use the new service to avoid duplicating code and a message was added to notify Developers:
-
-```php
-function drupal_set_message($message = NULL, $type = 'status', $repeat = FALSE) {
- @trigger_error('drupal_set_message() is deprecated in Drupal 8.5.0 and will be removed before Drupal 9.0.0. Use \Drupal\Core\Messenger\MessengerInterface::addMessage() instead. See https://www.drupal.org/node/2774931', E_USER_DEPRECATED);
-
- $messenger = \Drupal::messenger();
- if (isset($message)) {
- $messenger->addMessage($message, $type, $repeat);
- }
-
- return $messenger->all();
-}
-```
-
-This approach means that code can be refactored without breaking backwards-compatibility and, to upgrade any custom code to be compatible with Drupal 9, any references to `drupal_set_message()` just needed to be updated to use the new Messenger service.
-
-No large rewrite needed!
diff --git a/astro/src/content/daily-email/2023-05-18.md b/astro/src/content/daily-email/2023-05-18.md
deleted file mode 100644
index 33514f44..00000000
--- a/astro/src/content/daily-email/2023-05-18.md
+++ /dev/null
@@ -1,17 +0,0 @@
----
-title: >
- Why is backward compatibility important?
-pubDate: 2023-05-18
-permalink: >
- archive/2023/05/18/why-is-backward-compatibility-important
-tags:
- - software-development
----
-
-In yesterday's email, I mentioned that deprecating code allows it to be backwards compatible - but what does that mean?
-
-If I were to remove a function like `drupal_set_message()` that is used code elsewhere in an application, the code would no longer work and would break.
-
-As a module or library maintainer, I don't want to cause applications to break by making backward incompatible changes (a "BC break" or a "breaking change").
-
-Maintaining backward compatibility means that people who use the code can update to the latest version without breakages, and if they use any deprecated code, they know to update it to be compatible with future versions.
diff --git a/astro/src/content/daily-email/2023-05-19.md b/astro/src/content/daily-email/2023-05-19.md
deleted file mode 100644
index 91ce219c..00000000
--- a/astro/src/content/daily-email/2023-05-19.md
+++ /dev/null
@@ -1,19 +0,0 @@
----
-title: >
- Semantic versioning
-pubDate: 2023-05-19
-permalink: >
- archive/2023/05/19/semantic-versioning
-tags:
- - software-development
----
-
-The version number of a release is a key indicator of whether it’s compatible with existing code.
-
-Semantic versioning is a popular approach used by Drupal core, and many contributed modules, themes and distributions.
-
-It uses version numbers like 1.0.0 to show the major, minor and patch versions.
-
-If the second or third number changes, e.g. 1.1.0 or 1.0.1, the release contains new backwards-compatible features or fixes, so it’s safe to update.
-
-If the first number changes, e.g. 2.0.0, the release is not backwards compatible and contains breaking changes that you’ll need to review and update your code accordingly.
diff --git a/astro/src/content/daily-email/2023-05-20.md b/astro/src/content/daily-email/2023-05-20.md
deleted file mode 100644
index af772222..00000000
--- a/astro/src/content/daily-email/2023-05-20.md
+++ /dev/null
@@ -1,19 +0,0 @@
----
-title: >
- A minor breaking change
-pubDate: 2023-05-20
-permalink: >
- archive/2023/05/20/a-minor-breaking-change
-tags:
- - software-development
----
-
-Today, in the repository of an open-source project, I saw an issue comment saying, "This is a minor breaking change.".
-
-It detailed what was removed and suggested an alternative.
-
-I don't know how you define a "minor" breaking change.
-
-Is it because it's a single line and easy to replace, or is it part of the code that is rarely used by consumers and less likely to cause an issue?
-
-Regardless, if it's a breaking change, anyone using that project will need to update their code if they use something that was removed, whether it's minor or not.
diff --git a/astro/src/content/daily-email/2023-05-21.md b/astro/src/content/daily-email/2023-05-21.md
deleted file mode 100644
index ce732fe9..00000000
--- a/astro/src/content/daily-email/2023-05-21.md
+++ /dev/null
@@ -1,19 +0,0 @@
----
-title: >
- Drupal 9: almost end-of-life already
-pubDate: 2023-05-21
-permalink: >
- archive/2023/05/21/drupal-9-almost-end-of-life-already
-tags:
- - drupal
- - php
- - phpc
----
-
-With the focus being on Drupal 7's potential end-of-life this November, it's also worth being aware that Drupal 9 (released in June 2020) will also be unsupported as of November 2023.
-
-This is because of its dependency on Symfony 4, which is ending its security support in November.
-
-Drupal 10 was released in December 2022 and will be the main version until Drupal 11 is released in 2024.
-
-Luckily, major upgrades of Drupal are much easier these days, with no large code rewrite or data migration required.
diff --git a/astro/src/content/daily-email/2023-06-05.md b/astro/src/content/daily-email/2023-06-05.md
deleted file mode 100644
index bd289c1a..00000000
--- a/astro/src/content/daily-email/2023-06-05.md
+++ /dev/null
@@ -1,19 +0,0 @@
----
-title: >
- How long should a feature flag live?
-pubDate: 2023-06-05
-permalink: >
- archive/2023/06/05/how-long-should-a-feature-flag-live
-tags:
- - software-development
- - software-engineering
- - feature-flags
----
-
-Instead of creating a branch that lives for as long as the code takes to write, if it's behind a feature flag, the code can be merged into the mainline branch without affecting the rest of the codebase.
-
-Being able to release changes incrementally lowers the risk compared to releasing a large change all at once.
-
-But the same issue can occur with feature flags, and the longer that code is behind a feature flag, the more risk there will be when enabling the feature.
-
-So, like feature branches, feature flags should be short-lived and only used for as long as is needed to create the first releasable version of the feature. The feature flag can be removed once the feature is live, and the feature can continue to be iterated on and improved.
diff --git a/astro/src/content/daily-email/2023-06-06.md b/astro/src/content/daily-email/2023-06-06.md
deleted file mode 100644
index d10a4c6e..00000000
--- a/astro/src/content/daily-email/2023-06-06.md
+++ /dev/null
@@ -1,19 +0,0 @@
----
-title: >
- Drupal 7 end-of-life extended
-pubDate: 2023-06-06
-permalink: >
- archive/2023/06/06/drupal-7-end-of-life-extended
-tags:
- - drupal
- - php
- - phpc
----
-
-It was announced this week at DrupalCon that the end-of-life date for Drupal 7 has been extended until the 5th of January 2025, giving another year for people to upgrade the 40,000+ Drupal 7 websites.
-
-Whilst there's no official announcement yet, it seems this is the final extension and will be when support ends.
-
-Of course, it doesn't mean all of the contributed modules, themes and distributions will be supported or updated until then, but this will give additional time to plan and migrate the remaining Drupal 7 websites whilst still giving clarity by setting a final date that will not be extended again.
-
-If you're still on Drupal 7 and need to learn more about upgrading to Drupal 10, [book an advisory call](https://www.oliverdavies.uk/call) or [an upgrade roadmap](https://www.oliverdavies.uk/drupal7) for your Drupal 7 project.
diff --git a/astro/src/content/daily-email/2023-06-07.md b/astro/src/content/daily-email/2023-06-07.md
deleted file mode 100644
index 42f80176..00000000
--- a/astro/src/content/daily-email/2023-06-07.md
+++ /dev/null
@@ -1,27 +0,0 @@
----
-title: >
- What does the Drupal 7 EOL extension mean to you?
-pubDate: 2023-06-07
-permalink: >
- archive/2023/06/07/what-does-the-drupal-7-eol-extension-mean-to-you
-tags:
- - drupal
- - drupal-7
- - php
----
-
-Following the announcement at DrupalCon, the official announcement has been released regarding Drupal 7's end-of-life extension:
-
-> Today, we are officially announcing that Drupal 7 will reach its end of life on January 5, 2025.
->
-> With this final extension, the Drupal Security Team is also adjusting the level of support provided.
->
-> This will be the final extension.
-
-If you're involved with one of the ~400,000 Drupal 7 websites (according to https://www.drupal.org/project/usage/drupal), what does the additional year and a half of Drupal 7 mean to you?
-
-Will you use the time to find the budget to upgrade, assemble a migration plan, port any missing contributed modules or refactor your custom modules or theme to make it easier to upgrade?
-
-Is it different knowing it’s the final extension compared to the previous time when it wasn’t known if it would be extended again?
-
-If you're stuck on Drupal 7 or staying on it into 2024 or 2025, what's stopping you from upgrading?
diff --git a/astro/src/content/daily-email/2023-06-08.md b/astro/src/content/daily-email/2023-06-08.md
deleted file mode 100644
index 786006f8..00000000
--- a/astro/src/content/daily-email/2023-06-08.md
+++ /dev/null
@@ -1,18 +0,0 @@
----
-title: >
- Write less Drupal code
-pubDate: 2023-06-08
-permalink: >
- archive/2023/06/08/write-less-drupal-code
-tags:
- - drupal
- - php
----
-
-An approach I like to make my Drupal code more maintainable is to write less of it and move any generic PHP code into separate framework-agnostic libraries.
-
-These could be in open-sourced packages installed from Packagist or kept within the same repository.
-
-Having less Drupal-specific code keeps modules smaller and easier to maintain and upgrade.
-
-If I need to upgrade a module from Drupal 7 to Drupal 10, I can reuse the generic code and focus on changing its integration points with Drupal to make it compatible.
diff --git a/astro/src/content/daily-email/2023-06-09.md b/astro/src/content/daily-email/2023-06-09.md
deleted file mode 100644
index e196f5c0..00000000
--- a/astro/src/content/daily-email/2023-06-09.md
+++ /dev/null
@@ -1,20 +0,0 @@
----
-title: >
- Drupal is built by people
-pubDate: 2023-06-09
-permalink: >
- archive/2023/06/09/drupal-is-built-by-people
-tags:
- - drupal
- - php
----
-
-A quote I heard from DrupalCon, made by my former colleague Tim Lehnen - CTO at the Drupal Association - when talking about contribution:
-
-> Contribution is what makes Drupal thrive.
->
-> Drupal is built by people.
->
-> No one entity, no one person builds Drupal.
->
-> It's you who builds Drupal.
diff --git a/astro/src/content/daily-email/2023-06-10.md b/astro/src/content/daily-email/2023-06-10.md
deleted file mode 100644
index b359908e..00000000
--- a/astro/src/content/daily-email/2023-06-10.md
+++ /dev/null
@@ -1,15 +0,0 @@
----
-title: >
- How do you know when to remove a feature flag?
-pubDate: 2023-06-10
-permalink: >
- archive/2023/06/10/how-do-you-know-when-to-remove-a-feature-flag
-tags:
- - feature-flags
----
-
-But once a feature has been enabled, how do you know if you can remove its flag?
-
-A simple suggestion I've heard is to add a "Remove when..." comment above where the flag is used and detail what conditions need to be in place before the flag can be removed.
-
-It might be a period of time or after another feature has been shipped, but it will give some clarity when you see the flag in the code to if or when it can be removed.
diff --git a/astro/src/content/daily-email/2023-06-11.md b/astro/src/content/daily-email/2023-06-11.md
deleted file mode 100644
index 8cac2921..00000000
--- a/astro/src/content/daily-email/2023-06-11.md
+++ /dev/null
@@ -1,14 +0,0 @@
----
-title: >
- Failing fast
-pubDate: 2023-06-11
-permalink: >
- archive/2023/06/11/failing-fast
-tags: []
----
-
-Usually, failing fast in software development refers to errors in code, but another interpretation of this is "What's the quickest and simplest way to validate or prove an idea"?
-
-If it's fixing a bug or architecting a new feature, what's the simplest thing that can be done to achieve that? It could be writing a technical document or creating a simple proof of concept rather than building the entire feature.
-
-If it fails, your sunk cost is low as you've not invested much time, money or energy.
diff --git a/astro/src/content/daily-email/2023-06-12.md b/astro/src/content/daily-email/2023-06-12.md
deleted file mode 100644
index 5c780e62..00000000
--- a/astro/src/content/daily-email/2023-06-12.md
+++ /dev/null
@@ -1,17 +0,0 @@
----
-title: >
- Feature flags in a multi-tenancy application
-pubDate: 2023-06-12
-permalink: >
- archive/2023/06/12/feature-flags-in-a-multi-tenancy-application
-tags:
- - feature-flags
----
-
-A scenario for having long-lived feature flags is in a multi-tenant application where the same codebase serves multiple projects - e.g. a multi-site Drupal application or a module reused on multiple websites.
-
-This is the use case I have for a client project which uses a multi-site setup to serve multiple websites from the same Drupal codebase.
-
-If I need to add a feature to sites 1 and 3 but not site 2 or test a change to only site 2, I can do this by enabling a per-site feature flag.
-
-Instead of being removed, these flags will remain until the change can be made permanent on all websites, meaning it can be toggled on and off as needed - allowing each site to be configured separately whilst keeping it easy to maintain by having a single canonical codebase.
diff --git a/astro/src/content/daily-email/2023-06-13.md b/astro/src/content/daily-email/2023-06-13.md
deleted file mode 100644
index 90ff4ed8..00000000
--- a/astro/src/content/daily-email/2023-06-13.md
+++ /dev/null
@@ -1,17 +0,0 @@
----
-title: >
- Should you feature flag everything?
-pubDate: 2023-06-13
-permalink: >
- archive/2023/06/13/should-you-feature-flag-everything
-tags:
- - feature-flags
----
-
-Whilst it's probably impractical to feature flag every new feature or change to your application, considering it is something I do for each change.
-
-If you find a bug after a feature has been released, if it's feature flagged, you can quickly disable it without needing to make a code change or release another version.
-
-Instead of needing a rollback plan for a release and reverting to the previous version, it can be as simple as disabling the feature flag again to turn it off whilst the cause is investigated.
-
-There is a maintenance overhead to adding a feature flag, and it can cause complexity by creating separate paths within the code but using feature flags gives a lot of benefits too.
diff --git a/astro/src/content/daily-email/2023-06-14.md b/astro/src/content/daily-email/2023-06-14.md
deleted file mode 100644
index 58d3cb51..00000000
--- a/astro/src/content/daily-email/2023-06-14.md
+++ /dev/null
@@ -1,27 +0,0 @@
----
-title: >
- What if there was no open-source software
-pubDate: 2023-06-14
-permalink: >
- archive/2023/06/14/what-if-there-was-no-open-source-software
-tags:
- - open-source
----
-
-I was listening to a podcast today, and the question was mentioned - "What if there was no open-source software?".
-
-As a self-taught Developer who has worked with open-source technologies and become an expert in Drupal - an open-source content management system - this would have had a big effect.
-
-If there were no open-source frameworks or CMSes like Drupal, Symfony, Laravel or Vue.js, Developers would need to write everything from scratch, and companies would need to pay for the extra time.
-
-There would be no reusable knowledge as Developers move to different companies as everything would be written in-house.
-
-There would be no communities and events like conferences and meetups for open-source technologies.
-
-As well as frameworks, what about languages like PHP that are open-sourced? Would companies also need to write and maintain their own programming languages?
-
-What about Linux, which I use every day for my desktop environment and servers, and other tools like Neovim, PHPStan, PHPUnit and Pest that are all open-source?
-
-Even as someone who contributes to and sponsors open-source projects and their Developers, it's still a shock to think how things would work without open-source software.
-
-If you use open-source software, please consider sponsoring, supporting or contributing to the projects you use and depend on.
diff --git a/astro/src/content/daily-email/2023-06-15.md b/astro/src/content/daily-email/2023-06-15.md
deleted file mode 100644
index c92ed1a5..00000000
--- a/astro/src/content/daily-email/2023-06-15.md
+++ /dev/null
@@ -1,18 +0,0 @@
----
-title: >
- Done is better than perfect
-pubDate: 2023-06-15
-permalink: >
- archive/2023/06/15/done-is-better-than-perfect
-tags: []
----
-
-Whether I'm doing test-driven development or not, I focus on making the feature work or fixing the bug in the simplest way possible.
-
-Then, once this is done, I can pass through the code again and refactor it as needed.
-
-I can split code into separate files, move logic from the Controller into separate services, ensure that patterns like dependency injection are followed, and checks like coding standards and static analysis are passing.
-
-I might deploy a change in its passing state and leave TODO comments or create follow-up issues to describe potential refactors or changes to be addressed later.
-
-The main goal is to get the application working and providing value for its users.
diff --git a/astro/src/content/daily-email/2023-06-16.md b/astro/src/content/daily-email/2023-06-16.md
deleted file mode 100644
index 3fb11962..00000000
--- a/astro/src/content/daily-email/2023-06-16.md
+++ /dev/null
@@ -1,20 +0,0 @@
----
-title: >
- Make the change easy, then make the easy change
-pubDate: 2023-06-16
-permalink: >
- archive/2023/06/16/make-the-easy-change
-tags: []
----
-
-Have you worked on some code, whether it's to add or extend functionality or fix a bug and thought, "This would be much easier if..."?
-
-A quote by Kent Beck:
-
-> For each desired change, make the change easy (warning: this may be hard), then make the easy change
-
-If you can refactor the code and make it easier to implement your required change, do so.
-
-Any automated tests should be passing before and after, and I'd commit the refactored code to ensure any CI pipelines and checks are still passing.
-
-Then, go ahead and make the required change - add the feature or fix the bug - which should now be easy.
diff --git a/astro/src/content/daily-email/2023-06-17.md b/astro/src/content/daily-email/2023-06-17.md
deleted file mode 100644
index ca131161..00000000
--- a/astro/src/content/daily-email/2023-06-17.md
+++ /dev/null
@@ -1,26 +0,0 @@
----
-title: >
- Avoid Git merge hell with trunk-based development
-pubDate: 2023-06-17
-permalink: >
- archive/2023/06/17/avoid-git-merge-hell-with-trunk-based-development
-tags:
- - git
- - trunk-based-development
----
-
-Regardless of whether I was working as part of a team or individually, I used to create a new branch for every change. I'd do the work and merge the feature branch back into the mainline branch - usually either `main` or `develop`.
-
-When working on a team, conflicts are common that prevent different changes from being merged, and they're more likely the more time it's been since the last merge and how large the change is.
-
-Once, when demoing some in-progress work to a freelance client, I needed to switch branches as the changes were on different feature branches. Doing so broke my local environment and derailed the demo.
-
-## Trunk-based development
-
-These days, I advocate for and prefer to use trunk-based development. Instead of committing changes to feature branches, they are made directly to the mainline branch.
-
-As there are no feature branches, there are no merge conflicts when merging into mainline.
-
-Although there can still be conflicts when pulling remote changes, trunk-based development pairs nicely with continuous integration - when everyone works in small commits and pushes changes at least once daily. This makes conflicts less likely but also smaller and easier to resolve, and because everyone's changes are not hidden on feature branches, you know they will integrate and work together.
-
-It also stops me from breaking my environment during client demos!
diff --git a/astro/src/content/daily-email/2023-06-18.md b/astro/src/content/daily-email/2023-06-18.md
deleted file mode 100644
index 62886848..00000000
--- a/astro/src/content/daily-email/2023-06-18.md
+++ /dev/null
@@ -1,28 +0,0 @@
----
-title: >
- Are you really doing CI/CD?
-pubDate: 2023-06-18
-permalink: >
- archive/2023/06/18/are-you-doing-ci-cd
-tags:
- - continuous-integration
- - continuous-delivery
- - continuous-deployment
----
-
-Does your team really do CI/CD (continuous integration and delivery)?
-
-I recently watched a recording of a talk from another daily emailer, [Jonathan Hall](https://jhall.io), who started by asking the audience to raise their hands and keep them raised if...
-
-* They did a release to production in the last week.
-* They did a release to production yesterday.
-* They do not have a permanent branch called `develop`.
-* They do not have a special "hotfix" procedure.
-* Every Developer on their team merged work into `main` yesterday.
-* They have no pull requests more than 24 hours old.
-
-## CI/CD is about process
-
-This is an excellent way to highlight that CI/CD is about processes, not technologies.
-
-Continuous integration is about how often everyone merges and pushes their changes, and continuous delivery and deployment is how you create releasable software and how long it takes for a change to get into production - not whether or not you use GitHub Actions, GitLab CI, CircleCI or Jenkins.
diff --git a/astro/src/content/daily-email/2023-06-19.md b/astro/src/content/daily-email/2023-06-19.md
deleted file mode 100644
index da5ef17d..00000000
--- a/astro/src/content/daily-email/2023-06-19.md
+++ /dev/null
@@ -1,38 +0,0 @@
----
-title: >
- Should you upgrade from Drupal 7 to Drupal 10?
-pubDate: 2023-06-19
-permalink: >
- archive/2023/06/19/should-you-upgrade-from-drupal-7-to-drupal-10
-tags:
- - drupal
- - drupal-7
----
-
-If you're stuck on Drupal 7, why should you upgrade to Drupal 10 instead of moving to another platform?
-
-## Familarity
-
-Although there is a new admin theme, it works in the same way as it did in earlier versions of Drupal, so it will be familiar to anyone who is used to using or developing in it.
-
-And whilst there have been differences since Drupal 8, creating modules and themes should seem familiar too with similar concepts such as `.info` files (now `.info.yml` files), hooks, preprocess functions and templates.
-
-## Code reuse
-
-If you have existing custom modules, you should be able to reuse some of its code in newer versions of Drupal. It might need to be restructured or refactored and will depend on how tightly coupled your business logic is to your Drupal code, but if, for example, you have a custom module that creates a node programmatically, the same can be done in newer Drupal versions.
-
-## Built-in migration tools
-
-Whilst you do need to migrate your data from Drupal 7 into Drupal 10, the newer versions come with built-in migration tools that recreate your content types etc first as well as moving the data so you don't need to start from scratch.
-
-## New versions of existing modules
-
-Many modules and themes you use in Drupal 7 will either have equivalent versions for Drupal 10 or a nominated alternative (such as Field Collection to Paragraphs), so you don't need to look for a new solution if there's an updated version of something you already use.
-
-## Conclusion
-
-These are the initial things that I thought of, but there are many other reasons to upgrade to Drupal 10 instead of moving to something else.
-
-TLDR - you don't need to start from scratch if you can re-use parts of your existing code, and you can use the built-in modules to handle the data migration.
-
-If you have a reason, reply to let me know, and I'll post another list.
diff --git a/astro/src/content/daily-email/2023-06-20.md b/astro/src/content/daily-email/2023-06-20.md
deleted file mode 100644
index 5bb6fa25..00000000
--- a/astro/src/content/daily-email/2023-06-20.md
+++ /dev/null
@@ -1,29 +0,0 @@
----
-title: >
- Should you deploy on a Friday?
-pubDate: 2023-06-20
-permalink: >
- archive/2023/06/20/should-you-deploy-on-a-friday
-tags:
- - deployments
----
-
-There's a common saying about not deploying changes on a Friday to prevent outages or issues before the weekend.
-
-I've also seen this where people won't deploy after a particular time of the day as it's too close to the evening.
-
-## When did you last deploy?
-
-The longer it's been since the last deployment, the risker each deployment is.
-
-If there are weeks or months of changes, it will be risky regardless of which day it is.
-
-If your last deployment was an afternoon, deploying a small change the following morning will be low risk, even on a Thursday and Friday.
-
-## Conclusion
-
-If you're nervous about deploying on a Friday, I think you need to aim for smaller and more frequent deployments to minimise the risk.
-
-The issue isn't when you're deploying. You likely need to do so more often.
-
-If there is an issue after a large release, it will take more time to debug or roll back compared to a small release which is easier to find and fix the problem or revert that single change.
diff --git a/astro/src/content/daily-email/2023-06-21.md b/astro/src/content/daily-email/2023-06-21.md
deleted file mode 100644
index ce1a878b..00000000
--- a/astro/src/content/daily-email/2023-06-21.md
+++ /dev/null
@@ -1,18 +0,0 @@
----
-title: >
- Deployments or releases
-pubDate: 2023-06-21
-permalink: >
- archive/2023/06/21/deployments-or-releases
-tags:
- - deployments
- - releases
----
-
-"Deployments" and "releases" are often used interchangeably but mean different things.
-
-A deployment moves a change from one place to another, such as some updated code from a staging environment to production.
-
-A release is when the change made is available to users.
-
-They can happen at the same time, or you can use feature flags to separate them, deploying the code in advance, and the change is only released (or unreleased) by toggling the feature flag.
diff --git a/astro/src/content/daily-email/2023-06-22.md b/astro/src/content/daily-email/2023-06-22.md
deleted file mode 100644
index c8e7b172..00000000
--- a/astro/src/content/daily-email/2023-06-22.md
+++ /dev/null
@@ -1,14 +0,0 @@
----
-title: >
- It's only a bad situation if you fail to learn from it
-pubDate: 2023-06-22
-permalink: >
- archive/2023/06/22/fail-to-lear
-tags: []
----
-
-I heard this on a non-tech podcast but it applies to tech too:
-
-> It's only a bad situation if you fail to learn from it
-
-Whether its a missed deadline, a failed deployment, a production outage or pushing a bug to production, there are opportunities to learn and improve.
diff --git a/astro/src/content/daily-email/2023-06-23.md b/astro/src/content/daily-email/2023-06-23.md
deleted file mode 100644
index f1bb08d3..00000000
--- a/astro/src/content/daily-email/2023-06-23.md
+++ /dev/null
@@ -1,39 +0,0 @@
----
-title: >
- Why keep a Changelog?
-pubDate: 2023-06-23
-permalink: >
- archive/2023/06/23/why-keep-a-changelog
-tags:
- - changelog
----
-
-
-## What is a Changelog?
-
-A Changelog is a file that documents changes made to a codebase.
-
-In its simplest form, it's a plain text file within a code repository, or it can be written in Markdown or reStructuredText or kept within a separate tool like Confluence or Sharepoint. Regardless of where it's kept, the main thing is the content.
-
-It's not a copy of the Git log. It's a summary of the changes to be read by humans and for them to see what's changed, not a list of Git commits.
-
-If you're considering using my open-source package, you can see what changes I've released, when, and what changes are due to release.
-
-
-## How is it structured?
-
-Each version should have a heading specifying the version number and/or release date and a list of changes grouped by their type - whether something was added, changed, deprecated, removed, etc. This works well if you use conventional commits!
-
-I like to follow a format called [Keep a Changelog](https://keepachangelog.com).
-
-The headings link to a diff so you can see all of the commits and changes made to the code, and there's an `Unreleased` section that shows commits that have yet to be tagged and released.
-
-If you need to present changes to a review or approval board, having an easy-to-read list of changes, separated by their type, is a much clearer format than a list of Git commits.
-
-## When should it be updated?
-
-I recommend continually updating the Changelog rather than leaving it to just before a deployment. It's quick to add it to the `Unreleased` section as part of the commit and update the headings later.
-
-## Can I see an example?
-
-Sure. See the one I added to the [National Rail Enquiries feed parser library](https://github.com/opdavies/national-rail-enquiries-feed-parser/blob/main/CHANGELOG.md) I've been working on or the [Tailwind CSS starter kit theme for Drupal](https://git.drupalcode.org/project/tailwindcss/-/blob/5.x/CHANGELOG.md).
diff --git a/astro/src/content/daily-email/2023-06-24.md b/astro/src/content/daily-email/2023-06-24.md
deleted file mode 100644
index 4185442f..00000000
--- a/astro/src/content/daily-email/2023-06-24.md
+++ /dev/null
@@ -1,24 +0,0 @@
----
-title: >
- Credited on 200 fixed issues on Drupal.org
-pubDate: 2023-06-24
-permalink: >
- archive/2023/06/24/credited-on-200-fixed-issues
-tags:
- - drupal
- - open-source
----
-
-While writing yesterday's email, I saw this on my Drupal.org profile (https://www.drupal.org/u/opdavies):
-
-> Credited on 200 fixed issues
-
-This is not the number of commits I've made to projects and doesn't include issues on other websites like GitHub, but that I've been tagged as a contributor in 200 fixed issues on Drupal.org - aka "contribution credits".
-
-It includes issues for projects I maintain, like Override Node Options and the Tailwind CSS starter kit, as well as contributions for events I've spoken at, like DrupalCon Europe and BADCamp, and modules for Drupal.org itself that I worked on whilst at the Drupal Association.
-
-It also includes contrib projects others maintain, such as the Feature Toggle module and Drupal Commerce, and distributions like Commerce Kickstart and Open Atrium.
-
-In particular, I'm proud of the 17 issues for Drupal core - some for patches I've contributed, some I've reviewed, and some whilst I've mentored at events like DrupalCons and DrupalCamps.
-
-I've been allocating more open-source time recently, so expect the number of contributions on Drupal.org and GitHub to continue.
diff --git a/astro/src/content/daily-email/2023-06-25.md b/astro/src/content/daily-email/2023-06-25.md
deleted file mode 100644
index cf4cca17..00000000
--- a/astro/src/content/daily-email/2023-06-25.md
+++ /dev/null
@@ -1,16 +0,0 @@
----
-title: >
- Do you need permission to do Test-Driven Development?
-pubDate: 2023-06-25
-permalink: >
- archive/2023/06/25/do-you-need-permission-test-driven-development
-tags:
- - automated-testing
- - test-driven-development
----
-
-Something I've been asked before is "Do you need permission to write automated tests or do Test-Driven Development?".
-
-A response I heard recently was "Does a surgeon ask if they can wash their hands before operating?".
-
-The same as when I take my car to a garage, I expect the mechanic to do the appropriate diagnostic, repair work and testing to make it's working correctly and safely.
diff --git a/astro/src/content/daily-email/2023-06-26.md b/astro/src/content/daily-email/2023-06-26.md
deleted file mode 100644
index a0b03c9a..00000000
--- a/astro/src/content/daily-email/2023-06-26.md
+++ /dev/null
@@ -1,17 +0,0 @@
----
-title: >
- Is any code without tests legacy code?
-pubDate: 2023-06-26
-permalink: >
- archive/2023/06/26/is-any-code-without-tests-legacy
-tags:
- - automated-testing
----
-
-While I can't find the original quote, I've heard numerous people describe any code without automated tests as legacy.
-
-Legacy code is typically inherited from other Developers and is riskier to work on and harder to change, as there is no guarantee changing one piece of code won't cause breakages elsewhere in the codebase.
-
-This is true for code that doesn't have accompanying automated tests, regardless of when it was written.
-
-I can release a feature to an environment, and although it may be checked and tested at the time, it likely won't be again for every subsequent release. Automated tests can run automatically for every commit and before every deployment, ensuring the code continues to work and for it to be edited without causing regressions.
diff --git a/astro/src/content/daily-email/2023-06-27.md b/astro/src/content/daily-email/2023-06-27.md
deleted file mode 100644
index 08b24001..00000000
--- a/astro/src/content/daily-email/2023-06-27.md
+++ /dev/null
@@ -1,20 +0,0 @@
----
-title: >
- A CI pipeline is like an additional team member
-pubDate: 2023-06-27
-permalink: >
- archive/2023/06/27/ci-pipeline-additional-team-member
-tags:
- - continuous-integration
- - pipelines
----
-
-Imagine having a team member who tests each feature before every deployment, reviews the code to ensure its style is consistent, runs quality checks like linting and static analysis, and checks for insecure dependencies.
-
-If those checks all pass, they automatically deploy the changes and make them live or update a pre-production environment.
-
-## Here's the thing
-
-A CI pipeline can do that. Automatically. For every commit and change to your codebase.
-
-Having a CI pipeline is like having an additional team member and one who's always ready and waiting for someone to push a change to test.
diff --git a/astro/src/content/daily-email/2023-06-28.md b/astro/src/content/daily-email/2023-06-28.md
deleted file mode 100644
index 964625e0..00000000
--- a/astro/src/content/daily-email/2023-06-28.md
+++ /dev/null
@@ -1,20 +0,0 @@
----
-title: >
- There's no value in a broken CI pipeline
-pubDate: 2023-06-28
-permalink: >
- archive/2023/06/28/theres-no-value-in-a-broken-ci-pipeline
-tags:
- - continuous-integration
- - pipelines
----
-
-The value in a CI pipeline is when its commands and checks are running successfully, and the pipeline is passing.
-
-And then keeping it passing.
-
-If the pipeline fails, it loses all of its value.
-
-Passing should be its default state, and effort should be made to ensure it continues to pass.
-
-If a pipeline fails, the change is not deployed, and the failure should be investigated and rectified so the pipeline is returned to a passing state and providing value.
diff --git a/astro/src/content/daily-email/2023-06-29.md b/astro/src/content/daily-email/2023-06-29.md
deleted file mode 100644
index 3f53ad51..00000000
--- a/astro/src/content/daily-email/2023-06-29.md
+++ /dev/null
@@ -1,24 +0,0 @@
----
-title: >
- Tests won't tell you if your code works
-pubDate: 2023-06-29
-permalink: >
- archive/2023/06/29/tests-wont-tell-you-if-your-code-works
-tags:
- - automated-testing
- - test-driven-development
----
-
-Having a passing test suite or CI pipeline doesn't tell you if your appliction works.
-
-There could be scenarios or edge-cases that aren't covered within the test suite and contain bugs, but aren't covered by the test suite.
-
-There could be untested code that isn't covered at all.
-
-A passing test suite proves that the tests that have been written so far pass and that there are no regressions introduced by the latest change.
-
-## Here's the thing
-
-Instead of telling you that your application works by passing, the test suite tells you something is broken when it fails.
-
-If a previously-passing test is failing, the application is broken and should not be deployed - not that the application is working if the tests don't fail.
diff --git a/astro/src/content/daily-email/2023-06-30.md b/astro/src/content/daily-email/2023-06-30.md
deleted file mode 100644
index e54d746f..00000000
--- a/astro/src/content/daily-email/2023-06-30.md
+++ /dev/null
@@ -1,28 +0,0 @@
----
-title: >
- How did you learn automated testing?
-pubDate: 2023-06-30
-permalink: >
- archive/2023/06/30/how-did-you-learn-automated-testing
-tags:
- - automated-testing
- - test-driven-development
----
-
-I started to learn about automated testing in 2012 when I took over maintainership of the Drupal module, Override Node Options.
-
-At the time, it had around 9,000 active installations (now more than 35,000), and I was concerned about breaking those sites if I pushed a bug and wanted confidence to make changes without introducing regressions.
-
-Later, I started to learn about test-driven development and how to develop and design software by writing the tests first.
-
-Although I'm not a Laravel Developer, Adam Wathan's "Test Driven Laravel" course was a great resource and information, as well as a number of presentations and talks at PHP meetups and conferences.
-
-Once I understood how to write tests and do TDD, I took any opportunity to practice it, whether on projects or coding katas.
-
-At one point, I was writing module code during work hours and writing tests for it during the evening.
-
-## What about you?
-
-How did you learn automated testing or test-driven development? Reply to this email and let me know.
-
-Bonus points if it was at one of my conference talks or workshops!
diff --git a/astro/src/content/daily-email/2023-07-01.md b/astro/src/content/daily-email/2023-07-01.md
deleted file mode 100644
index 21323abb..00000000
--- a/astro/src/content/daily-email/2023-07-01.md
+++ /dev/null
@@ -1,30 +0,0 @@
----
-title: >
- Once you start writing tests, you can't stop
-pubDate: 2023-07-01
-permalink: >
- archive/2023/07/01/once-you-start-writing-tests-you-cant-stop
-tags:
- - automated-testing
- - test-driven-development
----
-
-Once you start testing/TDD, you can't go back
-
-Once you start writing automated tests or doing test-driven development, you can't go back to not doing it.
-
-When adding a new feature, you'd need to test every situation and use case manually in a browser or command line - and, very likely, do so multiple times.
-
-When fixing a bug, you'd need to follow the exact steps to replicate it and see it before attempting a fix. Again, you'd also need to test it manually.
-
-Also, because it passes a manual test, there's no guarantee it won't break unexpectedly in the future.
-
-While refactoring code without tests, bugs and regressions could be introduced as there's no test suite to run and ensure they're still passing.
-
-## Here's the thing
-
-When you're used to writing tests and doing test-driven development, you get used to the quick feedback loops and the confidence to make changes.
-
-It's easier to create a test that proves a bug exists and shows it'safixed because the test passes.
-
-Once you have these things, you can't stop and go back to not having tests.
diff --git a/astro/src/content/daily-email/2023-07-02.md b/astro/src/content/daily-email/2023-07-02.md
deleted file mode 100644
index 25f39990..00000000
--- a/astro/src/content/daily-email/2023-07-02.md
+++ /dev/null
@@ -1,51 +0,0 @@
----
-title: >
- Docker or Nix?
-pubDate: 2023-07-02
-permalink: >
- archive/2023/07/02/docker-or-nix
-tags:
- - docker
- - nix
----
-
-I've been a Nix user for about a year, starting with its package manager on my previously installed Linux distribution.
-
-I started to use Home Manager for my user configuration and dotfiles and later switched to the NixOS operating system.
-
-## Using Nix for software development
-
-I've also been using Nix Flakes for per-project configuration.
-
-A Flake file is a simple file written in the Nix language that defines the project's dependencies and installs them from the Nix package manager.
-
-Here is an example Flake for a PHP CLI application:
-
-```nix
-{
- inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
-
- outputs = inputs@{ flake-parts, ... }:
- flake-parts.lib.mkFlake { inherit inputs; } {
- systems = [ "x86_64-linux" ];
-
- perSystem = { config, self', inputs', pkgs, system, ... }: {
- devShells = {
- default = pkgs.mkShell {
- buildInputs = with pkgs; [ php82 php82Packages.composer ];
- };
- };
- };
- };
-}
-```
-
-It declares that PHP 8.2 and Composer are available, even if I have different versions installed globally.
-
-## Will Nix replace Docker?
-
-Nix and Flakes have replaced Docker for me on some projects.
-
-If I have a simple setup and need a specific version of PHP or Node and some additional programs, I can get those from the Flake.
-
-I don't know if it'll replace Docker for me completely and work on more complex projects, but it's working well for me where I'm using it.
diff --git a/astro/src/content/daily-email/2023-07-03.md b/astro/src/content/daily-email/2023-07-03.md
deleted file mode 100644
index 1d872ccd..00000000
--- a/astro/src/content/daily-email/2023-07-03.md
+++ /dev/null
@@ -1,43 +0,0 @@
----
-title: >
- Why write custom assertions in your tests?
-pubDate: 2023-07-03
-permalink: >
- archive/2023/07/03/why-write-custom-assertions-in-your-tests
-tags:
- - automated-testing
----
-
-I'm refactoring some code on a client project - creating a Repository class to centralise some logic before implementing the next feature.
-
-The repository class is responsible for finding and returning any nodes with a specified field value and some base conditions (it must be the correct node type, published, etc.).
-
-## Adding a custom assertion
-
-I'm using PHPUnit's native assertions to check it returns a Collection (I regularly include the `illuminate/collections` library from Laravel in other projects) and that each item is an instance of a `NodeInterface`, but there isn't an assertion to check each node is of the correct type.
-
-My initial implementation was to loop over each node and use `assertSame` on its bundle before refactoring to create an array of unique bundle names and comparing it to my expected names:
-
-```php
-self::assertSame(
- expected: [$nodeType],
- actual: $haystack
- ->map(fn (NodeInterface $item): string => $item->bundle())
- ->unique()
- ->toArray(),
-);
-```
-
-## Why write a custom assertion?
-
-Whilst this works, it likely won't be clear in the future what it's testing.
-
-My initial thought was to add a comment describing it, but then I decided to wrap it in a custom assertion - `assertContainsOnlyNodesOfType` - a private static function within my test class that wraps the native assertions.
-
-This approach makes the test more readable now and in the future and more domain-focused by giving it a descriptive name.
-
-It can be easily reused within the same test case or elsewhere.
-
-Although I only perform one assertion in this case, I can combine multiple assertions and perform any other required steps.
-
-Finally, I can contain any implementation details within the custom assertion. Here, I'm matching the result against an array of expected values, not just a single node type which is what I want. This detail can be contained within the assertion, making it easier to read and reuse in the future.
diff --git a/astro/src/content/daily-email/2023-07-04.md b/astro/src/content/daily-email/2023-07-04.md
deleted file mode 100644
index de124a8a..00000000
--- a/astro/src/content/daily-email/2023-07-04.md
+++ /dev/null
@@ -1,24 +0,0 @@
----
-title: >
- Think smaller with TDD
-pubDate: 2023-07-04
-permalink: >
- archive/2023/07/04/think-smaller-with-tdd
-tags:
- - automated-testing
- - test-driven-development
----
-
-I've recently added several custom search blocks and pages to a client project.
-
-Each requires a results page, a list of autocomplete suggestions for users to select from, a custom form, and a block to place it on the required pages.
-
-For each search, I'm first testing the results page, ensuring it exists and contains the correct results before testing the autocomplete results, creating the block and form, and linking everything together.
-
-## Thinking small
-
-This could seem like a large and daunting task, but with test-driven development, I can break everything into smaller, more manageable tasks.
-
-My objective is either to write the next failing test and then get it to pass or to refactor what I've written.
-
-I can focus on these small steps and make progress towards the end goal, guided by the tests I'm writing, instead of needing to focus always on one large and complex task.
diff --git a/astro/src/content/daily-email/2023-07-05.md b/astro/src/content/daily-email/2023-07-05.md
deleted file mode 100644
index b23b1287..00000000
--- a/astro/src/content/daily-email/2023-07-05.md
+++ /dev/null
@@ -1,46 +0,0 @@
----
-title: >
- Services vs Actions
-pubDate: 2023-07-05
-permalink: >
- archive/2023/07/05/services-vs-actions
-tags:
- - software-development
- - software-architecture
----
-
-When creating a custom module, where do you put your business logic?
-
-You want to keep classes like Controllers and Commands simple and move any reusable logic into separate files.
-
-Usually, this means 'Service' classes, but another approach I like is to use 'Action' classes.
-
-## What is an Action class?
-
-An Action is a PHP class representing a single action that must be performed.
-
-It usually contains a single method with a descriptive name summarising the task, such as `GetAccessToken`.
-
-This differs from a generic service like `ApiService` with multiple methods like `getAccessToken()`.
-
-## Using Action classes
-
-I'll register Action classes in the service container to use dependency injection and autowiring and easily inject the Action into other classes that need it, like Controllers and Commands.
-
-If you need multiple implementations, multiple actions can implement the same Interface and make them swappable, such as having `GetAccessToken` and `GetAndCacheAccessToken` implement the same `GetsAccessToken` interface.
-
-That also enables using design patterns like Decorators with Actions.
-
-## Why I like Actions
-
-I like more readable and meaningful class names and prefer working with multiple simpler classes than those with fewer complex ones.
-
-I like leveraging design patterns I'm used to, such as the Decorator pattern, by having common interfaces and contracts.
-
-I like that if I need to add another implementation, I can add it without changing the existing code, so it follows the SOLID principles.
-
-## What about you?
-
-Do you use Action classes in your code, or do you use Services or something else?
-
-Reply to this email and let me know.
diff --git a/astro/src/content/daily-email/2023-07-06.md b/astro/src/content/daily-email/2023-07-06.md
deleted file mode 100644
index 35440f3c..00000000
--- a/astro/src/content/daily-email/2023-07-06.md
+++ /dev/null
@@ -1,36 +0,0 @@
----
-title: >
- Automated testing is more than just unit testing
-pubDate: 2023-07-06
-permalink: >
- archive/2023/07/06/automated-testing-is-more-than-just-unit-testing
-tags:
- - automated-testing
- - test-driven-development
----
-
-When I speak to people about automated testing or hear others speak about it, it's often confused with unit testing.
-
-Drupal and many other projects use PHPUnit. Its website describes PHPUnit as "a programmer-oriented testing framework for PHP", whereas Wikipedia explicitly says "PHPUnit is a unit testing framework".
-
-But automated testing includes much more.
-
-## Other types of tests
-
-In Drupal, whilst there are unit tests, PHPUnit also does feature (aka functional or browser) testing, where it can make an HTTP request to an endpoint and perform assertions on the response's status code and the returned text. This is great for checking if a page exists at a certain path, whether the correct users can access it and whether it contains the expected text. This isn't something that can be done with a unit test.
-
-There are also integration (aka kernel) tests which don't access the browser but have access to Drupal's service container to interact with its services and can save and retrieve values from the database. Again, this isn't available in a unit test which relies heavily on mocking.
-
-## What else is there?
-
-In Drupal, I've also used Behat - a behaviour-driven development testing framework that allows writing tests in a plain English syntax called Gherkin instead of PHP.
-
-Pest PHP has an architecture plugin.
-
-There are dedicated front-end testing frameworks like Cypress for UI testing.
-
-Other quality tools like static analysis can also be considered testing tools.
-
-## Want to learn more?
-
-If you want to learn more about automated testing in Drupal, [I have a talk about that](https://www.oliverdavies.uk/talks/tdd-test-driven-drupal).
diff --git a/astro/src/content/daily-email/2023-07-15.md b/astro/src/content/daily-email/2023-07-15.md
deleted file mode 100644
index 399a33bd..00000000
--- a/astro/src/content/daily-email/2023-07-15.md
+++ /dev/null
@@ -1,22 +0,0 @@
----
-title: >
- Test-driven development makes you more productive
-pubDate: 2023-07-15
-permalink: >
- archive/2023/07/15/test-driven-development-makes-you-more-productive
-tags:
- - automated-testing
- - test-driven-development
----
-
-I think that test-driven development (TDD) makes you productive.
-
-Firstly, you save time by not needing to switch from your code to a terminal or browser to test it.
-
-But, just as importantly, TDD reduces procrastination. It's much clearer to see what the next steps are.
-
-You're either thinking and designing your code when writing a failing test or fixing the test failures in the implementation code to get the test to pass. You can focus on each failure and message separately and get them to pass instead of thinking about the whole feature or the rest of the application.
-
-Once you have a working test, you can focus on refactoring any code or moving on to writing the next assertion or the next test.
-
-I think that achieving small tasks with short feedback loops using test-driven development makes it much easier to remain productive and focussed.
diff --git a/astro/src/content/daily-email/2023-07-16.md b/astro/src/content/daily-email/2023-07-16.md
deleted file mode 100644
index d4855393..00000000
--- a/astro/src/content/daily-email/2023-07-16.md
+++ /dev/null
@@ -1,25 +0,0 @@
----
-title: >
- When writing a failing test, you're designing your code
-pubDate: 2023-07-16
-permalink: >
- archive/2023/07/16/when-writing-a-failing-test-youre-designing-your-code
-tags:
- - automated-testing
- - test-driven-development
----
-
-When doing test-driven development, you start by writing a failing test and then write the code to make it pass.
-
-This is the design phase where you ask questions and decide how you want the code to work.
-
-* Are you going to use a global function or a method on a class?
-* Will you create a new class or add a method to an existing class?
-* What will it be called?
-* Will you use a named method or make the class invokable like a single-method Controller or Action?
-* Will it accept any parameters?
-* If so, what will the parameters be, what will they be named, and will they take any default values?
-* Will it return a value?
-* Should it throw an Exception?
-
-You might iterate on the design and change it as you write more assertions or tests, but take the opportunity to decide how you want the code to work at this point before you start writing the implementation.
diff --git a/astro/src/content/daily-email/2023-07-17.md b/astro/src/content/daily-email/2023-07-17.md
deleted file mode 100644
index 55b736aa..00000000
--- a/astro/src/content/daily-email/2023-07-17.md
+++ /dev/null
@@ -1,30 +0,0 @@
----
-title: >
- Too many choices?
-pubDate: 2023-07-17
-permalink: >
- archive/2023/07/17/too-many-choices
-tags:
- - automation
- - terraform
----
-
-I've recently considered moving my infrastructure automation code from Pulumi to Terraform.
-
-One of Pulumi's features is that you can write your automation in a programming language instead of a domain-specific language (DSL) with Terraform.
-
-As a Developer, this seems appealing, but it poses an important question - which programming language should you use?
-
-I've written and re-written Pulumi code in TypeScript and Python and experimented with Go to see which feels best for me.
-
-If one of these were my primary language, it would be a no-brainer.
-
-## Here's the thing
-
-When I go into my automation repository, I want to write my code as quickly and simply as possible. I don't want to be thinking about how to write it or what language would be best to write it in.
-
-Whilst I'd have to learn another DSL for Terraform, it would simplify my options by removing that choice for me, but also if I write automation code and hand it over to a client.
-
-It's like taking my children to a restaurant.
-
-They'll get overwhelmed if there are too many options on the menu. If we limit the options or order for them, they won't.
diff --git a/astro/src/content/daily-email/2023-07-18.md b/astro/src/content/daily-email/2023-07-18.md
deleted file mode 100644
index a83e56cc..00000000
--- a/astro/src/content/daily-email/2023-07-18.md
+++ /dev/null
@@ -1,22 +0,0 @@
----
-title: >
- TDD as a concept is simple, but TDD is difficult
-pubDate: 2023-07-18
-permalink: >
- archive/2023/07/18/tdd-as-a-concept-is-simple-but-tdd-is-difficult
-tags:
- - automated-testing
- - test-driven-development
----
-
-Test-driven development as a concept is easy.
-
-Before you write any code, you write a failing test and then write enough code to get it to pass.
-
-But implementing test-driven development is harder.
-
-As well as overcoming the initial reluctance to write the tests first, it takes time to learn how to use it well.
-
-Code katas are great for practising TDD, but it can take time to progress from that to using it in a full application with more pieces.
-
-As with many things, practice and perseverance are key.
diff --git a/astro/src/content/daily-email/2023-07-19.md b/astro/src/content/daily-email/2023-07-19.md
deleted file mode 100644
index 8c27b400..00000000
--- a/astro/src/content/daily-email/2023-07-19.md
+++ /dev/null
@@ -1,14 +0,0 @@
----
-title: >
- TDD is like clicker training
-pubDate: 2023-07-19
-permalink: >
- archive/2023/07/19/tdd-is-like-clicker-training
-tags:
- - automated-testing
- - test-driven-development
----
-
-During a webinar I watched recently, someone described test-driven-development as clicker training for Developers.
-
-Similar to when people want to train an animal, the short cycles and quick feedback loops make it easier to stay focussed as you work on a task, and the satisfaction of getting a test to pass, completing a feature, or refactoring some messy code is the reward.
diff --git a/astro/src/content/daily-email/2023-07-20.md b/astro/src/content/daily-email/2023-07-20.md
deleted file mode 100644
index f63ec77b..00000000
--- a/astro/src/content/daily-email/2023-07-20.md
+++ /dev/null
@@ -1,20 +0,0 @@
----
-title: >
- Tests as communication
-pubDate: 2023-07-20
-permalink: >
- archive/2023/07/20/tests-as-communication
-tags:
- - automated-testing
- - test-driven-development
----
-
-Automated tests aren't just checks to verify your software is working.
-
-They're a communication tool that shows people working on the code how it's supposed to be used.
-
-It's a form of documentation.
-
-They are living examples of how to use the code with the benefit that you can run them and see if they still work, which isn't the case for markdown files or other types of static documentation that can become outdated.
-
-Something I often do when evaluating or using software that has a test suite is review the tests and see how it's supposed to be used.
diff --git a/astro/src/content/daily-email/2023-07-21.md b/astro/src/content/daily-email/2023-07-21.md
deleted file mode 100644
index 7a5a2aab..00000000
--- a/astro/src/content/daily-email/2023-07-21.md
+++ /dev/null
@@ -1,18 +0,0 @@
----
-title: >
- Comments as communication
-pubDate: 2023-07-21
-permalink: >
- archive/2023/07/21/comments-as-communication
-tags: []
----
-
-I often hear that code should be "self-documenting".
-
-Instead of writing a comment, you should create a function or class with that name instead.
-
-Whilst I agree with this, I think that code comments shouldn't describe what the code is doing - they should explain why the code is needed and provide any additional context to the person reading it.
-
-If a comment just says `Returns true` or `Sends an email`, that can be understood by reading the code, so isn't providing any extra value or context. They can also become outdated as the code changes.
-
-If a line of code is needed to fix a certain state or situation, or if a piece of code isn't particularly readable and isn't obvious what it does, those are good times to add comments.
diff --git a/astro/src/content/daily-email/2023-07-22.md b/astro/src/content/daily-email/2023-07-22.md
deleted file mode 100644
index fd273449..00000000
--- a/astro/src/content/daily-email/2023-07-22.md
+++ /dev/null
@@ -1,16 +0,0 @@
----
-title: >
- More code, more problems
-pubDate: 2023-07-22
-permalink: >
- archive/2023/07/22/more-code-more-problems
-tags: []
----
-
-The more code you have, the more potential problems you have.
-
-More code means more opportunities for bugs in your software.
-
-There's more code to maintain and more chance of encountering breaking changes as you update between major software versions of your project's dependencies, such as a CMS or framework.
-
-If you can keep your amount of code to a minimum and reduce the maintenance overhead, you are less likely to experience issues.
diff --git a/astro/src/content/daily-email/2023-07-23.md b/astro/src/content/daily-email/2023-07-23.md
deleted file mode 100644
index 1642221d..00000000
--- a/astro/src/content/daily-email/2023-07-23.md
+++ /dev/null
@@ -1,16 +0,0 @@
----
-title: >
- Tomorrow is easier if today's code is simpler
-pubDate: 2023-07-23
-permalink: >
- archive/2023/07/23/tomorrow-is-easier-if-todays-code-is-simpler
-tags: []
----
-
-If you write simple code, it is quicker and easier to read, extend and change.
-
-If you need to work on that code in the future - either tomorrow or in months or years - it will be easier to add the new feature or fix the bug.
-
-It will also be easier for others who didn't write it, so they must understand what it does (or doesn't do) before making changes.
-
-It will also likely be easier to debug with tools like Xdebug and PHPStan or upgrade with tools like Rector.
diff --git a/astro/src/content/daily-email/2023-07-24.md b/astro/src/content/daily-email/2023-07-24.md
deleted file mode 100644
index 0922bf1a..00000000
--- a/astro/src/content/daily-email/2023-07-24.md
+++ /dev/null
@@ -1,30 +0,0 @@
----
-title: >
- Testing is all about confidence
-pubDate: 2023-07-24
-permalink: >
- archive/2023/07/24/testing-is-all-about-confidence
-tags:
- - automated-testing
- - test-driven-development
----
-
-Testing - manual or automated - is about building confidence.
-
-If we deploy this change or release this feature, are we confident it will work as expected and not cause regressions elsewhere?
-
-What if someone asked you on a scale between one and ten?
-
-From an automated perspective, have you written enough tests for the feature to be confident it works?
-
-If you're fixing a bug, do you have a test that reproduces the bug that was originally failing but now passing since you've added the fix?
-
-Do the tests have enough assertions, and have you covered enough use cases and scenarios?
-
-## Here's the thing
-
-You can utilise code coverage metrics, but no hard rule says that the feature will work once x percentage is covered. Something with 100% coverage can still contain bugs.
-
-For me, it's about the answer to the question:
-
-If we deploy this change, how confident are you that it will work as expected?
diff --git a/astro/src/content/daily-email/2023-07-25.md b/astro/src/content/daily-email/2023-07-25.md
deleted file mode 100644
index c1638464..00000000
--- a/astro/src/content/daily-email/2023-07-25.md
+++ /dev/null
@@ -1,40 +0,0 @@
----
-title: >
- Working backwards
-pubDate: 2023-07-25
-permalink: >
- archive/2023/07/25/working-backwards
-tags: []
----
-
-Today, I did a show-and-tell session with my team where I demonstrated an integration I've been working on for a few months and recently released to production.
-
-The simplified workflow is we collate some data, send it to a third-party system for translation, receive the translated file and import the translations into Drupal's translation system.
-
-## Where did I start?
-
-The first thing I did was not to collate the data and generate the file but to send a minimal, hard-coded version of the contents to the third-party system.
-
-I'd have started with the code to import the translated strings if I hadn't already done this in an earlier spike.
-
-This allowed me to send the file, check the response from the third party and ensure they could work with that file type and my proposed content structure.
-
-If needed, I could have changed direction and avoided investing much time. This wouldn't have been the case if I'd left this until the end of the process.
-
-I also have a working end-to-end test, and I can send a file and get the response I need.
-
-What if I'd written all the code and discovered something wouldn't work?
-
-## What next?
-
-Now, I can work backwards and start to make the content dynamic.
-
-I can introduce more authentic and complicated data, remove the hard-coded test data, and check that things still work.
-
-I still have the quick feedback loop, as I can always send the data to the third-party system and verify things work as I iterate on my implementation.
-
-With the main pieces of the puzzle in place, I can continue building and filling in the others.
-
-Once I have a complete feature with all the pieces in place, I can refactor as needed.
-
-I still have the same finished puzzle - I just built it in a different order.
diff --git a/astro/src/content/daily-email/2023-07-26.md b/astro/src/content/daily-email/2023-07-26.md
deleted file mode 100644
index 0d5fdc95..00000000
--- a/astro/src/content/daily-email/2023-07-26.md
+++ /dev/null
@@ -1,19 +0,0 @@
----
-title: >
- Prove the concept
-pubDate: 2023-07-26
-permalink: >
- archive/2023/07/26/prove-the-concept
-tags:
- - software-development
----
-
-When starting a new task, find the simplest way to prove the concept.
-
-Investigate upfront and evaluate potential approaches.
-
-What's the smallest or quickest thing you could do to validate an idea?
-
-It could be a small script that you can run and verify something works before moving it to its correct place within your application or creating a first implementation with hard-coded data that you refactor once you've proven the concept.
-
-If you can't, you'll know it won't work without investing a large amount of time and you can move on to the next potential approach.
diff --git a/astro/src/content/daily-email/2023-07-27.md b/astro/src/content/daily-email/2023-07-27.md
deleted file mode 100644
index 29e6295d..00000000
--- a/astro/src/content/daily-email/2023-07-27.md
+++ /dev/null
@@ -1,23 +0,0 @@
----
-title: >
- Stick to conventions
-pubDate: 2023-07-27
-permalink: >
- archive/2023/07/27/stick-to-conventions
-tags:
- - software-development
----
-
-If you're performing a task as there's already a convention on how to do it, stick to it.
-
-If the codebase follows a particular coding standard, use it.
-
-If a project uses repository classes instead of interacting directly with a database, do that with your code too.
-
-If you use a framework with a service container and uses dependency injection, do that instead of manually creating classes.
-
-If you need additional functionality for a Drupal project and there's an established and well-known module that adds it, use it. Unless it doesn't meet your needs, in which case, document why that's the case and why you used a different module or wrote a custom implementation.
-
-If you need to create a content listing page, use the Views module, which is a standard approach. If not, document why and then explore other solutions.
-
-If you don't follow a convention, it will be harder for you or others to work on it in the future.
diff --git a/astro/src/content/daily-email/2023-07-28.md b/astro/src/content/daily-email/2023-07-28.md
deleted file mode 100644
index fda270db..00000000
--- a/astro/src/content/daily-email/2023-07-28.md
+++ /dev/null
@@ -1,23 +0,0 @@
----
-title: >
- Don't write generic commit messages
-pubDate: 2023-07-28
-permalink: >
- archive/2023/07/28/generic-commit-messages
-tags:
- - git
----
-
-This week, I reviewed a client's Drupal 9 website and investigated the steps needed to upgrade to Drupal 10.
-
-Looking at the Git log to see the commits for a module, I see `Week 20 development` as the latest commit message.
-
-That commit changed 106 files, added 3,453 lines and removed 17 lines, including custom module and theme changes, contrib module updates and library updates.
-
-This should have been several commits, each performing a clear and separate task.
-
-Updating the dependencies should be its own commit, and changes to the custom modules and theme should be separate commits.
-
-Then each commit could have its own clear and descriptive commit message explaining why each change was needed, any issues that were encountered during the change, and any alternative approaches considered.
-
-That would have been more useful for me whilst looking through the logs than `Week 20 development`.
diff --git a/astro/src/content/daily-email/2023-07-29.md b/astro/src/content/daily-email/2023-07-29.md
deleted file mode 100644
index 28c226f8..00000000
--- a/astro/src/content/daily-email/2023-07-29.md
+++ /dev/null
@@ -1,25 +0,0 @@
----
-title: >
- Should I wait to upgrade from Drupal 7?
-pubDate: 2023-07-29
-permalink: >
- archive/2023/07/29/should-i-wait-to-upgrade-from-drupal-7
-tags:
- - drupal
- - drupal-7
- - php
----
-
-It was announced at DrupalCon that Drupal 7 support was being extended one final time until January 2025.
-
-But if you have a Drupal 7 website, does that mean you should wait to start upgrading it?
-
-I recommend starting the process as soon as possible.
-
-Even though Drupal core support is extended, I've looked at projects that use modules marked as unsupported by their maintainers for some time as they focus on versions for Drupal 8, 9 or 10.
-
-In that case, those modules will have no new features, bug fixes or security updates, although Drupal core support has been extended.
-
-You may have a lot of custom code that needs to be ported to Drupal 10 or a complex data structure that needs to be migrated, These things will take time, so it's best not to leave it until the last minute.
-
-If you're stuck on Drupal 7, book an [upgrade consultation call](https://www.oliverdavies.uk/call) with me or purchase an [upgrade roadmap for your project](https://www.oliverdavies.uk/drupal7) and I'll get you unstuck.
diff --git a/astro/src/content/daily-email/2023-07-30.md b/astro/src/content/daily-email/2023-07-30.md
deleted file mode 100644
index 457eab20..00000000
--- a/astro/src/content/daily-email/2023-07-30.md
+++ /dev/null
@@ -1,26 +0,0 @@
----
-title: >
- Commit often, deploy often
-pubDate: 2023-07-30
-permalink: >
- archive/2023/07/30/commit-often-deploy-often
-tags:
- - git
- - deployments
----
-
-This is a follow-up to Friday's email on generic commit messages.
-
-In it, I discussed seeing commit messages like `Week 20 development` in project codebases and why you should write specific commit messages for each change.
-
-The other thing is, if you only commit once a week, you can only deploy once a week.
-
-That's assuming that, on this project, the changes were committed and pushed weekly. It could have been fortnightly, monthly, or longer.
-
-As well as increasing the time between deployments, it also makes them larger and riskier as they include more changes.That commit changed 106 files, added 3,453 lines and removed 17 lines, including custom module and theme changes, contrib module updates and library updates.
-
-If the dependencies were committed and deployed first, followed by a series of small custom module and theme changes, even though it would have resulted in more deployments, each one would have been smaller and less risky as there were fewer changes and easier to debug any issues and fail forward.
-
-I recommend that everyone commits and pushes their changes at least daily and use trunk-based development so everyone's changes apply and work together and are not separated on feature branches.
-
-I recommend that they're pushed live daily, too, or as often as possible - reducing the chance of errors and getting the changes providing value for customers and clients.
diff --git a/astro/src/content/daily-email/2023-07-31.md b/astro/src/content/daily-email/2023-07-31.md
deleted file mode 100644
index fdc11a06..00000000
--- a/astro/src/content/daily-email/2023-07-31.md
+++ /dev/null
@@ -1,26 +0,0 @@
----
-title: >
- Upgrading from Drupal 9 is easier
-pubDate: 2023-07-31
-permalink: >
- archive/2023/07/31/upgrading-from-drupal-9-is-easier
-tags:
- - drupal
- - php
----
-
-Upgrading from Drupal 7 to 8, 9 or 10 is a large task.
-
-You must create a new empty site, migrate your configuration and data, manually recreate anything else and rewrite any custom modules and themes.
-
-Since Drupal 8, things have been different.
-
-You can upgrade your site in place.
-
-No large code rewrite or data migration.
-
-Many contributed modules support multiple major Drupal versions simultaneously, so they may not need upgrading.
-
-Others may need small changes to remove deprecated code or be compatible with breaking changes, and some tools can automate some or all of the changes.
-
-The same applies to upgrading from Drupal 9 to 10, which will be the same for Drupal 11 next year.
diff --git a/astro/src/content/daily-email/2023-08-01.md b/astro/src/content/daily-email/2023-08-01.md
deleted file mode 100644
index 80953d2d..00000000
--- a/astro/src/content/daily-email/2023-08-01.md
+++ /dev/null
@@ -1,40 +0,0 @@
----
-title: >
- Maintaining a module used on 35,000 Drupal websites
-pubDate: 2023-08-01
-permalink: >
- archive/2023/08/01/maintaining-a-module-used-on-35000-drupal-websites
-tags:
- - drupal
- - open-source
----
-
-Note: The numbers within this post are taken from my [Test-Driven Drupal talk](https://www.oliverdavies.uk/talks/tdd-test-driven-drupal), in which I also talk about this.
-
-My first commit to the 7.x-1.x branch of the Override Node Options module was in March 2012. According to Drupal.org, the module was used on 9,212 websites then.
-
-As well as the 7.x-1.x branch, there's the 8.x-2.x branch which supports Drupal 9 and 10, and previously Drupal 8.
-
-The most recent statistics show the module is currently used on 34,981 websites and is consistently around 35,000.
-
-## What does that mean?
-
-The module is considered feature complete, but I'm not ruling out any new additions.
-
-The main thing is ensuring that any changes don't break 35,000 websites!
-
-I do this by relying on the module's automated test suite and ensuring that tests are added for any features or bugs and that the tests are passing before any new release.
-
-## This has worked well
-
-A few years ago, I committed a feature request to both versions. While it didn't include additional tests, I verified the existing functionality worked after resolving a large merge conflict by ensuring the original tests passed.
-
-More recently, a colleague and I refactored the module and split each override into its own class, making adding and maintaining overrides easier.
-
-Because the tests were still passing, we knew our refactor was successful and not causing regressions.
-
-## Here's the thing
-
-Having automated tests and ensuring they're always passing has allowed me to add features and refactor code that I wouldn't have done or had the confidence to do otherwise.
-
-It's great to have a popular module, but on the other hand, I don't want to break 35,000 websites which makes the tests invaluable.
diff --git a/astro/src/content/daily-email/2023-08-02.md b/astro/src/content/daily-email/2023-08-02.md
deleted file mode 100644
index 1f662bd3..00000000
--- a/astro/src/content/daily-email/2023-08-02.md
+++ /dev/null
@@ -1,17 +0,0 @@
----
-title: >
- A crash course into automated testing with Drupal
-pubDate: 2023-08-02
-permalink: >
- archive/2023/08/02/a-crash-course-into-drupal-testing
-tags:
- - drupal
- - automated-testing
- - test-driven-development
----
-
-Next week, I'll be presenting a lightning talk at the North West Drupal user group (NWDUG)'s August meetup.
-
-It'll be a crash course into automated testing and test-driven development with Drupal, in which I plan to show how to get started by writing and running your first automated tests whilst exploring the different types of tests that are available.
-
-It's an online event, so if you'd like to see this and other lightning talks on the 8th of August, RSVP at .
diff --git a/astro/src/content/daily-email/2023-08-03.md b/astro/src/content/daily-email/2023-08-03.md
deleted file mode 100644
index 49ca9cb6..00000000
--- a/astro/src/content/daily-email/2023-08-03.md
+++ /dev/null
@@ -1,19 +0,0 @@
----
-title: >
- What problem are we trying to solve?
-pubDate: 2023-08-03
-permalink: >
- archive/2023/08/03/what-problem-are-we-trying-to-solve
-tags:
- - drupal
----
-
-The Override Node Options module that I said yesterday is used on 35,000 websites isn't a complicated module.
-
-It doesn't add a lot of features.
-
-It solves a problem by adding additional permissions to Drupal that site administrators can assign to user roles and not need to give a more global permission like "administer nodes".
-
-The problem being solved is allowing users to set node options, like the created date or published status, in a secure way.
-
-If it wasn't solving a problem, it wouldn't be used on 35,000 Drupal websites.
diff --git a/astro/src/content/daily-email/2023-08-04.md b/astro/src/content/daily-email/2023-08-04.md
deleted file mode 100644
index 3817e91e..00000000
--- a/astro/src/content/daily-email/2023-08-04.md
+++ /dev/null
@@ -1,27 +0,0 @@
----
-title: >
- Laravel Prompts and framework-agnostic tools
-pubDate: 2023-08-04
-permalink: >
- archive/2023/08/04/laravel-prompts
-tags:
- - php
- - laravel
- - open-source
----
-
-Although I wouldn't consider myself a "Laravel Developer", I enjoy watching the talks from the Laravel conferences, most recently Laracon US, that took place last week.
-
-I like to learn from other communities and adopt relevant practices or tools within my projects. I did this with Laravel Collections, which I use on nearly every project.
-
-## Laravel Prompts
-
-I watched Jess Archer's talk on the new Laravel Prompts and was happy when she said it worked with plain PHP projects, not just Laravel.
-
-This means I can potentially use it with Drupal and Drush or Symfony Console applications, too, such as my build configuration file generator.
-
-## Here's the thing
-
-I like tools I can use across multiple technologies and prefer framework-agnostic tools to specific ones.
-
-Then, if I'm working on a different project, I can use the tools I already know instead of learning something different just for that.
diff --git a/astro/src/content/daily-email/2023-08-05.md b/astro/src/content/daily-email/2023-08-05.md
deleted file mode 100644
index 92e33cdb..00000000
--- a/astro/src/content/daily-email/2023-08-05.md
+++ /dev/null
@@ -1,20 +0,0 @@
----
-title: >
- Use Drupal to own your content
-pubDate: 2023-08-05
-permalink: >
- archive/2023/08/05/use-drupal-to-own-your-content
-tags:
- - drupal
- - open-source
----
-
-I recently saw a social media website taking over users' handles - renaming them so they can have the original.
-
-There were similar issues a few years ago when a website put a paywall in front of articles written by its users.
-
-I've written articles and tutorials for companies I've worked at that no longer exist as the companies have been acquired.
-
-This is why I like to own and control my content. I still have my versions if a website shuts down or changes its settings.
-
-There are a lot of options, including Drupal, that can help with this. It's easy to set up a new website and start publishing your own content.
diff --git a/astro/src/content/daily-email/2023-08-06.md b/astro/src/content/daily-email/2023-08-06.md
deleted file mode 100644
index 78d00133..00000000
--- a/astro/src/content/daily-email/2023-08-06.md
+++ /dev/null
@@ -1,16 +0,0 @@
----
-title: >
- YAGNI
-pubDate: 2023-08-06
-permalink: >
- archive/2023/08/06/yagni
-tags: []
----
-
-During a recent coding dojo session, we spoke about YAGNI - i.e. "You aren't going to need it".
-
-In this situation, we discussed how many numbers we should support passing to a method in a calculator application.
-
-There's no technical limit to how many numbers we can pass, but there may be a requirement where we only need to add or subtract two numbers. In that case, we don't need to calculate three or more numbers, so there's no benefit or value to writing that code.
-
-If we follow YAGNI, we only write the code we need now. If the requirement changes in the future, we revisit the code and change it as required.
diff --git a/astro/src/content/daily-email/2023-08-07.md b/astro/src/content/daily-email/2023-08-07.md
deleted file mode 100644
index e103fa22..00000000
--- a/astro/src/content/daily-email/2023-08-07.md
+++ /dev/null
@@ -1,27 +0,0 @@
----
-title: >
- Tests make upgrades less risky
-pubDate: 2023-08-07
-permalink: >
- archive/2023/08/07/tests-make-upgrades-less-risky
-tags:
- - automated-testing
- - test-driven-development
- - drupal
----
-
-I recently reviewed a client's Drupal 9 website to gather information about upgrading it to Drupal 10.
-
-The site has a number of custom modules. They all require changes to make them Drupal 10-compatible - some are a `core_version_requirement` update, and some are more complex.
-
-None of these modules have automated tests.
-
-If they did, I'd be able to run them and see if they pass, make my changes, and rerun the tests to verify they still pass, and the module works as it did previously.
-
-But I can't.
-
-I'd need to test each module beforehand to understand what it does manually and again after making the changes.
-
-This is more time-consuming, riskier, and easier for me to introduce regressions or new bugs.
-
-Whether it's a major CMS version upgrade, updating a contrib module or refactoring custom code, having a passing test suite you can use and rely on makes updates easier and less risky.
diff --git a/astro/src/content/daily-email/2023-08-08.md b/astro/src/content/daily-email/2023-08-08.md
deleted file mode 100644
index 501291e8..00000000
--- a/astro/src/content/daily-email/2023-08-08.md
+++ /dev/null
@@ -1,22 +0,0 @@
----
-title: >
- 8 years of dotfiles
-pubDate: 2023-08-08
-permalink: >
- archive/2023/08/08/8-years-of-dotfiles
-tags:
- - dotfiles
- - open-source
----
-
-Today, I was speaking with a colleague about configuring Git, which led to a conversation about dotfiles repositories - somewhere where you version the changes to your configuration files and, usually, create symlinks to their expected locations.
-
-Afterwards, I realised the first commit to [my personal dotfiles repository](https://github.com/opdavies/dotfiles) was over eight years ago, in July 2015.
-
-What started as a repository to put my own Git configuration has undergone various changes since the tools I use changed, as well as the tools to manage the files themselves.
-
-In 2021, I switched my `.vimrc` configuration file to an `init.vim` and switched to Neovim full-time and, most recently, almost a year ago, I started to use the Nix package manager and later adopted NixOS as my primary Linux distribution.
-
-My complete NixOS and Home Manager configurations are within my `dotfiles` repository, and the configuration for tools, including Neovim, tmux and Git.
-
-I wonder what the repository will look like in another eight years...
diff --git a/astro/src/content/daily-email/2023-08-09.md b/astro/src/content/daily-email/2023-08-09.md
deleted file mode 100644
index f9b6abb9..00000000
--- a/astro/src/content/daily-email/2023-08-09.md
+++ /dev/null
@@ -1,17 +0,0 @@
----
-title: >
- Vim is my lightsaber
-pubDate: 2023-08-09
-permalink: >
- archive/2023/08/09/vim-is-my-lightsaber
-tags:
- - vim
----
-
-"Vim is my lightsaber" is the final chapter of Jess Archer's Neovim course on Laracasts.
-
-In this summary, Jess explains that some Star Wars characters have lightsabers customised to their preferences and fighting style.
-
-Vim is her lightsaber - her personalised tool to develop software. It works how she wants it to, with the features she needs.
-
-I've written before about mastering your tools and thought this was a nice spin on it.
diff --git a/astro/src/content/daily-email/2023-08-10.md b/astro/src/content/daily-email/2023-08-10.md
deleted file mode 100644
index 5bad4dba..00000000
--- a/astro/src/content/daily-email/2023-08-10.md
+++ /dev/null
@@ -1,16 +0,0 @@
----
-title: >
- Testing, fixed prices and bug-free guarantees
-pubDate: 2023-08-10
-permalink: >
- archive/2023/08/10/testing-fixed-prices-and-bug-free-guarantees
-tags:
- - automated-testing
- - test-driven-development
----
-
-After my lightning talk for NWDUG on automated testing with Drupal, the question was asked how to find time for testing.
-
-I've written about whether you need to ask for permission to write tests (you don't), and if you need to estimate tasks, you include the time and effort for writing tests as part of the estimate.
-
-As someone who only offers fixed prices for development work and covers all work with a bug-free guarantee, I want to provide well-written, stable and tested software to my customers so I'm not always fixing bugs for free.
diff --git a/astro/src/content/daily-email/2023-08-11.md b/astro/src/content/daily-email/2023-08-11.md
deleted file mode 100644
index 2686843b..00000000
--- a/astro/src/content/daily-email/2023-08-11.md
+++ /dev/null
@@ -1,22 +0,0 @@
----
-title: >
- Everyone tests their code
-pubDate: 2023-08-11
-permalink: >
- archive/2023/08/11/everyone-tests-their-code
-tags:
- - automated-testing
- - test-driven-development
----
-
-No one writes code, commits it and pushes it to production without checking it works.
-
-Everyone tests their code, but they usually do it manually. They switch from the code to a browser or terminal, run the code and evaluate the result.
-
-This takes time, you need to switch contexts, and the test is only valid for that time.
-
-There's no guarantee it will still work in the future.
-
-Automated testing, however, means you can write your code and run the tests without leaving your IDE or text editor.
-
-The tests can also be run in the future to ensure the functionality works without needing to re-test it manually.
diff --git a/astro/src/content/daily-email/2023-08-12.md b/astro/src/content/daily-email/2023-08-12.md
deleted file mode 100644
index 6ca6b495..00000000
--- a/astro/src/content/daily-email/2023-08-12.md
+++ /dev/null
@@ -1,20 +0,0 @@
----
-title: >
- Does not writing tests actually save time?
-pubDate: 2023-08-12
-permalink: >
- archive/2023/08/12/does-not-writing-tests-actually-save-time
-tags:
- - automated-testing
- - test-driven-development
----
-
-One of the most common responses to why people don't write tests is, "We don't have time".
-
-So, people don't write tests to save time.
-
-While you write less code, it takes longer to test everything manually during development, and more bugs will likely be found, which also takes longer to diagnose, fix, and deal with any knock-on effects.
-
-Bugs in production add more administrative overhead as new tickets need to be created and managed, prevent other tickets from being worked on whilst they're fixed, and require more communication with clients and customers.
-
-If you save ten minutes not writing a test but spend hours later fixing bugs, you didn't save time - you spent more time in the end.
diff --git a/astro/src/content/daily-email/2023-08-13.md b/astro/src/content/daily-email/2023-08-13.md
deleted file mode 100644
index 1ca1e1b6..00000000
--- a/astro/src/content/daily-email/2023-08-13.md
+++ /dev/null
@@ -1,18 +0,0 @@
----
-title: >
- Don't estimate separately for testing
-pubDate: 2023-08-13
-permalink: >
- archive/2023/08/13/dont-estimate-separately-for-testing
-tags:
- - automated-testing
- - test-driven-development
----
-
-A common issue I see for people introducing automated testing is estimating the testing and implementation of a task separately.
-
-Something like, "It'll take x to do the work and x to write the tests for it".
-
-As well as implying you'd write all the code and then all the tests or vice versa, if you provide separate estimates, it's easy for someone to think the tests are optional and can be removed.
-
-If you provide one estimate for both, this can't happen.
diff --git a/astro/src/content/daily-email/2023-08-14.md b/astro/src/content/daily-email/2023-08-14.md
deleted file mode 100644
index e27a6073..00000000
--- a/astro/src/content/daily-email/2023-08-14.md
+++ /dev/null
@@ -1,27 +0,0 @@
----
-title: >
- Why keep a dotfiles repository
-pubDate: 2023-08-14
-permalink: >
- archive/2023/08/14/why-keep-a-dotfiles-repository
-tags:
- - dotfiles
----
-
-A few days ago, I said it's been 8 years since I started my dotfiles repository and kept my configuration files in version control.
-
-But why do this?
-
-It makes it easy to share the same configuration across multiple computers, such as personal and work or different setups for clients.
-
-It's also a backup of my configuration. If I need to reinstall my system or start fresh, I don't need to configure everything again manually.
-
-If you work on a team, you can share your configuration with colleagues, find things that work well for the team, and anything that could cause issues.
-
-I can experiment with settings and programs and then revert them again if I want to.
-
-If I add or remove a program or change a setting, I have the Git commit log to refer to, and I can document why I made that change and what problem it solves in the message body.
-
-I can review it in the future in case I need it again or want to re-evaluate it.
-
-Like on other projects, capturing the why is important. The what can be seen in the diff and speaks for itself, but it doesn't explain why I made the change and won't help if I look at that commit in the future.
diff --git a/astro/src/content/daily-email/2023-08-15.md b/astro/src/content/daily-email/2023-08-15.md
deleted file mode 100644
index 29fb7940..00000000
--- a/astro/src/content/daily-email/2023-08-15.md
+++ /dev/null
@@ -1,24 +0,0 @@
----
-title: >
- Writing test and implementation code are the same task
-pubDate: 2023-08-15
-permalink: >
- archive/2023/08/15/writing-test-and-implementation-code-are-the-same-task
-tags:
- - automated-testing
- - test-driven-development
----
-
-In Sunday's email, I said not to estimate separately for testing and implementation.
-
-But you can't do this anyway if you're doing test-driven development.
-
-With TDD, you aren't writing all of your tests and all of the implementation code or vice versa.
-
-You're continuously switching back and forth, starting by writing a failing test and then enough implementation code for it to pass.
-
-Then you write more test code, whether expanding the same test or writing a new one until you have a new failure.
-
-You get it to pass, refactor, and repeat the process until the task is complete.
-
-It's all part of the same task and the same estimate.
diff --git a/astro/src/content/daily-email/2023-08-16.md b/astro/src/content/daily-email/2023-08-16.md
deleted file mode 100644
index 6e615a33..00000000
--- a/astro/src/content/daily-email/2023-08-16.md
+++ /dev/null
@@ -1,32 +0,0 @@
----
-title: >
- Writing tests in your own time
-pubDate: 2023-08-16
-permalink: >
- archive/2023/08/16/writing-tests-in-your-own-time
-tags:
- - automated-testing
- - test-driven-development
----
-
-This is how I first started writing automated tests.
-
-I was working at a well-known digital agency, so I didn't want it to affect my output and cause me to deliver work late.
-
-I wanted to give myself a less pressured opportunity to learn and experiment with different options and approaches.
-
-So, when creating custom modules, I wrote the implementation code during billable work hours and the tests during the evening on my own time.
-
-I was investing time in learning a new skill and one that I knew would pay dividends.
-
-## How did it go?
-
-As I'd already written the implementation code, I wasn't doing test-driven development, so most of the tests were confirming what I'd written was correct with a passing test and being able to make it fail in expected ways.
-
-One time, though, I found a bug I'd written that day. I think it was an incorrect permission name I'd typed.
-
-I was able to fix it before it was submitted for quality assurance checks and client testing.
-
-This saved the time and effort of creating another issue and branch, fixing it, going through the development cycle again and having it re-tested.
-
-After that, for me, there was no going back.
diff --git a/astro/src/content/daily-email/2023-08-17.md b/astro/src/content/daily-email/2023-08-17.md
deleted file mode 100644
index 91aadf2e..00000000
--- a/astro/src/content/daily-email/2023-08-17.md
+++ /dev/null
@@ -1,29 +0,0 @@
----
-title: >
- Writing custom assertions in your tests
-pubDate: 2023-08-17
-permalink: >
- archive/2023/08/17/writing-custom-assertions-in-your-tests
-tags:
- - automated-testing
- - test-driven-development
----
-
-Writing custom assertions is a great way to clean up your test code.
-
-Here's an example from one of my client Drupal projects:
-
-```php
-private static function assertProductVariationHasPrice(ProductVariationInterface $productVariation, string $expectedPrice): void {
- self::assertSame(
- actual: $productVariation->getPrice()->getNumber(),
- expected: $expectedPrice,
- );
-}
-```
-
-This one wraps a single assertion, but they could also include multiple assertions or additional steps.
-
-## Here's the thing
-
-A custom assertion is a simple function but it makes the test code more readable and less repetitive.
diff --git a/astro/src/content/daily-email/2023-08-18.md b/astro/src/content/daily-email/2023-08-18.md
deleted file mode 100644
index 82f85526..00000000
--- a/astro/src/content/daily-email/2023-08-18.md
+++ /dev/null
@@ -1,28 +0,0 @@
----
-title: >
- Types vs tests
-pubDate: 2023-08-18
-permalink: >
- archive/2023/08/18/types-vs-tests
-tags:
- - automated-testing
- - test-driven-development
- - static-analysis
----
-
-Today, I saw a Twitter poll - "Poll: Imagine your team has to build a project with either types or tests. You can't have both.".
-
-The results were:
-
-- Types - 50.9%
-- Tests - 49.1%
-
-I was surprised by this.
-
-If I can't add type declarations (type hints) or return types, I can still write tests to check what happens when different types are used.
-
-I can also perform checks and throw errors or Exceptions if something isn't what I'd expect.
-
-## Here's the thing
-
-I use types heavily, but I'd be more confident that my application would work if I had tests and that's the main objective when writing code for myself or clients and for my clients' customers.
diff --git a/astro/src/content/daily-email/2023-08-19.md b/astro/src/content/daily-email/2023-08-19.md
deleted file mode 100644
index ba451fa7..00000000
--- a/astro/src/content/daily-email/2023-08-19.md
+++ /dev/null
@@ -1,43 +0,0 @@
----
-title: >
- Asserting all the things
-pubDate: 2023-08-19
-permalink: >
- archive/2023/08/19/asserting-all-the-things
-tags:
- - php
----
-
-As well as assertions within tests, you can also check within implementation code that things are in an expected state or contain a certain value.
-
-In PHP, this is done by throwing an Exception if a condition is met.
-
-For example:
-
-```php
-if (!is_array(false)) {
- throw new \Exception('Not an array');
-}
-```
-
-There's also the `assert` construct which, since PHP 8.0, throws an Exception by default:
-
-```php
-assert(is_array(false));
-```
-
-You can also use an assertion library, such as `webmozart/assert` or `beberlei/assert` which provide assertions and guard methods:
-
-```php
-use Webmozart\Assert\Assert;
-
-Assert::isArray(false);
-```
-
-Similarly, if the condition fails, it throws an Exception that can be caught elsewhere.
-
-As well as basic assertions such as the item is the expected type or don't match the condition, there are more complex assertions, such as all items within an array are a certain type or that an integer is positive.
-
-## Here's the thing
-
-I use guard conditions a lot within my code. If something is not as I'd expect, I like for an error to be thrown. This makes is easy to test and to debug any failures compared to failing silently.
diff --git a/astro/src/content/daily-email/2023-08-20.md b/astro/src/content/daily-email/2023-08-20.md
deleted file mode 100644
index 8b787b71..00000000
--- a/astro/src/content/daily-email/2023-08-20.md
+++ /dev/null
@@ -1,57 +0,0 @@
----
-title: >
- PHP types and assertions
-pubDate: 2023-08-20
-permalink: >
- archive/2023/08/20/php-types-and-assertions
-tags:
- - php
----
-
-Following yesterday's email about input validation, guard clauses and assertion libraries, these can be used to compliment PHP's native types and checking.
-
-For example:
-
-```php
-function createJourney(string $from, string $to, int $duration): void {
- var_dump($from, $to, $duration);
-}
-```
-
-In this code, each parameter has a type, but there's no validation on the values.
-
-If I run this:
-
-```plain
-createJourney('', '', -10);
-```
-
-I would get this output:
-
-```plain
-string(0) ""
-string(0) ""
-int(-10)
-```
-
-This is probably not what you want.
-
-I expect `$to` and `$from` to be not empty and the duration to be greater than zero.
-
-## Here's the thing
-
-I can use an assertion library or throw my own Exceptions if the values pass the type checks but aren't what I need.
-
-For example:
-
-```php
-function createJourney(string $from, string $to, int $duration): void {
- Assert::stringNotEmpty($from);
- Assert::stringNotEmpty($to);
- Assert::positiveInteger($duration);
-
- var_dump($from, $to, $duration);
-}
-```
-
-Now, if an empty string or negative duration is passed - in my implementation or test code - an Exception will be thrown.
diff --git a/astro/src/content/daily-email/2023-08-21.md b/astro/src/content/daily-email/2023-08-21.md
deleted file mode 100644
index d1cf6ea5..00000000
--- a/astro/src/content/daily-email/2023-08-21.md
+++ /dev/null
@@ -1,27 +0,0 @@
----
-title: >
- Which part of the CI pipeline has the most value?
-pubDate: 2023-08-21
-permalink: >
- archive/2023/08/21/which-part-of-the-ci-pipeline-has-the-most-value
-tags:
- - continuous-integration
- - automated-testing
- - static-analysis
----
-
-The main part of my CI pipeline tasks are running the automated tests, coding standards checks and static analysis.
-
-But which of these are the most valuable?
-
-I used to run the coding standards check first as it was the quickest, followed by static analysis and the automated tests.
-
-If a task were going to fail, it would fail quickly.
-
-But is that the objective of the CI pipeline?
-
-Whilst it needs to be quick, the main reason to run these is to ensure things work as expected.
-
-Recently, I changed my pipelines to run the tests first, as these verify the code's behaviour.
-
-I want to know if the code works but has a coding standard error that needs to be fixed rather than the pipeline failing on the error and not knowing whether the code works.
diff --git a/astro/src/content/daily-email/2023-08-22.md b/astro/src/content/daily-email/2023-08-22.md
deleted file mode 100644
index c2b04a51..00000000
--- a/astro/src/content/daily-email/2023-08-22.md
+++ /dev/null
@@ -1,32 +0,0 @@
----
-title: >
- Deployments with your CI pipeline
-pubDate: 2023-08-22
-permalink: >
- archive/2023/08/22/deployments-with-your-ci-pipeline
-tags:
- - continuous-integration
- - pipelines
----
-
-You have a CI pipeline in your project.
-
-Every time you push a commit, the CI pipeline runs and performs its checks.
-
-It runs the automated tests and verifies they pass, statically analyses the code to identify any issues and validates the code follows the correct coding style and standards.
-
-Everything passes.
-
-## What next?
-
-If the pipeline passes, your change is deployable.
-
-So, why not extend the pipeline to deploy the change once the checks pass?
-
-If the checks don't pass, don't deploy.
-
-It could be as simple as pushing the code to an S3 bucket, a separate Git branch or repository for managing deployments, or creating an artifact like a Docker image.
-
-Instead of waiting for someone to do this manually, remove a step and automate it within the pipeline.
-
-The sooner it's deployed, the sooner it provides value for your application's users.
diff --git a/astro/src/content/daily-email/2023-08-23.md b/astro/src/content/daily-email/2023-08-23.md
deleted file mode 100644
index 3e55b975..00000000
--- a/astro/src/content/daily-email/2023-08-23.md
+++ /dev/null
@@ -1,19 +0,0 @@
----
-title: >
- Don't use third-party services directly
-pubDate: 2023-08-23
-permalink: >
- archive/2023/08/23/dont-use-third-party-services-directly
-tags:
- - automated-testing
----
-
-If you need to integrate your application with a third-party service, don't integrate it directly - even if it has an SDK.
-
-Doing so locks you into a single implementation and a single vendor.
-
-If you write your own integration layer, it's possible to add multiple implementations, such as different payment gateways, that conform with a single interface.
-
-If you need to switch to a different provider or add multiple options, you can without changing the existing code.
-
-It also makes it easier to test as you can write a fake implementation and use it for testing.
diff --git a/astro/src/content/daily-email/2023-08-24.md b/astro/src/content/daily-email/2023-08-24.md
deleted file mode 100644
index 1012ddb3..00000000
--- a/astro/src/content/daily-email/2023-08-24.md
+++ /dev/null
@@ -1,24 +0,0 @@
----
-title: >
- Testing multiple implementations with contract tests
-pubDate: 2023-08-24
-permalink: >
- archive/2023/08/24/testing-multiple-implementations-with-contract-tests
-tags:
- - automated-testing
- - test-driven-development
----
-
-If you have multiple implementations of a service, as I [mentioned in yesterday's email](https://www.oliverdavies.uk/archive/2023/08/23/dont-use-third-party-services-directly), you need to ensure they all provide the same functionality.
-
-You need to be able to run the same tests against each implementation and have them pass.
-
-## How do you do this?
-
-In PHP, I use a trait that contains the test methods and then have a test class for each implementation that uses the trait and sets up any test data.
-
-Then, each test class will run the methods from the contract test trait and ensure they all provide the same behaviour, regardless of how it does so - whether it communicates with an API, uses an SDK, or returns fake values.
-
-If one implementation doesn't return the same result as the others, its test will fail.
-
-If you add a new implementation, you create a new test class, use the trait and get the tests to pass.
diff --git a/astro/src/content/daily-email/2023-08-25.md b/astro/src/content/daily-email/2023-08-25.md
deleted file mode 100644
index cc2670a0..00000000
--- a/astro/src/content/daily-email/2023-08-25.md
+++ /dev/null
@@ -1,18 +0,0 @@
----
-title: >
- Start with a vague test
-pubDate: 2023-08-25
-permalink: >
- archive/2023/08/25/start-with-a-vague-test
-tags:
- - automated-testing
- - test-driven-development
----
-
-If you're unsure what your first test should be, start by writing a test with an intentionally vague name, just to get you started.
-
-It may not be clear straight away what you're trying to test.
-
-Once you get the ball rolling and you write more, it will usually become clear.
-
-Then you can go back and rename the test method to something more specific.
diff --git a/astro/src/content/daily-email/2023-08-26.md b/astro/src/content/daily-email/2023-08-26.md
deleted file mode 100644
index 971c0a34..00000000
--- a/astro/src/content/daily-email/2023-08-26.md
+++ /dev/null
@@ -1,20 +0,0 @@
----
-title: >
- Work in small chunks
-pubDate: 2023-08-26
-permalink: >
- archive/2023/08/26/work-in-small-chunks
-tags:
- - automated-testing
- - test-driven-development
----
-
-When working with teams who are starting with automated tests and test-driven development, a common issue is being stuck on a failing test and trying to do too much at once while getting it to pass.
-
-Instead, work in small bite-sized iterations and focus on getting the test to pass as quickly as possible.
-
-You don't want to be stuck in a failing state for longer than you need to.
-
-Run the tests often, write the simplest code possible and don't write any code that isn't driven by a failing test.
-
-Don't make too many changes at once so, if you do get stuck, you can reset to the last working test and start again.
diff --git a/astro/src/content/daily-email/2023-08-27.md b/astro/src/content/daily-email/2023-08-27.md
deleted file mode 100644
index f8a4409f..00000000
--- a/astro/src/content/daily-email/2023-08-27.md
+++ /dev/null
@@ -1,25 +0,0 @@
----
-title: >
- Pull requests are great for open-source, but not for teams
-pubDate: 2023-08-27
-permalink: >
- archive/2023/08/27/pull-requests-are-great-for-open-source
-tags:
- - code-review
- - git
- - trunk-based-development
----
-
-Code review with pull and merge requests is great for open-source but not for development teams or soloists.
-
-On an open-source project, the code changes are most likely being submitted by someone you don't know and don't work with regularly, so having a step to review the code prior to merging it and decide if you want to take on the responsibility of maintaining it is a big decision.
-
-On a development team, you work closely with the person submitting the change request and you have a shared responsibility and ownership of the code being added. The person isn't going to submit their change and not be seen again.
-
-It takes time for code to be reviewed, which means it takes longer for the change to be released to users.
-
-If you're a soloist, are you going to submit a request for you to review your own code?
-
-If you don't need to do code review on your team, do you need to create feature or topic branches?
-
-I'd suggest sticking to one canonical branch and doing trunk-based development instead.
diff --git a/astro/src/content/daily-email/2023-08-28.md b/astro/src/content/daily-email/2023-08-28.md
deleted file mode 100644
index 5111bdbd..00000000
--- a/astro/src/content/daily-email/2023-08-28.md
+++ /dev/null
@@ -1,21 +0,0 @@
----
-title: >
- Pair and mob programming are continuous code review
-pubDate: 2023-08-28
-permalink: >
- archive/2023/08/28/pair-and-mob-programming-are-continuous-code-review
-tags:
- - code-review
- - pair-programming
- - mob-programming
----
-
-Instead of a single Developer working individually on a task and submitting it for a code review once complete, try pair or mob programming.
-
-As well as extra benefits, such as knowledge sharing and shared responsibility for the code, it's continuously reviewed and improved during the session.
-
-Questions from "Why are we doing it this way?" to "What's the best name for this variable?" can be asked, and decisions and changes can be made in real time.
-
-So, why wait until the task is complete and the code is harder to change to review it?
-
-Why not have it reviewed as it's written?
diff --git a/astro/src/content/daily-email/2023-08-29.md b/astro/src/content/daily-email/2023-08-29.md
deleted file mode 100644
index 189f06e5..00000000
--- a/astro/src/content/daily-email/2023-08-29.md
+++ /dev/null
@@ -1,34 +0,0 @@
----
-title: >
- CI pipelines are an automated code review
-pubDate: 2023-08-29
-permalink: >
- archive/2023/08/29/ci-pipelines-are-an-automated-code-review
-tags:
- - code-review
- - ci-pipelines
----
-
-I've worked on various teams over the last 13 years on which we've needed to do feature branches, pull requests and code reviews.
-
-If the request isn't approved by (usually) two people, it won't be merged.
-
-Instead of focusing on the problem that needed to be solved and how I'd done it, many reviews focused on the small details.
-
-Do the lines have the correct number of spaces before them?
-
-Do the comments end with a full stop?
-
-Do the lines wrap at the correct point, and are your variable names in the right case?
-
-Essentially, does the code comply with the agreed coding standards?
-
-## Here's the thing
-
-Whilst important (you want the code to follow standards and be in a consistent format), doing these checks manually is not a good use of time and is not what the code review should focus on.
-
-These checks can be automated using CI pipelines or Git hooks to run tools like PHPCS to review and sometimes fix coding standards issues.
-
-Automating these checks means the Developers can focus on what they should be reviewing.
-
-How are they solving the problem, not how many spaces is the code indented by.
diff --git a/astro/src/content/daily-email/2023-08-30.md b/astro/src/content/daily-email/2023-08-30.md
deleted file mode 100644
index af2f00cb..00000000
--- a/astro/src/content/daily-email/2023-08-30.md
+++ /dev/null
@@ -1,22 +0,0 @@
----
-title: >
- TDD and "Unexpected errors"
-pubDate: 2023-08-30
-permalink: >
- archive/2023/08/30/tdd-and-unexpected-errors
-tags:
- - automated-testing
- - test-driven-development
----
-
-When working on projects, it's common to see messages like "The website encountered an unexpected error. Please try again later.".
-
-Usually, this is the message shown to the user, whilst a more detailed error message is logged for Developers to diagnose and fix the underlying error.
-
-The wording "unexpected error" has been intriguing to me, though. When do you expect an error?
-
-The best example I can think of for an expected error is when doing test-driven development.
-
-When doing TDD, you want to see an error to start as you start with a failing test.
-
-Then, you write the code to remove the error and get the test passing.
diff --git a/astro/src/content/daily-email/2023-08-31.md b/astro/src/content/daily-email/2023-08-31.md
deleted file mode 100644
index 9aca2822..00000000
--- a/astro/src/content/daily-email/2023-08-31.md
+++ /dev/null
@@ -1,16 +0,0 @@
----
-title: >
- Code review discourages small refactorings
-pubDate: 2023-08-31
-permalink: >
- archive/2023/08/31/code-review-discourages-small-refactorings
-tags:
- - code-reviews
- - trunk-based-development
----
-
-If, for every change to a codebase, you need to create a topic branch, create a pull or merge request, and wait for it to be reviewed and approved - which can take days, weeks or longer - does that discourage you from making small changes?
-
-If you spotted some unused commented-out code whilst working in a file and went to remove it or a variable that could have a better name, would you change it?
-
-Alternatively, if you could make the change and know from a CI pipeline within a few minutes that everything still worked, would you be more likely to make the change and improve the code for yourself and the next person to work on it?
diff --git a/astro/src/content/daily-email/2023-09-01.md b/astro/src/content/daily-email/2023-09-01.md
deleted file mode 100644
index 8b4e13d9..00000000
--- a/astro/src/content/daily-email/2023-09-01.md
+++ /dev/null
@@ -1,28 +0,0 @@
----
-title: >
- Non-blocking code reviews
-pubDate: 2023-09-01
-permalink: >
- archive/2023/09/01/non-blocking-code-reviews
-tags:
- - ci-pipelines
- - code-review
----
-
-If your team wants or needs to do code reviews, but you don't want it to slow down development, you could implement non-blocking code reviews.
-
-Instead of creating a topic branch for a feature or fix, creating a pull or merge request and waiting for it to be reviewed before merging, the commit is merged, and the code is reviewed afterwards.
-
-The ticket workflow could look like this:
-
-To Do -> Doing -> Merged -> Reviewed -> Tested -> Deployed
-
-Or:
-
-To Do -> Doing -> Merged -> Deployed -> Tested -> Reviewed
-
-The focus is getting the update to production, and the review is deferred.
-
-The same CI pipeline rules apply - it must be passing before the code can be deployed, so the same quality checks are run.
-
-With this approach, the code is still reviewed, either in the pull or merge request or by the commits on the mainline branch if doing trunk-based development. It's just done later.
diff --git a/astro/src/content/daily-email/2023-09-02.md b/astro/src/content/daily-email/2023-09-02.md
deleted file mode 100644
index e5381f54..00000000
--- a/astro/src/content/daily-email/2023-09-02.md
+++ /dev/null
@@ -1,31 +0,0 @@
----
-title: >
- Planning first or reviewing last?
-pubDate: 2023-09-02
-permalink: >
- archive/2023/09/02/planning-first-or-reviewing-last
-tags:
- - code-review
- - pair-programming
- - mob-programming
----
-
-Code reviews are something that happens after the code has been written.
-
-Usually, a task is assigned to someone who completes it and makes the code available to their team members before it's merged.
-
-The problem is that if the implementation is wrong, it's already been written, which costs time and money.
-
-If the change needed to be rewritten or majorly changed before it could be merged, as well as being an awkward conversation, it would cost more time and money to do.
-
-## Here's the thing
-
-Instead of reviewing the code after it's been written, invest more time into planning how the implementation should work upfront.
-
-What potential solutions exist, and which would work best in this situation?
-
-Write technical design documents and, if needed, create a small proof of concept.
-
-Do this as a team and decide on the approach before any code is written and time or effort is spent.
-
-Then, the person working on the task will have a clearer path, and if you still want to review the code afterwards, you have something to compare it to.
diff --git a/astro/src/content/daily-email/2023-09-03.md b/astro/src/content/daily-email/2023-09-03.md
deleted file mode 100644
index 48aa684d..00000000
--- a/astro/src/content/daily-email/2023-09-03.md
+++ /dev/null
@@ -1,18 +0,0 @@
----
-title: >
- Including time for tests in estimates
-pubDate: 2023-09-03
-permalink: >
- archive/2023/09/03/including-time-for-tests-in-estimates
-tags:
- - automated-testing
- - test-driven-development
- - software-development
- - estimation
----
-
-If you need to provide estimates for your tasks and intend to write tests, include the time for the tests within the estimate.
-
-Don't provide different estimates for testing and the implementation, or with tests and without tests - give one estimate that includes both.
-
-Writing tests and testable code will take longer to begin with, but practice makes perfect and will save time in the long run.
diff --git a/astro/src/content/daily-email/2023-09-04.md b/astro/src/content/daily-email/2023-09-04.md
deleted file mode 100644
index c355fa9f..00000000
--- a/astro/src/content/daily-email/2023-09-04.md
+++ /dev/null
@@ -1,22 +0,0 @@
----
-title: >
- Charging more _not_ to write tests
-pubDate: 2023-09-04
-permalink: >
- archive/2023/09/04/charging-more-not-to-write-tests
-tags:
- - automated-testing
- - test-driven-development
----
-
-Joel Clermont [replied to a previous email on Twitter](https://twitter.com/jclermont/status/1690872089878691840):
-
-> I once toyed around with the idea of charging MORE to do it without tests. Had a client pushing back very hard when I mentioned testing (what I thought they’d perceive as a benefit). Ended up not pursuing it, but was a fun idea at the time.
-
-It's an interesting idea.
-
-How much more would you charge not to write tests?
-
-How much more would make you feel comfortable and confident that the application works as expected, and would cover the additional time for finding and fixing the bugs caused by not writing tests?
-
-As Joel said, it was a fun idea, though it seems counter-intuitive to me, as the a client would be paying more for worse software.
diff --git a/astro/src/content/daily-email/2023-09-05.md b/astro/src/content/daily-email/2023-09-05.md
deleted file mode 100644
index 093df338..00000000
--- a/astro/src/content/daily-email/2023-09-05.md
+++ /dev/null
@@ -1,24 +0,0 @@
----
-title: >
- Spring clean before upgrading
-pubDate: 2023-09-05
-permalink: >
- archive/2023/09/05/spring-clean-before-upgrading
-tags:
- - drupal
- - software-upgrades
----
-
-One of the first things I do when reviewing whether an application can be upgraded is to look for anything that can be removed.
-
-If it has modules that aren't used, uninstall and remove them.
-
-A common one for Drupal projects is modules left from previous migrations, such as from Field Collections to Paragraphs that are no longer needed but still present.
-
-Remove any old themes that are no longer used.
-
-If you have content types, fields or views that aren't used, remove them, assuming you don't need the data.
-
-Remove unused routes, Controllers or other classes not used in custom modules, or any other unused custom code.
-
-Less moving parts means less to upgrade now and maintain in the future.
diff --git a/astro/src/content/daily-email/2023-09-06.md b/astro/src/content/daily-email/2023-09-06.md
deleted file mode 100644
index 9262a863..00000000
--- a/astro/src/content/daily-email/2023-09-06.md
+++ /dev/null
@@ -1,25 +0,0 @@
----
-title: >
- Verbosity over abstraction
-pubDate: 2023-09-06
-permalink: >
- archive/2023/09/06/verbosity-over-abstraction
-tags:
- - software-development
----
-
-Recently, a steamer said they "prefer verbosity over abstraction/confusion".
-
-In that scenario, it was regarding the name of a microservice they were creating. It was long and verbose, but it described what it did.
-
-It was clear to anyone working on that project what that service did, now and in the future.
-
-I prefer this to shorter, less-descriptive names.
-
-I hardly ever create a variable called `$x`, `$k` or `$v`. I only would if it was clear what it meant within its context.
-
-I like to write descriptive names for test methods that explain what the test is doing. Even if I start with a vague name, I'll refactor it to make it more specific and clearer.
-
-I prefer not to use PHP functions like `compact` and to write it out and avoid the abstraction and any confusion it could cause.
-
-I prefer code to be verbose, descriptive and easy to read, understand and change.
diff --git a/astro/src/content/daily-email/2023-09-07.md b/astro/src/content/daily-email/2023-09-07.md
deleted file mode 100644
index 295643ba..00000000
--- a/astro/src/content/daily-email/2023-09-07.md
+++ /dev/null
@@ -1,59 +0,0 @@
----
-title: >
- What's the simplest test to begin with?
-pubDate: 2023-09-07
-permalink: >
- archive/2023/09/07/what-s-the-simplest-test-to-begin-with
-tags:
- - software-development
- - automated-testing
- - test-driven-development
- - php
- - drupal
----
-
-When giving talks and workshops or coaching on automated testing and test-driven development, some people may not have written tests before and aren't familiar with the structure or know where to begin.
-
-In the workshops I ran for DrupalCamp London and DrupalCamp NYC, I wanted to cover this first before writing any implementation code.
-
-Where do you put a test class, and what does it contain?
-
-How do you run the tests, and how can you make it pass or fail?
-
-## What we did
-
-To start, we wrote a test for existing functionality within Drupal core - anonymous users can visit the front page.
-
-This is the whole test:
-
-```php
-drupalGet('');
-
- $this->assertResponse(Response::HTTP_OK);
- }
-
-}
-```
-
-This is a test someone can write, run and see the test pass.
-
-They can then experiment by changing the values to make the test fail in different ways.
-
-## What next?
-
-Then, we tested anonymous users cannot access the administration pages, which is also already the case in Drupal core, and then authenticated users with the correct permissions could access them.
-
-People were getting the idea by now, and we moved on to writing and testing some of our own code.
diff --git a/astro/src/content/daily-email/2023-09-08.md b/astro/src/content/daily-email/2023-09-08.md
deleted file mode 100644
index bfe9566b..00000000
--- a/astro/src/content/daily-email/2023-09-08.md
+++ /dev/null
@@ -1,24 +0,0 @@
----
-title: >
- Do you proactively refactor your code?
-pubDate: 2023-09-08
-permalink: >
- archive/2023/09/08/do-you-proactively-refactor-your-code
-tags:
- - software-development
- - refactoring
----
-
-Do you go back and proactively refactor code you've previously written?
-
-In my experience, once some code is working, it's usually not reviewed again and refactored, and any TODO comments are still there.
-
-If code is refactored, it's usually triggered by adding a new feature or fixing a bug that will be difficult or impossible with the existing code - i.e., make the change easy, then make the easy change.
-
-Very rarely have I seen code be refactored to make it easier to read or change in the future.
-
-Do you proactively refactor code or wait until something forces it to happen?
-
-Do you not refactor code at all once it's been written?
-
-Reply to this email and let me know which and why.
diff --git a/astro/src/content/daily-email/2023-09-09.md b/astro/src/content/daily-email/2023-09-09.md
deleted file mode 100644
index ed5878c3..00000000
--- a/astro/src/content/daily-email/2023-09-09.md
+++ /dev/null
@@ -1,26 +0,0 @@
----
-title: >
- A lack of tests discourages refactoring
-pubDate: 2023-09-09
-permalink: >
- archive/2023/09/09/a-lack-of-tests-discourages-refactoring
-tags:
- - automated-testing
- - test-driven-development
- - refactoring
- - software-development
----
-
-A common cause of not refactoring code is a lack of test coverage.
-
-Why change some code if it works? What if we break it whilst refactoring it and introduce a regression?
-
-If the code has accompanying automated tests, this can't happen.
-
-The tests should be passing before starting a refactor and should be passing once the refactor is complete.
-
-If the tests fail, the refactor was unsuccessful and should be reverted.
-
-If you have a CI pipeline, a failing test should break the pipeline and prevent any further steps if you're doing continuous delivery or deployment whilst signalling to the Developer their refactor was unsuccessful and the pipeline needs to be fixed.
-
-Without tests, the code could be broken during the refactor, and we wouldn't know.
diff --git a/astro/src/content/daily-email/2023-09-10.md b/astro/src/content/daily-email/2023-09-10.md
deleted file mode 100644
index a927f52a..00000000
--- a/astro/src/content/daily-email/2023-09-10.md
+++ /dev/null
@@ -1,19 +0,0 @@
----
-title: >
- Code is read more than it's written
-pubDate: 2023-09-10
-permalink: >
- archive/2023/09/10/code-is-read-more-than-it-s-written
-tags:
- - software-development
----
-
-A lot of code is written once by one person and not changed again.
-
-But it's read by multiple people at multiple times.
-
-If the code is read more than it's written, we should be optimising it for readability so it's easier for people to understand.
-
-The application doesn't care whether you wrote the code the "clever" way or the "boring" way, but people will appreciate the more readable version.
-
-If I need to review or work on the code in the future, I want to read and understand it easily.
diff --git a/astro/src/content/daily-email/2023-09-11.md b/astro/src/content/daily-email/2023-09-11.md
deleted file mode 100644
index 7fa426ae..00000000
--- a/astro/src/content/daily-email/2023-09-11.md
+++ /dev/null
@@ -1,61 +0,0 @@
----
-title: >
- Don't use "else"
-pubDate: 2023-09-11
-permalink: >
- archive/2023/09/11/dont-use-else
-tags:
- - software-development
- - clean-code
----
-
-
-A popular approach to writing clean code is to avoid the "else" keyword and, if possible, avoid nesting `if` statements within other `if` statements.
-If I look at some code, I want to see as few indentation levels as possible, making the code easier to read and understand.
-
-## What should I do instead?
-
-Instead, you check for a condition; if that isn't met, you return early.
-For example, here is some code I saw recently during a meetup talk:
-
-```php
-$callingClass = $scope->getClassReflection()->getName();
-
-if ($callingClass === TextMessageQueueProcessor::class) {
- return [];
-}
-
-$type = $scope->getType($node->var);
-
-foreach ($type->getReferencedClasses() as $targetClass) {
- if ($targetClass === TextMessageSender::class) {
- return [
- RuleErrorBuilder::message(
- sprintf(
- "Can not call %s from %s",
- $targetClass,
- $callingClass
- )
- )->build()
- ];
- }
-}
-
-return [];
-```
-
-There are no `else` statements.
-
-If the calling class isn't of the required type, it returns immediately with no violations, and we continue, knowing the calling class must be what we need.
-
-If the target class is one where the code shouldn't be called from, it returns immediately with the violation.
-
-Finally, if no violations were found within the referenced classes, it returns an empty array.
-
-## Here's the thing
-
-The code always returns an array of rule violations but does so as soon as possible at each point.
-
-The code is clean and readable, and I can understand it, knowing once each condition is passed, I don't need to continue thinking about it.
-
-Whilst there are some situations to use `else`, most of the time I've found that I can use an early return instead.
diff --git a/astro/src/content/daily-email/2023-09-12.md b/astro/src/content/daily-email/2023-09-12.md
deleted file mode 100644
index 9a1c5d1b..00000000
--- a/astro/src/content/daily-email/2023-09-12.md
+++ /dev/null
@@ -1,22 +0,0 @@
----
-title: >
- Don't inject too many dependencies
-pubDate: 2023-09-12
-permalink: >
- archive/2023/09/12/dont-inject-too-many-dependencies
-tags:
- - software-development
- - clean-code
----
-
-While dependency injection is a good practice - i.e., passing dependencies into a class, usually via a constructor method - you want to be aware of how many dependencies you inject into each class.
-
-There's no hard and fast rule, but I usually notice when I get to three dependencies and rarely inject more than four or five into a class.
-
-Having too many dependencies suggests that the class is doing too much and has too many responsibilities and that another class may be needed.
-
-## Here's the thing
-
-Having smaller and simpler classes makes them easier to read, maintain and review. Ideally, each class should only have one responsibility, so it adheres to the Single Responsibility Principle (the "S" in SOLID).
-
-Creating classes is cheap, so why not split one large and difficult-to-maintain class with many dependencies into multiple smaller and easier-to-work-with ones?
diff --git a/astro/src/content/daily-email/2023-09-13.md b/astro/src/content/daily-email/2023-09-13.md
deleted file mode 100644
index f7d42a0a..00000000
--- a/astro/src/content/daily-email/2023-09-13.md
+++ /dev/null
@@ -1,48 +0,0 @@
----
-title: >
- Which type of test should I use?
-pubDate: 2023-09-13
-permalink: >
- archive/2023/09/13/which-type-of-test-should-i-use
-tags:
- - drupal
- - php
- - automated-testing
- - test-driven-development
----
-
-Drupal offers a few different types of tests you can use, but how do you know which one to pick?
-
-This is how I decide based on what I need to test by asking these questions:
-
-## Do I need to test HTTP requests and responses?
-
-Do I need to make GET or POST requests to a URL and check its response code, e.g. to check the endpoint exists, that I get an expected "Page not found" or "Forbidden" message, or to check if an item was created or updated?
-
-If so, use a `Functional` test like `BrowserTestBase`.
-
-## Do I need to test with JavaScript?
-
-`BrowserTestBase` doesn't include JavaScript, so use a `FunctionaJavaScript` test if needed.
-
-## Do I need to retrieve services from the service/Dependency Injection container?
-
-If I don't need to make HTTP requests but need access to the service container, I use a Kernel test such as `KernelTestBase`.
-
-There's more setup for kernel tests compared to functional tests, such as installing the required configuration and creating schema tables in the database. However, having less installed means the tests run faster.
-
-There are different base classes, such as `EntityKernelTestBase`, that can be used depending on the situation to simplify the setup.
-
-## Can I test the code in isolation without the service container?
-
-If I can test the code without needing the service container and mock simple dependencies, then use a `Unit` test.
-
-These are very fast to run, but you can overuse mocks and sometimes test the mocks instead of the code you intended to test.
-
-## Here's the thing
-
-As well as the regular unit test type, Drupal offers various types of test that can be used depending on the situation.
-
-I like to start with functional tests first and switch to kernel or unit tests when needed. They're slower to run but easier to write as they need less setup and arguably provide the most value.
-
-If you're just getting started with testing, they're probably the quickest to learn too.
diff --git a/astro/src/content/daily-email/2023-09-14.md b/astro/src/content/daily-email/2023-09-14.md
deleted file mode 100644
index 026c6615..00000000
--- a/astro/src/content/daily-email/2023-09-14.md
+++ /dev/null
@@ -1,25 +0,0 @@
----
-title: >
- Outside-in or inside-out?
-pubDate: 2023-09-14
-permalink: >
- archive/2023/09/14/outside-in-or-inside-out
-tags:
- - software-development
- - automated-testing
- - test-driven-development
----
-
-[In yesterday's email][yesterday], I described the different types of tests available in Drupal and how to determine which test I should use.
-
-I start with functional tests and move to kernel or unit tests when needed, so I usually have more functional tests, some kernel tests and a few unit tests.
-
-This is the outside-in approach to testing.
-
-The opposite is inside-out testing when you start with unit tests and have fewer functional tests.
-
-Tests written outside-in are slower to run as they need to perform tasks like HTTP requests and interact with the database, compared to unit tests, which are fast to run but do reply on mocking dependencies rather than using real services and content.
-
-Which do you prefer? Reply and let me know.
-
-[yesterday]: https://www.oliverdavies.uk/archive/2023/09/13/which-type-of-test-should-i-use
diff --git a/astro/src/content/daily-email/2023-09-15.md b/astro/src/content/daily-email/2023-09-15.md
deleted file mode 100644
index 6b5b18bf..00000000
--- a/astro/src/content/daily-email/2023-09-15.md
+++ /dev/null
@@ -1,53 +0,0 @@
----
-title: >
- Types or no types
-pubDate: 2023-09-15
-permalink: >
- archive/2023/09/15/types-or-no-types
-tags:
- - software-development
- - types
- - JavaScript
- - TypeScript
----
-
-Here are two versions of some example code I've recently been working on.
-
-One has types and uses TypeScript, the other is JavaScript and has no types.
-
-Which do you prefer and why?
-
-## TypeScript (with types)
-
-```js
-add(...numbers: number[]): number {
- return numbers.reduce((a: number, b: number) => a + b, 0);
-}
-
-subtract(...numbers: number[]): number {
- let total = numbers[0];
-
- for (var i = 1, length = numbers.length; i < length; i++) {
- total -= numbers[i];
- }
- return total;
-}
-```
-
-## JavaScript (no types)
-
-```js
-add(...numbers){
- return numbers.reduce((a, b) => a + b, 0);
-}
-
-subtract(...numbers) {
- let total = numbers[0];
-
- for (var i = 1, length = numbers.length; i < length; i++) {
- total -= numbers[i];
- }
-
- return total;
-}
-```
diff --git a/astro/src/content/daily-email/2023-09-16.md b/astro/src/content/daily-email/2023-09-16.md
deleted file mode 100644
index 153ff5b5..00000000
--- a/astro/src/content/daily-email/2023-09-16.md
+++ /dev/null
@@ -1,60 +0,0 @@
----
-title: >
- How not to break 36,000 websites
-pubDate: 2023-09-16
-permalink: >
- archive/2023/09/16/how-not-to-break-36-000-websites
-tags:
- - drupal
- - php
- - automated-testing
- - test-driven-development
----
-
-I've maintained the Override Node Options module for Drupal since early 2012.
-
-I've maintained the Drupal 7 version and written new versions for Drupal 8 onwards.
-
-At the time of writing, the module is used on at least 36,244 active Drupal websites.
-
-I don't want to break 36,000 websites, and automated testing is my way of avoiding that.
-
-I have three examples of how automated testing helped me when working on this module.
-
-## Upgrading to Drupal 8
-
-When writing the initial Drupal 8 version of the module, as I started re-writing a feature, the first thing I did was recreate the tests from the Drupal 7 version.
-
-Then, I followed a test-driven development approach to get the test passing using the Drupal 7 code for reference.
-
-When the whole test suite was in place and passing, I knew there was feature parity between the two versions.
-
-## Resolving a large merge conflict
-
-I was reviewing a feature request that had been open for some time, which included a large patch file with the code changes to implement it.
-
-However, the patch no longer applied to the code, which caused various merge conflicts.
-
-There were no additional tests within the patch, but I was able to use the existing tests to ensure the original functionality worked once the merge conflicts were resolved and there were no regressions caused by committing the patch.
-
-I did later add tests for the new functionality, but without the original test suite, I would have likely not have accepted the patch and not committed the feature.
-
-## Refactoring the code
-
-A few years ago, a colleague and I wanted to refactor the module code to make it more maintainable and easier to work on.
-
-Then, the module was used on around 30,000 websites, so this could have been risky.
-
-However, we had the test suite to ensure the functionality still worked and that our refactors were successful.
-
-If we broke something and introduced a regression, a test would fail, and we could fix it.
-
-Following the release containing the refactored code, there were no reported issues or regressions from the community.
-
-## Here's the thing
-
-Automated testing is about providing confidence.
-
-Confidence the software works as expected and is releasable, either to clients for custom software or consumers of open-source software.
-
-With a passing test suite, you can add and change code with confidence and without worrying about breaking it.
diff --git a/astro/src/content/daily-email/2023-09-17.md b/astro/src/content/daily-email/2023-09-17.md
deleted file mode 100644
index d7742d1b..00000000
--- a/astro/src/content/daily-email/2023-09-17.md
+++ /dev/null
@@ -1,26 +0,0 @@
----
-title: >
- How much refactoring should I be doing?
-pubDate: 2023-09-17
-permalink: >
- archive/2023/09/17/how-much-refactoring-should-i-be-doing
-tags:
- - software-development
- - test-driven-development
- - automated-testing
- - refactoring
----
-
-I watched a webinar recently, and one of the panellists asked, "How much refactoring should I be doing?".
-
-The reply was, "More than you're doing now.".
-
-It was quite tongue-in-cheek, but I agree that, in general, code isn't refactored enough.
-
-One main reason is a fear of introducing regressions, and to avoid that, you need a good automated test suite.
-
-If you break the existing functionality whilst refactoring, you want the test suite to fail so you can identify and fix the regression.
-
-If the test suite passes, you can release the new code.
-
-How many tests and how much coverage do you need? There's no specfic answer - enough for you to be confident everything still works.
diff --git a/astro/src/content/daily-email/2023-09-18.md b/astro/src/content/daily-email/2023-09-18.md
deleted file mode 100644
index 979c7f4e..00000000
--- a/astro/src/content/daily-email/2023-09-18.md
+++ /dev/null
@@ -1,27 +0,0 @@
----
-title: >
- Increasing test coverage with regression tests
-pubDate: 2023-09-18
-permalink: >
- archive/2023/09/18/increasing-test-coverage-with-regression-tests
-tags:
- - software-development
- - automated-testing
- - test-driven-development
----
-
-Automated test suites don't tell you everything works - they tell you what you've tested isn't broken.
-
-Having tests doesn't mean your code is bug-free. There could be edge cases or scenarios you haven't tested for that contain bugs, even though your test suite is passing.
-
-## What do we do?
-
-When you find a bug, try replicating it within an automated test before attempting to fix it.
-
-Once you have a failing test and can replicate the issue, go ahead and fix it.
-
-If the test passes, you know you've fixed the bug and solved the issue.
-
-## Here's the thing
-
-Now you have this test, you cannot re-add the bug again without the test failing. You've prevented anyone from accidentally re-introducing it in the future and increased your test coverage.
diff --git a/astro/src/content/daily-email/2023-09-19.md b/astro/src/content/daily-email/2023-09-19.md
deleted file mode 100644
index b5855707..00000000
--- a/astro/src/content/daily-email/2023-09-19.md
+++ /dev/null
@@ -1,31 +0,0 @@
----
-title: >
- Stop writing tests
-pubDate: 2023-09-19
-permalink: >
- archive/2023/09/19/stop-writing-tests
-tags:
- - software-development
- - test-driven-development
- - automated-testing
----
-
-A few years ago, I worked at an agency on a client project.
-
-We were writing automated tests and doing test-driven development. We were releasing features, and everything was going well.
-
-Mid-way through the project, we were told to stop writing tests as it was taking "too long".
-
-We did, and the number of bugs increased almost instantly.
-
-We went from essentially no bugs to having a number of tickets being rejected through our quality assurance and the client's user-acceptance testing, as well as in production by the website's users.
-
-The time we spent re-working the issues, fixing the bugs and doing remedial work in production would likely have been less than the time it would have taken to write the tests initially and avoided any reputational damage.
-
-We started writing tests again later during that project, but the middle phase was the most stressful part, and the most bugs were created.
-
-## Here's the thing
-
-It's not just about how long it takes to write the tests.
-
-Having tests will save time overall by having fewer bugs that need to be fixed, less remedial work in production, and less reshuffling of priorities to re-work tickets that affect the project plan and timescales as well as the team's output and velocity.
diff --git a/astro/src/content/daily-email/2023-09-20.md b/astro/src/content/daily-email/2023-09-20.md
deleted file mode 100644
index b272529c..00000000
--- a/astro/src/content/daily-email/2023-09-20.md
+++ /dev/null
@@ -1,46 +0,0 @@
----
-title: >
- Why I prefer types
-pubDate: 2023-09-20
-permalink: >
- archive/2023/09/20/why-i-prefer-types
-tags:
- - software-development
- - types
- - javascript
- - typescript
----
-
-Whether it's PHP or JavaScript/TypeScript, I prefer type declarations in my code.
-
-As well as benefits like auto-completion in your IDE or text editor and being able to more effectively statically analyse the code, to me, the code is more readable and easier to understand with the types included.
-
-It's more to read, but I can do so easily and immediately know what a function expects as function arguments and what it will return.
-
-Here's the code from my previous email on types from a few days ago, with and without the types declared:
-
-```js
-add(...numbers) {
- // ...
-}
-
-subtract(...numbers) {
- // ...
-}
-
-add(...numbers: number[]): number {
- // ...
-}
-
-subtract(...numbers: number[]): number {
- // ...
-}
-```
-
-Without types, I can infer what the function accepts and returns, but that's based on my assumption, which could be incorrect.
-
-What if `numbers` was an array of strings of numbers - e.g. `['one', 'two', 'three']` - and what if instead of returning the result, it stored it in state to return from a different method like `equals()` or `calculate()`?
-
-With the type declarations included, I don't need to presume, infer or make best guesses.
-
-It's clear from just reading the code.
diff --git a/astro/src/content/daily-email/2023-09-21.md b/astro/src/content/daily-email/2023-09-21.md
deleted file mode 100644
index 6195e7bc..00000000
--- a/astro/src/content/daily-email/2023-09-21.md
+++ /dev/null
@@ -1,25 +0,0 @@
----
-title: >
- Buggy software causes reputational damage
-pubDate: 2023-09-21
-permalink: >
- archive/2023/09/21/buggy-software-causes-reputational-damage
-tags:
- - software-development
- - automated-testing
- - feature-flags
- - continuous-integration
- - continuous-delivery
----
-
-As well as taking longer to fix than locally or in a failed CI pipeline, shipping buggy software to production causes reputational damage.
-
-If an application goes down or doesn't run as expected, it could get noticed by your customers, clients, or your clients' customers.
-
-You want your customers and clients to be assured you're writing the correct software based on their needs and requirements, and doing so with as few bugs and issues as possible.
-
-While there are always bugs in software and occasional unexpected downtime, having these happen regularly can damage your and, if applicable, your client's reputation.
-
-Therefore, it's in everyone's interest to write high-quality and well-tested software.
-
-There will be fewer bugs, and by following practices such as feature flags and continuous integration and delivery, they can be fixed faster.
diff --git a/astro/src/content/daily-email/2023-09-22.md b/astro/src/content/daily-email/2023-09-22.md
deleted file mode 100644
index 0af1e4d1..00000000
--- a/astro/src/content/daily-email/2023-09-22.md
+++ /dev/null
@@ -1,23 +0,0 @@
----
-title: >
- Documentation and comments get stale. Tests don't.
-pubDate: 2023-09-22
-permalink: >
- archive/2023/09/22/documentation-and-comments-get-stale
-tags:
- - software-development
- - automated-testing
- - static-analysis
----
-
-I'm sure you've seen code comments that say the code will do something when, in fact, it does something different.
-
-Or documentation that has become outdated and stale and no longer correct.
-
-Automated tests and other tools, such as static analysis, are executable documentation, so they can't become stale.
-
-If the implementation code changes and no longer matches the tests, the tests will fail, and either the implementation or test can be updated.
-
-Then, if you need to refer to the test, as long as it's passing, you know what it shows is still applicable.
-
-The same can't be said for markdown files, Confluence pages, Word documents or other static documentation.
diff --git a/astro/src/content/daily-email/2023-09-23.md b/astro/src/content/daily-email/2023-09-23.md
deleted file mode 100644
index 87607398..00000000
--- a/astro/src/content/daily-email/2023-09-23.md
+++ /dev/null
@@ -1,27 +0,0 @@
----
-title: >
- Everyone tests their code, but not everyone writes automated tests
-pubDate: 2023-09-23
-permalink: >
- archive/2023/09/23/not-everyone-writes-automated-tests
-tags:
- - software-development
- - test-driven-development
- - automated-testing
----
-
-Everyone tests their code.
-
-No one writes code and ships it to production before testing it works.
-
-It's just that most Developers test their code manually.
-
-They write the code, switch to a browser or terminal, and run it.
-
-It might be a quick task, such as reloading a page or executing a command, or it could be complex and time-consuming, such as filling in a long form and checking the results.
-
-In this case, automated testing is a good option.
-
-Instead of filling in the form, have the tests do it for you.
-
-It will be quicker and more reliable than doing it manually.
diff --git a/astro/src/content/daily-email/2023-09-24.md b/astro/src/content/daily-email/2023-09-24.md
deleted file mode 100644
index 7f865ea8..00000000
--- a/astro/src/content/daily-email/2023-09-24.md
+++ /dev/null
@@ -1,33 +0,0 @@
----
-title: >
- Test to save your job
-pubDate: 2023-09-24
-permalink: >
- archive/2023/09/24/test-to-save-your-job
-tags:
- - software-development
- - automated-testing
- - test-driven-development
----
-
-I've recently been going through my YouTube "Watch Later" list and watching (or rewatching) videos of conference and meetup talks that I saved to watch later.
-
-Today's talk was by Matt Stauffer at one of the previous Laracon conferences.
-
-I've quoted Matt previously when explaining what to test on applications. The answer: "The thing you'd lose your job for if it broke".
-
-In this talk, Matt has a slide that goes further into this, titled "Test to save your job".
-
-## What Matt said
-
-The best place to start your tests is by asking yourself: "What part of this app, if broken, would make me worried for my job?"
-
-* What's most likely to break?
-* What do I have the least control over?
-* What are we about to refactor?
-* What would make my clients stress out?
-* What would make me stressed out?
-
-## What about you?
-
-Do you have any other ways to decide what code to test? Reply and let me know, as I'd love to know.
diff --git a/astro/src/content/daily-email/2023-09-25.md b/astro/src/content/daily-email/2023-09-25.md
deleted file mode 100644
index d44d8b1b..00000000
--- a/astro/src/content/daily-email/2023-09-25.md
+++ /dev/null
@@ -1,27 +0,0 @@
----
-title: >
- Should you use a staging environment?
-pubDate: 2023-09-25
-permalink: >
- archive/2023/09/25/should-you-use-a-staging-environment
-tags:
- - software-development
----
-
-The purpose of any pre-production version of your website or application (any version that isn't the public live one) is to mimic the production version and as a test run for deployments.
-
-**If I deploy this feature, will it break the website?**
-
-The issue with most staging and other pre-production environments is that they differ from what's on production. It may have been some time since the latest data was added, and its value is only as good as how close to production it is and how likely it is to find potential issues in production.
-
-If they differ greatly, the staging environment offers no value.
-
-It's not a true comparison, and instead of being a test run for a deployment to production, you're only reviewing the deployment to the staging environment itself.
-
-## Here's the thing
-
-The best situation I've experienced is where a sanitised snapshot was synced to all pre-production environments every night.
-
-I knew that my environment was, at most, a single day out of date, and I was confident that my changes would work in production if they did there.
-
-In that situation, the staging site works and testing it has value, but if it's weeks or months out of date, it doesn't, as there are too many differences for it to be an accurate representation.
diff --git a/astro/src/content/daily-email/2023-09-26.md b/astro/src/content/daily-email/2023-09-26.md
deleted file mode 100644
index 3e5f9322..00000000
--- a/astro/src/content/daily-email/2023-09-26.md
+++ /dev/null
@@ -1,36 +0,0 @@
----
-title: >
- Which branch should be in which environment?
-pubDate: 2023-09-26
-permalink: >
- archive/2023/09/26/which-branch-should-be-in-which-environment
-tags:
- - software-development
- - git
- - trunk-based-development
- - feature-flags
----
-
-A common question is which [Git] branch should be on which environment.
-
-Most projects I've worked on have two or more environments: production, staging (or test) and development.
-
-Earlier in my career, we used Git Flow heavily. A Git branching workflow based on having different branches - i.e. `develop`, `master` and any arbitrary short-lived feature, hotfix and release branches.
-
-These matched nicely with our three environments.
-
-Usually, the `develop` branch would be used in the development environment. The `master` branch would be on staging and a tagged release from `master` on production.
-
-## What about now?
-
-I prefer trunk-based development, where there is one long-lived branch to which everyone commits their changes.
-
-There's only one branch, so you can either follow continuous deployment and use the same branch for all environments - including production - or separate production using a dedicated branch or tag if you need more control.
-
-The mainline branch is used in all pre-production environments, such as staging and development.
-
-## What about differences between the environments?
-
-What if we need differences, such as a feature that must be enabled in a particular environment if the same code is on both?
-
-My go-to approach is feature flagging, and this approach is something I'll describe more in tomorrow's email.
diff --git a/astro/src/content/daily-email/2023-09-27.md b/astro/src/content/daily-email/2023-09-27.md
deleted file mode 100644
index 0315396d..00000000
--- a/astro/src/content/daily-email/2023-09-27.md
+++ /dev/null
@@ -1,28 +0,0 @@
----
-title: >
- Separating environments with feature flags
-pubDate: 2023-09-27
-permalink: >
- archive/2023/09/27/separating-environments-with-feature-flags
-tags:
- - software-development
- - feature-flags
----
-
-You have two or more environments and versions of your application, but you do trunk-based development, so you only have a single branch that you use on all environments.
-
-But if all environments have the same code, how can we have differences between them?
-
-What if we want a feature enabled on one environment and not the other?
-
-## Feature flags
-
-Feature flags are an approach I've previously written about. You have two branches of logic within your code, and the flow changes based on whether a flag is enabled.
-
-If a flag is enabled, execute the first block of code. Otherwise, execute the second.
-
-Now, you enable and disable the required feature flags for each environment.
-
-**The code is the same for all environments, but the enabled features and functionality are different.**
-
-Then, once the feature has been deployed and released in production, the feature flag can be removed.
diff --git a/astro/src/content/daily-email/2023-09-28.md b/astro/src/content/daily-email/2023-09-28.md
deleted file mode 100644
index 33060eef..00000000
--- a/astro/src/content/daily-email/2023-09-28.md
+++ /dev/null
@@ -1,36 +0,0 @@
----
-title: >
- Feature flags enable continuous integration
-pubDate: 2023-09-28
-permalink: >
- archive/2023/09/28/feature-flags-enable-continuous-integration
-tags:
- - software-development
- - git
- - continuous-integration
- - feature-flags
----
-
-I was recently working on a feature over a few mob programming sessions.
-
-After the session, we implemented part of the feature but couldn't merge it as it wasn't complete.
-
-After working on other things that day, I'd need to rebase my local commits and push the last-but-one commit to the remote repository to keep the incomplete feature only in my local repository (I forgot a few times and almost pushed it accidentally).
-
-The commit prevented me from following continuous integration - where everyone commits and pushes their code a minimum of once daily.
-
-What if someone else wanted to look at that code between mob sessions? They couldn't, as it was only on my laptop.
-
-If I'd made a temporary branch, it would be outdated and behind other changes to our mainline branch.
-
-## Feature flags to the rescue
-
-As this commit was part of a larger change, it couldn't be merged, so we added a feature flag around it.
-
-The values were set to null and hidden by default, and populated by the new changes and displayed if the flag was enabled.
-
-## Here's the thing
-
-This meant we could safely push the commit, make the changes available to everyone and enable the feature on the environments we wanted - preventing it from showing on production.
-
-This allowed us to get back to our usual working practices, and I didn't need to worry about accidentally pushing the commit and prematurely showing our changes in production.
diff --git a/astro/src/content/daily-email/2023-09-29.md b/astro/src/content/daily-email/2023-09-29.md
deleted file mode 100644
index df636fe3..00000000
--- a/astro/src/content/daily-email/2023-09-29.md
+++ /dev/null
@@ -1,36 +0,0 @@
----
-title: >
- 92 changed files with 885 additions and 156 deletions
-pubDate: 2023-09-29
-permalink: >
- archive/2023/09/29/92-changed-files-with-885-additions-and-156-deletions
-tags:
- - software-development
- - automated-testing
- - test-driven-development
- - refactoring
----
-
-Today, I refactored some code on a client's Drupal project I've been working on.
-
-This is what the commit says:
-
-> Showing 92 changed files with 885 additions and 156 deletions
-
-So, it's not a small refactor.
-
-As I worked on the custom modules needed for the site, I noticed that some common functionality was spread over multiple modules. This refactor moved that functionality into its own module, which is now a dependency of the others.
-
-The code is better, and the responsibilities of the modules are clearer.
-
-Whilst a large amount of those additions are adding test modules with test configuration, it's not a small refactor.
-
-## Here's the thing
-
-This is what it says at the bottom of the CI pipeline output:
-
-> OK (79 tests, 565 assertions)
-
-This is the same number of passing tests and assertions I had before I started the refactor, so I know the functionality still works.
-
-If I didn't have those tests, I wouldn't have done the refactor.
diff --git a/astro/src/content/daily-email/2023-09-30.md b/astro/src/content/daily-email/2023-09-30.md
deleted file mode 100644
index 353135ee..00000000
--- a/astro/src/content/daily-email/2023-09-30.md
+++ /dev/null
@@ -1,34 +0,0 @@
----
-title: >
- Automated testing offers repeatability
-pubDate: 2023-09-30
-permalink: >
- archive/2023/09/30/automated-testing-offers-repeatability
-tags:
- - automated-testing
- - test-driven-development
----
-
-You work on feature or bug fix.
-
-It gets tested manually by you, a tester, and the person who requested the feature or reported the bug.
-
-It may get tested on multiple environments.
-
-It passes and it moved to production.
-
-But now it's live, it's not tested again.
-
-Although it works now, there's no guarantee it's not broken or regressed by subsequent changes.
-
-It's definitely not tested manually before every future release.
-
-## Here's the thing
-
-Automated testing offers repeatability.
-
-The tests pass, so the functionality works when you wrote it, and you can re-check it by re-running the test.
-
-The test suite can be run by Developers whilst working on other changes, before code review and before deployments.
-
-The test suite can be run automatically in a CI pipeline for every change that's pushed, and you'll know your change not only worked at the time but will continue to work.
diff --git a/astro/src/content/daily-email/2023-10-01.md b/astro/src/content/daily-email/2023-10-01.md
deleted file mode 100644
index b21d0a01..00000000
--- a/astro/src/content/daily-email/2023-10-01.md
+++ /dev/null
@@ -1,26 +0,0 @@
----
-title: >
- TDD: repeat and refactor
-pubDate: 2023-10-01
-permalink: >
- archive/2023/10/01/tdd--repeat-and-refactor
-tags:
- - automated-testing
- - software-development
- - test-driven-development
- - refactoring
----
-
-With test-driven development, you start with a failing test and focus on getting it to pass.
-
-But what do you do once it's passing?
-
-You either repeat the process, adding more assertions to the same test until you generate the next failure or write the next failing test, or take the opportunity to refactor the code.
-
-Is there something you'd like to change within the implementation or test code? You can do that whilst the tests are passing.
-
-You may want to extract a new class or method to improve the implementation or create some test helpers to reduce duplication within the tests.
-
-You just need to keep the tests passing to ensure the code still works. If something breaks, you fix it as soon as possible, either by fixing the code or reverting to the previously passing code.
-
-Then, once you've completed the refactoring, move back into the red/green phase with the next test failure.
diff --git a/astro/src/content/daily-email/2023-10-02.md b/astro/src/content/daily-email/2023-10-02.md
deleted file mode 100644
index 56381718..00000000
--- a/astro/src/content/daily-email/2023-10-02.md
+++ /dev/null
@@ -1,37 +0,0 @@
----
-title: >
- Only comment what needs to be commented
-pubDate: 2023-10-02
-permalink: >
- archive/2023/10/02/only-comment-what-needs-to-be-commented
-tags:
- - software-development
- - clean-code
----
-
-"If you comment everything, people won't read them."
-
-"As soon as one comment is incorrect, the result will be ignored."
-
-These are two comments I heard recently referring to code comments.
-
-If there are too many comments, people will get lost in the information. They won't be able to differentiate boilerplate comments from valuable ones, and as soon as one comment is incorrect, people will assume that others could likely be incorrect too and ignore them.
-
-A solution to these is to only comment what needs to be commented.
-
-Only write comments that add value, and if there are fewer comments, they are easier to read and maintain - making it more likely they will be incorrect.
-
-This is an example from an open source pull request:
-
-```php
-/**
- * An interface for field access override.
- */
-interface FieldAccessOverrideInterface {
-```
-
-In my opinion, this doesn't add any value or additional context as it repeats what's already there.
-
-Something I put in my project configuration files is to tweak the coding standards to not check, for example, for class and method docblocks - allowing me to add them where I want and where I think they're needed and add value.
-
-I think this is better than having comments everywhere, and I can focus on the ones that matter.
diff --git a/astro/src/content/daily-email/2023-10-03.md b/astro/src/content/daily-email/2023-10-03.md
deleted file mode 100644
index cd09f048..00000000
--- a/astro/src/content/daily-email/2023-10-03.md
+++ /dev/null
@@ -1,33 +0,0 @@
----
-title: >
- There is no perfect solution
-pubDate: 2023-10-03
-permalink: >
- archive/2023/10/03/there-is-no-perfect-solution
-tags:
- - software-development
----
-
-Something I've said recently when mentoring bootcamp students and working with Junior Developers is that there isn't a perfect solution to each problem, and there are multiple ways to achieve the same result.
-
-Similarly, there isn't a perfect tool for every situation.
-
-You can use different tools and get the same outcome.
-
-In some of my early emails, I talked about `run` files and `just` - two ways to write project-specific commands or aliases that simplify complex commands or group multiple commands together.
-
-Both do the same thing, but each have pros and cons.
-
-`run` files are files written in Bash, which are more verbose but can run anywhere.
-
-just is its own program that needs to be installed for it to be available, so Developers will need to have it installed, and it will need to be added to a CI pipeline to be available.
-
-I've had CI pipelines fail because they can't download just, and not because of anything in the application code.
-
-I like the simplicity of justfiles, though, and that the files are simpler.
-
-## Here's the thing
-
-If there isn't a perfect solution, approach, or tool, it comes down to the pros and cons of each. Which option is best for you, your project, or your team?
-
-There isn't a "one size fits all" solution that works for everyone all the time.
diff --git a/astro/src/content/daily-email/2023-10-04.md b/astro/src/content/daily-email/2023-10-04.md
deleted file mode 100644
index 8fb1b3de..00000000
--- a/astro/src/content/daily-email/2023-10-04.md
+++ /dev/null
@@ -1,21 +0,0 @@
----
-title: >
- The best solution is the one that gets the tests to pass
-pubDate: 2023-10-04
-permalink: >
- archive/2023/10/04/the-best-solution-is-the-one-that-gets-the-tests-to-pass
-tags:
- - software-development
- - automated-testing
- - test-driven-development
----
-
-As I said yesterday, there is no perfect solution or approach for every situation.
-
-However, when doing test-driven development, there is a best solution.
-
-The simplest thing that gets a failing test to pass.
-
-Whether it's hard-coding a return value or putting the initial logic in a Controller, that's the objective.
-
-Once the test is passing, you can refactor the code or continue writing tests, which will each have their own best solution.
diff --git a/astro/src/content/daily-email/2023-10-05.md b/astro/src/content/daily-email/2023-10-05.md
deleted file mode 100644
index 7dc094ee..00000000
--- a/astro/src/content/daily-email/2023-10-05.md
+++ /dev/null
@@ -1,20 +0,0 @@
----
-title: >
- Some solutions are good enough
-pubDate: 2023-10-05
-permalink: >
- archive/2023/10/05/some-solutions-are-good-enough
-tags:
- - software-development
- - technical-debt
----
-
-Once you have a passing test and you're confident your code works as expected, what do you do next?
-
-Do you keep refactoring and changing it, or is it good enough?
-
-Do you need to extract additional classes and methods now, or as the test is passing, do you move on to the next task?
-
-The main objective is to ship the change and for it to provide value to users, not to have a perfect or "gold-plated" solution.
-
-Once it's shipped, because you have tests, you can confidently refactor it in the future.
diff --git a/astro/src/content/daily-email/2023-10-06.md b/astro/src/content/daily-email/2023-10-06.md
deleted file mode 100644
index 61db2883..00000000
--- a/astro/src/content/daily-email/2023-10-06.md
+++ /dev/null
@@ -1,19 +0,0 @@
----
-title: >
- Software development is like going to the Dentist
-pubDate: 2023-10-06
-permalink: >
- archive/2023/10/06/software-development-is-like-going-to-the-dentist
-tags:
- - software-development
- - refactoring
- - deployments
----
-
-Working on software development tasks is like going to the Dentist.
-
-Releasing new features, bug fixes, dependency updates, and refactoring is better and less painful when done regularly.
-
-Doing these changes in small and regular batches is less risky than less frequent and larger releases.
-
-It's easier to identify the cause of any issues and correct course if things aren't going to plan.
diff --git a/astro/src/content/daily-email/2023-10-07.md b/astro/src/content/daily-email/2023-10-07.md
deleted file mode 100644
index 9921ca82..00000000
--- a/astro/src/content/daily-email/2023-10-07.md
+++ /dev/null
@@ -1,31 +0,0 @@
----
-title: >
- A breakdown of tests from a current project
-pubDate: 2023-10-07
-permalink: >
- archive/2023/10/07/a-breakdown-of-tests-from-a-current-project
-tags:
- - software-development
- - automated-testing
- - test-driven-development
----
-
-I've just added the hundredth test to a client project I'm developing.
-
-I'm following [the outside-in approach](https://www.oliverdavies.uk/archive/2023/09/14/outside-in-or-inside-out), starting with functional tests and moving to kernel and unit tests where needed - meaning more functional tests and fewer unit tests - most of which cover some complex search functionality containing custom blocks, forms, endpoints for autocomplete lists, pattern matching and results pages, which is the core functionality of the project.
-
-Here's the breakdown of the different types of tests:
-
-* Functional - 57 tests, 180 assertions
-* Kernel - 38 tests, 495 assertions
-* Unit - 5 tests, 18 assertions
-
-The tests are run automatically in a CI pipeline by GitHub Actions and Docker and usually run in two or three minutes.
-
-The project is still in progress, so I'll add more tests for the remaining functionality and possibly remove some too, as I refactor some of the code.
-
----
-
-P.S. Are you interested in automated testing and test-driven development? I'm speaking about it at DrupalCon Europe on the 17th of October!
-
-You can also pre-register for my free 7-day automated testing email course at https://opdavi.es/testing-email-course.
diff --git a/astro/src/content/daily-email/2023-10-08.md b/astro/src/content/daily-email/2023-10-08.md
deleted file mode 100644
index 56bab954..00000000
--- a/astro/src/content/daily-email/2023-10-08.md
+++ /dev/null
@@ -1,25 +0,0 @@
----
-title: >
- Is test-driven development difficult?
-pubDate: 2023-10-08
-permalink: >
- archive/2023/10/08/is-test-driven-development-difficult
-tags:
- - software-development
- - automated-testing
- - test-driven-development
- - continuous-integration
- - trunk-based-development
----
-
-I recently read a post where the writer said automated testing, test-driven development, continuous integration, trunk-based development, etc, are difficult.
-
-I'm familiar with them and have been using them for some time, but I think trunk-based development is easier as there's only a single branch instead of many.
-
-Continuous integration is pulling everyone else's code at least once daily and pushing yours to ensure it doesn't conflict.
-
-Test-driven development is writing failing tests before any implementation code and refactoring once it passes.
-
-I don't think these are technically difficult, but they do require an open mind, a willingness to learn, evaluate and consider alternative approaches and, in some cases, change existing behaviour.
-
-Change can be the difficult part, not which brand you commit to, how often you push your code or when you write your tests.
diff --git a/astro/src/content/daily-email/2023-10-09.md b/astro/src/content/daily-email/2023-10-09.md
deleted file mode 100644
index ca4c16cc..00000000
--- a/astro/src/content/daily-email/2023-10-09.md
+++ /dev/null
@@ -1,20 +0,0 @@
----
-title: >
- Spotting new things in Drupal 10.1
-pubDate: 2023-10-09
-permalink: >
- archive/2023/10/09/spotting-new-things-in-drupal-10-1
-tags:
- - php
- - drupal
----
-
-I've recently updated my [Drupal Docker example project][project] to Drupal 10.1.5 and have been spotting new things.
-
-From British English as my default option during installation, UX improvements to the admin pages, and developer settings such as Twig caching being configurable in the admin UI.
-
-Something I've loved since Drupal 8 is the constant new features and iterative improvements being added to Drupal core.
-
-I'm looking forward to finding more of these as I keep upgrading my Docker example project as well as others.
-
-[project]: https://github.com/opdavies/docker-example-drupal
diff --git a/astro/src/content/daily-email/2023-10-10.md b/astro/src/content/daily-email/2023-10-10.md
deleted file mode 100644
index 9b41c5a0..00000000
--- a/astro/src/content/daily-email/2023-10-10.md
+++ /dev/null
@@ -1,56 +0,0 @@
----
-title: >
- Why use Composer to manage Drupal dependencies?
-pubDate: 2023-10-10
-permalink: >
- archive/2023/10/10/why-use-composer-to-manage-drupal-dependencies
-tags:
- - software-development
- - drupal
- - php
- - phpc
- - composer
----
-
-One of the initial negatives when Drupal 8 launched was introducing Composer, PHP's dependency manager, and how it could affect non-technical users.
-
-When I started doing Drupal, I downloaded the .tar.gz or .zip file of Drupal, extracted it, and placed it within my project.
-
-I did the same for any additional modules I needed.
-
-To update them, I needed to delete my files and repeat the process of downloading and replacing them.
-
-## Drush
-
-Then, instead of doing it manually, I used Drush, the "Drupal shell", to download the files. This saved some time, but it still has down-sides.
-
-What if you needed to install a module like Pathauto, which has dependencies you also need to download and install?
-
-With Drush or downloading the files manually, you'd need to download the dependencies separately.
-
-## Composer
-
-Composer is a dependency manager, which means it can handle these dependencies for us.
-
-It looks at each project's `composer.json` file to find its dependencies and downloads them.
-
-For example, to install Pathauto, you run `composer require drupal/pathauto`.
-
-Within its output, you'll see this:
-
-```plain
-Package operations: 3 installs, 0 updates, 0 removals
- - Downloading drupal/token (1.12.0)
- - Downloading drupal/ctools (4.0.4)
- - Downloading drupal/pathauto (1.12.0)
-```
-
-As well as Pathauto, it's downloading its dependencies - ctools and pathauto.
-
-Instead of downloading three modules, we can do it with one command.
-
-In fact, we don't need to know what its dependencies are - Composer will do that.
-
-Also, updating the modules is just another simple command - `composer update`.
-
-While it may be intimidating to non-technical users, learning a few simple commands makes installing and updating modules much easier!
diff --git a/astro/src/content/daily-email/2023-10-11.md b/astro/src/content/daily-email/2023-10-11.md
deleted file mode 100644
index 15053b23..00000000
--- a/astro/src/content/daily-email/2023-10-11.md
+++ /dev/null
@@ -1,25 +0,0 @@
----
-title: >
- Do you need that module?
-pubDate: 2023-10-11
-permalink: >
- archive/2023/10/11/do-you-need-that-module
-tags:
- - software-development
- - drupal
- - php
----
-
-Drupal includes a lot of default functionality and additional core modules you can enable to extend it.
-
-There are also over 50,000 community-contributed modules you can download and add.
-
-But is it worth adding every module?
-
-If you're browsing the list of modules on Drupal.org and find one of interest, is the functionality it adds more valuable than the cost of maintaining it?
-
-Each module increases the number of updates you'll need to do to maintain the website.
-
-What if it becomes unmaintained in the future and prevents you from updating your website to the next version of Drupal or has a security issue and introduces a vulnerability?
-
-Some modules will be crucial to your website, others you can do without if you prefer a smaller maintenance overhead.
diff --git a/astro/src/content/daily-email/2023-10-12.md b/astro/src/content/daily-email/2023-10-12.md
deleted file mode 100644
index 4837b430..00000000
--- a/astro/src/content/daily-email/2023-10-12.md
+++ /dev/null
@@ -1,22 +0,0 @@
----
-title: >
- Business logic in template files?
-pubDate: 2023-10-12
-permalink: >
- archive/2023/10/12/business-logic-in-template-files
-tags:
- - software-development
- - drupal
- - twig
- - automated-testing
----
-
-I've often heard and advocated for not "putting logic" in template files and having a separation of concerns.
-
-The templates should be as simple to read and change as possible, and any complicated logic should be moved elsewhere.
-
-There can be presentational logic - such as a simple if condition to determine if a value should be shown or looping over a list of items, but business logic should be within custom code - ideally within Service, Action or Command classes - and injected into the templates.
-
-As well as making the templates simpler and cleaner, this logic can be tested separately with automated tests to ensure it works as expected. If the logic is within a template, this can be done for some things using Functional tests, such as whether some text appears on a page, but testing whether it appears in a certain order, for example, is much harder. This is best done within kernel or unit tests.
-
-As well as being more testable, extracting the logic from a template makes it more reusable. You can use a service from multiple places within your website without duplicating it, making your website code smaller and easier to maintain.
diff --git a/astro/src/content/daily-email/2023-10-13.md b/astro/src/content/daily-email/2023-10-13.md
deleted file mode 100644
index ecf4e45d..00000000
--- a/astro/src/content/daily-email/2023-10-13.md
+++ /dev/null
@@ -1,17 +0,0 @@
----
-title: >
- Writing tests is an investment
-pubDate: 2023-10-13
-permalink: >
- archive/2023/10/13/writing-tests-is-an-investment
-tags:
- - software-development
- - automated-testing
- - test-driven-development
----
-
-It can take time to write automated tests and do test-driven development, but it is an investment in a project's future stability.
-
-Spending time to write tests upfront will save time as the project progresses, make the code easier to change, and result in better software, fewer bugs, and quicker changes.
-
-Even though it takes time, it's time well spent.
diff --git a/astro/src/content/daily-email/2023-10-14.md b/astro/src/content/daily-email/2023-10-14.md
deleted file mode 100644
index 53d0580b..00000000
--- a/astro/src/content/daily-email/2023-10-14.md
+++ /dev/null
@@ -1,27 +0,0 @@
----
-title: >
- Do you need to write tests for small or short-lived projects?
-pubDate: 2023-10-14
-permalink: >
- archive/2023/10/14/do-you-need-to-write-tests-for-small-or-short-lived-projects
-tags:
- - software-development
- - automated-testing
- - test-driven-development
----
-
-When does it make sense not to write automated tests?
-
-Tests prevent regressions in codebases that are changed and updated over time.
-
-So, if you're working on a short-term project, such as a marketing campaign website that will only be live for a few months, you won't get as much benefit from having tests, especially if you may not even change it once it's live.
-
-Likewise, tests are useful for projects on which you want to avoid downtime and outages, especially if you sell products via your website or it contains important information. For other websites, such as personal blogs, that are less critical, testing may be less beneficial.
-
-Also, one of Drupal's key benefits is that you can build websites within the Drupal UI, without needing to write custom code.
-
-If you're going down this route, there is no custom code to test and a separate tool that checks URLs exist and returns the correct response code would be a better fit.
-
-If you then need to add any custom code and functionality, you may want to add tests.
-
-Whilst there are some situations where not writing tests is reasonable, there are more reasons and situations when you should, compared to not.
diff --git a/astro/src/content/daily-email/2023-10-15.md b/astro/src/content/daily-email/2023-10-15.md
deleted file mode 100644
index 9857a320..00000000
--- a/astro/src/content/daily-email/2023-10-15.md
+++ /dev/null
@@ -1,14 +0,0 @@
----
-title: >
- Off to DrupalCon
-pubDate: 2023-10-15
-permalink: >
- archive/2023/10/15/off-to-drupalcon
-tags:
- - drupal
- - drupalcon
----
-
-This week, I'll be in Lille, France for DrupalCon Europe, where I'm presenting a session on automated testing and test-driven development in Drupal.
-
-I'll be taking a short break from these emails to enjoy the conference, focus on my talk, and finish my free email course on automated testing in Drupal.
diff --git a/astro/src/content/daily-email/2023-10-23.md b/astro/src/content/daily-email/2023-10-23.md
deleted file mode 100644
index 59f09cfc..00000000
--- a/astro/src/content/daily-email/2023-10-23.md
+++ /dev/null
@@ -1,31 +0,0 @@
----
-title: >
- When should you run your tests?
-pubDate: 2023-10-23
-permalink: >
- archive/2023/10/23/when-should-run-your-tests
-tags:
- - software-development
- - automated-testing
- - test-driven-development
----
-
-After my talk at DrupalCon, I was asked when you should run your tests.
-
-Of course, if you're doing test-driven development, you have to run the tests as you work on them and have the red, green, refactor cycle as you work on the feature or bug fix.
-
-If you're not doing TDD, I'd recommend running the whole test suite before you push your code to know it works before a peer review or to an environment for quality assurance or user-acceptance testing.
-
-## What about CI pipelines?
-
-As well as running tests manually, I'd add them to a CI pipeline, such as GitHub Actions, GitLab CI or Bitbucket Pipelines.
-
-There, tasks can be run automatically each time a commit is pushed, so you don't need to rely on them being run manually.
-
-If you're doing trunk-based development, you want the CI pipeline to run on every push to prevent regressions and ensure the tests continue to pass.
-
-If you're working with feature branches and doing code review, run the tests as part of the merge or pull request so you know everything works as expected before the code is reviewed.
-
-This answers the main "Does it work?" question, and allows the reviewer to focus on reviewing the code and suggesting improvements.
-
-If the CI pipeline in the merge or pull request fails, it needs to be fixed before submitting it for review as there's no need to review the code before it changes to fix the pipeline.
diff --git a/astro/src/content/daily-email/2023-10-24.md b/astro/src/content/daily-email/2023-10-24.md
deleted file mode 100644
index 32fa0e5d..00000000
--- a/astro/src/content/daily-email/2023-10-24.md
+++ /dev/null
@@ -1,31 +0,0 @@
----
-title: >
- How to test code you didn't write
-pubDate: 2023-10-24
-permalink: >
- archive/2023/10/24/how-to-test-code-you-didnt-write
-tags:
- - software-development
- - automated-testing
- - test-driven-development
----
-
-I was also asked at DrupalCon how you write tests for code you didn't write and how you cover all of the use cases and scenarios.
-
-This is tricky. If you didn't write the code, how can you know all the scenarios you need to test?
-
-Presumably, there is some documentation, Jira tickets, user stories or acceptance criteria from when the code was written that will help you with this.
-
-Decide the most critical functionality to be tested and focus on that, as that will provide the most value.
-
-I'd start with functional tests and test for high-level outcomes, such as whether a page loads, returns the correct status code, and contains the expected text.
-
-Then, iteratively add more tests for other scenarios. Once you have the first one written, this should be easier as you already have the setup steps, such as which modules must be enabled and what configuration needs to be installed.
-
-**One test is better than none.**
-
-If you need to add any new features or fixes, ensure they have their own tests to keep a consistent level of coverage.
-
-Even with a simple module, you're unlikely to be able to identify all of the scenarios, write all the tests in one go, and have everything covered.
-
-Start with the most important test first and continue to add more iteratively.
diff --git a/astro/src/content/daily-email/2023-10-25.md b/astro/src/content/daily-email/2023-10-25.md
deleted file mode 100644
index 69c59c15..00000000
--- a/astro/src/content/daily-email/2023-10-25.md
+++ /dev/null
@@ -1,29 +0,0 @@
----
-title: >
- Automated tests prevent regressions when upgrading
-pubDate: 2023-10-25
-permalink: >
- archive/2023/10/25/automated-tests-prevent-regressions-when-upgrading
-tags:
- - software-development
- - php
- - drupal
- - automated-testing
- - test-driven-development
----
-
-With Drupal 9 almost being end-of-life and unsupported, I've recently been doing a lot of Drupal 9 to 10 upgrade work.
-
-As it's a major version update, there are breaking changes that mean you may need to change your code.
-
-Here's an example of an error caused by a breaking change:
-
-> Drupal\Core\Entity\Query\QueryException: Entity queries must explicitly set whether the query should be access checked or not. See Drupal\Core\Entity\Query\QueryInterface::accessCheck().
-
-To fix this, you need to call the `accessCheck()` method before executing a query and specify whether it should be checked.
-
-But how do you know if it should be checked?
-
-If you have automated tests that pass beforehand and still pass afterwards, you picked the correct option.
-
-If the test passes before and fails afterwards, you found the bug and can fix it immediately to ensure the functionality works as before.
diff --git a/astro/src/content/daily-email/2023-10-26.md b/astro/src/content/daily-email/2023-10-26.md
deleted file mode 100644
index 8fade6ee..00000000
--- a/astro/src/content/daily-email/2023-10-26.md
+++ /dev/null
@@ -1,34 +0,0 @@
----
-title: >
- Is decoupled Drupal still a thing?
-pubDate: 2023-10-26
-permalink: >
- archive/2023/10/26/is-decoupled-drupal-still-a-thing
-tags:
- - software-development
- - drupal
- - decoupled-drupal
- - vuejs
----
-
-A few years ago, decoupled or headless Drupal - where Drupal is used as an API with a separate front-end - was very popular with some large Drupal agencies and clients using it.
-
-[I gave a conference talk][talk] about how to use Drupal as a backend application for a Vue.js frontend.
-
-Recently, though, I haven't heard much about it.
-
-Some previous advocates have moved back to the more traditional approach.
-
-Interestingly, though, I did hear quite a bit about it at DrupalCon and about Drupal and Next.js in particular.
-
-I want to try using Drupal with Astro in the future and see what the landscape is like now.
-
-## What about you?
-
-Do you use Drupal in a decoupled or headless way? If so, what do you use for the frontend?
-
-If not, or if you've moved back to a more traditional approach, why?
-
-Reply and let me know.
-
-[talk]: https://www.oliverdavies.uk/talks/decoupling-drupal-vuejs
diff --git a/astro/src/content/daily-email/2023-10-27.md b/astro/src/content/daily-email/2023-10-27.md
deleted file mode 100644
index 9152d1b4..00000000
--- a/astro/src/content/daily-email/2023-10-27.md
+++ /dev/null
@@ -1,38 +0,0 @@
----
-title: >
- Work with me and support the Drupal Association
-pubDate: 2023-10-27
-permalink: >
- archive/2023/10/27/work-with-me-and-support-the-drupal-association
-tags:
- - drupal
- - open-source
- - php
- - phpc
----
-
-I used to work for the [Drupal Association][association] - the non-profit organisation that supports the Drupal project, organises DrupalCon, and maintains Drupal.org.
-
-I improved Drupal.org, fixed Drupal 8 release blockers, improved user profiles, helped make the Drupal.org theme responsive, and assisted with new websites like Drupal Events and Jobs.
-
-At DrupalCon, one of the keynote speakers said, "The Drupal Association is a small but mighty team".
-
-On the [Association staff page][staff], there are 15 staff members listed, including only five people in the Engineering team.
-
-I've been in the Drupal community for a long time and worked for various companies that make money from Drupal - a free and open-source project.
-
-However, it's "free as in puppies". You can have the puppy for free, but it costs time and money to look after it.
-
-There are programs like the Supporting Partners program which provide funding to the DA, but, at least when I worked there, a large amount of income was from event revenue from DrupalCon.
-
-## Here's the thing
-
-As someone who works mainly on Drupal consulting and development projects, I'm pledging to commit a fixed percentage from my Drupal-related services and products to the Drupal Association, including my new [team coaching] service.
-
-If the Association or Drupal weren't there, I wouldn't be able to provide those products and services, so it's in my interest to support the Drupal project and the Drupal Association. Maybe others will do the same.
-
-**Work with me and support the Drupal Association.**
-
-[association]: https://www.drupal.org/association
-[staff]: https://www.drupal.org/association/staff
-[team coaching]: https://www.oliverdavies.uk/team-coaching
diff --git a/astro/src/content/daily-email/2023-10-28.md b/astro/src/content/daily-email/2023-10-28.md
deleted file mode 100644
index fcb0c6ad..00000000
--- a/astro/src/content/daily-email/2023-10-28.md
+++ /dev/null
@@ -1,19 +0,0 @@
----
-title: >
- Can you move faster without tests?
-pubDate: 2023-10-28
-permalink: >
- archive/2023/10/28/can-you-move-faster-without-tests
-tags:
- - software-development
- - automated-testing
- - test-driven-development
----
-
-If you don't write automated tests or do test-driven development, you might move quickly to begin with - writing code and doing small amounts of manual testing.
-
-But, once you start changing the code to add new features or fix bugs, things will begin to slow down.
-
-You'll have more to test and need to ensure you don't break the existing functionality as well as your new code works.
-
-Whilst it may be faster initially, skipping tests will cause problems later.
diff --git a/astro/src/content/daily-email/2023-10-29.md b/astro/src/content/daily-email/2023-10-29.md
deleted file mode 100644
index 526e15bb..00000000
--- a/astro/src/content/daily-email/2023-10-29.md
+++ /dev/null
@@ -1,22 +0,0 @@
----
-title: >
- I can drive my car blindfolded, but is it a good idea?
-pubDate: 2023-10-29
-permalink: >
- archive/2023/10/29/i-can-drive-my-car-blindfolded-but-is-it-a-good-idea
-tags:
- - software-development
- - automated-testing
- - test-driven-development
----
-
-After sending [yesterday's email][yesterday], Dave Hall replied [with a LinkedIn comment][comment] I liked and wanted to share (done with permission):
-
-> In theory I can drive my car on the motorway, blind folded while not wearing a seat belt. It sounds really exciting and loads of fun. When something goes wrong it gets really messy.
->
-> I tend to think of skipping automated tests in the same way.
-
-Just because you can do something, it doesn't mean you should.
-
-[comment]: https://www.linkedin.com/feed/update/urn:li:activity:7124401304315027456
-[yesterday]: https://www.oliverdavies.uk/archive/2023/10/28/can-you-move-faster-without-tests
diff --git a/astro/src/content/daily-email/2023-10-30.md b/astro/src/content/daily-email/2023-10-30.md
deleted file mode 100644
index 1516324f..00000000
--- a/astro/src/content/daily-email/2023-10-30.md
+++ /dev/null
@@ -1,25 +0,0 @@
----
-title: >
- Is Drupal a CMS or a framework?
-pubDate: 2023-10-30
-permalink: >
- archive/2023/10/30/is-drupal-a-cms-or-a-framework
-tags:
- - php
- - phpc
- - drupal
----
-
-Drupal is typically called a CMS (content management system) - somewhere you add and edit the content for your website.
-
-However, unlike some other CMSes, unless a Drupal website uses only the default page and article content type, no Drupal websites are the same. Each will have its specific content model with different content types and fields.
-
-Instead of being a content management system, Drupal can be described as a content management framework (CMF) - a framework for building a content management system specific to each application.
-
-But as well as a content management framework, Drupal could also be considered an application framework like Symfony or Laravel.
-
-As well as building the content model, you can extend Drupal's functionality with custom modules and add custom themes to make it visually different.
-
-But, there's a lot of functionality in Drupal core itself - such as user accounts, authentication, a query builder (Views), JSON:API endpoints, and a visual page editor (Layout Builder) - to name a few things!
-
-Drupal offers much more than just managing content.
diff --git a/astro/src/content/daily-email/2023-10-31.md b/astro/src/content/daily-email/2023-10-31.md
deleted file mode 100644
index 053fd3a3..00000000
--- a/astro/src/content/daily-email/2023-10-31.md
+++ /dev/null
@@ -1,33 +0,0 @@
----
-title: >
- One official Drupal development environment?
-pubDate: 2023-10-31
-permalink: >
- archive/2023/10/31/one-official-drupal-development-environment
-tags:
- - drupal
- - php
----
-
-Yesterday, I read [a post by Kevin Quillen][post] titled 'DDEV being considered as the "official" Drupal development environment'.
-
-I've been a DDEV user, and I've also used most, if not all, of the other popular Drupal development environments.
-
-These days, I use [my own Docker Compose-based setup][mine], but I feel having an official development environment would be an excellent move for the Drupal community and project - and for new Drupal users, evaluators and contributors in particular.
-
-Anything that lowers the barrier to using or contributing to Drupal is a good thing and allows for more focused documentation and a simpler onboarding experience, similar to what other projects have - such as Laravel with Homestead, Valet and now, Sail.
-
-## Collaboration is key
-
-Instead of multiple similar projects creating the same features and fixing the same issues, there could be an opportunity to collaborate or even combine projects and resources in the future.
-
-## But what about existing teams and projects?
-
-If your company or team already uses another option, you can continue to use it.
-
-If you have an existing solution, I don't think it will be removed or abandoned in the near future.
-
-But, for new Drupal users and teams, one official development environment would be a big plus.
-
-[mine]: https://www.oliverdavies.uk/archive/2022/08/21/2022-08-21
-[post]: https://kevinquillen.com/ddev-being-considered-official-drupal-development-environment
diff --git a/astro/src/content/daily-email/2023-11-01.md b/astro/src/content/daily-email/2023-11-01.md
deleted file mode 100644
index 66cc0a46..00000000
--- a/astro/src/content/daily-email/2023-11-01.md
+++ /dev/null
@@ -1,26 +0,0 @@
----
-title: >
- Drupal 9 is now end of life
-pubDate: 2023-11-01
-permalink: >
- archive/2023/11/01/drupal-9-is-now-end-of-life
-tags:
- - drupal
- - php
----
-
-As of today, Drupal 9 is end-of-life and no longer supported.
-
-## Why?
-
-Drupal 9 relies on several other software projects, including Symfony, CKEditor, and Twig.
-
-With Symfony 4's end of life, CKEditor 4's end of life, and Twig 2's end of life all coming up soon, Drupal 9 went end of life on November 1st, 2023.
-
-## What do I do next?
-
-There will be no further releases of Drupal 9 so you need to upgrade.
-
-If you're stuck on Drupal 9, 8, or 7, get unstuck with a [Drupal upgrade roadmap][roadmap] and get directions how to upgrade to Drupal 10.
-
-[roadmap]: https://www.oliverdavies.uk/drupal-upgrade
diff --git a/astro/src/content/daily-email/2023-11-02.md b/astro/src/content/daily-email/2023-11-02.md
deleted file mode 100644
index 3549fc21..00000000
--- a/astro/src/content/daily-email/2023-11-02.md
+++ /dev/null
@@ -1,25 +0,0 @@
----
-title: >
- Is code coverage an objective or guideline?
-pubDate: 2023-11-02
-permalink: >
- archive/2023/11/02/is-code-coverage-an-objective-or-guideline
-tags:
- - software-development
- - automated-testing
- - test-driven-development
----
-
-Many development teams and projects use code coverage - e.g. how many lines of code are covered by automated tests - as an objective, and saying it must be 100% or another percentage.
-
-But is this an effective metric?
-
-In the same way as deleting failing tests to fix a pipeline, a code coverage amount can be faked.
-
-With this in mind, what if, instead of setting an objective such as 100% code coverage, you used it as a guideline?
-
-If you're working on a legacy project, what if you set a minimum code coverage amount as a guideline to ensure any new code has tests by not dropping under that level?
-
-Would that be better than saying every line of code needs to be covered?
-
-Code coverage is something I'm thinking of using more, so I want to know what you think.
diff --git a/astro/src/content/daily-email/2023-11-03.md b/astro/src/content/daily-email/2023-11-03.md
deleted file mode 100644
index d4199b0f..00000000
--- a/astro/src/content/daily-email/2023-11-03.md
+++ /dev/null
@@ -1,28 +0,0 @@
----
-title: >
- Why your company should contribute to open-source software
-pubDate: 2023-11-03
-permalink: >
- archive/2023/11/03/why-your-company-should-contribute-to-open-source-software
-tags:
- - software-development
- - open-source
----
-
-I've always thought companies should contribute to open-source software.
-
-Whether it's financial or contributing time, if companies use free, open-source software (and especially if they're directly making money from it).
-
-Contributing to the software you use will improve the software, whether adding new features, fixing a bug, or contributing translations.
-
-Having contributors to the software is a great way to differentiate your company from the competition, and the knowledge gained from contributing will result in better code for your projects.
-
-If you organise or sponsor events such as conferences and meetups, you also get exposure from the event and help support the event and community.
-
-## Here's the thing...
-
-I've recently pledged to donate a percentage of income from Drupal-related services to the Drupal Association and would like to see others do the same if they can.
-
-I also sponsor several individuals and organisations on GitHub who build software and create content I use so I get better tools and knowledge for myself and my projects.
-
-If your company can contribute to open-source, I'd encourage them to do so and help support open-source software projects and communities.
diff --git a/astro/src/content/daily-email/2023-11-04.md b/astro/src/content/daily-email/2023-11-04.md
deleted file mode 100644
index 7931dbe0..00000000
--- a/astro/src/content/daily-email/2023-11-04.md
+++ /dev/null
@@ -1,26 +0,0 @@
----
-title: >
- Why you should contribute to open-source software
-pubDate: 2023-11-04
-permalink: >
- archive/2023/11/04/why-you-should-contribute-to-open-source-software
-tags:
- - software-development
- - open-source
----
-
-[Yesterday's email][yesterday] explained why your company should contribute to open-source software, but why should you contribute as an individual?
-
-Most of the same reasons apply, such as gaining experience and improved knowledge from contributing.
-
-As an individual, you can build your own reputation and personal brand.
-
-You'll get exposure from contributions and involvement with initiatives, such as the Drupal admin UI improvements and other core initiatives, which look great on your CV and LinkedIn profile.
-
-This could lead to better career opportunities and potential projects.
-
-I've had paid development work directly from my open-source code contributions, as well as public speaking and event organising, so I can vouch for this.
-
-Like companies, if you make money from open-source software - either a salary or from paid projects or courses - it's in your interest to contribute so the software you use is maintained and improved so it's the best it can be.
-
-[yesterday]: https://www.oliverdavies.uk/archive/2023/11/03/why-your-company-should-contribute-to-open-source-software
diff --git a/astro/src/content/daily-email/2023-11-05.md b/astro/src/content/daily-email/2023-11-05.md
deleted file mode 100644
index 521ae3a3..00000000
--- a/astro/src/content/daily-email/2023-11-05.md
+++ /dev/null
@@ -1,21 +0,0 @@
----
-title: >
- I'm starting a podcast
-pubDate: 2023-11-05
-permalink: >
- archive/2023/11/05/i-m-starting-a-podcast
-tags:
- - software-development
- - podcast
----
-
-This week, I'm starting my own podcast - [Beyond Blocks][podcast].
-
-I'll be interviewing different people in every week, focussing on Drupal and related software development topics.
-
-I have the first guests lined up, including some speakers from last month's DrupalCon Europe conference, where we can discuss their topics in more detail.
-
-If you'd like to be a guest, [get in touch][form] and let me know what you'd like to discuss.
-
-[form]: https://forms.gle/wdVqmEyQSWUx8cnm8
-[podcast]: https://www.oliverdavies.uk/podcast
diff --git a/astro/src/content/daily-email/2023-11-06.md b/astro/src/content/daily-email/2023-11-06.md
deleted file mode 100644
index 69b6b801..00000000
--- a/astro/src/content/daily-email/2023-11-06.md
+++ /dev/null
@@ -1,24 +0,0 @@
----
-title: >
- The first Beyond Blocks podcast episode is recorded
-pubDate: 2023-11-06
-permalink: >
- archive/2023/11/06/the-first-beyond-blocks-podcast-episode-is-recorded
-tags:
- - software-development
- - podcast
- - drupal
- - php
----
-
-For my first time in the podcast host chair, I interviewed Matt Glaman - Principal Software Engineer at Acquia.
-
-I initially knew Matt from his work on Drupal Commerce, but I wanted to learn about his new project, Retrofit - a tool to make it easier to upgrade from Drupal 7 (which will be end of life in January 2025) to Drupal 10.
-
-We also talked briefly about PHPStan Drupal and drupal-check, which are some of Matt's other projects and contributions to the Drupal community.
-
-Thank you, Matt, for being the first guest on the Beyond Blocks podcast.
-
-I have other guests booked for this week, so the episode with Matt will be [published soon][podcast].
-
-[podcast]: https://www.oliverdavies.uk/podcast
diff --git a/astro/src/content/daily-email/2023-11-07.md b/astro/src/content/daily-email/2023-11-07.md
deleted file mode 100644
index 1e861ee7..00000000
--- a/astro/src/content/daily-email/2023-11-07.md
+++ /dev/null
@@ -1,37 +0,0 @@
----
-title: >
- It depends
-pubDate: 2023-11-07
-permalink: >
- archive/2023/11/07/it-depends
-tags:
- - software-development
----
-
-Usually, in software development, there isn't always a definitive black-and-white answer to a question or situation.
-
-Most of the time, the answer is "it depends".
-
-How you approach a problem depends on context.
-
-How long do you have?
-
-Are you working on the final version or a prototype or minimum-viable product?
-
-Should you use a contributed module or write one yourself?
-
-What if an existing module hasn't been updated for some time or doesn't have tests or other quality checks included?
-
-Do you write custom CSS or use a framework like Tailwind CSS or Bootstrap?
-
-Should this project be written in this framework or CMS, or would a different one be better suited?
-
-## Here's the thing...
-
-There are usually multiple approaches to achieve the same result.
-
-Decisions will depend on a combination of various factors. In a different situation, the answer could be different.
-
-This doesn't make any solution outright wrong.
-
-It was right given the situation.
diff --git a/astro/src/content/daily-email/2023-11-08.md b/astro/src/content/daily-email/2023-11-08.md
deleted file mode 100644
index 375bebf7..00000000
--- a/astro/src/content/daily-email/2023-11-08.md
+++ /dev/null
@@ -1,28 +0,0 @@
----
-title: >
- "Building Build Configs" at PHP South West
-pubDate: 2023-11-08
-permalink: >
- archive/2023/11/08/building-build-configs
-tags:
- - software-development
- - php
- - public-speaking
----
-
-This evening, I'm presenting a lightning talk at the PHP South West meetup in Bristol.
-
-The talk is 'Building "Build Configs"' - a Symfony command-line tool I wrote (based on TheAltF4Stream's Rust version with the same name) that generates project-specific build configuration files.
-
-Since creating it, I've used it for personal projects, projects for clients, and example projects on GitHub - such as [my Docker Example Drupal project][example].
-
-Having a set of standardised and configurable templates makes it much easier and quicker to start a new project, which I did when creating a [Drupal Commerce Kickstart example][commerce_example] at DrupalCon.
-
-[The slides are already online][slides] and I've created [an example video][video] where I go from nothing to a ready-to-work-on Drupal website in less than a minute!
-
-If you have any questions, hit reply and let me know!
-
-[commerce_example]: https://github.com/opdavies/docker-example-drupal-commerce-kickstart
-[example]: https://github.com/opdavies/docker-example-drupal
-[slides]: https://www.oliverdavies.uk/talks/building-build-configs
-[video]: https://www.oliverdavies.uk/build-configs
diff --git a/astro/src/content/daily-email/2023-11-09.md b/astro/src/content/daily-email/2023-11-09.md
deleted file mode 100644
index dce5c3bb..00000000
--- a/astro/src/content/daily-email/2023-11-09.md
+++ /dev/null
@@ -1,24 +0,0 @@
----
-title: >
- README-driven development
-pubDate: 2023-11-09
-permalink: >
- archive/2023/11/09/readme-driven-development
-tags:
- - software-development
- - documentation
----
-
-As well as test-driven development (TDD), I also like README-driven development - a.k.a. documentation-driven development.
-
-In short, you write the documentation first, followed by the code.
-
-Like writing tests in TDD, it allows you to think about how your code will work, what functions and methods it will contain, how they'll interact together and how you expect people to use your code.
-
-This can also contain flowcharts, diagrams, example code snippets and anything else that would be useful.
-
-If you like, you could have a colleague review it in a pull/merge request before progressing.
-
-Once the README file is written and you're happy with its contents, you can start coding.
-
-Also, documentation is commonly missed or skipped in projects, so moving it forward in the development process ensures it will be done and, as it's being written nearer to the writing of the code, it's more likely to be correct instead of writing it all once the code has been written.
diff --git a/astro/src/content/daily-email/2023-11-10.md b/astro/src/content/daily-email/2023-11-10.md
deleted file mode 100644
index 1b965b67..00000000
--- a/astro/src/content/daily-email/2023-11-10.md
+++ /dev/null
@@ -1,23 +0,0 @@
----
-title: >
- Retrofit with Matt Glaman
-pubDate: 2023-11-10
-permalink: >
- archive/2023/11/10/retrofit-with-matt-glaman
-tags:
- - drupal
- - php
- - drupal-upgrades
- - podcast
- - beyond-blocks
----
-
-Today, I released [the first episode of the "Beyond Blocks" podcast](https://www.oliverdavies.uk/podcast/1-retrofit).
-
-I spoke with Matt Glaman - Principal Software Engineer at Acquia and author of Retrofit.
-
-Retrofit makes it easier to upgrade from Drupal 7 by adding compatibility layers to run your legacy code within Drupal 10 - giving you more time to port it to the modern approaches and standards.
-
-I've been aware of Matt and his work for some time, including his work on Drupal Commerce, so it was great to speak with him and for him to be the first guest on the podcast.
-
-Future episodes will be [published online](https://www.oliverdavies.uk/podcast) weekly, so feel free to subscribe and let me know if you have feedback, suggestions for future guests and topics, or want to be a guest.
diff --git a/astro/src/content/daily-email/2023-11-11.md b/astro/src/content/daily-email/2023-11-11.md
deleted file mode 100644
index 5e2a1381..00000000
--- a/astro/src/content/daily-email/2023-11-11.md
+++ /dev/null
@@ -1,28 +0,0 @@
----
-title: >
- Work in small batches
-pubDate: 2023-11-11
-permalink: >
- archive/2023/11/11/work-in-small-batches
-tags:
- - software-development
- - git
- - continuous-integration
- - continuous-delivery
- - continuous-deployment
- - trunk-based-development
----
-
-Software should be designed, written, and deployed in small batches.
-
-This is the first line from a blog post by Eric Ries and is something that gets discussed with a guest in an upcoming episode of the Beyond Blocks podcast.
-
-In the post, Eric continues by saying, "Of all of the insights I've contributed to the companies I've worked at over the years, the one I am most proud of is the importance of working in small batches".
-
-Small batches mean faster feedback, more localised problems as there are fewer changes, and reduced risk and overhead.
-
-If you work in small batches and make smaller changes, merge them regularly into the mainline branch (ideally, at least once a day), and often deploy changes to production, the releases will be quicker and less stressful, and clients and customers will be happy as their changes will be available sooner.
-
-I've worked this way, and with long-lived feature branches and large, infrequent deployments, I prefer to work in small batches and deploy often.
-
-The full blog post is found at .
diff --git a/astro/src/content/daily-email/2023-11-12.md b/astro/src/content/daily-email/2023-11-12.md
deleted file mode 100644
index b73943e5..00000000
--- a/astro/src/content/daily-email/2023-11-12.md
+++ /dev/null
@@ -1,33 +0,0 @@
----
-title: >
- Drupal gives you so much out-of-the-box
-pubDate: 2023-11-12
-permalink: >
- archive/2023/11/12/drupal-gives-you-so-much-out-of-the-box
-tags:
- - software-development
- - drupal
----
-
-When you download and install Drupal, you get so much functionality available out-of-the-box.
-
-For example:
-
-* Content creation and editing capabilities with a flexible content type
-* A taxonomy system for categorising content.
-* Tools for managing editorial workflows.
-* User registration and authentication.
-* A role-based permission system.
-* Support for creating multilingual websites with translation tools.
-* Caching mechanisms to optimise performance.
-* Scalability features for handling high-traffic websites.
-* Built-in search functionality.
-* Robust security features, including input validation and output filtering.
-* RESTful web services for building web applications and mobile apps.
-* A flexible page and layout builder.
-
-There are over 50,000 contributed modules on Drupal.org that you can download to add functionality like eCommerce, analytics, social media integrations, quizzes, webforms and surveys.
-
-You can add specific functionality by writing your own modules, and customise a project by creating a theme.
-
-It's a great choice for a new web project.
diff --git a/astro/src/content/daily-email/2023-11-13.md b/astro/src/content/daily-email/2023-11-13.md
deleted file mode 100644
index 172570f3..00000000
--- a/astro/src/content/daily-email/2023-11-13.md
+++ /dev/null
@@ -1,34 +0,0 @@
----
-title: >
- PHPUnit does more than unit testing
-pubDate: 2023-11-13
-permalink: >
- archive/2023/11/13/phpunit-does-more-than-unit-testing
-tags:
- - software-development
- - automated-testing
- - software-development
- - test-driven-development
- - phpunit
- - php
- - drupal
- - symfony
----
-
-As the name suggests, [PHPUnit][] is a unit testing framework for PHP.
-
-It's the defacto PHP testing framework used by the major PHP projects, such as Drupal, Symfony, Laravel.
-
-But unit testing isn't all that PHPUnit can do.
-
-These frameworks extend PHPUnit to give it more functionality.
-
-Drupal allows you to run functional/browser tests to make requests to pages, check the response codes and content, as well as integration/kernel tests to test real services instead of relying on mocking within unit tests.
-
-Symfony does the same with its web and kernel test cases.
-
-## Here's the thing
-
-If you use a framework and want to more than unit testing, intsead of including another testing framework, try using some of the PHPUnit extensions that are provided by the framework.
-
-[phpunit]: http://phpunit.de
diff --git a/astro/src/content/daily-email/2023-11-14.md b/astro/src/content/daily-email/2023-11-14.md
deleted file mode 100644
index f9b9b8e0..00000000
--- a/astro/src/content/daily-email/2023-11-14.md
+++ /dev/null
@@ -1,26 +0,0 @@
----
-title: >
- Why I prefer integration tests to unit tests
-pubDate: 2023-11-14
-permalink: >
- archive/2023/11/14/why-i-prefer-integration-tests-to-unit-tests
-tags:
- - software-development
- - automated-testing
- - test-driven-development
- - mocking
----
-
-With unit tests, you need to mock __everything__.
-
-If what you're testing has a dependency, you need to create and use a mock version.
-
-If the mock has its own dependencies, you need to mock those, too.
-
-I've written unit tests with mocks and accidentally only tested the mocks instead of the functionality I intended.
-
-## Here's the thing
-
-With integration tests, you can use and test the real dependencies.
-
-Whilst they may be slightly slower to run, I prefer the simpler setup, less need for mocks, and knowing the real services work - not just the mocked versions.
diff --git a/astro/src/content/daily-email/2023-11-15.md b/astro/src/content/daily-email/2023-11-15.md
deleted file mode 100644
index c24757fa..00000000
--- a/astro/src/content/daily-email/2023-11-15.md
+++ /dev/null
@@ -1,33 +0,0 @@
----
-title: >
- Don't pre-optimise and over-customise
-pubDate: 2023-11-15
-permalink: >
- archive/2023/11/15/dont-pre-optimise-and-over-customise
-tags:
- - software-development
- - clean-code
- - automated-testing
- - test-driven-development
----
-
-I've been re-watching a livestream series from a few years ago, showing a SaaS product being built.
-
-The series was created from two full-day live streams to create a minimum viable product (MVP) version of the application.
-
-Several times, things like this were said:
-
-* This will eventually need to be customisable.
-* When we have multiple users, but now we only have one.
-* Let's hard-code this for now and refactor it later.
-* This isn't pixel-perfect, but let's move on.
-
-## Here's the thing
-
-As they focused on creating an MVP version, they added these things to a to-do list or wrote comments in the code to revisit it later rather than slowing down the initial development and pre-optimising the code for use cases that didn't exist yet.
-
-If there's only one user, there's no need to write code to handle multiple users.
-
-Later, once the application is launched, that feature can be added.
-
-And, because they were writing automated tests, they'd be able to refactor and extend the code and not worry about breaking it as the tests would confirm that the functionality still worked.
diff --git a/astro/src/content/daily-email/2023-11-16.md b/astro/src/content/daily-email/2023-11-16.md
deleted file mode 100644
index c0c00474..00000000
--- a/astro/src/content/daily-email/2023-11-16.md
+++ /dev/null
@@ -1,90 +0,0 @@
----
-title: >
- Avoiding over-mocking
-pubDate: 2023-11-16
-permalink: >
- archive/2023/11/16/avoiding-over-mocking
-tags:
- - software-development
- - automated-testing
- - test-driven-development
----
-
-In unit tests, and sometimes in kernel tests, you need to mock the dependencies you aren't testing, but you can over-mock and only be testing the mocks and not the code you want to test.
-
-Here's an example (thanks, ChatGPT, for the code).
-
-## The Class to be tested (MyClass.php)
-
-```php
-dependency->performAction();
-
- return "Result: " . $result;
- }
-}
-```
-
-## Dependency Interface (DependencyInterface.php)
-
-```php
-createMock(DependencyInterface::class);
-
- // Setting up the mock to return a specific value.
- $dependencyMock->expects($this->once())
- ->method('performAction')
- ->willReturn('Mocked result');
-
- // Creating an instance of MyClass with the mock.
- $myClass = new MyClass($dependencyMock);
-
- // Calling the method to be tested.
- $result = $myClass->doSomething();
-
- // Asserting that the result matches the expected value.
- $this->assertEquals('Result: Mocked result', $result);
- }
-
-}
-```
-
-## Here's the thing
-
-In this example, the test creates a mock for the `DependencyInterface` and sets up an expectation that the performAction method will be called once, returning a specific value.
-
-The test then calls the `doSomething` method on `MyClass` and asserts that the result is as expected.
-
-The issue with this test is that it's not testing the actual behaviour of `MyClass`.
-
-It's only testing that the mock is configured correctly.
-
-If the real implementation of `MyClass` has a bug, this test won't catch it.
diff --git a/astro/src/content/daily-email/2023-11-17.md b/astro/src/content/daily-email/2023-11-17.md
deleted file mode 100644
index 2a9d7d21..00000000
--- a/astro/src/content/daily-email/2023-11-17.md
+++ /dev/null
@@ -1,19 +0,0 @@
----
-title: >
- Drupal's Alternate Realities
-pubDate: 2023-11-17
-permalink: >
- archive/2023/11/17/drupal-s-alternate-realities
-tags:
- - drupal
- - php
- - phpc
- - beyond-blocks
- - podcast
----
-
-[This week's episode][episode] of the Beyond Blocks podcast is live, where I speak with Panagiotis Moutsopoulos (vensires on Drupal.org) - Drupal Backend Developer at E-Sepia.
-
-We discuss his first time DrupalCon and, more specifically, his session "Drupal's Alternate Realities" - a "Birds of a Feather" (BoF) session presenting some history, but mainly the different ways to tackle a problem in Drupal using different methodologies.
-
-[episode]: https://www.oliverdavies.uk/podcast/2-alternate-realities
diff --git a/astro/src/content/daily-email/2023-11-18.md b/astro/src/content/daily-email/2023-11-18.md
deleted file mode 100644
index 8ae8a8c8..00000000
--- a/astro/src/content/daily-email/2023-11-18.md
+++ /dev/null
@@ -1,48 +0,0 @@
----
-title: >
- Writing good test names
-pubDate: 2023-11-18
-permalink: >
- archive/2023/11/18/writing-good-test-names
-tags:
- - software-development
- - test-driven-development
- - automated-testing
- - php
- - phpunit
----
-
-In PHPUnit, there are different ways to write test methods.
-
-The standard way is to use camel-case method names with a `test` prefix, for example:
-
-```php
-public function testTheProjectNameShouldBeAString(): void
-{
- // ...
-}
-```
-
-Another popular way, particularly in some frameworks, is to use snake-case method names:
-
-```php
-/** @test */
-public function the_project_name_should_be_a_string(): void
-{
- // ...
-}
-```
-
-This may be more readable but only works if the `@test` annotation is present.
-
-What if you need to add another annotation, such as `@dataProvider` to the test? Do you do multi-line docblocks everywhere, or mix and match single and multiple line docblocks depending on the test?
-
-## Here's the thing
-
-My preference switches between both ways of writing test methods.
-
-But, whichever way I write it, I write descriptive method names that explain what the test does - even if it means having a long method name.
-
-I avoid short and generic names like `testUpdate()`.
-
-People should be able to read the test name and understand what it does and what it's testing.
diff --git a/astro/src/content/daily-email/2023-11-19.md b/astro/src/content/daily-email/2023-11-19.md
deleted file mode 100644
index f2ac0886..00000000
--- a/astro/src/content/daily-email/2023-11-19.md
+++ /dev/null
@@ -1,26 +0,0 @@
----
-title: >
- Why I've standardised on 'run' scripts
-pubDate: 2023-11-19
-permalink: >
- archive/2023/11/19/why-ive-standardised-on-run-scripts
-tags:
- - software-development
- - continuous-integration
----
-
-In some of my first emails to this list, I wrote about `just` and `run` files.
-
-Both allow you to write project-specific aliases and commands. For example, instead of running `docker compose exec php phpunit`, you run `just test` or `run test`.
-
-While `just` uses a simple Makefile-like syntax, it requires its own program, so it needs to be installed.
-
-While I have it installed locally, I've had instances where CI pipelines have failed because they can't download and install `just` and not because of an error in my code.
-
-## Here's the thing
-
-A `run` script is a file of Bash functions.
-
-Because it's written in Bash, it runs anywhere without installing additional dependencies.
-
-If a CI pipeline fails, which is less often, it's due to a failure within my code and not because of a download error.
diff --git a/astro/src/content/daily-email/2023-11-20.md b/astro/src/content/daily-email/2023-11-20.md
deleted file mode 100644
index 048e8363..00000000
--- a/astro/src/content/daily-email/2023-11-20.md
+++ /dev/null
@@ -1,35 +0,0 @@
----
-title: >
- What'll be in Drupal 11?
-pubDate: 2023-11-20
-permalink: >
- archive/2023/11/20/whatll-be-in-drupal-11
-tags:
- - drupal
- - php
- - phpc
----
-
-Drupal 9 is end-of-life and no longer supported.
-
-Drupal 10 is the current stable version, and the development branch for Drupal 11 has just been started.
-
-But what will be in Drupal 11?
-
-Well, we don't know yet.
-
-Drupal's release schedule is based on fixed dates and not on features.
-
-Whatever is ready on the release date will be included. If something isn't ready, it'll be in a future version.
-
-If something is ready sooner, it'll be in a minor 10 version, such as Drupal 10.2 or 10.3. We've seen it recently with various UI improvements in 10.1 - with more in 10.2.
-
-We saw new features, such as Layout Builder, added to Drupal core within the Drupal 8 lifecycle, and there's still time to add more to Drupal 10.
-
-## Here's the thing
-
-But, like Drupal 9 and 10, Drupal 11 won't mean a major rewrite to your code.
-
-Drupal 11 is based on Drupal 10, so the modules and themes you use will be able to work with both, allowing you to upgrade incrementally.
-
-While there isn't a definitive list of new features or changes for Drupal 11, based on things I saw and learned about at DrupalCon, I'm excited to see what makes it.
diff --git a/astro/src/content/daily-email/2023-11-21.md b/astro/src/content/daily-email/2023-11-21.md
deleted file mode 100644
index f63103ca..00000000
--- a/astro/src/content/daily-email/2023-11-21.md
+++ /dev/null
@@ -1,52 +0,0 @@
----
-title: >
- Why I built "Build Configs"
-pubDate: 2023-11-21
-permalink: >
- archive/2023/11/21/why-i-built-build-configs
-tags:
- - docker
- - docker-compose
- - php
- - phpc
- - drupal
- - symfony
----
-
-[Build Configs] is a tool I wrote and recently [gave a lightning talk about][talk] at the PHP South West meetup in Bristol, UK.
-
-It's a command-line tool that creates customised per-project configuration files from a set of reusable templates.
-
-It's a Symfony project using components such as Console, Validator, and Twig for templating.
-
-But why did I build it?
-
-## What was I doing before?
-
-When starting a new project, I'd copy configuration files from an existing project and alter them as needed.
-
-If a project uses a `docroot` directory instead of `web`, a different version of PHP, or Caddy instead of Nginx, I'd need to change the files manually for the new project, add any required features, or fix any bugs.
-
-## What was the issue with this?
-
-It took time to set up new projects, and there would be drift between them.
-
-I may have added a feature to one project, but it wouldn't exist in the one I was working on.
-
-If I needed to move a feature from one project to another, I needed to do it manually.
-
-## How does Build Configs solve the issue?
-
-Now, I have a canonical set of template files.
-
-Instead of making ad-hoc changes to each project, I can add new features and fix bugs in the templates, and re-generate the configuration files for each project.
-
-I don't need to worry about drift between projects because they're all in sync and generated automatically.
-
-It's quicker to create and onboard projects using existing configurations instead of copying files and making manual changes.
-
-If you want to see an example, [watch this video][video] where I set up a new Drupal 10 project from nothing to running website in less than a minute.
-
-[build configs]: https://www.oliverdavies.uk/build-configs
-[talk]: https://www.oliverdavies.uk/talks/building-build-configs
-[video]: https://www.youtube.com/watch?v=LkhsdmxReUc
diff --git a/astro/src/content/daily-email/2023-11-22.md b/astro/src/content/daily-email/2023-11-22.md
deleted file mode 100644
index 9a0a93c6..00000000
--- a/astro/src/content/daily-email/2023-11-22.md
+++ /dev/null
@@ -1,23 +0,0 @@
----
-title: >
- Frequency reduces difficulty
-pubDate: 2023-11-22
-permalink: >
- archive/2023/11/22/frequency-reduces-difficulty
-tags:
- - software-development
- - agile
- - continuous-delivery
- - git
- - trunk-based-development
----
-
-"Frequency reduces difficulty" is a phrase I heard on a podcast today, though I have heard it before.
-
-It's a better way of saying, "If it hurts, do it more often".
-
-If software deployments and releases are large, risky, and contain bugs, break them into smaller, less-risky deployments and release them more often.
-
-If you get a lot of merge conflicts in Git, merge your code more frequently. Make your topic branches as short-lived as possible, or try trunk-based development and avoid topic branches by default.
-
-If writing tests is difficult and takes time, persevere. It will get easier the more you do it, and you'll save time in the future by releasing fewer bugs and being able to refactor safely.
diff --git a/astro/src/content/daily-email/2023-11-23.md b/astro/src/content/daily-email/2023-11-23.md
deleted file mode 100644
index f24584ae..00000000
--- a/astro/src/content/daily-email/2023-11-23.md
+++ /dev/null
@@ -1,50 +0,0 @@
----
-title: >
- Partial mocking
-pubDate: 2023-11-23
-permalink: >
- archive/2023/11/23/partial-mocking
-tags:
- - automated-testing
- - test-driven-development
- - drupal
- - php
- - phpunit
- - phpc
----
-
-Today, I wrote a test whilst fixing a bug in some legacy custom Drupal code.
-
-The code is for a custom block, which can be configured using user-defined settings - including a link URL.
-
-In this case, if the link was null (one hadn't been provided), the link was generated to the home page instead of the desired destination.
-
-## My first attempt
-
-There was a combination of settings needed to replicate the bug, such as the current site language, the node type the block was placed on and, of course, an empty link URL.
-
-Because the block uses the current route to get the current node, my first attempt to test this was to use a browser/functional test.
-
-That failed quickly after having to enable various other custom modules due to dependencies and to add and configure unrelated configuration settings.
-
-## My second attempt
-
-My second attempt used kernel/integration tests, but as there's no `setParameter()` method on the route matcher I could use in the test, I'd need to rely on mocking.
-
-In a unit test, everything needs to be mocked, but a kernel test allows me to be more selective, only mock what I need, and use the real services for everything else - a.k.a. partial mocking.
-
-## The result
-
-I replicated the bug by setting the default and current languages, creating a mock language manager, creating a node of the required type and returning it from a mocked route match.
-
-Everything else remained the same.
-
-Then, I fixed the bug and used a data provider to provide different variables into the test so each use case was covered.
-
-## Here's the thing
-
-The whole test file is 129 lines and would have been much more if I'd had to replicate all the configuration in a functional test or mock everything in a unit test.
-
-An integration test with partial mocking was ideal in this case, as it gave me the most flexibility to test what I needed whilst keeping the code simple.
-
-Whilst I'm aware of over-using mocks, this was an ideal situation to use them.
diff --git a/astro/src/content/daily-email/2023-11-24.md b/astro/src/content/daily-email/2023-11-24.md
deleted file mode 100644
index b813927a..00000000
--- a/astro/src/content/daily-email/2023-11-24.md
+++ /dev/null
@@ -1,30 +0,0 @@
----
-title: >
- Are conventional commits worth it?
-pubDate: 2023-11-24
-permalink: >
- archive/2023/11/24/are-conventional-commits-worth-it
-tags:
- - software-development
- - git
----
-
-For some time, I've written commit messages following the Conventional Commits specification, where you start the subject with the type of commit - such as `feat`, `fix`, `chore`, `docs`, etc - and provide an optional scope before completing the subject line (the first line in the message).
-
-Then, it is encouraged to add a longer body to the message and provide any links and task IDs that the change relates to.
-
-Now I've been using it for a while, I'm deciding whether it adds value for me and whether it's worth me using it.
-
-I don't create automatic CHANGELOG files from the commit types.
-
-The scopes are usually arbitrary, it's unclear which scope (or scopes) should be added, or it repeats the module name I'm working on (which I could see from the Git diff).
-
-While I see value in writing descriptive commit messages, I'm unsure if I do to format the subject line in this way.
-
-## Here's the thing
-
-I like to use an iterative approach to my workflow. I like to try things and see if they work for me. If not, I can stop or continue iterating.
-
-If working with others, should you focus on writing commits that categorise commit messages within their subject or writing descriptive commit messages that capture why the change is needed?
-
-Which provides the most value when looking back at the Git log in the future?
diff --git a/astro/src/content/daily-email/2023-11-25.md b/astro/src/content/daily-email/2023-11-25.md
deleted file mode 100644
index abf4ea09..00000000
--- a/astro/src/content/daily-email/2023-11-25.md
+++ /dev/null
@@ -1,23 +0,0 @@
----
-title: >
- Community engagement for non-technical Drupal enthusiasts
-pubDate: 2023-11-25
-permalink: >
- archive/2023/11/25/community-engagement-for-non-technical-drupal-enthusiasts
-tags:
- - drupal
- - drupalcon
- - open-source
- - contribution
- - podcast
----
-
-This week's guest on the Beyond Blocks podcast is Niklas Franke - Digital Marketing Manager at Factorial.
-
-Niklas was a fellow speaker at the recent DrupalCon conference in Lille - presenting multiple sessions, whilst Factorial were sponsors of the event.
-
-In this episode, Niklas and I discussed his first experience of DrupalCon, presenting a session on contribution for non-technical Drupalers, the German Drupal community, what the Splash Awards are and how to organise your own event.
-
-[Listen to the episode now][episode].
-
-[episode]: https://www.oliverdavies.uk/podcast/3-non-technical-contribution
diff --git a/astro/src/content/daily-email/2023-11-26.md b/astro/src/content/daily-email/2023-11-26.md
deleted file mode 100644
index 7221adaa..00000000
--- a/astro/src/content/daily-email/2023-11-26.md
+++ /dev/null
@@ -1,98 +0,0 @@
----
-title: >
- To docblock or not to docblock
-pubDate: 2023-11-26
-permalink: >
- archive/2023/11/26/to-docblock-or-not-to-docblock
-tags:
- - php
- - phpstan
- - static-analysis
- - clean-code
----
-
-## What are docblocks?
-
-Docblocks are comment blocks that describe a class or method and document its parameters and return types.
-
-Unfortunately, they're often overused and are outdated compared to the code they're describing, or repeat the same information again.
-
-For example, here's some PHP code:
-
-```php
-function sayHello(string $name, array $options = ['shout' => false]): void {
- echo 'Hello, ' . $name;
-}
-
-sayHello('');
-sayHello('Oliver', ['shout2' => true]);
-sayHello('Oliver', ['shout' => 'banana']);
-```
-
-It's readable and understandable.
-
-It has types.
-
-We know that the name needs to be a string and that an array of options can be passed.
-
-This is how I like to write my code. In a clear and readable way with minimal comments.
-
-This code works, but there are issues with it.
-
-Do we want the name to potentially be an empty string?
-
-What if different options are passed in?
-
-## Step 1
-
-If you use PHPStan (a PHP static analysis tool), you won't get any errors until you test against level 6.
-
-Then you'll get this error:
-
-> Function sayHello() has parameter $options with no value type specified in iterable type array.
-
-Now, we can use a docblock to provide more information to PHPStan to describe the structure of the `$options` array and that it has strings for keys and boolean values.
-
-```php
-/**
- * @param array $options
- */
-```
-
-Although it's not erroring, we can add the `$name` parameter and declare it as a `string`.
-
-```php
-/**
- * @param string $name
- * @param array $options
- */
-```
-
-Now, the docblock adds some context and value but essentially repeats the defined types.
-
-## Step 2
-
-We can do more with the docblock and tell PHPStan more about what we want the values to be.
-
-We don't want an empty string for a name and want the correct options and values.
-
-Let's change the docblock to this:
-
-```php
-/**
- * @param non-empty-string $name
- * @param array{shout: bool} $options
- */
-```
-
-This specified the name cannot be an empty string and the shape of the options array.
-
-With this, we get these errors that weren't included before:
-
-* Parameter #1 $name of function sayHello expects non-empty-string, '' given.
-* Parameter #2 $options of function sayHello expects array{shout: bool}, array{shout2: true} given.
-* Parameter #2 $options of function sayHello expects array{shout: bool}, array{shout: 'banana'} given.
-
-## Here's the thing
-
-While I like to write minimal, readable and "self-documenting" code and not overuse docblocks by adding them everywhere, I only add them and comments where needed and provide value, either to someone reading the code in the future or to tools like PHPStan that help me make the code better.
diff --git a/astro/src/content/daily-email/2023-11-27.md b/astro/src/content/daily-email/2023-11-27.md
deleted file mode 100644
index 3585e288..00000000
--- a/astro/src/content/daily-email/2023-11-27.md
+++ /dev/null
@@ -1,99 +0,0 @@
----
-title: >
- Finding the best test base
-pubDate: 2023-11-27
-permalink: >
- archive/2023/11/27/finding-the-best-test-base
-tags:
- - software-development
- - automated-testing
- - test-driven-development
- - php
- - drupal
----
-
-As well as different base classes for types of tests - i.e. functional, kernel and unit - there are other test base classes within those that can be used to simplify things.
-
-For example, if we have this test:
-
-```php
-installEntitySchema(entity_type_id: 'node');
- $this->installEntitySchema(entity_type_id: 'user');
- }
-
- public function testExample(): void {
- $user = $this->createUser();
-
- $article = $this->createNode([
- 'title' => 'Test article',
- 'uid' => $user,
- ]);
-
- self::assertSame('1', $article->getOwnerId());
- }
-
-}
-```
-
-Both creation traits must be imported, the `node` and `user` modules must be enabled, and the entity tables must be installed.
-
-When writing a lot of tests, this can result in duplication and more complex tests that take longer to write.
-
-This can be simplified using `EntityKernelTestBase` instead of `KernelTestBase`:
-
-```php
-createUser();
-
- $article = $this->createNode([
- 'title' => 'Test article',
- 'uid' => $user,
- ]);
-
- self::assertSame('1', $article->getOwnerId());
- }
-
-}
-```
-
-The class is simpler, fewer modules must be specified, and the entity schemas are automatically installed.
-
-As well as the core modules, some contrib modules also provide their own base test cases.
-
-If you're using the Webform module, you may want to use `WebformAccessTestBase` instead of the standard `UnitTestCase`.
-
-It's definitely worth spending some time looking at what base test cases are available and which are the best ones to use for your own tests.
diff --git a/astro/src/content/daily-email/2023-11-28.md b/astro/src/content/daily-email/2023-11-28.md
deleted file mode 100644
index fd58644d..00000000
--- a/astro/src/content/daily-email/2023-11-28.md
+++ /dev/null
@@ -1,52 +0,0 @@
----
-title: >
- Which PHPStan level should you use?
-pubDate: 2023-11-28
-permalink: >
- archive/2023/11/28/which-phpstan-level-should-you-use
-tags:
- - software-development
- - clean-code
- - static-analysis
- - phpstan
----
-
-Which PHPStan level should you use?
-
-PHPStan has different levels.
-
-When you run it on your code, the errors you see will depend on what level you set.
-
-[In yesterday's email][yesterday], the first example code block didn't generate an error until level 5 was used.
-
-So, how do you know which level to use?
-
-## For greenfield projects
-
-For new (greenfield) code, install and configure PHPStan before you write any code and have and have it run automatically as part of a CI pipeline.
-
-If you work on a team, speak with the other members and decide how strict you want PHPStan to be.
-
-Read the rule levels and decide which are the most valuable for your team.
-
-If you haven't used PHPStan or static analysis before, maybe start with a lower level.
-
-For me, typehints and return type checking are a must, though I like to use as high a level as possible.
-
-The more information you can provide to PHPStan, the more it will understand your code, give better results and be more likely to find potential bugs or issues.
-
-## For brownfield projects
-
-For existing (brownfield) code, start at the lowest level, which will give you the least number of errors.
-
-Fix any errors, exclude any rules you want to ignore or generate a baseline containing any existing errors.
-
-If you like, increase the level and repeat the process.
-
-Keep increasing the level as long as you feel comfortable, and PHPStan gives you meaningful results.
-
-Again, if you haven't used PHPStan or static analysis before, maybe stick with a lower level.
-
-If you start with a lower level, you can increase it later.
-
-[yesterday]: https://www.oliverdavies.uk/archive/2023/11/27/finding-the-best-test-base
diff --git a/astro/src/content/daily-email/2023-11-29.md b/astro/src/content/daily-email/2023-11-29.md
deleted file mode 100644
index bc45f7d6..00000000
--- a/astro/src/content/daily-email/2023-11-29.md
+++ /dev/null
@@ -1,26 +0,0 @@
----
-title: >
- The lowest level is better than no level
-pubDate: 2023-11-29
-permalink: >
- archive/2023/11/29/the-lowest-level-is-better-than-no-level
-tags:
- - software-development
- - clean-code
- - static-analysis
- - php
- - phpstan
----
-
-[Yesterday's email][yesterday] introduced the different levels that PHPStan offers and which you may want to use on your codebase.
-
-In the same way as having a single test is better than none, even if you run PHPStan at the lowest level, it's better than not running it at all.
-
-Level 0 includes:
-
-> Basic checks, unknown classes, unknown functions, unknown methods called on $this, wrong number of arguments passed to those methods and functions, always undefined variables
-
-P.S. If you want to utilise PHPStan and static analysis on your development team and get fewer bugs, I have [availability for team coaching][coaching]. I'll show you how!
-
-[coaching]: https://www.oliverdavies.uk/team-coaching
-[yesterday]: https://www.oliverdavies.uk/archive/2023/11/28/which-phpstan-level-should-you-use
diff --git a/astro/src/content/daily-email/2023-11-30.md b/astro/src/content/daily-email/2023-11-30.md
deleted file mode 100644
index 2cdaa057..00000000
--- a/astro/src/content/daily-email/2023-11-30.md
+++ /dev/null
@@ -1,28 +0,0 @@
----
-title: >
- Are bugs good for users?
-pubDate: 2023-11-30
-permalink: >
- archive/2023/11/30/are-bugs-good-for-users
-tags:
- - software-development
- - automated-testing
- - test-driven-development
- - static-analysis
----
-
-I recently listened to a podcast episode that was discussing if bugs are good for users.
-
-It suggested that bugs allowed for engagement between you and the user.
-
-If someone reports a bug, you can tell them when you've fixed it. This encourages communication, and the customer will feel more connected to the product.
-
-While this may be true, I think that users would prefer applications that just work.
-
-If your application has major bugs, they may just go elsewhere. Maybe they won't even report the issue to you.
-
-Major bugs can damage your reputation with your users and potential customers, as well as affect potential sales.
-
-If you can avoid them to begin with, that's what I'd suggest. That's what tools and processes such as automated testing, test-driven development and static analysis are for.
-
-When a user reports it (if they do at all), it could be too late.
diff --git a/astro/src/content/daily-email/2023-12-01.md b/astro/src/content/daily-email/2023-12-01.md
deleted file mode 100644
index 9b08f9d5..00000000
--- a/astro/src/content/daily-email/2023-12-01.md
+++ /dev/null
@@ -1,32 +0,0 @@
----
-title: >
- The contribution-first workflow
-pubDate: 2023-12-01
-permalink: >
- archive/2023/12/01/the-contribution-first-workflow
-tags:
- - software-development
- - open-source
----
-
-I've worked on many software projects with a lot of custom code.
-
-Not all the code is specific to that client or project, and often, code is identified as it can be extracted from the project and open-sourced as a Drupal module, PHP or JavaScript library, or Tailwind CSS plugin.
-
-Usually, the code is written as custom code initially, with the best intentions to revisit it once the project is complete and open-source it.
-
-But this rarely happens, as there's always the next sprint or project waiting.
-
-It takes too long to extract the code as it usually needs to be tidied or refactored beforehand.
-
-It may have been written with the client or project name within the code, which needs changing.
-
-My suggestion is to avoid this step.
-
-## Here's the thing
-
-Instead of writing it as custom code and hopefully extracting it later, start it as a separate module, library or plugin, and use Composer or npm to add it to your project as another dependency.
-
-Whilst it's a slightly smaller overhead, it's better and less risky than rewriting or refactoring code later and it's already open-sourced.
-
-Plus, you may get some issues, testing and improvements from others along the way.
diff --git a/astro/src/content/daily-email/2023-12-04.md b/astro/src/content/daily-email/2023-12-04.md
deleted file mode 100644
index d5f9512e..00000000
--- a/astro/src/content/daily-email/2023-12-04.md
+++ /dev/null
@@ -1,45 +0,0 @@
----
-title: >
- Writing contrib modules as glue between your custom code
-pubDate: 2023-12-04
-permalink: >
- archive/2023/12/04/writing-contrib-modules-as-glue-between-your-custom-code
-tags:
- - software-development
- - contribution
- - open-source
- - drupal
- - php
----
-
-
-A few years ago, I worked on an event booking and management website for a charity in the UK.
-
-One required piece of functionality was to allow event organisers to send a private message to all attendees of an event.
-
-We decided to use the [Private Message module] but were concerned about hitting memory limits or timeouts, as some events had several hundred attendees.
-
-We decided that we needed to use a queue and have it process and send the messages.
-
-This split the feature into three parts:
-
-* The UI for event organisers to enter and send their messages.
-* The queue that stores and processes pending messages in the background.
-* The Private Message module that would create and send each message, provide an inbox for each user, and provide notifications.
-
-The UI for event organisers was specific to the project and had to be custom code and not open-sourced.
-
-The Private Message module is already a contributed module, but what about the queue part?
-
-This is why the [Private Message Queue module] was created.
-
-Instead of keeping it within the project's custom code, we created it as an open-source module on Drupal.org.
-
-It contains no customer or project-specific information and only adds generic functionality - it creates a queue to hold private messages to be processed in the background.
-
-It provides the glue between our custom UI and the Private Message module.
-
-As there was no reason why we needed to keep it private, we made it public and developed it as its own project from the beginning instead of planning and hoping to do so later.
-
-[private message module]: https://www.drupal.org/project/private_message
-[private message queue module]: https://www.drupal.org/project/private_message_queue
diff --git a/astro/src/content/daily-email/2023-12-05.md b/astro/src/content/daily-email/2023-12-05.md
deleted file mode 100644
index e46b53bc..00000000
--- a/astro/src/content/daily-email/2023-12-05.md
+++ /dev/null
@@ -1,47 +0,0 @@
----
-title: >
- Open-source encourages more open-source
-pubDate: 2023-12-05
-permalink: >
- archive/2023/12/05/open-source-encourages-open-source
-tags:
- - software-development
- - contribution
- - open-source
- - drupal
- - php
----
-
-[In yesterday's email][yesterday], I mentioned the Private Message Queue module - a contributed Drupal module we wrote for a project as part of a contribution-first workflow.
-
-In our experience, doing that and releasing Private Message Queue as its own open-source project encouraged more open-source contributions.
-
-We started to ask questions like, "Which user should the messages be sent from?".
-
-## System Users
-
-This led us to create the [System User module].
-
-Inspired by system users in Linux, it provides a way to identify and retrieve system users that aren't tied to individuals' accounts and without relying on "magic" user IDs.
-
-But what if a website doesn't have a system user?
-
-## Null Users
-
-This led to the [Null User module].
-
-Following the Null object pattern, if there isn't a system user, instead of returning `NULL` or `FALSE`, you return a null user that you use in the same way, though they'll have default empty values and won't perform any actions.
-
-This pattern simplifies your code as you don't need to check for `NULL` or `FALSE` values.
-
-## Here's the thing
-
-If I remember correctly, as part of the project, we created and released around ten new contributed modules to Drupal.org.
-
-We were able to move straight onto the next phase of the project.
-
-We didn't need to clean them up or refactor them beforehand. We didn't need to dedicate any additional time as they were already released.
-
-[null user module]: https://www.drupal.org/project/null_user
-[system user module]: https://www.drupal.org/project/system_user
-[yesterday]: https://www.oliverdavies.uk/archive/2023/12/04/writing-contrib-modules-as-glue-between-your-custom-code
diff --git a/astro/src/content/daily-email/2023-12-06.md b/astro/src/content/daily-email/2023-12-06.md
deleted file mode 100644
index 3b58791e..00000000
--- a/astro/src/content/daily-email/2023-12-06.md
+++ /dev/null
@@ -1,27 +0,0 @@
----
-title: >
- Open-source first doesn't mean you need to cover every use case
-pubDate: 2023-12-06
-permalink: >
- archive/2023/12/06/open-source-first-doesnt-mean-you-need-to-cover-every-use-case
-tags:
- - software-development
- - open-source
- - contribution
----
-
-An argument against the [contribution-first and open-source-first approach](https://www.oliverdavies.uk/archive/2023/12/01/the-contribution-first-workflow) is that it takes longer than writing custom code.
-
-I think that this is due to thinking that you need to cover all use cases within the code if it's open-sourced, whereas, in custom code, you only write the code you need.
-
-My approach is to write the same code, whether it's private and custom or open-sourced.
-
-The code is based on the same set of requirements, and the only code that should be written should be enough to satisfy those requirements.
-
-It doesn't get written if something isn't part of that objective.
-
-It could be added to a public roadmap for the future if it doesn't need to be part of the initial minimal version.
-
-If someone creates an issue to request new functionality or submits a pull request to contribute potential changes, you decide whether to accept or reject it or even add them as a maintainer to manage their own contributions as well as administrative tasks like managing the issue queues.
-
-If you accept their code, you get the benefit of it (though you also need to maintain and own it) or, if you reject it, you can continue focusing on your minimum-viable version for its initial project.
diff --git a/astro/src/content/daily-email/2023-12-07.md b/astro/src/content/daily-email/2023-12-07.md
deleted file mode 100644
index 9bc30e29..00000000
--- a/astro/src/content/daily-email/2023-12-07.md
+++ /dev/null
@@ -1,20 +0,0 @@
----
-title: >
- A Drupal case study from Oxfam
-pubDate: 2023-12-07
-permalink: >
- archive/2023/12/07/a-drupal-case-study-from-oxfam
-tags:
- - software-development
- - drupal
- - php
- - agile
----
-
-In the latest episode of the Beyond Blocks podcast, Ed Crompton and I discuss his case study of upgrading 15 websites for Oxfam on how to build and test a multilingual, multisite Drupal migration.
-
-We discussed focussing on delivering value, prioritising based on usefulness to users and stakeholders, Agile vs agile, and how they pivoted from a "big bang" approach to delivering rapid increments in smaller batches.
-
-[Listen to the episode now][listen].
-
-[listen]: https://www.oliverdavies.uk/podcast/4-ed-crompton-oxfam-case-study
diff --git a/astro/src/content/daily-email/2023-12-08.md b/astro/src/content/daily-email/2023-12-08.md
deleted file mode 100644
index 35ea03a3..00000000
--- a/astro/src/content/daily-email/2023-12-08.md
+++ /dev/null
@@ -1,22 +0,0 @@
----
-title: >
- Don't just rewrite. Re-invent.
-pubDate: 2023-12-08
-permalink: >
- archive/2023/12/08/dont-just-rewrite
-tags:
- - software-development
- - neovimconf
----
-
-A quote that stuck out to me from today's Neovimconf conference was this by Björn Linse (aka bfredl):
-
-> Don't just rewrite. Re-invent.
->
-> If you're going to start over from scratch, reconsider everything.
-
-This was in the context of what would be added to the core editor, what would be delegated to plugins, etc, but this also applies to other things.
-
-I'm discussing with someone whether to build a new Drupal theme or keep iterating on the existing one.
-
-If they start from scratch, they can re-invent and re-consider everything and decide which parts of the existing theme to reuse and which to leave and re-create.
diff --git a/astro/src/content/daily-email/2023-12-09.md b/astro/src/content/daily-email/2023-12-09.md
deleted file mode 100644
index dade4f91..00000000
--- a/astro/src/content/daily-email/2023-12-09.md
+++ /dev/null
@@ -1,36 +0,0 @@
----
-title: >
- Rebuild or iterate
-pubDate: 2023-12-09
-permalink: >
- archive/2023/12/09/rebuild-or-iterate
-tags:
- - software-development
- - drupal
----
-
-As I said in [yesterday's email][yesterday], I'm discussing with a team how to implement their new website design.
-
-Their website has been live for a couple of years, and now they want to refresh its look and feel.
-
-The current theme includes a lot of technical debt and legacy code, such as using an older CSS framework and build tools that need unsupported versions of packages to compile it and generate the scripts and stylesheets.
-
-There are two ways they could approach this:
-
-They could continue to iterate on the current theme, making and releasing small changes to move forward in small steps and slowly repaying the technical debt.
-
-Alternatively, they could create a new theme from scratch.
-
-This would allow them to start with new build tools, a modern CSS framework and small and simple stylesheets.
-
-## Here's the thing
-
-There are advantages and disadvantages to both approaches.
-
-Iterating on the original theme allows for continuous improvement, but it would take longer to remove the old frameworks and build tools - if that would be possible at all.
-
-Rebuilding and re-inventing would mean immediately avoiding the technical debt and legacy tools, but it comes with its own risks, and you'd need to wait until the whole theme was completed before it could be launched.
-
-There isn't a right and wrong answer, and it will depend on the thoughts and objectives of the team and business.
-
-[yesterday]: https://www.oliverdavies.uk/archive/2023/12/08/dont-just-rewrite
diff --git a/astro/src/content/daily-email/2023-12-10.md b/astro/src/content/daily-email/2023-12-10.md
deleted file mode 100644
index 61635142..00000000
--- a/astro/src/content/daily-email/2023-12-10.md
+++ /dev/null
@@ -1,29 +0,0 @@
----
-title: >
- Suffixing names
-pubDate: 2023-12-10
-permalink: >
- archive/2023/12/10/suffixing-names
-tags:
- - software-development
- - php
- - drupal
- - symfony
- - clean-code
----
-
-When writing code, it's common to suffix the class name with the type of class it is.
-
-I do this often for most types of classes, such as Controllers, EventListeners, Factories, Repositories and Builders.
-
-However, I don't always for value objects and data transfer objects (DTOs).
-
-Also, I don't always suffix interfaces with `Interface`.
-
-I've been re-reading the documentation for the Symfony Serializer component, which references both `NameConverterInterface` and `MyDto::class`.
-
-Whilst it does make the names more verbose, it does clarify what the class is used for.
-
-Symfony's coding standards and Drupal's PHP coding standards have conventions for this, but what do you think?
-
-Do you add suffixes to your class or interface names, or do you prefer the simplified versions?
diff --git a/astro/src/content/daily-email/2023-12-11.md b/astro/src/content/daily-email/2023-12-11.md
deleted file mode 100644
index bca03e94..00000000
--- a/astro/src/content/daily-email/2023-12-11.md
+++ /dev/null
@@ -1,44 +0,0 @@
----
-title: >
- Custom coding standards and conventions
-pubDate: 2023-12-11
-permalink: >
- archive/2023/12/11/custom-coding-standards-and-conventions
-tags:
- - software-development
- - php
- - drupal
- - symfony
- - clean-code
----
-
-Open-source projects like Drupal and Symfony have their own published coding standards and conventions.
-
-For example, from [Symfony's coding standards][symfony]:
-
-* Prefix all abstract classes with `Abstract` except PHPUnit `*TestCase`.
-* Suffix interfaces with `Interface`;
-* Suffix traits with `Trait`;
-
-And from [Drupal's][drupal]:
-
-* Use an indent of 2 spaces, with no tabs.
-* Lines should have no trailing whitespace at the end.
-* Variables should be named using lowercase, and words should be separated either with uppercase characters (example: `$lowerCamelCase`) or with an underscore (example: `$snake_case`). Be consistent; do not mix camelCase and snake_case variable naming inside a file.
-
-But what about within custom applications?
-
-Do you have your own agreed coding standards and conventions to keep the code consistent?
-
-Do you explicitly follow the published coding standards, customise them, or follow something else?
-
-## Here's the thing
-
-Do you know where to put new custom modules, how to name them and what conventions to follow when writing code?
-
-Do you know where to add a new stylesheet to your theme?
-
-If not, or it's implied, it's worth writing it down and being explicit - either within your project's or company's documentation or publicly.
-
-[drupal]: https://www.drupal.org/docs/develop/standards/php/php-coding-standards
-[symfony]: https://symfony.com/doc/current/contributing/code/standards.html
diff --git a/astro/src/content/daily-email/2023-12-12.md b/astro/src/content/daily-email/2023-12-12.md
deleted file mode 100644
index 09e8b2f2..00000000
--- a/astro/src/content/daily-email/2023-12-12.md
+++ /dev/null
@@ -1,64 +0,0 @@
----
-title: >
- DrupalCon session survey results
-pubDate: 2023-12-12
-permalink: >
- archive/2023/12/12/drupalcon-session-survey-results
-tags:
- - software-development
- - test-driven-development
- - automated-testing
- - php
- - phpc
- - drupal
- - drupalcon
----
-
-The survey results from my automated testing and test-driven development session at DrupalCon Lille are in, and here they are:
-
-## How would you rate the speaker(s)'s mastery of this topic?
-
-24 responses.
-
-* Excellent - 33.3%
-* Very good - 50%
-* Good - 16.7%
-* Fair - 0%
-* Poor - 0%
-
-## How would you rate the speaker(s)'s presentation skills?
-
-24 responses.
-
-* Excellent - 20.8%
-* Very good - 37.5%
-* Good - 33.3%
-* Fair - 8.3%
-* Poor - 0%
-
-## How would you rate the speaker(s)’s slides and other session materials?
-
-25 responses.
-
-* Excellent - 24%
-* Very good - 32%
-* Good - 36%
-* Fair - 8%
-* Poor - 0%
-
-## Overall, how would you rate this session?
-
-25 responses.
-
-* Excellent - 36%
-* Very good - 28%
-* Good - 36%
-* Fair - 0%
-* Poor - 0%
-
-Thanks to everyone who completed the survey for their feedback.
-
-P.S. If you'd like your own software development training or coaching, including automated testing and test-driven development, I currently have availability for [team coaching] and [private talks and workshops][workshops].
-
-[team coaching]: https://www.oliverdavies.uk/team-coaching
-[workshops]: https://www.oliverdavies.uk/pricing
diff --git a/astro/src/content/daily-email/2023-12-13.md b/astro/src/content/daily-email/2023-12-13.md
deleted file mode 100644
index 462e47d3..00000000
--- a/astro/src/content/daily-email/2023-12-13.md
+++ /dev/null
@@ -1,42 +0,0 @@
----
-title: >
- Reviving an old PHP project
-pubDate: 2023-12-13
-permalink: >
- archive/2023/12/13/reviving-an-old-php-project
-tags:
- - php
- - phpc
- - open-source
----
-
-I use Gmail/Google Apps for my email address, and I used to use a LOT of filters.
-
-Inspired by a Ruby gem, I created a PHP library that allows me to declare my filters in PHP and create them in XML.
-
-I could import the generated XML into Gmail to create the filters.
-
-## Gmail Filter Buider
-
-The project is [Gmail Filter Builder], and the last commit was in July 2020.
-
-It was based on PHP 7 (unsupported since November 2022) and uses five Symfony components and several other packages.
-
-Today, as I looked at my current Gmail filters, I decided to revisit and update Gmail Filter Builder.
-
-## Updating the project
-
-I set PHP 8.1 as the minimum required version and used a Nix Flake to ensure this was available.
-
-I updated the Symfony components from the 3.x versions to 6.x, the latest versions compatible with PHP 8.1. I also updated the other PHP packages to their compatible versions.
-
-After some small changes to the application's code, it worked with PHP 8.1 and generated filters.
-
-Once it worked, I updated [the examples][examples].
-
-Whilst it wasn't a difficult process in this instance, having a test suite I could rely on helped me to know it worked as expected during the upgrade.
-
-I don't know if I'll continue to use or maintain Gmail Filter Builder again, but it was an interesting exercise to do this morning.
-
-[examples]: https://github.com/opdavies/gmail-filter-builder/tree/3.x/examples
-[gmail filter builder]: https://github.com/opdavies/gmail-filter-builder/tree/3.x
diff --git a/astro/src/content/daily-email/2023-12-14.md b/astro/src/content/daily-email/2023-12-14.md
deleted file mode 100644
index 9174d9d9..00000000
--- a/astro/src/content/daily-email/2023-12-14.md
+++ /dev/null
@@ -1,28 +0,0 @@
----
-title: >
- Save time and effort with Drupal distributions
-pubDate: 2023-12-14
-permalink: >
- archive/2023/12/14/save-time-and-effort-with-drupal-distributions
-tags:
- - software-development
- - drupal
- - php
- - phpc
----
-
-Drupal distributions are pre-built versions of Drupal for specific use cases.
-
-Need an eCommerce store? Use Commerce Kickstart.
-
-Are you a local council looking for a new website? Look at LocalGov Drupal.
-
-Contenta CMS is an API-first Drupal distribution for headless and decoupled content.
-
-There are numerous others - each containing a list of pre-installed and configured modules to give you more functionality out of the box.
-
-If you're starting a new project, try starting with an appropriate distribution instead of starting from scratch with a standard installation of Drupal core and save yourself time and effort.
-
-Don't know if using a distribution could help for you? [Book a 1-on-1 consulting call][call], and I'll help you out.
-
-[call]: https://www.oliverdavies.uk/call
diff --git a/astro/src/content/daily-email/2023-12-15.md b/astro/src/content/daily-email/2023-12-15.md
deleted file mode 100644
index dff09ad7..00000000
--- a/astro/src/content/daily-email/2023-12-15.md
+++ /dev/null
@@ -1,23 +0,0 @@
----
-title: >
- Building your own in-house Drupal distribution
-pubDate: 2023-12-15
-permalink: >
- archive/2023/12/15/building-your-own-in-house-drupal-distribution
-tags:
- - software-development
- - php
- - drupal
----
-
-On several occasions, I've seen companies who build a lot of Drupal projects creating their own in-house [Drupal distribution] for new projects.
-
-Whilst this seems like a good idea, the ones I've seen are either not well maintained due to limited time between projects, or they're bloated with features and trying to include too much out of the box.
-
-If you maintain an in-house distribution, or are thinking of creating one, my advice is to ensure it's maintained by allocating enough time for this, and to keep it lean and only include the minimum amount of required functionality.
-
-Alternatively, maybe keep a template composer.json file to base new projects on instead of a full distribution.
-
-That could declare the modules and themes you want to include, without the additional overhead.
-
-[drupal distribution](https://www.oliverdavies.uk/archive/2023/12/14/save-time-and-effort-with-drupal-distributions)
diff --git a/astro/src/content/daily-email/2023-12-16.md b/astro/src/content/daily-email/2023-12-16.md
deleted file mode 100644
index 5149f5b9..00000000
--- a/astro/src/content/daily-email/2023-12-16.md
+++ /dev/null
@@ -1,28 +0,0 @@
----
-title: >
- Adding snapshot tests to Build Configs
-pubDate: 2023-12-16
-permalink: >
- archive/2023/12/16/adding-snapshot-tests-to-build-configs
-tags:
- - software-development
- - php
- - symfony
- - build-configs
- - automated-testing
- - test-driven-development
----
-
-This week, I've started to add snapshot tests to the [Build Configs project][build configs].
-
-I had unit tests for the DTO validation to ensure the configuration was correct, but the main thing I wanted to test was I could run it for a given configuration file and get the expected files and contents to be generated.
-
-With snapshot tests, I generate the files for each configuration and compare them to a set that I know to be correct.
-
-If the files match, the tests pass, but, if they don't - such as a bug in the code, the tests will fail.
-
-This is the level that I want to be testing this project and that provides the most value.
-
-If a snapshot test fails, I can try to replicate the underlying issue in a unit test whilst also fixing the snapshot test.
-
-[build configs]: https://www.oliverdavies.dev/build-configs
diff --git a/astro/src/content/daily-email/2023-12-17.md b/astro/src/content/daily-email/2023-12-17.md
deleted file mode 100644
index 763b98ed..00000000
--- a/astro/src/content/daily-email/2023-12-17.md
+++ /dev/null
@@ -1,34 +0,0 @@
----
-title: >
- Fail fast, fix fast
-pubDate: 2023-12-17
-permalink: >
- archive/2023/12/17/fail-fast-fix-fast
-tags:
- - software-development
- - continuous-delivery
- - continuous-deployment
- - deployments
- - feature-flags
----
-
-I recently listened to a podcast that discussed Elon Musk and quoted something like, "If 20% of attempts aren't failing, you aren't taking enough risk".
-
-In a software context, I'm not advocating that one in five production releases should fail, but I like trying new ideas and approaches.
-
-If you're releasing small changes regularly or practising continuous deployment, changes are easy to revert if there's a problem or the smaller the deployment and the more recently the code was written, then it should be easier to resolve the issue and "fix forward" instead of rolling back.
-
-Using feature flags lets you quickly turn off a feature flag while investigating and resolving the issue without needing another deployment.
-
-If you have an appropriate plan to follow in the case of an issue, that mitigates the risk and minimises the impact of a potential issue - making it quicker to resolve and restore the service.
-
-Two of the DORA metrics refer to failure rate and restoration time:
-
-* Deployment frequency
-* Lead time for changes
-* Change failure rate
-* Time to restore service
-
-Then, it depends on your organisation's tolerance for risk and what's acceptable.
-
-But, the more frequent the releases, the lower the failure rate and the quicker it will be to restore the service if there is an issue.
diff --git a/astro/src/content/daily-email/2023-12-18.md b/astro/src/content/daily-email/2023-12-18.md
deleted file mode 100644
index 7165103c..00000000
--- a/astro/src/content/daily-email/2023-12-18.md
+++ /dev/null
@@ -1,29 +0,0 @@
----
-title: >
- Should you run static analysis on your tests?
-pubDate: 2023-12-18
-permalink: >
- archive/2023/12/18/static-analysis-on-tests
-tags:
- - software-development
- - php
- - phpstan
- - static-analysis
- - automated-testing
----
-
-I'm an advocate of both automated testing and static analysis but have mostly kept the two separate.
-
-I've typically not run PHPStan on my automated test files - ignoring them in my PHPStan configuration.
-
-As tests aren't production/implementation code, what's the benefit of analysing them?
-
-Recently, though, I've challenged this and, on some projects, started to run PHPStan on my test classes.
-
-Depending on what level PHPStan is running, the more changes you're likely to have to make to get your test classes to pass the static analysis, and whilst it results in more verbose and explicit code, I prefer that and being able to easily understand what it does rather than implicit.
-
-If you have a bug in your test, static analysis will potentially find that, too, making your test suite more robust.
-
-Looking at some large open-source PHP projects, they run static analysis on their test code.
-
-Presumably, they're benefiting from it, so I'll try it and see if I get the same.
diff --git a/astro/src/content/daily-email/2023-12-19.md b/astro/src/content/daily-email/2023-12-19.md
deleted file mode 100644
index 9c11e2bd..00000000
--- a/astro/src/content/daily-email/2023-12-19.md
+++ /dev/null
@@ -1,23 +0,0 @@
----
-title: >
- PHP TUIs, CLIs and open-source with Dan Leech
-pubDate: 2023-12-19
-permalink: >
- archive/2023/12/19/php-tui-dan-leech
-tags:
- - php
- - phpc
- - open-source
- - neovim
----
-
-This week on the [Beyond Blocks podcast][podcast], I'm joined by Dan Leech - a PHP Developer and open-source project creator.
-
-He and I recently gave talks at the PHP South West meetup, where Dan introduced a new project - PHP-TUI - for building terminal user interfaces (TUIs) with PHP.
-
-I use one of Dan's other open-source projects - Phpactor - within Neovim, and he also presented at PHP South Wales about PHPBench, so it was great to discuss and learn more about these in this episode.
-
-[Listen to the episode now][episode], and I'll be back with more in the New Year.
-
-[episode]: https://www.oliverdavies.uk/podcast/6-dan-leech-php-tui
-[podcast]: https://www.oliverdavies.uk/podcast
diff --git a/astro/src/content/daily-email/2023-12-20.md b/astro/src/content/daily-email/2023-12-20.md
deleted file mode 100644
index 424ddd19..00000000
--- a/astro/src/content/daily-email/2023-12-20.md
+++ /dev/null
@@ -1,34 +0,0 @@
----
-title: >
- hover + focus = hocus
-pubDate: 2023-12-20
-permalink: >
- archive/2023/12/20/hover-focus-hocus
-tags:
- - software-development
- - accessibility
- - css
- - tailwind-css
----
-
-When creating accessible websites, as well as hover states for focusable elements, such as buttons, you also need to add focus styles that apply when users navigate the page using a keyboard and focusing on an element.
-
-With Tailwind, that can mean a lot of duplication if your hover and focus states are similar or the same, as the same classes need to be added with both the `:hover` and `:focus` variants.
-
-One of Tailwind's best features is its extensibility, which means I can create a new interaction state - `:hocus` - that works for both.
-
-It's very easy to do by adding this code to your `tailwind.config.js` or `tailwind.config.ts` file:
-
-```javascript
-const plugin = require("tailwindcss/plugin");
-
-module.exports = plugin(({ addVariant }) => {
- addVariant("hocus", ["&:hover", "&:focus"]);
-});
-```
-
-Or, use [the Tailwind CSS plugin I wrote][plugin].
-
-Get more accessible websites and less duplication today!
-
-[plugin]: https://www.npmjs.com/package/tailwindcss-plugin-hocus-state
diff --git a/astro/src/content/daily-email/2023-12-21.md b/astro/src/content/daily-email/2023-12-21.md
deleted file mode 100644
index b26e2981..00000000
--- a/astro/src/content/daily-email/2023-12-21.md
+++ /dev/null
@@ -1,14 +0,0 @@
----
-title: >
- New year coaching
-pubDate: 2023-12-21
-permalink: >
- archive/2023/12/21/new-year-coaching
-tags:
- - software-development
- - coaching
----
-
-I have availability to work with a small number of software development teams in the new year and help them ship better software, faster, using tools and techniques like automated testing, test-driven development and static analysis.
-
-Would you like to work with me?
diff --git a/astro/src/content/daily-email/2023-12-22.md b/astro/src/content/daily-email/2023-12-22.md
deleted file mode 100644
index fc32359b..00000000
--- a/astro/src/content/daily-email/2023-12-22.md
+++ /dev/null
@@ -1,23 +0,0 @@
----
-title: >
- Which is the best programming language, CMS or framework?
-pubDate: 2023-12-22
-permalink: >
- archive/2023/12/22/best-language-cms-or-framework
-tags:
- - software-development
- - php
- - drupal
----
-
-I started developing websites in HTML and CSS in 2007 before adopting PHP and Drupal in 2008.
-
-Since then, I've used Drupal 6, 7, 8, 9 and 10 to deliver applications for clients, agencies and in-house teams.
-
-I also use Symfony and Laravel, as well as JavaScript, TypeScript and Vue.js.
-
-## Here's the thing
-
-There isn't one outright "best" programming language, CMS or framework.
-
-It depends on the project and its requirements as well as the knowledge and experience of the team working on it.
diff --git a/astro/src/content/daily-email/2023-12-23.md b/astro/src/content/daily-email/2023-12-23.md
deleted file mode 100644
index 3ff9b50d..00000000
--- a/astro/src/content/daily-email/2023-12-23.md
+++ /dev/null
@@ -1,28 +0,0 @@
----
-title: >
- Using a whole framework or part of it
-pubDate: 2023-12-23
-permalink: >
- archive/2023/12/23/using-a-whole-framework-or-part-of-it
-tags:
- - software-development
- - php
- - composer
- - drupal
- - symfony
- - laravel
----
-
-[In yesterday's email][yesterday], I mentioned using several programming languages and frameworks.
-
-Drupal is my main specialism and the one I have the most experience and knowledge of, but you don't need to use only Drupal code.
-
-Using Composer, you can add parts of other frameworks to other projects.
-
-I don't use Laravel often as a full-stack framework, but I use the Collections library, and recently the Pipelines library, in almost every project - whether it's Drupal or Symfony, it can be added to any PHP project.
-
-Start small, keep things simple, and add what you need.
-
-You don't need to go all in on one option, you can pick the pieces you like and that work for you.
-
-[yesterday]: https://www.oliverdavies.uk/archive/2023/12/22/best-language-cms-or-framework
diff --git a/astro/src/content/daily-email/2023-12-24.md b/astro/src/content/daily-email/2023-12-24.md
deleted file mode 100644
index b8d951e7..00000000
--- a/astro/src/content/daily-email/2023-12-24.md
+++ /dev/null
@@ -1,20 +0,0 @@
----
-title: >
- This should never happen
-pubDate: 2023-12-24
-permalink: >
- archive/2023/12/24/this-should-never-happen
-tags:
- - software-development
- - clean-code
----
-
-How often do you see comments like "This should never happen" in a software codebase?
-
-If that's true, why is it there?
-
-If it truly should never happen, the additional code only adds more noise and distracts from the code that is run.
-
-You can add a test that checks a method isn't called, but what value does this offer?
-
-If it doesn't happen or some code isn't run, remove it and keep it as simple, clean and easy to understand as possible.
diff --git a/astro/src/content/daily-email/2023-12-25.md b/astro/src/content/daily-email/2023-12-25.md
deleted file mode 100644
index e577d67c..00000000
--- a/astro/src/content/daily-email/2023-12-25.md
+++ /dev/null
@@ -1,206 +0,0 @@
----
-title: >
- A sneak peek of my Drupal automated testing course
-pubDate: 2023-12-25
-permalink: >
- archive/2023/12/25/zero-to-test
-tags:
- - software-development
- - drupal
- - php
- - phpunit
- - automated-testing
- - test-driven-development
----
-
-Happy Christmas!
-
-Here's my present - a sneak peek at the first lesson in my free upcoming Automated Testing for Drupal email course.
-
-In this lesson, we start from scratch and end with a working test suite.
-
-If you like it, [register for free and get the full course][atdc] when it launches.
-
-## Creating a Drupal project
-
-If you don't have one, you'll need to create a new Drupal project. I'd suggest using Drupal 10.2 and the instructions at .
-
-You'll need [PHP](https://www.php.net/manual/en/install.php) and [Composer](https://getcomposer.org/doc/00-intro.md).
-
-First, run `composer create-project drupal/recommended-project drupal` followed by `cd drupal && composer require --dev drupal/core-dev` to add the development dependencies, including PHPUnit.
-
-At this point, you should have a `web` directory and a `phpunit` file within `vendor/bin`.
-
-Finally, run `php -S 0.0.0.0:8000 -t web` to start a local web server.
-
-You don't need to install Drupal - as long as you see the installation page, that's fine.
-
-## Creating a custom module
-
-Before adding tests, you must create a module to place them in.
-
-Run `mkdir -p web/modules/custom/atdc` to create an empty module directory, and create an `atdc.info.yml` file within it with this content:
-
-```yaml
-name: Example
-type: module
-core_version_requirement: ^10
-package: Custom
-```
-
-This is the minimum content needed for a module to be installable.
-
-### Writing your first test class
-
-Test classes are placed within each module's `tests/src` directory.
-
-Run `mkdir -p web/modules/custom/atdc/tests/src/Functional && touch web/modules/custom/atdc/tests/src/Functional/ExampleTest.php` to create the directory structure and a blank test class.
-
-Then, add this content.
-
-```php
- PHPUnit\TextUI\RuntimeException: Class "Drupal\Tests\BrowserTestBase" not found.
-
-This isn't an assertion failure, but that PHPUnit can't find the files it needs to run.
-
-To fix this, let's configure PHPUnit.
-
-## Configuring PHPUnit
-
-Create a new `phpunit.xml.dist` file at the root of your project, with this content:
-
-```xml
-
-
-
-
-
-
-
-
-
-
- ./web/modules/**
-
-
-
-```
-
-This is based on `web/core/phpunit.xml.dist` with some project-specific changes.
-
-Namely, setting the `bootstrap` value to include the `web/core` path and fix the error, and populating the `SIMPLETEST_BASE_URL` and `SIMPLETEST_DB` environment variables.
-
-PHPUnit now knows where the files are, to connect to Drupal at (matching the PHP web server address) and an SQLite database.
-
-I've also added a `testsuite` that declares where any test classes will be located so the path doesn't need to be specified on the command line.
-
-## Re-running the tests
-
-Running the tests again will give the expected error about a failing assertion:
-
-> Failed asserting that false is true.
-
-Fix the assertion in the test by changing `FALSE` to `TRUE`, run `vendor/bin/phpunit` again, and you should see a passing test.
-
-> OK (1 test, 2 assertions)
-
-## Improving the tests
-
-Now you have as passing test and know PHPUnit is working, let's improve it.
-
-Instead of the basic check, let's check whether certain pages exist and are accessible.
-
-To keep things simple and focused on writing and running tests, let's use some standard Drupal pages - the front and administration pages instead of writing your own.
-
-As you're writing functional tests by extending `BrowserTestBase`, you can make HTTP requests to the web server, and make assertions on the responses.
-
-Replace the `testBasic` test method with the following:
-
-```php
-public function testFrontPage(): void {
- $this->drupalGet('/');
-
- $assert = $this->assertSession();
- $assert->statusCodeEquals(Response::HTTP_FORBIDDEN);
-}
-
-public function testAdminPage(): void {
- $this->drupalGet('/admin');
-
- $assert = $this->assertSession();
- $assert->statusCodeEquals(Response::HTTP_OK);
-}
-```
-
-These tests will make HTTP requests to the specified paths and assert the status code on the response matches the expected values.
-
-I'm using the constants on the `Response` class, but you can also use the status code numbers - e.g. `200` and `403`.
-
-## Running the updated tests
-
-Running `vendor/bin/phpunit`, you'll get two errors:
-
-> 1) Drupal\Tests\atdc\Functional\ExampleTest::testFrontPage
-> Behat\Mink\Exception\ExpectationException: Current response status code is 200, but 403 expected.
->
-> 2) Drupal\Tests\atdc\Functional\ExampleTest::testAdminPage
-> Behat\Mink\Exception\ExpectationException: Current response status code is 403, but 200 expected.
->
-> ERRORS!
-> Tests: 2, Assertions: 4, Errors: 2.
-
-The responses are not returning the expected status codes, so the tests are failing.
-
-Reviewing them, the front page should return a 200 response code (`HTTP_OK`) as it's accessible to all users, including anonymous users.
-
-As we're logged out, the administration page should return a 403 (`HTTP_FORBIDDEN`).
-
-Swapping the assertions should get the tests to pass.
-
-Now, running `vendor/bin/phpunit` returns no errors or failures.
-
-> OK (2 tests, 4 assertions)
-
-Congratulations!
-
-## Conclusion
-
-In this lesson, you've created a new Drupal 10 project, configured PHPUnit and created a custom module with your first passing browser tests.
-
-From this, you can hopefully see that automated testing doesn't need to be difficult, and the configuration you've done here will work for the upcoming lessons, where you'll expand on what you've done and explore more that Drupal and PHPUnit have to offer.
-
-I hope you enjoyed this sneak peek, and if you'd like to receive the course once it's complete, [register here for free][atdc].
-
-[atdc]: https://www.oliverdavies.uk/atdc
diff --git a/astro/src/content/daily-email/2023-12-26.md b/astro/src/content/daily-email/2023-12-26.md
deleted file mode 100644
index 4729ca76..00000000
--- a/astro/src/content/daily-email/2023-12-26.md
+++ /dev/null
@@ -1,18 +0,0 @@
----
-title: >
- Good code is not about being easy to write
-snippet: >-
- Good code is not about being easy to write. It's about how easy it is to change.
-pubDate: 2023-12-26
-permalink: >-
- archive/2023/12/26/good-code-is-not-about-being-easy-to-write
-tags:
- - software-development
- - clean-code
----
-
-Good code is not about being easy to write. It's about how easy it is to change.
-
-Once you've written some code, how easily and confidently could you change it in the future, either adding new features or fixing a bug?
-
-How easily could you refactor the code or remove it altogether if it's no longer needed?
diff --git a/astro/src/content/daily-email/2023-12-27.md b/astro/src/content/daily-email/2023-12-27.md
deleted file mode 100644
index 02ca57a8..00000000
--- a/astro/src/content/daily-email/2023-12-27.md
+++ /dev/null
@@ -1,38 +0,0 @@
----
-title: >-
- Writing new code is quick, to begin with
-pubDate: 2023-12-27
-permalink: >
- archive/2023/12/27/writing-new-code-is-quick-to-begin-with
-snippet: >-
- Why is it quick to write new code in a new application, but slower as the project progresses,
- with tasks that would take hours to begin with later taking days, weeks or longer.
-tags:
- - software-development
- - technical-debt
- - clean-code
----
-
-When you first start a new application, adding new features is quick and easy.
-
-There's no existing code, and everything is written from scratch.
-
-As the project progresses, you need to account for and, in some cases, work around the existing code - ensuring the existing functionality continues to work.
-
-Even if a sole Developer is working on the project, inconsistencies start to be introduced.
-
-One feature was implemented in one way and the next in a different way.
-
-One follows a particular design pattern, and the other does not.
-
-There is code within the application that isn't used and is no longer needed but hasn't been removed - creating confusion and uncertainty.
-
-It can't be removed, just in case it does something and removing it breaks something elsewhere.
-
-A task that would have taken hours to complete when the application started now takes days, weeks or longer.
-
-Having automated tests, using tools like static analysis, and minimising technical debt helps to minimise this, as does having written technical design documents, ADRs or flow charts to ensure consistency and to document the "why" for future Developers.
-
-P.S. Is your New Year's resolution to deliver better software faster? [I have availability for team coaching][team coaching] starting in January 2024 and can help you avoid issues like this in your applications.
-
-[team coaching]: https://www.oliverdavies.uk/team-coaching
diff --git a/astro/src/content/daily-email/2023-12-28.md b/astro/src/content/daily-email/2023-12-28.md
deleted file mode 100644
index c05c9aee..00000000
--- a/astro/src/content/daily-email/2023-12-28.md
+++ /dev/null
@@ -1,31 +0,0 @@
----
-title: >-
- Don't let pride get in the way of productivity
-pubDate: 2023-12-28
-permalink: >
- archive/2023/12/28/pride-and-productivity
-snippet: >-
- Have you over been too proud to ask a question, even if it affects your productivity?
-tags:
- - software-development
----
-
-Today, I was reading a support request on a public forum.
-
-The poster asked a question about a technical issue and explained the problem they were experiencing. I was experiencing the same thing, which is how I found it.
-
-A community member responded and suggested a solution.
-
-To this, the original poster responded:
-
-> Not too proud to ask where I [make the change].
-
-The response to this was what caught my attention:
-
-> No problem. Don't let pride get in the way of productivity.
-
-## Here's the thing
-
-Don't be afraid to ask questions or say you don't know or understand something.
-
-No one knows everything, and there's no such thing as a stupid question.
diff --git a/astro/src/content/daily-email/2023-12-29.md b/astro/src/content/daily-email/2023-12-29.md
deleted file mode 100644
index b4c2aa4e..00000000
--- a/astro/src/content/daily-email/2023-12-29.md
+++ /dev/null
@@ -1,37 +0,0 @@
----
-title: >-
- Decide, automate, document
-pubDate: 2023-12-29
-permalink: >
- archive/2023/12/29/decide-automate-document
-snippet: >
- How do you make and document decisions on your team? Here are three steps that have worked well for me.
-
- Decide, automate, document.
-tags:
- - software-development
----
-
-Decide, automate, document
-
-Here are three steps to making decisions, such as introducing new tools and processes:
-
-Decide.
-
-Automate.
-
-Document.
-
-First of all, a decision needs to be made about what you will introduce.
-
-It could be whether to write automated tests, use static analysis, choose which coding standard to use, or make architecture decisions about how you want to build your application.
-
-Once you've decided and added the tool or process, automate it if you can.
-
-A CI pipeline or Git Hooks can run tests and checks automatically to know if the code complies with what was agreed upon rather than relying on this being done manually.
-
-Finally, document it so that it's available for others to read and reference, including new team members.
-
-Ensure to document why this was added, what problem it solves, any alternatives that were considered and any side effects or consequences. Technical design documents and ADRs (architectural decision records) are great for this!
-
-In the future, you may want to revisit the decision and decide if it's still correct, and you'll appreciate having the information documented.
diff --git a/astro/src/content/daily-email/2023-12-30.md b/astro/src/content/daily-email/2023-12-30.md
deleted file mode 100644
index 2dae8519..00000000
--- a/astro/src/content/daily-email/2023-12-30.md
+++ /dev/null
@@ -1,27 +0,0 @@
----
-title: >-
- We've always done it this way
-pubDate: 2023-12-30
-permalink: >
- archive/2023/12/30/weve-always-done-it-this-way
-snippet: >
- Has anyone told you "We've always done it this way." or "We've never needed to write tests before."?
-
- In my experience, these are two of the worst phases to hear from new development teams.
-tags:
- - software-development
- - agile
- - continuous-improvement
----
-
-Two of the worst phrases I've heard when working with new development teams is "We've always done it this way" or "We've never needed to do this before".
-
-Whether it's writing automated tests, using static analysis, having a CI pipeline or using a specific framework or tool, this mindset prevents experimentation, growth and improvement.
-
-Instead, try to think about what benefits alternative approaches could offer and how they could improve any situations you're currently experiencing.
-
-You don't need to do it forever. Decide on something you want to try on a trial basis and set an end date.
-
-Then, when the trial is finished, you can decide if it achieved what you wanted, and if you want to continue with it.
-
-Even if you don't continue with it, you still learned something by trying.
diff --git a/astro/src/content/daily-email/2023-12-31.md b/astro/src/content/daily-email/2023-12-31.md
deleted file mode 100644
index 652458a4..00000000
--- a/astro/src/content/daily-email/2023-12-31.md
+++ /dev/null
@@ -1,29 +0,0 @@
----
-title: >-
- Just...
-pubDate: 2023-12-31
-permalink: >
- archive/2023/12/31/just
-snippet: >-
- Can you just...
-tags:
- - software-development
----
-
-If you have a request that starts with "Just", it's likely a red flag!
-
-Why is it being made?
-
-What problem is it going to solve?
-
-Whose problem does it solve?
-
-Is the problem time-sensitive?
-
-What value does it add?
-
-Is it the best solution to fix the problem?
-
-Is it the best solution to fix the problem right now?
-
-To know this, we need to know why it's needed and it "just" needs doing.
diff --git a/astro/src/content/podcast-episode/1-retrofit.md b/astro/src/content/podcast-episode/1-retrofit.md
deleted file mode 100644
index c59fa895..00000000
--- a/astro/src/content/podcast-episode/1-retrofit.md
+++ /dev/null
@@ -1,43 +0,0 @@
----
-date: 2023-11-10
-topic: Retrofit
-guests:
- - Matt Glaman
-links:
- - - Retrofit
- - https://retrofit-drupal.com
-
- - - Retrofit on GitHub
- - https://github.com/retrofit-drupal/retrofit
-
- - - Running legacy Drupal 7 code on your Drupal 10 site
- - https://mglaman.dev/blog/retrofit-running-legacy-drupal-7-code-your-drupal-10-site
-
- - - PHPStan
- - https://phpstan.org
-
- - - phpstan-drupal
- - https://github.com/mglaman/phpstan-drupal
-
- - - Centarro
- - https://www.centarro.io
-
- - - Drupal Commerce
- - https://drupalcommerce.org
-
- - - Matt on GitHub
- - https://github.com/mglaman
-
- - - Matt on Drupal.org
- - https://www.drupal.org/u/mglaman
-
- - - Matt on YouTube
- - https://www.youtube.com/@nmdmatt
-
- - - Matt on Twitch
- - https://www.twitch.tv/mglaman
-transistor:
- id: 7d728873
----
-
-In this episode, Oliver is joined by Matt Glaman to discuss Retrofit. A tool that makes it easier to upgrade Drupal websites by allowing legacy Drupal code to run on any version of Drupal.
diff --git a/astro/src/content/podcast-episode/2-alternate-realities.md b/astro/src/content/podcast-episode/2-alternate-realities.md
deleted file mode 100644
index 34d63fbf..00000000
--- a/astro/src/content/podcast-episode/2-alternate-realities.md
+++ /dev/null
@@ -1,31 +0,0 @@
----
-date: 2023-11-17
-topic: Drupal's Alternate Realities
-guests:
- - Panagiotis Moutsopoulos
-links:
-- - DrupalCon Lille
- - https://events.drupal.org/lille2023
-
-- - Panagiotis' BoF session
- - https://events.drupal.org/lille2023/session/drupals-alternate-realities
-
-- - Panagiotis on Drupal.org (vensires)
- - https://www.drupal.org/u/vensires
-
-- - E-Sepia
- - https://www.e-sepia.gr
-
-- - Panagiotis on LinkedIn
- - https://www.linkedin.com/in/panagiotis-moutsopoulos/
-
-- - https://drupal.org.gr
- - https://drupal.org.gr
-
-- - Frontend United
- - https://www.frontendunited.com
-transistor:
- id: 5f7e3397
----
-
-In this episode, Oliver is joined by Panagiotis Moutsopoulos to discuss about the whole first-time DrupalCon experience of Lille (France) and more specifically, his session Drupal’s Alternate Realities A BoF session presenting some history but mainly the different ways to tackle a problem in Drupal using different methodologies.
diff --git a/astro/src/content/podcast-episode/3-non-technical-contribution.md b/astro/src/content/podcast-episode/3-non-technical-contribution.md
deleted file mode 100644
index 77edae05..00000000
--- a/astro/src/content/podcast-episode/3-non-technical-contribution.md
+++ /dev/null
@@ -1,43 +0,0 @@
----
-date: 2023-11-24
-topic: Community engagement for non-technical Drupal enthusiasts
-guests:
- - Niklas Franke
-links:
- - - DrupalCon Lille
- - https://events.drupal.org/lille2023
-
- - - 'Beyond the code: Community engagement for non-technical Drupal enthusiasts'
- - https://events.drupal.org/lille2023/session/beyond-code-community-engagement-non-technical-drupal-enthusiasts
-
- - - 'How to organise your own Splash Awards'
- - https://events.drupal.org/lille2023/session/how-organise-your-own-splash-awards
-
- - - 'DrupalCon sponsored talk: What developers really want: Uncovering the essential work benefits for software developers (sponsored by Factorial)'
- - https://events.drupal.org/lille2023/session/what-developers-really-want-uncovering-essential-work-benefits-software
-
- - - 'Splash Awards'
- - https://www.drupal.org/community/splash-awards
-
- - - 'Splash Awards - Germany & Austria'
- - https://splashawards.de
-
- - - 'Group module'
- - https://www.drupal.org/project/group
-
- - - 'Niklas Franke on Drupal.org'
- - https://www.drupal.org/u/heroicnick
-
- - - 'Factorial GmbH'
- - https://www.factorial.io/en/drupal-agency
-
- - - 'Factorial GmbH on Drupal.org'
- - https://www.drupal.org/factorial-gmbh
-
- - - 'Factorial on YouTube'
- - https://www.youtube.com/channel/UCJslkuiIJLTRmYEvN2y-jzA
-transistor:
- id: 85bdc4c7
----
-
-This week, Oliver is joined by Niklas Franke to discuss DrupalCon Lille, contributing to Drupal as a non-technical enthusiast, the Splash Awards and the Drupal community in Germany.
diff --git a/astro/src/content/podcast-episode/4-ed-crompton-oxfam-case-study.mdx b/astro/src/content/podcast-episode/4-ed-crompton-oxfam-case-study.mdx
deleted file mode 100644
index 2e2ebc13..00000000
--- a/astro/src/content/podcast-episode/4-ed-crompton-oxfam-case-study.mdx
+++ /dev/null
@@ -1,48 +0,0 @@
----
-date: 2023-12-01
-topic: A case study from Oxfam
-guests:
- - Ed Crompton
-transistor:
- id: 0ff9802a
-links:
- -
- - Ed Crompton on Drupal.org
- - https://www.drupal.org/u/eddie_c
- -
- - 'Oxfam country sites: From big bang to small batch delivery'
- - https://www.linkedin.com/pulse/oxfam-country-sites-from-big-bang-small-batch-edward-crompton
- -
- - Oxfam.org
- - https://www.oxfam.org/en
- -
- - https://cambodia.oxfam.org
- - https://cambodia.oxfam.org
- -
- - Pattern Lab
- - https://patternlab.io
- -
- - Fractal
- - https://fractal.build
- -
- - Twig
- - https://twig.symfony.com
- -
- - Working in small batches
- - http://www.startuplessonslearned.com/2009/02/work-in-small-batches.html
- -
- - Behat
- - http://www.behat.org
- -
- - Behat integration with Drupal
- - https://www.drupal.org/project/behat
- -
- - phenaproxima on Drupal.org
- - https://www.drupal.org/u/phenaproxima
- -
- - I've been using Behat wrong this whole time
- - https://phenaproxima.net/2018/08/07/behat-insanity.html
- -
- - Drupal Test Traits
- - https://gitlab.com/weitzman/drupal-test-traits
----
diff --git a/astro/src/content/podcast-episode/5-dieter-blomme-technical-debt.mdx b/astro/src/content/podcast-episode/5-dieter-blomme-technical-debt.mdx
deleted file mode 100644
index c03bbafe..00000000
--- a/astro/src/content/podcast-episode/5-dieter-blomme-technical-debt.mdx
+++ /dev/null
@@ -1,38 +0,0 @@
----
-date: 2023-12-09
-topic: Managing technical debt
-guests:
- - Dieter Blomme
-transistor:
- id: 40066a7f
-links:
- - - DrupalCon Lille
- - https://events.drupal.org/lille2023
-
- - - 'Managing technical debt: lessons learned and how modern Drupal helps you'
- - https://events.drupal.org/lille2023/session/managing-technical-debt-lessons-learned-and-how-modern-drupal-helps-you
-
- - - Understanding Technical Debt in the Drupal ecosystem
- - https://www.youtube.com/watch?v=1YSL4Be7jDY
-
- - - Dieter Blomme on Drupal.org
- - https://www.drupal.org/u/daften
-
- - - Dropsolid website
- - https://dropsolid.com/
-
- - - Dropsolid on Drupal.org
- - https://www.drupal.org/dropsolid
-
- - - Dropsolid on YouTube
- - https://www.youtube.com/@dropsolid.experiencecompany
-
- - - DrupalCon session video
- - https://youtu.be/S-B7_YiskVM
-
- - - Concerns vs objectives
- - https://blog.holacracy.org/holacracy-basics-understanding-objections-d87b579d00d1
-
- - - Decision by traffic light
- - https://www.linkedin.com/pulse/decision-making-101-traffic-lights-puppy-case-study-valerio-magliulo
----
diff --git a/astro/src/content/podcast-episode/6-dan-leech-php-tui.mdx b/astro/src/content/podcast-episode/6-dan-leech-php-tui.mdx
deleted file mode 100644
index ea69b57f..00000000
--- a/astro/src/content/podcast-episode/6-dan-leech-php-tui.mdx
+++ /dev/null
@@ -1,49 +0,0 @@
----
-date: 2023-12-19
-topic: 'PHP: TUIs, CLIs and open-source'
-guests:
- - Dan Leech
-transistor:
- id: 45d57d43
-links:
- - - PHP TUI on GitHub
- - https://github.com/php-tui
-
- - - Phpactor on GitHub
- - https://github.com/phpactor
-
- - - PHPbench on GitHub
- - https://github.com/phpbench
-
- - - Phpactor documentation
- - https://phpactor.readthedocs.io
-
- - - PHPBench documentation
- - https://phpbench.readthedocs.io
-
- - - Testing code performance with PHPBench
- - https://youtu.be/-qxu6n9Q-3k?si=2N8Ee9GIgCul7_e1
-
- - - PHP-TUI Progress
- - https://www.dantleech.com/blog/2023/11/03/php-tui-progress
-
- - - PHP Term
- - https://www.dantleech.com/blog/2023/11/27/php-term
-
- - - PHP Architecture Tester (phpat)
- - https://github.com/carlosas/phpat
-
- - - Jess Archer
- - https://jessarcher.com
-
- - - Neovim as a PHP and JavaScript IDE (Laracasts)
- - https://laracasts.com/series/neovim-as-a-php-ide
-
- - - Laravel Prompts
- - https://github.com/laravel/prompts
-
- - - Symfony Terminal component
- - https://speakerdeck.com/fabpot/the-symfony-terminal-component
----
-
-In this week's episode, Oliver is joined by Dan Leech to discuss building command-line applications and TUIs with PHP based on Dan's open-source projects - Phpactor, PHPBench and, most recently, PHP-TUI.
diff --git a/astro/src/content/talk/about-drupal-association.md b/astro/src/content/talk/about-drupal-association.md
deleted file mode 100644
index 8442c9de..00000000
--- a/astro/src/content/talk/about-drupal-association.md
+++ /dev/null
@@ -1,10 +0,0 @@
----
-title: About the Drupal Association
-description: An impromptu talk about what the Drupal Association is, and what work I’ve been doing since I joined the Association staff.
-events:
- - name: South Wales Drupal user group (SWDUG)
- location: Cardiff, UK
- date: "2014-08-19"
----
-
-An impromptu talk about what the Drupal Association is, and what work I’ve been doing since I joined the Association staff.
diff --git a/astro/src/content/talk/automated-testing-lightning-talk.md b/astro/src/content/talk/automated-testing-lightning-talk.md
deleted file mode 100644
index b42a2226..00000000
--- a/astro/src/content/talk/automated-testing-lightning-talk.md
+++ /dev/null
@@ -1,14 +0,0 @@
----
-title: Automated testing crash course
-description: A crash course in automated testing with Drupal and test-driven development (lightning talk).
-events:
- - name: NWDUG
- location: Manchester, UK
- date: "2023-08-08"
- url: https://www.meetup.com/nwdrupal/events/293429104
- online: true
----
-
-A short talk introducing automated testing with Drupal and test-driven development.
-
-Example repository:
diff --git a/astro/src/content/talk/automated-testing-test-driven-development-drupal-8.md b/astro/src/content/talk/automated-testing-test-driven-development-drupal-8.md
deleted file mode 100644
index 19e6d155..00000000
--- a/astro/src/content/talk/automated-testing-test-driven-development-drupal-8.md
+++ /dev/null
@@ -1,19 +0,0 @@
----
-title: Automated testing and Test-Driven Development in Drupal 8
-description: A workshop that I gave about automated testing and test driven development in Drupal 8.
-events:
- - name: Drupal Bristol
- location: Bristol, UK
- date: "2018-06-27"
-
- - name: DrupalCamp London 2020
- location: London, UK
- url: https://drupalcamp.london/training/Automated-Testing-and-Test-Driven-Development-in-Drupal-8
- date: "2020-03-13"
-
- - name: DrupalCamp NYC
- location: New York, USA
- url: https://2020.drupalcamp.nyc/training/automated-testing-and-test-driven-development-drupal-8
- date: "2020-11-14"
- online: true
----
diff --git a/astro/src/content/talk/building-build-configs.mdx b/astro/src/content/talk/building-build-configs.mdx
deleted file mode 100644
index f8ccae3c..00000000
--- a/astro/src/content/talk/building-build-configs.mdx
+++ /dev/null
@@ -1,19 +0,0 @@
----
-title: Building "Build Configs"
-description: In this lightning talk, I discuss the "Build Configs" tool I've built to create configuration files.
-speakerdeck:
- id: e1403f0dfd8245e5a71df9761dc6bc7b
- ratio: "1.78343949044586"
- url: https://speakerdeck.com/opdavies/building-build-configs
-video: ~
-image: ~
-events:
- - name: PHP South West (PHPSW)
- location: Bristol, UK
- date: 2023-11-08
- url: https://www.meetup.com/php-sw/events/296917370
----
-
-[Build Configs](/build-configs) is a tool I've created for creating and managing customised per-project configuration files, such as Docker, Docker Compose, Nix Flakes, and PHPUnit and PHPStan configuration.
-
-In this lightning talk, I'll discuss why I created it, what problem it solves, more about what it does, and how it works.
diff --git a/astro/src/content/talk/building-presenting-slide-decks-rst2pdf.md b/astro/src/content/talk/building-presenting-slide-decks-rst2pdf.md
deleted file mode 100644
index 16680447..00000000
--- a/astro/src/content/talk/building-presenting-slide-decks-rst2pdf.md
+++ /dev/null
@@ -1,22 +0,0 @@
----
-title: Building and presenting slide decks with rst2pdf
-description: A short talk on using reStructuredText and rst2pdf to build presentation slides, built with rst2pdf.
-
-speakerdeck:
- id: 80498c7b5e7448f194091461cb14f1c1
- ratio: "1.77777777777778"
- url: https://speakerdeck.com/opdavies/building-and-presenting-slide-decks-with-rst2pdf
-
-video:
- id: KZ89tGG-p6M
- type: youtube
-
-events:
- - name: PHP South Wales
- location: Cardiff, UK
- url: https://www.meetup.com/PHP-South-Wales/events/275625320
- date: "2021-01-28"
- online: true
----
-
-I've recently used [rst2pdf](https://rst2pdf.org) for building presentation slides. This short talk will show some examples of how I built and presented a slide deck using reStructuredText and rst2pdf.
diff --git a/astro/src/content/talk/building-static-websites-sculpin.md b/astro/src/content/talk/building-static-websites-sculpin.md
deleted file mode 100644
index 553eb5a7..00000000
--- a/astro/src/content/talk/building-static-websites-sculpin.md
+++ /dev/null
@@ -1,49 +0,0 @@
----
-title: Building Static Websites with Sculpin
-description: How to use Sculpin to generate static HTML websites.
-speakerdeck:
- id: 6c9c4be1a1344f1291ff13a391674a66
- ratio: "1.77777777777778"
- url: https://speakerdeck.com/opdavies/building-static-websites-with-sculpin
-code: https://github.com/opdavies/sculpin-demo
-tags: [meetups, phpsw, sculpin]
-tweets: yes
-video:
- type: youtube
- id: xRTiWR9nBSA
-events:
- - name: PHP South West
- location: Bristol, UK
- date: "2015-10-14"
- url: https://phpsw.uk/events/2015-10-lightning-talks
- joindin: https://joind.in/talk/view/15486
-
- - name: Drupal Yorkshire
- date: "2021-08-19"
- location: Leeds, UK
- url: https://www.meetup.com/DrupalYorkshire/events/280100968
- online: true
-
- - name: PHP North West (PHPNW)
- date: "2021-09-07"
- location: Manchester, UK
- url: https://www.phpnw.org.uk
- online: true
-
- - name: GroningenPHP
- date: "2021-12-09"
- location: Groningen, Netherlands
- url: https://www.meetup.com/GroningenPHP/events/281648855
- online: true
----
-
-[Sculpin][0] is a static site generator written in PHP. It converts Markdown
-files, Twig templates and standard HTML into a static HTML site that can be
-easily deployed.
-
-This talk will cover a little of the background to Sculpin and what it is, and
-then will move into some demonstrations of how to build a Sculpin site and what
-it can do!
-
-[0]: http://sculpin.io
-[1]: https://opdavies.github.io/slides-phpsw-sculpin
diff --git a/astro/src/content/talk/communities-contribution.md b/astro/src/content/talk/communities-contribution.md
deleted file mode 100644
index 11705486..00000000
--- a/astro/src/content/talk/communities-contribution.md
+++ /dev/null
@@ -1,21 +0,0 @@
----
-title: Communities and contribution
-description: Why I mentor, why I've organised meetups and conferences, why I give talks, and why I maintain and contribute to open-source software.
-
-speakerdeck:
- id: 63c2fcc2294641688f433d062282a968
- ratio: "1.78343949044586"
- url: https://speakerdeck.com/opdavies/building-and-presenting-slide-decks-with-rst2pdf
-
-events:
- - name: TechConnect London
- location: London, UK
- date: "2023-09-28"
- url: https://www.eventbrite.co.uk/e/techconnect-london-tickets-698416712187
----
-
-I'm a self-taught Developer who's been writing code since 2007, working with and contributing to open-source technologies. I've been a mentor at events like DrupalCon and for bootcamps, including School of Code.
-
-I'm part of different open-source and tech communities, organised meetups and conferences, and have given nearly 100 presentations.
-
-In this talk, I'll speak more about the communities I'm part of, my contributions, how I started, why I do it, and who benefits and how.
diff --git a/astro/src/content/talk/configuring-all-the-things-drupal-8.md b/astro/src/content/talk/configuring-all-the-things-drupal-8.md
deleted file mode 100644
index 6ca54ea9..00000000
--- a/astro/src/content/talk/configuring-all-the-things-drupal-8.md
+++ /dev/null
@@ -1,19 +0,0 @@
----
-title: "Configuring all the Things (in Drupal 8)"
-description: A short notice talk on configuration management in Drupal 8, and things I’ve learned working on my current Drupal 8 project.
-
-speakerdeck:
- id: 6de3fe8947a34727b79eb9d9dcc66bf2
- ratio: "1.37081659973226"
- url: https://speakerdeck.com/opdavies/configuring-all-the-things-in-drupal-8
-
-video: ~
-
-events:
- - name: Drupal Bristol
- location: Bristol, UK
- url: https://www.drupalbristol.org.uk
- date: "2018-07-25"
----
-
-A short notice talk on configuration management in Drupal 8, and things I’ve learned working on my current Drupal 8 project.
diff --git a/astro/src/content/talk/dancing-for-drupal.md b/astro/src/content/talk/dancing-for-drupal.md
deleted file mode 100644
index c2661137..00000000
--- a/astro/src/content/talk/dancing-for-drupal.md
+++ /dev/null
@@ -1,33 +0,0 @@
----
-title: Dancing for Drupal
-description: A talk on Drupal, presented alongside others representing Umbraco, Sitecore and Episerver.
-tags: [meetup, umbristol, drupal]
-tweets: yes
-
-speakerdeck:
- id: ffa9b6dea6dc4a8eb207b9982ed6e1bd
- ratio: "1.33333333333333"
- url: https://speakerdeck.com/opdavies/umbristol-dancing-for-drupal
-
-events:
- - name: umBristol
- location: Bristol, UK
- url: http://umbristol.co.uk
- date: "2015-08-25"
----
-
-As part of their [CMS Dance-Off][1], I was selected to speak about Drupal alongside other speakers representing Umbraco, Sitecore and Episerver.
-
-The points to cover were:
-
-- How does your CMS store configuration data, 'structure' and content?
-- How do you manage source-control, versioning and deployment?
-- How do you manage multiple simultaneous editors and/or developers?
-- How do you manage upgrades?
-- What are the 3 best things about your CMS?
-- What are the 3 worst things about your CMS?
-- What does the future of your CMS look like?
-
-In each point, tried to cover the differences between Drupal core and developing a project using Drupal, as well as between Drupal 7 and Drupal 8, as things like source control and versioning would be approached differently.
-
-[1]: http://www.meetup.com/umBristol/events/223807592
diff --git a/astro/src/content/talk/decoupling-drupal-vuejs.md b/astro/src/content/talk/decoupling-drupal-vuejs.md
deleted file mode 100644
index e5a2da3e..00000000
--- a/astro/src/content/talk/decoupling-drupal-vuejs.md
+++ /dev/null
@@ -1,22 +0,0 @@
----
-title: Decoupling Drupal with Vue.js
-description: Decoupling Drupal with Vue.js.
-code: https://github.com/opdavies/blue-conf-2019
-
-speakerdeck:
- id: 60c8b7abdf194946b7a78a1bb74a0982
- ratio: "1.77777777777778"
- url: https://speakerdeck.com/opdavies/decoupling-drupal-with-vue-dot-js
-
-events:
- - name: Blue Conf 2019
- location: Cardiff, UK
- url: https://blueconf.co.uk
- date: "2019-06-07"
----
-
-Decoupled or headless Drupal has been a trend for a number of years, with modules like RESTful Web Services available for Drupal 7 to expose data, and Drupal 8 becoming more API-first with JSON:API module now included as part of core. This makes it easier for third party systems or alternative front-end applications to consume and work with the data provided by Drupal.
-
-In this talk, we’ll look at how to build progressively and fully decoupled applications - passing data from a Drupal 8 back-end to a Vue.js front-end.
-
-The demo code used in the talk is [available on GitHub](https://github.com/opdavies/blue-conf-2019 "View the demo code for this talk on GitHub.").
diff --git a/astro/src/content/talk/deploying-drupal-fabric.md b/astro/src/content/talk/deploying-drupal-fabric.md
deleted file mode 100644
index 8d2f8efc..00000000
--- a/astro/src/content/talk/deploying-drupal-fabric.md
+++ /dev/null
@@ -1,34 +0,0 @@
----
-title: "Deploying Drupal with Fabric"
-description: How to use Fabric, a Python command line based library, to deploy your Drupal applications.
-meta:
- og:
- title: Deploying Drupal with Fabric
- description: "You've built your Drupal site, now learn how to deploy it with Fabric."
- type: website
-
-speakerdeck:
- id: 40d1eca4bd484afc86295924fff5dd41
- ratio: "1.77777777777778"
- url: "https://speakerdeck.com/opdavies/deploying-drupal-and-anything-else-with-fabric"
- embed: ''
-
-events:
- - name: DrupalCamp Dublin 2017
- location: Dublin, Ireland
- url: http://2017.drupal.ie
- date: "2017-10-20"
- time: "15:00 - 15:40"
-
- - name: Drupal Somerset
- location: Glastonbury, UK
- date: "2017-10-26"
----
-
-You’ve built your website, and now you just need to deploy it. There are various ways that this could be done - from (S)FTP, to SCP and rsync, to running commands like “git pull” and “composer install” directly on the server (not recommended).
-
-My favourite deployment tool of late is [Fabric][1] - a Python based command line tool for running commands locally as well as on remote servers. It’s language and framework agnostic, and unopinionated so you define the steps and workflow that you need - from a basic few-step deployment to a full Capistrano style zero-downtime deployment.
-
-This talk will cover some introduction to Fabric and how to write your own fabfiles, to then covering some examples and demos of different use case deployments for your Drupal project.
-
-[1]: http://www.fabfile.org
diff --git a/astro/src/content/talk/deploying-php-ansible-ansistrano.md b/astro/src/content/talk/deploying-php-ansible-ansistrano.md
deleted file mode 100644
index cae2cbbf..00000000
--- a/astro/src/content/talk/deploying-php-ansible-ansistrano.md
+++ /dev/null
@@ -1,98 +0,0 @@
----
-title: Deploying PHP applications with Ansible, Ansible Vault and Ansistrano
-description: |
- How to use Ansible and Ansistrano to perform robust, secure deployments of
- your PHP applications.
-speakerdeck:
- id: c11fe635ed8f4741b35bf3ebe53e8323
- ratio: "1.77777777777778"
- url: https://speakerdeck.com/opdavies/deploying-php-applications-with-ansible-ansible-vault-and-ansistrano
-video:
- type: youtube
- id: dQL-gOnxXCM
-events:
- - name: Drupal Bristol
- date: "2019-01-23"
- location: Bristol, UK
- url: https://www.drupalbristol.org.uk
-
- - name: PHP South Wales
- date: "2019-07-23"
- location: Cardiff, UK
- url: https://www.phpsouthwales.uk
-
- - name: DrupalCon Europe 2019
- date: "2019-10-30"
- location: Amsterdam, NL
- url: https://events.drupal.org/amsterdam2019
-
- - name: Bristol Cloud Native & DevOps
- date: "2020-01-30"
- location: Bristol, UK
- url: https://www.meetup.com/Bristol-Cloud-Native-DevOps/events/266609627
-
- - name: Drupal Edinburgh
- date: "2020-03-12"
- location: Edinburgh, UK
- url: https://www.meetup.com/Drupal-Edinburgh/events/267905594
- online: true
-
- - name: CMS Philly
- date: "2020-05-01"
- location: Philadelphia, USA
- url: https://cmsphilly.org
- online: true
-
- - name: Drupal Yorkshire
- date: "2020-05-21"
- location: Leeds, UK
- url: https://www.meetup.com/DrupalYorkshire/events/zwzsfpybchbcc
- online: true
-
- - name: PHP London
- date: "2020-06-04"
- location: London, UK
- url: https://www.meetup.com/phplondon/events/270930524
- online: true
-
- - name: PHP North East
- date: "2020-06-16"
- location: Newcastle Upon Tyne, UK
- url: https://www.meetup.com/phpnortheast
- online: true
-
- - name: PHP Sussex
- date: "2020-07-01"
- location: Brighton, UK
- url: https://www.meetup.com/PHP-Sussex/events/271472628
- online: true
-
- - name: Midwest PHP
- date: "2021-04-23"
- url: https://midwestphp.org/talks/1q5XUF2tTdXXLYOoujMkpF/Deploying_PHP_applications_with_Ansible_Ansible_Vault_and_Ansistrano
- online: true
-
- - name: PHP Oxford
- date: "2021-04-28"
- location: Oxford, UK
- url: https://www.meetup.com/PHP-Oxford/events/qmbkfsyccgblc
- online: true
-
- - name: Ansible London
- date: "2021-05-25"
- location: London, UK
- url: https://www.meetup.com/Ansible-London/events/278093392
- online: true
-
- - name: DrupalNYC
- date: "2021-06-15"
- location: New York, USA
- url: https://ti.to/drupalnyc/lunch-learn-2021-06-15
- online: true
----
-
-Great! You’ve built your website, and now you just need to deploy it. There are various ways that this could be done - from (S)FTP, to SCP and rsync, to running commands like `git pull` and `composer install` directly on the server which is not ideal.
-
-As well provisioning and maintaining your server configuration and running commands, you can also use [Ansible](https://www.ansible.com) to deploy your PHP application - leveraging relevant Ansible modules such as Git and Composer, custom Ansible roles, [Ansible Vault](https://docs.ansible.com/ansible/latest/user_guide/vault.html) for managing secrets, and features such as idempotency out of the box to build a simple deployment playbook. We can then extend that and make it more robust by adding [Ansistrano](https://ansistrano.com) - a port of [Capistrano](https://capistranorb.com) - which adds extra features such as storing multiple builds for each project and the ability to roll-back if needed, customising your build steps using built-in hooks, multi-stage environments and more.
-
-I've been using Ansible and Ansistrano to deploy a variety of PHP projects - including Drupal 7 & 8, Symfony, Laravel and Sculpin, as well as basic HTML websites, and found it to be very flexible and easy to install and use, and by the end of this talk we will have a fully working deployment playbook, deploying real code onto a real server.
diff --git a/astro/src/content/talk/deploying-php-fabric.md b/astro/src/content/talk/deploying-php-fabric.md
deleted file mode 100644
index 0e1945ba..00000000
--- a/astro/src/content/talk/deploying-php-fabric.md
+++ /dev/null
@@ -1,46 +0,0 @@
----
-title: Deploying PHP Applications with Fabric
-description: How to use Fabric, a Python command line based library, to deploy your PHP applications.
-speakerdeck:
- id: c147618ce07546ca92f92983c52d6a41
- ratio: "1.77777777777778"
- url: https://speakerdeck.com/opdavies/deploying-php-applications-with-fabric
-tags: [meetup, conference, php, fabric]
-meta:
- og:
- title: Deploying PHP Applcations with Fabric
- description: "You've built your PHP application, now learn how to deploy it with Fabric."
- type: website
- image:
- url: /images/talks/deploying-php-fabric.png
- width: 2560
- height: 1440
- type: image/png
-events:
- - name: Nomad PHP
- date: "2017-04-20"
- time: "19:00 (CET)"
- url: https://nomadphp.com
- online: true
-
- - name: PHP South West
- location: Bristol, UK
- url: https://phpsw.uk
- date: "2017-09-13"
- joindin: https://joind.in/talk/a5ff3
-
- - name: PHP North West 2017
- location: Manchester, UK
- date: "2017-10-01"
- time: "09:00 - 09:45"
- url: http://conference.phpnw.org.uk/phpnw17
- joindin: https://joind.in/talk/4e35d
----
-
-You’ve built your application, and now you just need to deploy it. There are various ways that this could be done – from (S)FTP, to SCP and rsync, to running commands like “git pull” and “composer install” directly on the server (not recommended).
-
-My favourite deployment tool of late is [Fabric][1] – a Python based command line tool for running commands locally as well as on remote servers. It’s language and framework agnostic, and unopinionated so you define the steps and workflow that you need – from a basic few-step deployment to a full Capistrano style zero-downtime deployment.
-
-This talk will cover some introduction to Fabric and how to write your own fabfiles, and then look at some examples of different use case deployments for your PHP project.
-
-[1]: http://www.fabfile.org
diff --git a/astro/src/content/talk/drupal-8-module-development.md b/astro/src/content/talk/drupal-8-module-development.md
deleted file mode 100644
index 54b46bb4..00000000
--- a/astro/src/content/talk/drupal-8-module-development.md
+++ /dev/null
@@ -1,41 +0,0 @@
----
-title: Getting Started with Drupal 8 Module Development
-description: How to build your first module for Drupal 8.
-tags: [conference, php, drupal, drupalcamp, drupal-8]
-tweets: yes
-code: https://github.com/opdavies/dclondon16-d8-module
-speakerdeck:
- id: 0041804e52664d12a8e31cd118264813
- ratio: "1.77777777777778"
- url: https://speakerdeck.com/opdavies/getting-started-with-drupal-8-module-development
-video:
- type: youtube
- id: qO_Wh5WE3VA
-meta:
- og:
- title: Getting Started with Drupal 8 Module Development
- image:
- url: /images/talks/dclondon16.png
- type: "image/png"
- height: 540
- width: 960
-events:
- - name: DrupalCamp London 2016
- location: London, UK
- date: "2016-03-05"
----
-
-New to object-orientated PHP, Symfony or YAML, and want to get started building modules in Drupal 8? This is the session for you!
-
-In this session, we’ll cover:
-
-- Where Drupal 8 modules are located, and how they are structured.
-- How to build a simple module, including our own permissions and routes.
-- How to add your own controller and service classes.
-- What is the service/dependency injection container, and how do we use it?
-- How we can use tools such as PhpStorm and Drupal Console to speed up the process.
-
-What we won’t be covering:
-
-- Automated testing in PHPUnit or Simpletest.
-- Adding third party libraries and external dependencies via Composer.
diff --git a/astro/src/content/talk/drupal-8-php-libraries-drupalorg-api.md b/astro/src/content/talk/drupal-8-php-libraries-drupalorg-api.md
deleted file mode 100644
index 84c02fbb..00000000
--- a/astro/src/content/talk/drupal-8-php-libraries-drupalorg-api.md
+++ /dev/null
@@ -1,56 +0,0 @@
----
-title: Having Fun with Drupal 8, PHP libraries and the Drupal.org API
-description: A crash course in developing PHP packages and Drupal 8 modules, based on the Drupal.org API.
-speakerdeck:
- id: 6e42ae9620bb4e91b3955f8c30d66934
- ratio: "1.77777777777778"
- url: https://speakerdeck.com/opdavies/having-fun-with-drupal-8-php-libraries-and-the-drupal-dot-org-api
-image:
- url: /images/talks/having-fun-drupalorg-api.png
- width: 2000
- height: 1125
- type: image/png
-video:
- type: youtube
- id: JyDjC7gGDpU
-events:
- - name: Drupal Bristol
- location: Bristol, UK
- url: https://www.drupalbristol.org.uk
- date: "2018-04-18"
- joindin: https://joind.in/talk/14851
-
- - name: DrupalCamp London 2019
- location: London, UK
- url: http://drupalcamp.london
- date: "2019-03-03"
- time: "12:05 - 12:50"
----
-
-A overview and demo of some of the open source projects that I’ve been working on lately that are based on information from the Drupal.org API, including a PHP library for the API itself as well as some Drupal 8 modules that use it.
-
-This session will cover various topics including:
-
-- Why would you want to separate your code into reusable packages
-- An overview of how to structure a PHP package (e.g. an API for interacting with Drupal.org)
-- How to add a PHP package as a dependency for a Drupal module using Composer
-- How to create routes and services, and use dependency injection in Drupal 8
-- How to use Drupal to configure the packages
-- How to increase performance and reliability by using Drupal's cache system to store API results
-
-## Links
-
-- [Drupal.org API library][2]
-- [Drupal.org API documentation][3]
-- [Laravel Collections][4]
-- Example module: [Drupal.org project statistics][5]
-- Example module: [Drupalversary][6]
-- Talk: [Using Laravel Collections outside Laravel][7]
-
-[0]: https://www.drupalbristol.org.uk
-[2]: https://github.com/opdavies/drupalorg-api-php
-[3]: https://www.drupal.org/drupalorg/docs/api
-[4]: https://laravel.com/docs/collections
-[5]: https://github.com/opdavies/drupal-module-drupalorg-project-statistics
-[6]: https://github.com/opdavies/drupal-module-drupalversary
-[7]: /talks/using-laravel-collections-outside-laravel/
diff --git a/astro/src/content/talk/drupal-8-rejoining-the-herd.md b/astro/src/content/talk/drupal-8-rejoining-the-herd.md
deleted file mode 100644
index 7a36bf5e..00000000
--- a/astro/src/content/talk/drupal-8-rejoining-the-herd.md
+++ /dev/null
@@ -1,21 +0,0 @@
----
-title: "Drupal 8: Rejoining the Herd"
-description: A talk highlighting some of the recent technical and non-technical changes in Drupal 8.
-tags: [conference, php, drupal, drupal-8]
-speakerdeck:
- id: 440fd6592f474741bc606c96bc32c104
- ratio: "1.37081659973226"
- url: https://speakerdeck.com/opdavies/drupal-rejoining-the-herd
-events:
- - name: PHP South Coast 2016
- location: Portsmouth, UK
- url: http://2016.phpsouthcoast.co.uk
- date: "2016-06-11"
- joindin: https://joind.in/talk/41d0f
----
-
-[Drupal 8][0] was (finally) released on November 19th 2015, after almost 4 years of work and code commits by over 3,200 different contributors. Whilst it’s pretty much the same as the Drupal that we know and, hopefully, love, a lot has changed behind the scenes and under the hood!
-
-In this talk, I'll highlight some of the new features and improvements in Drupal 8, and discuss some of the benefits to Drupal site builders, themers, and module developers. I'll also talk about some of the non-technical changes and the cultural shift from "not invented here" to "proudly found elsewhere", and how we are rejoining the PHP herd.
-
-[0]: https://www.drupal.org/8
diff --git a/astro/src/content/talk/drupal-8.md b/astro/src/content/talk/drupal-8.md
deleted file mode 100644
index ecce3629..00000000
--- a/astro/src/content/talk/drupal-8.md
+++ /dev/null
@@ -1,26 +0,0 @@
----
-title: Drupal 8
-description:
- A lightning talk presented to the PHPSW user group, highlighting some of the
- relevant changes in Drupal 8.
-speakerdeck:
- url: https://speakerdeck.com/opdavies/drupal-8
- id: 46ba4ba577d94a32b7abdade610ceb69
- ratio: "1.29456384323641"
-video:
- type: youtube
- id: 36zCxPrOOzM
-tweets: yes
-events:
- - name: PHP South West
- location: Bristol, UK
- url: https://phpsw.uk
- date: "2015-04-08"
----
-
-This was a ten minute lightning talk, designed to highlight the major changes
-coming in Drupal 8.
-
-I categorised the technical changes into groups for site builders, developers
-and themers, and also highlighted the cultural shift from "not invented here" to
-"proudly found elsewhere" and the benefits that brings.
diff --git a/astro/src/content/talk/drupal-ldap-module.md b/astro/src/content/talk/drupal-ldap-module.md
deleted file mode 100644
index 8d15f3c6..00000000
--- a/astro/src/content/talk/drupal-ldap-module.md
+++ /dev/null
@@ -1,10 +0,0 @@
----
-title: Drupal and the LDAP module
-description: A review and demonstration of some of the recent single sign-on work that I did using Drupal’s LDAP module.
-events:
- - name: South Wales Drupal user group (SWDUG)
- location: Cardiff, UK
- date: "2013-07-10"
----
-
-A review and demonstration of some of the recent single sign-on work that I did using Drupal’s LDAP module.
diff --git a/astro/src/content/talk/drupal-vm-generator.md b/astro/src/content/talk/drupal-vm-generator.md
deleted file mode 100644
index 678b7d61..00000000
--- a/astro/src/content/talk/drupal-vm-generator.md
+++ /dev/null
@@ -1,27 +0,0 @@
----
-title: Drupal VM Generator
-description: Announcing the Drupal VM Generator CLI tool.
-type: Lightning talk
-code: https://github.com/opdavies/drupal-vm-generator
-tags: [drupal-vm, drupal-vm-generator, meetup, symfony]
-speakerdeck:
- id: a27ee1d2bfed4a209dc395fa455acb41
- ratio: "1.37081659973226"
- url: https://speakerdeck.com/opdavies/bristol-dug-drupal-vm-generator
-video:
- type: youtube
- id: U1pbKAAO2Wo
-events:
- - name: NWDUG
- url: http://nwdrupal.org.uk
- location: Manchester, UK
- date: "2016-03-08"
- - name: Drupal Bristol
- location: Bristol, UK
- url: https://www.drupalbristol.org.uk
- date: "2016-04-02"
----
-
-An short talk about the [Drupal VM Generator][1] project.
-
-[1]: https://github.com/opdavies/drupal-vm-generator
diff --git a/astro/src/content/talk/drupal-vm-meet-symfony-console.md b/astro/src/content/talk/drupal-vm-meet-symfony-console.md
deleted file mode 100644
index 1506d74f..00000000
--- a/astro/src/content/talk/drupal-vm-meet-symfony-console.md
+++ /dev/null
@@ -1,24 +0,0 @@
----
-title: Drupal VM, Meet Symfony Console
-description: How to develop command line applications using Symfony Console, using the Drupal VM CLI as an example.
-speakerdeck:
- id: 56c79770f73f4e47a542a30243437c49
- ratio: "1.37081659973226"
- url: https://speakerdeck.com/opdavies/drupal-vm-meet-symfony-console
-image: drupal-vm-meet-symfony-console.png
-events:
- - name: DrupalCamp Bristol 2016
- location: Bristol, UK
- date: "2016-07-23"
----
-
-_TL;DR - Come and learn about Symfony Console, with examples from a real-world
-project._
-
-The [Drupal VM Generator][2] is a CLI application, built on [Symfony Console][0], that generates configuration files for [Drupal VM][1] based on personal settings and user interaction.
-
-After an introduction to Drupal VM itself and the Drupal VM Generator, we’ll jump into the code and see how Symfony Console applications are structured, how to write new commands, and how to integrate additional libraries like Guzzle, Twig and other Symfony components - whilst referencing code from the Drupal VM Generator project.
-
-[0]: http://symfony.com/doc/current/components/console/introduction.html
-[1]: https://www.drupalvm.com
-[2]: https://www.drupalvmgenerator.com
diff --git a/astro/src/content/talk/drupalorg-2015.md b/astro/src/content/talk/drupalorg-2015.md
deleted file mode 100644
index 5a941ed3..00000000
--- a/astro/src/content/talk/drupalorg-2015.md
+++ /dev/null
@@ -1,18 +0,0 @@
----
-title: "Drupal.org in 2015: What's Coming Next"
-description: A retrospective of the Drupal Association’s work in 2014 and a look forward to what we’ll be working on in 2015.
-tags: [conference, drupalcamp, drupalcamp-london, drupal-association]
-speakerdeck:
- id: 0cf8d7b647c94ae289e9db2b46a9e8f2
- ratio: "1.77777777777778"
- url: https://speakerdeck.com/opdavies/drupal-dot-org-in-14
-events:
- - name: DrupalCamp Brighton
- location: Brighton, UK
- date: "2015-01-18"
- - name: DrupalCamp London 2015
- location: London, UK
- date: "2015-02-28"
----
-
-A retrospective of the Drupal Association’s work in 2014 and a look forward to what we’ll be working on in 2015.
diff --git a/astro/src/content/talk/drush-make-drupalbristol.md b/astro/src/content/talk/drush-make-drupalbristol.md
deleted file mode 100644
index 9f1c8e7c..00000000
--- a/astro/src/content/talk/drush-make-drupalbristol.md
+++ /dev/null
@@ -1,15 +0,0 @@
----
-title: drush make drupalbristol
-description: How to Drush Make to build your Drupal websites.
-speakerdeck:
- id: 42605700f102013198de5a5f6f23ab67
- ratio: "1.29456384323641"
- url: https://speakerdeck.com/opdavies/drush-make-drupalbristol
-events:
- - name: Drupal Bristol
- location: Bristol, UK
- url: https://www.drupalbristol.org.uk
- date: "2014-08-19"
----
-
-An introduction to Drush Make and how to use it to build reusable custom installation profiles or entire websites.
diff --git a/astro/src/content/talk/getting-your-data-into-drupal-8.md b/astro/src/content/talk/getting-your-data-into-drupal-8.md
deleted file mode 100644
index ceacd84c..00000000
--- a/astro/src/content/talk/getting-your-data-into-drupal-8.md
+++ /dev/null
@@ -1,38 +0,0 @@
----
-title: Getting (Your Data) Into Drupal 8
-description: An overview of Drupal’s Migrate functionality, and a look at how to write your own migrations.
-speakerdeck:
- id: 63e5dfce996e46699e304d50e896477b
- ratio: "1.77777777777778"
- url: "https://speakerdeck.com/opdavies/getting-your-data-into-drupal-8-drupal_bristol"
-video:
- type: youtube
- id: jtmARTuYhp8
-tags: [drupalcamp, migration, drupal-8]
-meta:
- og:
- title: Getting (Your Data) into Drupal 8
- description: "How I migrated the Drupal Bristol website onto Drupal 8."
- type: website
- image:
- url: /images/talks/getting-your-data-into-drupal-8.png
- width: 2560
- height: 1440
- type: image/png
-events:
- - name: Drupal Bristol
- date: "2017-01-18"
- location: Bristol, UK
- url: https://www.drupalbristol.org.uk
-
- - name: DrupalCamp London 2017
- date: "2017-03-04"
- time: "12:05 - 12:50"
- location: London, UK
----
-
-If you’ve moved a site from Drupal 6 to 7, the chances are that you’ve either used the upgrade path to update your old site in-place, or you built a new site from scratch and used the Migrate module from contrib to migrate your data from the old database.
-
-In Drupal 8, things have changed as there’s no upgrade path from Drupal 7 and the Migrate module has been moved into core, though there are still migration related modules available in contrib.
-
-This talk will look at the core Migrate module and how it implements Drupal 8 features such as YAML and the plugin and configuration systems, and how to write your own migrations to get your data into Drupal 8.
diff --git a/astro/src/content/talk/git-flow.md b/astro/src/content/talk/git-flow.md
deleted file mode 100644
index 83665896..00000000
--- a/astro/src/content/talk/git-flow.md
+++ /dev/null
@@ -1,18 +0,0 @@
----
-title: Never Commit to Master - An Introduction to Git Flow
-description: An introduction to and demonstration of the Git Flow branching model.
-speakerdeck:
- id: 201559e0f103013198dd5a5f6f23ab67
- ratio: "1.29456384323641"
- url: https://speakerdeck.com/opdavies/never-commit-to-master-an-introduction-to-git-flow
-video:
- type: youtube
- id: T-miCpHxfds
-tweets: yes
-events:
- - name: DrupalCamp London 2014
- location: London, UK
- date: "2014-03-01"
----
-
-An introduction to the Git Flow branching model and the git-flow plugin, and how I’ve used them to manage a Drupal development project.
diff --git a/astro/src/content/talk/goodbye-drush-make-hello-composer.md b/astro/src/content/talk/goodbye-drush-make-hello-composer.md
deleted file mode 100644
index 59a9276a..00000000
--- a/astro/src/content/talk/goodbye-drush-make-hello-composer.md
+++ /dev/null
@@ -1,32 +0,0 @@
----
-title: Goodbye Drush Make. Hello Composer!
-description: How to use Composer to manage your Drupal applications.
-tags: ["meetup", "drupal", "composer"]
-speakerdeck:
- id: 1c1e0e129ab34816bd4c4edb5f6642c2
- ratio: "1.37081659973226"
- url: https://speakerdeck.com/opdavies/goodbye-drush-make-hello-composer
-video:
- type: youtube
- id: ZL2FtRTX9Y8
-events:
- - name: Drupal Bristol
- location: Bristol, UK
- url: https://www.drupalbristol.org.uk
- date: "2016-11-17"
-
- - name: PHP UK Conference 2018
- location: London, UK
- date: "2018-02-16"
- time: "14:40 - 15:40"
- url: https://www.phpconference.co.uk
- joindin: https://joind.in/talk/650ab
----
-
-One of the main outcomes of Drupal 8 was “getting off the island” with third-party code included in core and adopting modern best practices from the wider PHP ecosystem - including [Composer][1], PHP’s dependency manager.
-
-Included to manage core’s dependencies, it has also gained traction in the contrib space with the creation of the Drupal Composer project, and the Drupal Packagist and now native endpoints on Drupal.org exposing contrib project metadata.
-
-In this session, I'll show how to fully manage a Drupal 7 or Drupal 8 website including contributed modules and themes and external libraries with Composer.
-
-[1]: https://getcomposer.org
diff --git a/astro/src/content/talk/introduction-to-mob-programming.md b/astro/src/content/talk/introduction-to-mob-programming.md
deleted file mode 100644
index 8354cc3e..00000000
--- a/astro/src/content/talk/introduction-to-mob-programming.md
+++ /dev/null
@@ -1,18 +0,0 @@
----
-title: An introduction to mob programming
-description: |
- What is mob programming, how does it work, and why should we do it?
-speakerdeck:
- id: f37b16f915d64bc0b4a20f9f965e5353
- ratio: '1.77725118483412'
- url: https://speakerdeck.com/opdavies/an-introduction-to-mob-programming
-events:
- - name: PHP South Wales
- location: Cardiff, Wales
- date: '2022-09-28'
- url: https://www.meetup.com/php-south-wales/events/288359737
----
-
-Pair and mob programming are collaborative approaches to software development where tasks are completed in small groups instead of by individuals.
-
-In this talk, I’ll explain more about mob programming, its benefits and how it works, and then we’ll put it into practice with an interactive mob session where we add a feature to a codebase.
diff --git a/astro/src/content/talk/it-all-started-with-a-patch.md b/astro/src/content/talk/it-all-started-with-a-patch.md
deleted file mode 100644
index 218d1878..00000000
--- a/astro/src/content/talk/it-all-started-with-a-patch.md
+++ /dev/null
@@ -1,18 +0,0 @@
----
-title: It All Started With A Patch
-description: A lightning talk on how and why to get involved with open source.
-speakerdeck:
- id: 5862bdecb7a24cfaa5fc844696fafa0c
- ratio: "1.37081659973226"
- url: https://speakerdeck.com/opdavies/it-all-started-with-a-patch-phpsw
-video:
- type: youtube
- id: 5FYMRR61sdo
-events:
- - name: PHP South West
- location: Bristol, UK
- url: https://phpsw.uk
- date: "2017-02-08"
----
-
-A crash course of why and how to get involved with open source.
diff --git a/astro/src/content/talk/modern-drupal-development-with-composer.md b/astro/src/content/talk/modern-drupal-development-with-composer.md
deleted file mode 100644
index ae271e5b..00000000
--- a/astro/src/content/talk/modern-drupal-development-with-composer.md
+++ /dev/null
@@ -1,24 +0,0 @@
----
-title: Modern Drupal Development with Composer
-description: A lightning talk on how to use Composer to manage your Drupal projects.
-type: Lightning talk
-tags: ["meetups", "phpsw", "drupal", "composer"]
-speakerdeck:
- id: 7a1358502526425a9cfd288f85fb32f3
- ratio: "1.37081659973226"
- url: https://speakerdeck.com/opdavies/modern-drupal-development-with-composer
-video:
- type: youtube
- id: Yi_FPI3xHwc
-events:
- - name: PHP South West
- location: Bristol, UK
- url: https://phpsw.uk
- date: "2016-11-09"
----
-
-Building a Drupal application? You no longer need to download archives to add new modules or update core, or deal with Drupal specific tools to manage your codebase.
-
-With Drupal "getting off the island" there has been an increase in the adoption of common PHP tools within the Drupal ecosystem.
-
-In this lightning talk, I’ll show how to build a Drupal application using Composer for dependency management.
diff --git a/astro/src/content/talk/out-of-the-box-initiative-update.md b/astro/src/content/talk/out-of-the-box-initiative-update.md
deleted file mode 100644
index 80412014..00000000
--- a/astro/src/content/talk/out-of-the-box-initiative-update.md
+++ /dev/null
@@ -1,26 +0,0 @@
----
-title: Out of the Box Initiative Update
-description: An update on Drupal’s "out of the box" initiative, and core’s new Umami installation profile.
-speakerdeck:
- id: 3f66c48653f44ed4867fc3cc05c1db06
- ratio: "1.77777777777778"
- url: https://speakerdeck.com/opdavies/out-of-the-box-initiative-update
-video: ~
-events:
- - name: Drupal Bristol
- location: Bristol, UK
- url: https://www.drupalbristol.org.uk
- date: "2019-03-27"
----
-
-From the [DrupalCamp London website](https://drupalcamp.london/session/out-box-initiative-update):
-
-> Since the last DrupalCamp London, the Umami Demo install profile is now one of the options shown to anyone installing Drupal. But this doesn't mean we've finished.
-
-> There are many existing Drupal features that we want to showcase, and new features stabilising with each minor release. Join the Out of the Box initiative leads Keith Jay (kjay) and Gareth Goodwin (smaz) for this session, where we'll talk about:
-
-> - Where we are, and how we got here
-
-- Our targets for inclusion in Drupal 8.7.0
-- How you can help!
-- Plans for the more distant future
diff --git a/astro/src/content/talk/so-what-is-this-drupal-thing.md b/astro/src/content/talk/so-what-is-this-drupal-thing.md
deleted file mode 100644
index 29a7b0d5..00000000
--- a/astro/src/content/talk/so-what-is-this-drupal-thing.md
+++ /dev/null
@@ -1,14 +0,0 @@
----
-title: So, what is this Drupal thing?
-description: My first talk, where I talk about Drupal, what it is and what it can do.
-video:
- type: vimeo
- id: '49827006'
-events:
- - name: unified.diff
- location: Cardiff, UK
- url: http://unifieddiff.co.uk
- date: "2012-09-05"
----
-
-My very first talk, where I talk about Drupal, what it is and what it can do.
diff --git a/astro/src/content/talk/taking-flight-with-tailwind-css.md b/astro/src/content/talk/taking-flight-with-tailwind-css.md
deleted file mode 100644
index 653656dd..00000000
--- a/astro/src/content/talk/taking-flight-with-tailwind-css.md
+++ /dev/null
@@ -1,118 +0,0 @@
----
-title: Taking Flight with Tailwind CSS
-description:
- An introduction to the utility-first approach to writing CSS with a focus on the Tailwind CSS framework.
-speakerdeck:
- id: 10ca51f23560443d83b898a92929b4b3
- ratio: "1.77777777777778"
- url: https://speakerdeck.com/opdavies/taking-flight-with-tailwind-css
-video:
- id: C20QZbGlmZ8
- type: youtube
-tags: [css, tailwind, meetup]
-events:
- - name: Drupal Bristol
- location: Bristol, UK
- date: "2018-01-17"
- url: https://www.drupalbristol.org.uk
-
- - name: PHP South Wales
- location: Cardiff, UK
- date: "2018-07-31"
- url: https://www.phpsouthwales.uk
-
- - name: Cheltenham WordPress Meetup
- location: Cheltenham, UK
- date: "2019-04-17"
- url: https://www.meetup.com/Cheltenham-WordPress-Meetup
-
- - name: WordCamp Bristol 2019
- location: Bristol, UK
- date: "2019-05-18"
- url: https://2019.bristol.wordcamp.org
-
- - name: Blue Conf 2019
- location: Cardiff, UK
- date: "2019-06-07"
- url: https://blueconf.co.uk
-
- - name: CMS Philly
- location: Philadelphia, USA
- date: "2020-05-01"
- url: https://cmsphilly.org
- online: true
-
- - name: PHP Hampshire
- location: Portsmouth, UK
- date: "2020-07-08"
- url: https://www.meetup.com/meetup-group-yzpbvTYv/events/271430269
- online: true
-
- - name: Drupal Yorkshire
- location: Leeds, UK
- date: "2020-08-20"
- url: https://www.meetup.com/DrupalYorkshire/events/zwzsfpybclbbc
- online: true
-
- - name: DigitalCamp Atlanta 2020
- location: Atlanta, GA
- date: "2020-09-11"
- url: https://www.drupalcampatlanta.com/2020/sessions/taking-flight-tailwind-css
- online: true
-
- - name: Bristol JS
- location: Bristol, UK
- date: "2020-09-30"
- url: https://techtalks.io/events/f8e26038-2561-484e-8a74-7a1e3a0369b8
- online: true
-
- - name: "Drupal Virtual Cafe #3"
- location: Kyiv, Ukraine
- date: "2020-10-15"
- url: https://groups.drupal.org/ukraine
- online: true
-
- - name: PHP Cambridge
- location: Cambridge, UK
- date: "2021-01-19"
- url: https://www.meetup.com/phpcambridge
- online: true
-
- - name: Nashville PHP
- location: Nashville, TN, USA
- date: "2021-02-09"
- url: https://www.meetup.com/nashvillephp/events/kzkdwryccdbmb
- online: true
-
- - name: Bristol Software Development Meetup
- location: Bristol, UK
- date: "2023-02-16"
- url: https://www.meetup.com/south-wales-tech/events/291092930
-
- - name: Norfolk Developers Conference
- location: Norwich, UK
- date: "2023-02-23"
- url: https://nordevcon.com
-meta:
- og:
- title: Taking Flight with Tailwind CSS
- description: An introduction to utility CSS and Tailwind.
- type: website
- image:
- url: "/images/talks/taking-flight-tailwind.jpg"
- width: 2560
- height: 1440
- type: "image/png"
----
-
-An introduction to utility class and component-based styling, and how to soar with [Tailwind CSS][1].
-
-Things we'll cover:
-
-- Advantages and disadvantages to utility-based styling and Tailwind CSS.
-- How to add Tailwind CSS to your project and configure and customise it.
-- How to avoid duplication by moving repeating classes into re-usable components for better maintainability.
-- How to extend Tailwind CSS and add extra classes with community-written plugins.
-- How to write and test your own custom project-specific plugins.
-
-[1]: https://tailwindcss.com
diff --git a/astro/src/content/talk/tdd-test-driven-drupal.md b/astro/src/content/talk/tdd-test-driven-drupal.md
deleted file mode 100644
index 2696a638..00000000
--- a/astro/src/content/talk/tdd-test-driven-drupal.md
+++ /dev/null
@@ -1,83 +0,0 @@
----
-title: TDD - Test-Driven Drupal
-description: How to write automated tests for Drupal, and how to create a new Drupal module using test driven development.
-speakerdeck:
- id: 088cb18033064f5cb18d1079795294a1
- ratio: "1.77777777777778"
- url: "https://speakerdeck.com/opdavies/tdd-test-driven-drupal"
-video:
- type: youtube
- id: 81J0dPvqG-g
-image:
- url: /images/talks/test-driven-drupal-development.png
- width: 2560
- height: 1440
- type: image/png
-use: [talks]
-events:
- - name: DrupalCamp London 2017
- location: London, UK
- date: "2017-03-04"
- time: "16:15 - 17:00"
-
- - name: DrupalCamp Dublin 2017
- location: Dublin, Ireland
- date: "2017-10-21"
- time: "12:00 - 12:40"
- url: http://2017.drupal.ie
-
- - name: Drupal Bristol
- date: "2017-11-22"
- location: Bristol, UK
- url: https://www.drupalbristol.org.uk
-
- - name: Drupal Somerset
- date: "2018-06-14"
- location: Glastonbury, UK
-
- - name: Drupal Developer Days 2018
- date: "2018-07-05"
- time: "12:15 - 13:00"
- location: Lisbon, Portugal
- url: http://lisbon2018.drupaldays.org
-
- - name: DrupalCamp London 2019
- date: "2019-03-02"
- time: "14:00 - 14:45"
- location: London, UK
- url: http://drupalcamp.london
-
- - name: NWDUG
- date: "2020-05-12"
- location: Manchester, UK
- url: http://nwdrupal.org.uk
- online: true
-
- - name: Bay Area Drupal Camp (BADCamp)
- date: "2020-10-14"
- url: https://2020.badcamp.org/session/tdd-test-driven-drupal
- online: true
-
- - name: DrupalCon Europe 2020
- date: "2020-12-08"
- url: https://events.drupal.org/europe2020/sessions/tdd-test-driven-drupal
- online: true
-
- - name: DrupalCon Lille 2023
- location: Lille, France
- date: "2023-10-17"
- time: "15:00 - 15:45"
- url: https://events.drupal.org/lille2023/session/tdd-test-driven-drupal-introduction-automated-testing-and-test-driven-development
----
-
-Testing is important.
-
-Why? It allows developers to add new features and edit and refactor existing code without the worry of adding regressions, reduces the reliance on manual testing to discover bugs, and by taking a test driven approach, your implementation code is leaner as you only write what is needed for your tests to pass.
-
-Drupal 7 includes the SimpleTest module for unit and functional testing, whilst Drupal 8 onwards uses PHPUnit - the defacto PHP testing framework, used by other PHP projects including Symfony and Laravel - making it easier for people to test their code. And with testing being one of the Drupal core gates with tests needing to be included with every new feature or bug fix, and core’s 100% pass rate policy, testing has become an essential skill when contributing to core, or when working on your own projects.
-
-In this talk, we’ll cover the methodology and terminology involved with automated testing, and then take a test driven approach to creating a new Drupal module.
-
-P.S. If you want to learn more about automated testing and test-driven development in Drupal, [register for my free 7-day email course][course].
-
-[course]: /atdc
diff --git a/astro/src/content/talk/test-drive-twig-with-sculpin.md b/astro/src/content/talk/test-drive-twig-with-sculpin.md
deleted file mode 100644
index 6c3fb71e..00000000
--- a/astro/src/content/talk/test-drive-twig-with-sculpin.md
+++ /dev/null
@@ -1,24 +0,0 @@
----
-title: Test Drive Twig with Sculpin
-description: With Drupal 8 just around the corner, see how you can develop your Twig skills with Sculpin - a static site generator based on Symfony components and Twig.
-speakerdeck:
- id: 54589d2e50a3476a9a75aed809e9edf1
- ratio: "1.77777777777778"
- url: https://speakerdeck.com/opdavies/test-drive-twig-with-sculpin
-code: https://github.com/opdavies/sculpin-demo
-tweets: yes
-events:
- - name: DrupalCamp North 2015
- location: Sunderland, UK
- url: http://drupalcampnorth.org
- date: "2015-07-25"
----
-
-[Sculpin][1] is a static site generator written in PHP, and based on [Symfony components][2]. It uses [YAML][3] and [Twig][4], which makes it very appealing to Drupal people wanting to learn these in preparation for Drupal 8.
-
-This session covered how to install Sculpin itself, as well as how to use it to build a static site from Markdown, HTML and Twig templates. We also covered Sculpin concepts such as content types, themes and partials, and Twig layouts, blocks and inheritance, as well as some tips and tricks that I've found whilst developing with Sculpin.
-
-[1]: https://sculpin.io
-[2]: http://symfony.com/doc/current/components/index.html
-[3]: http://yaml.org
-[4]: http://twig.sensiolabs.org
diff --git a/astro/src/content/talk/things-you-should-know-about-php.md b/astro/src/content/talk/things-you-should-know-about-php.md
deleted file mode 100644
index 4ac7ccea..00000000
--- a/astro/src/content/talk/things-you-should-know-about-php.md
+++ /dev/null
@@ -1,32 +0,0 @@
----
-title: Things you should know about PHP
-description: An introduction to PHP, presented to the Swansea Software Development Community (SSDC) meetup and PHPSW.
-speakerdeck:
- id: fe360f1030f34bdb9eb14cdab907bb3c
- ratio: "1.78343949044586"
- url: https://speakerdeck.com/opdavies/things-you-should-know-about-php-a58cd83b-e10c-40df-9ab4-3ed5d55827e7
-video:
- id: NH1mVSwCzWs
- type: youtube
-meta:
- og:
- image:
- url: /images/talks/things-you-should-know-about-php.png
-events:
- - name: Swansea Software Development Meetup (SSDC)
- location: Swansea, UK
- url: https://www.meetup.com/Swansea-Software-Development-Meetup
- date: "2019-01-28"
-
- - name: PHP South West
- location: Bristol, UK
- url: https://www.meetup.com/php-sw/events/284341510
- date: "2022-03-09"
-
- - name: PHP Stoke
- location: Stoke-on-Trent, UK
- url: https://www.eventbrite.com/e/php-stoke-tickets-429043128547
- date: "2023-01-12"
----
-
-An introduction to PHP, presented to the Swansea Software Development Community (SSDC) meetup and PHP South West.
diff --git a/astro/src/content/talk/upgrading-your-site-drupal-9.md b/astro/src/content/talk/upgrading-your-site-drupal-9.md
deleted file mode 100644
index 90d6d154..00000000
--- a/astro/src/content/talk/upgrading-your-site-drupal-9.md
+++ /dev/null
@@ -1,42 +0,0 @@
----
-title: Upgrading your site to Drupal 9
-description:
- How to update your site to Drupal 9, and why it's much different to any
- major Drupal version upgrade before!
-speakerdeck:
- id: 19f439b7a9a4450baa79bb73ec3dd117
- ratio: "1.77777777777778"
- url: https://speakerdeck.com/opdavies/deploying-php-applications-with-ansible-ansible-vault-and-ansistrano
-video:
- type: youtube
- id: AcYMXiom0o8
-events:
- - name: DrupalNYC
- location: New York, USA
- url: https://ti.to/drupalnyc/meetup-2020-09-02
- date: "2020-09-02"
- online: true
-
- - name: Leeds PHP
- location: Leeds, UK
- url: https://www.meetup.com/leedsphp/events/272504993
- date: "2020-09-23"
- online: true
-
- - name: Midwest PHP
- url: https://midwestphp.org/talks/7C0m4I87vq72cDoXvsHFRp/Upgrading_your_site_to_Drupal_9
- date: "2021-04-22"
- online: true
----
-
-For most Drupal Developers and users, the idea of moving a project from one
-major version of Drupal to another can be daunting, with modules and themes
-having to being changed significantly or rebuilt completely, and data being
-migrated from the old site to the new one.
-
-This was no more so than the move from Drupal 7 to 8, but luckily this has
-changed for Drupal 9 and an upgrade can be done with minimal changes and not a
-data migration in sight!
-
-In this talk, we'll look at some of the changes to Drupal's tools and processes
-that have made this possible, and how to move your Drupal site to Drupal 9.
diff --git a/astro/src/content/talk/using-illuminate-collections-outside-laravel.md b/astro/src/content/talk/using-illuminate-collections-outside-laravel.md
deleted file mode 100644
index c77726cd..00000000
--- a/astro/src/content/talk/using-illuminate-collections-outside-laravel.md
+++ /dev/null
@@ -1,27 +0,0 @@
----
-title: Using Illuminate Collections... Outside Laravel
-description: How to include and use Laravel’s Illuminate Collections in your non-Laravel PHP projects.
-speakerdeck:
- id: 76f1718a75a74940b0b028aac8b9f78b
- ratio: "1.77777777777778"
- url: https://speakerdeck.com/opdavies/using-laravel-collections-dot-dot-dot-outside-laravel-php-south-wales-august-2018
-video:
- type: youtube
- id: 1l0kO-iaN_o
-tags: [nomad-php, lightning-talk, laravel, collections]
-type: Lightning talk
-events:
- - name: Nomad PHP
- url: https://nomadphp.com
- online: true
- date: "2017-12-21"
- time: 19:00 CET
- - name: PHP South Wales
- location: Cardiff, UK
- url: https://www.phpsouthwales.uk
- date: "2018-08-28"
----
-
-Laravel's Illuminate Collections are a powerful object-orientated way of interacting with PHP arrays, but did you know that they can be used outside of Laravel, in any PHP project?
-
-This short talk shows how we can use Composer to include Illuminate Collections within a non-Laravel project and put them to use within your own code.
diff --git a/astro/src/content/talk/working-with-workspace.md b/astro/src/content/talk/working-with-workspace.md
deleted file mode 100644
index b88a0bda..00000000
--- a/astro/src/content/talk/working-with-workspace.md
+++ /dev/null
@@ -1,30 +0,0 @@
----
-title: Working with Workspace
-description: Workspace is an open-source local development tool from Inviqa. This talk covers what it is, what it does, and how to use it in your PHP project.
-speakerdeck:
- id: e87103bd5f8b4f16bbed73a9d4d2a592
- ratio: "1.77777777777778"
- url: https://speakerdeck.com/opdavies/taking-flight-with-tailwind-css
-video:
- type: youtube
- id: oO0-E_FBS-U
-events:
- - name: NWDUG
- location: Manchester, UK
- url: https://www.meetup.com/nwdrupal/events/272098270
- date: "2020-08-11"
- online: true
- - name: PHP South West
- location: Bristol, UK
- url: https://www.meetup.com/php-sw/events/272787346
- date: "2020-09-09"
- online: true
- - name: PHP North West
- url: https://www.phpnw.org.uk
- date: "2021-02-02"
- online: true
----
-
-[Workspace](https://github.com/my127/workspace) is an open source tool developed by [Inviqa](https://inviqa.com), as a way to create custom commands for your project environments, and an alternative to a bash script or a Makefile.
-
-In this short talk and demo, we'll look at what Workspace does, some of its features including attributes, generating configuration files and managing secrets, and and how it can be added to and used on a project.
diff --git a/astro/src/content/talk/working-without-workspace.md b/astro/src/content/talk/working-without-workspace.md
deleted file mode 100644
index 7d1c689f..00000000
--- a/astro/src/content/talk/working-without-workspace.md
+++ /dev/null
@@ -1,15 +0,0 @@
----
-title: Working without Workspace
-description: |
- A look at how I configure my development environments and the tools I use with PHP, such as Nix, Home Manager, Docker, Neovim and tmux.
-speakerdeck:
- id: dd406a45f04047fda765346b75efa3c3
- ratio: "1.77798682972719"
- url: https://speakerdeck.com/opdavies/working-without-workspace
-video: ~
-events:
- - name: PHP London
- location: London, UK
- url: https://www.meetup.com/phplondon/events/292657869
- date: "2023-04-06"
----
diff --git a/astro/src/content/testimonial/adam-cuddihy.json b/astro/src/content/testimonial/adam-cuddihy.json
deleted file mode 100644
index e26038e2..00000000
--- a/astro/src/content/testimonial/adam-cuddihy.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
- "name": "Adam Cuddihy",
- "tagline": "Web Development Manager",
- "text": "
A fantastic and highly knowledgeable Drupal Developer. Oliver saved a struggling Drupal project with his wealth of Drupal experience.
I have had the pleasure of working with Oliver on several projects at Microserve. He is a natural innovator and a great mentor who inspires others to explore new technologies and approaches. He is a highly knowledgeable professional with a passion for all things Drupal and the tenacity required to get the job done well.
Hi Oliver, we met briefly at the Tech Connect event in London last month. Been reading through a few of your latest posts and have found the messages valuable, especially as we spent the week learning about unit, integration and e2e testing. I have signed up to your mailing list to keep the good advice flowing!
Oliver was great to work with. He has expert knowledge with Drupal and delivered exactly what we were looking for on time. He's understanding, friendly and easy to get along with. I would enjoy working with him again in the future.
\n",
- "image": null,
- "url": null
-}
diff --git a/astro/src/content/testimonial/brian-healy.json b/astro/src/content/testimonial/brian-healy.json
deleted file mode 100644
index 2febeb43..00000000
--- a/astro/src/content/testimonial/brian-healy.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
- "name": "Brian Healy",
- "tagline": "Director of Business Development at Tincan",
- "text": "
Oliver was fantastic to work with - pro-active and highly responsive, he worked well remotely and as part of a project team. His understanding of the project requirement(s) and ability to translate it into working code was essential and he delivered.
Oliver is a skilled and enthusiastic developer, always putting the clients interests first. His approach to work is diligent and confident and this makes working with him a pleasure!
Oliver is seasoned Drupal and all round highly skilled and experienced web developer. I have worked with Oliver on an important project where he was reliable, prompt and ensured strict client deadline delivery and confidentiality at all times.
Oliver is a pleasure to work with, and I would engage him again without hesitation. He communicates regularly, ensures that he meets requirements, and suggests improvements to the potential solutions to the brief.
Oliver has been an outstanding contributor to the Drupal Association team. He is a talented developer who writes great code and applies his curiosity and love of learning to every project. He is also a fantastic team member, who gives to the team as much as he gets.
\n
Oliver is the embodiment of everything good about the Drupal community.
\n",
- "image": "holly-ross.png"
-}
diff --git a/astro/src/content/testimonial/huw-davies.json b/astro/src/content/testimonial/huw-davies.json
deleted file mode 100644
index 42ce6b61..00000000
--- a/astro/src/content/testimonial/huw-davies.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
- "name": "Huw Davies",
- "tagline": "Web Dev Manager / DevOps / Team Manager at Admiral Group Plc",
- "url": "https://admiral.com",
- "text": "
I had the pleasure of working with Oliver whilst building the first version of our drupal based intranet. His knowledge of Drupal and the wider infrastructure required to run a site was really invaluable.
\n
At the time, we were very new to Drupal, so it gave us a great platform to learn from and expand our own knowledge.
\n
He's the only external contractor that we've kept in touch with over the years, which goes to show how much we valued his input.
We used Oliver on a number of occasions throughout 2012 and I have to say we've been delighted with his work. His skills working with Drupal are excellent particularly with custom module development and we wouldn’t hesitate to recommend him others.
I've worked with Oliver for a number of years on B2C and B2B web projects and he has always demonstrated himself to be an expert in his field.
As an insurance provider, some of our products and services don't naturally fit within a traditional ecommerce journey - but Oliver has always been able to come up with innovative ways to leverage core Drupal functionality and develop custom modules to meet our needs.
Friendly, flexible and diligent – I wouldn't hesitate to recommend Oliver to anyone looking for a Drupal developer to progress their next project.
",
- "image": "joe-howell.jpg",
- "url": "https://bastioninsurance.co.uk"
-}
diff --git a/astro/src/content/testimonial/jon-hallett.json b/astro/src/content/testimonial/jon-hallett.json
deleted file mode 100644
index d1f237d8..00000000
--- a/astro/src/content/testimonial/jon-hallett.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
- "name": "Jon Hallett",
- "tagline": "Senior Systems Administrator at the University of Bristol",
- "url": "https://bristol.ac.uk",
- "text": "
We use Oliver for maintaining a couple of Drupal sites for which we no longer have the skills ourselves. We became aware of Oliver through his work in the Drupal community, and about a year ago we approached him to help us with the deep dive aspects of maintaining and developing Drupal sites. He's been really helpful and very responsive. Much appreciated!
Oliver is a skilled Drupal developer with a passion for the Drupal community. As his direct supervisor, I was able to watch Oliver grow with the Drupal Association and contribute an amazing amount of effort and integrity to all of his work.
\n
Everything we have thrown at Oliver, he has approached with an open and flexible mind that has allowed him to work on a wide range of projects and features for Drupal products.
Oliver is a flexible and hardworking developer, with a terrific knowledge of Drupal. He promotes accessibility best practice within the Drupal community, and is always happy to share his knowledge with other people.
I am a big fan of your git approaches. I especially remember pairing with you and watching how many commands you run to solve many problems and how fast you were. It's a skill I believe not many have, particularly those who are used to working with a GUI like me, and personally I think it is quite valuable.
Oliver is a great guy and really easy to work with. He really goes the extra mile to make sure the project is done properly. I would recommend him and will not hesitate to use him again in future.
For over a decade we have worked with Oliver on a number of different projects. Initially our collaboration consisted of web maintenance and troubleshooting but we soon tapped Oliver to design, build and maintain a custom awards site which includes both submission and judging functionality. Oliver has deep and wide-ranging skills and I would certainly recommend his services!
Ollie handled the tech support issues efficiently and effectively, leaving time at the end for further troubleshooting and follow up. Much appreciated!
Working with Oliver on the Seren website has been easy and beneficial.
As well as providing general maintenance support, he built a new Drupal module which integrated with our partners Glassboxx so that we could sell ebooks directly from our website. Oliver worked closely with the team at Glassboxx to create the integration which needed to communicate with the Glassboxx app so that users could download their purchases. He was able to resolve issues which came up along the way in order to create a functioning module which we now use on our site.
Oliver has extensive knowledge of Drupal and his familiarity with the Seren site meant he was able to fix problems quickly and efficiently as they arose.
He is reliable and has always been willing to discuss new ideas for how the site could function.
We would recommend working with him for his invaluable knowledge and ability to find solutions to problems at short notice. It has been a pleasure to work with him over the years.
I have been working to build and develop my website with Oliver over the last year and I couldn't recommend higher. His ideas, knowledge and completion are to a very high standard and I look forward to continuing my build with him.
Oliver really knows his stuff. Whether you are just starting out or looking to take your knowledge to the next level, his patient and clear way of explaining will help get you there.
I've wanted to explore testing for a while, but as a PHP developer with 10 years of Drupal experience who'd written next to no tests, I really needed guidance. Oliver's expertise in testing and TDD motivated me to seek his help.
Before our call, I'd started writing tests for my modules but needed direction, understanding the code to a degree but needing help with approach. Oliver clarified both unit and integration testing, providing solutions for my challenges, and shared his code for inspiration and help. He also gave me ideas on how to utilise contrib code to help me further.
Consulting with an expert, I gained the clarity and confidence I needed in tackling testing with structured, maintainable practices. Oliver's adaptability and tailored services make him highly recommendable.
Thanks, Oliver - I feel empowered and know exactly what approach to take now!
I had the opportunity and good fortune to work with Oliver solving two problems that I was having on a Drupal Commerce site. I have done several Drupal sites using UberCart, but since it is deprecated, I chose to use Commerce. I had searched, posted to forums, and other normal means to find answers to my problems, to no response and to no avail.
I got a referral to Oliver and scheduled an appointment to discuss the problems on a Zoom call. After showing him via screen share where I was stumped, he offered different approaches to what I was doing, which I was fine with as long as it worked.
Once we solved the first problem, I was really elated and then focused on the second one, which was an easier fix. So in a short period of time, both problems were fixed and tested.
I found Oliver was affable and easy to work with. He has a strong work ethic and a desire to solve problems for his customers and can recommend working with him. I think one of his strengths is to find alternative solutions to problems.
- {false && (
- Register now for my Drupal automated testing workshop →"} />
- )}
-
- {false && (
- Drupal upgrade roadmap and upgrade to Drupal 10."} />
- )}
-
- {true && (
- team coaching starting in January 2024."} />
- )}
-
-
-
-
- {showDrupalAssociationMessage && (
-
-
- Work with me and support the Drupal project.
- 5% from any Drupal-related product or service is donated to the Drupal Association.
-
-
- )}
-
-
{title}
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/astro/src/layouts/PageLayout.astro b/astro/src/layouts/PageLayout.astro
deleted file mode 100644
index 48efd8a6..00000000
--- a/astro/src/layouts/PageLayout.astro
+++ /dev/null
@@ -1,12 +0,0 @@
----
-import BaseLayout from "./Layout.astro";
-import Markdown from "~/components/Markdown.astro";
-
-const { isFront, title } = Astro.props.frontmatter || Astro.props;
----
-
-
-
-
-
-
diff --git a/astro/src/layouts/PodcastEpisodeLayout.astro b/astro/src/layouts/PodcastEpisodeLayout.astro
deleted file mode 100644
index 85479af3..00000000
--- a/astro/src/layouts/PodcastEpisodeLayout.astro
+++ /dev/null
@@ -1,24 +0,0 @@
----
-import AboutMe from "../components/AboutMe.astro";
-import BaseLayout from "./PageLayout.astro";
-import DailyEmailForm from "../components/DailyEmailForm.astro";
-import Markdown from "../components/Markdown.astro";
-
-const { episodeUrl, title } = Astro.props.frontmatter || Astro.props;
----
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/astro/src/pages/404.mdx b/astro/src/pages/404.mdx
deleted file mode 100644
index cb8ac547..00000000
--- a/astro/src/pages/404.mdx
+++ /dev/null
@@ -1,33 +0,0 @@
----
-title: Page not found
----
-
-import AboutMe from "~/components/AboutMe.astro";
-import DailyEmailForm from "~/components/DailyEmailForm.astro";
-import Layout from "~/layouts/PageLayout.astro";
-
-
- Perhaps you were looking for one of these pages:
-
- - [Products and services](/pricing)
- - [Public speaking and workshops](/talks)
- - [My daily email list](/daily)
- - [The Beyond Blocks podcast](/podcast)
-
- If you were looking for something else, you can [search for it](/search).
-
-
-
diff --git a/astro/src/pages/blog/index.astro b/astro/src/pages/blog/index.astro
deleted file mode 100644
index 591951b9..00000000
--- a/astro/src/pages/blog/index.astro
+++ /dev/null
@@ -1,32 +0,0 @@
----
-import ListingPage from "~/components/ListingPage.astro";
-import PageLayout from "~/layouts/PageLayout.astro";
-import { getCollection } from 'astro:content';
-
-const posts = await getCollection('blog');
-
-// TODO: show all posts when running locally.
-const filteredPosts = posts
- .filter((post) => !post.data.draft)
- .filter((post) => post.data.date);
-
-const sortedPosts = filteredPosts
- .map((post) => {
- const slug = `/blog/${post.slug}`;
-
- return { item: post, slug };
- })
- .sort(
- (a, b) =>
- new Date(b.item.data.date).valueOf() -
- new Date(a.item.data.date).valueOf()
- );
----
-
-
-
- This is where I used to publish my blog posts, technical posts
- and tutorials. These days, I focus instead on my
- daily email list.
-
-
diff --git a/astro/src/pages/build-configs.mdx b/astro/src/pages/build-configs.mdx
deleted file mode 100644
index 80669f7f..00000000
--- a/astro/src/pages/build-configs.mdx
+++ /dev/null
@@ -1,81 +0,0 @@
----
-layout: ~/layouts/PageLayout.astro
-title: "Build Configs - configuration files as a service"
----
-
-import AboutMe from "~/components/AboutMe.astro";
-import Button from "~/components/Button.astro";
-import YouTubeVideo from "~/components/YouTubeVideo.astro";
-
-export const products = [
- {
- price: "2,500",
- link: "https://buy.stripe.com/14kbJs98K1fc0p29AC",
- buttonText: "Get started",
- },
- {
- price: "1,000",
- link: "https://buy.stripe.com/7sIdRAbgS8HEfjWfZ1",
- buttonText: "Sign up",
- },
-];
-
-**Sprint zero in a box.**
-
-All of my projects contain similar build configuration files, such as Docker and Docker Compose files, PHPUnit and PHPStan configuration, and CI/CD pipeline workflows. I used to maintain these manually which was time-intensive and there was no guarantee that the same features or options were available from project to project.
-
-Build Configs is a tool I've written to maintain a canonical set of templates and generate them for each project based on a per-project configuration file.
-
-This makes it quicker and easier for me to create or onboard new projects to work on and, as all of the base files are centralised, when I fix something or add a new feature, the changes can be pushed to every project that uses it.
-
-I've been using this on personal projects such as my [Drupal](https://github.com/opdavies/docker-example-drupal), [LocalGov Drupal](https://github.com/opdavies/docker-example-drupal-localgov) and [Drupal Commerce Kickstart](https://github.com/opdavies/docker-example-drupal-commerce-kicksart) Docker examples and for various client projects.
-
-## How does it work?
-
-- I create a `build.yaml` file for the project that contains its configuration - what version of PHP it needs, which web server to use, which paths to run automated tests from or static analysis on, etc.
-- I run the `build-configs` tool which generates the required files, such as a Dockerfile, Docker Compose file, PHPStan and PHPUnit configuration files, and a `run` script for automating project commands.
-- The files are committed to version control and pushed to your code repository (GitHub, GitLab, Bitbucket, etc).
-- As I add new features or make changes, I will re-run the process to re-generate the files and push any changes - ensuring you’re always up to date.
-
-## What are some of the recent new features?
-
-* Adding additional databases for working with migrations or multi-site projects.
-* Adding additional `run` tasks.
-* Adding CI pipelines with GitHub Actions to run automated quality checks.
-* Creating and running Git hooks to run automated checks before changes are pushed.
-
-## Example
-
-In this short video, I show how Build Configs works by creating a new Drupal 10 project, generating its configuration files, and opening it in a browser.
-
-From nothing to a ready-to-work-on Drupal website in less than a minute.
-
-
-
-## Options
-
-### Initial project setup - £{products[0].price}
-
-To get your project started on the right foot, I will create a new Drupal project skeleton for you using `build-configs` that is ready to work on, including all of the generated files. You can even edit them if you like as they will get no ongoing updates.
-
-
-
-### Ongoing updates and support (single site) - £{products[1].price} per month
-
-Once you have a project with `build-configs`, if you want to receive ongoing updates to the generated files, I can automatically refresh your files once changes are available and push them to your code repository.
-
-This also includes unlimited support via a dedicated Slack channel and you can make feature requests for me to consider adding to the roadmap.
-
-If you like, I can add you to a beta users list and you’ll get new experimental features before anyone else.
-
-
-
-If you have multiple Drupal sites, [contact me](/contact) and we can work something out.
-
-### Retro-fitting into an existing project
-
-`build-configs` can also be added to an existing project. It can be tricky and will be different from project to project so [contact me](/contact) and we can discuss it further.
-
-Once I know more about your project, I’ll be happy to give you a fixed-price quote to do the work.
-
-
diff --git a/astro/src/pages/call.mdx b/astro/src/pages/call.mdx
deleted file mode 100644
index 7ca08443..00000000
--- a/astro/src/pages/call.mdx
+++ /dev/null
@@ -1,106 +0,0 @@
----
-layout: ~/layouts/PageLayout.astro
-title: Book a 1-on-1 consulting call
-link: https://savvycal.com/opdavies/consulting-call
-price: £350
-testimonials:
- - tawny-bartlett
- - tom-evans
- - michael-itkoff2
-faqs:
- - - What happens after I pay?
- - Your call is scheduled at the time you pay. So after payment is received, we're all set!
-
- - - What if I can't find a suitable time?
- - If you can't find a suitable time, due to your time zone, or weekly schedule, just send me an email, and we can arrange something. I try to be as flexible as possible!
-
- - - Can my colleague or business partner join the call?
- - No. This is a 1-on-1 call. You are welcome to record the conversation to share it after the fact.
-
- - - Do you offer something more hands-on?
- - Sure! Book a pair programming session instead and we’ll work on your code together.
-
- - - I still have questions!
- - No problem. Send me an email at oliver@oliverdavies.uk.
----
-
-import Button from "~/components/Button.astro";
-import Callout from "~/components/Callout.astro";
-import Testimonials from "~/components/Testimonials.astro";
-import { numberOfYears } from '~/utils';
-
-{/*
-## Who is this for?
-*/}
-
-{/* Pain */}
-
-{/* Dream */}
-
-{/* Fix */}
-
-As a professional Software Developer and Consultant with over {numberOfYears} years of Drupal and PHP experience, I have a lot of knowledge that I use to help customers and their projects.
-
-## Some things I can help you with
-
-- How to approach a new project or task.
-- PHP and Drupal fundamentals and best practices.
-- Adding eCommerce functionality with Drupal Commerce.
-- Upgrading Drupal websites from unsupported versions.
-- Writing your first automated tests with PHPUnit or starting with test-driven development.
-- Introducing static analysis or other code quality tools to your project.
-- Adopting a utility-first CSS approach, e.g. Tailwind CSS, within a new or existing theme.
-- Configuring continuous integration (CI) pipelines with GitHub Actions, GitLab CI or Bitbucket Pipelines.
-- Automating tasks with Docker or Ansible.
-- Help fixing a bug or some broken code.
-- Reviewing your code and providing advice and suggestions.
-
-In this 1-on-1 video call, I can help you answer questions in these areas or any others you may have.
-
-{/* 1st call to action */}
-
-
-
-{/* Social proof */}
-
-
-
-{/* Overcome objections */}
-
-## 100% money-back guarantee!
-
-If you don't find the call valuable, just let me know, and I'll refund 100% of the cost.
-
-## Frequently asked questions
-
-{frontmatter.faqs.map((faq) => (
-
-
{faq[0]}
-
-
-))}
-
-{/* Uniqueness */}
-
-## Who am I?
-
-- I'm an Acquia-certified Drupal expert with over {numberOfYears} years of professional development experience.
-- I'm a former Drupal Association employee who was responsible for improving and maintaining Drupal.org.
-- I'm a Drupal core contributor and maintain numerous Drupal projects, including the Override Node Options module, which is used on over 38,000 websites.
-- I'm a multiple-time DrupalCon speaker who regularly presents talks and workshops at conferences and meetups.
-
-{/* 2nd CTA */}
-
-
-
-
-
You can pay and reserve your time slot straight away. There are a limited number of available slots each month. If, after the call, you decide to do a longer engagement with me, the cost of this call will be deducted from that engagement.
-
-
-{/* Urgency */}
-
-## Availability is limited
-
-I’m only available for a few 1-on-1 calls per month.
-
-Scheduling is first come, first served, so the sooner you book your time slot, the sooner you will have the answers you need to move your project forward.
diff --git a/astro/src/pages/company-information.mdx b/astro/src/pages/company-information.mdx
deleted file mode 100644
index 66d182c1..00000000
--- a/astro/src/pages/company-information.mdx
+++ /dev/null
@@ -1,10 +0,0 @@
----
-layout: ~/layouts/PageLayout.astro
-title: Company information
----
-
-Company name : Oliver Davies Ltd (previously Oliver Davies Web Development Ltd)
-
-Registered address : 3 Westfield Close, Caerleon, Newport, NP18 3ED
-
-Company number : 8017706
diff --git a/astro/src/pages/contact.mdx b/astro/src/pages/contact.mdx
deleted file mode 100644
index dae5e8f1..00000000
--- a/astro/src/pages/contact.mdx
+++ /dev/null
@@ -1,12 +0,0 @@
----
-layout: ~/layouts/PageLayout.astro
-title: Contact Oliver
----
-
-export const email = "oliver@oliverdavies.uk";
-
-The best way to get in touch with me is via email: {email}. I usually reply within one business day.
-
-I'm also on [LinkedIn][linkedin].
-
-[linkedin]: https://www.linkedin.com/in/opdavies
diff --git a/astro/src/pages/daily.mdx b/astro/src/pages/daily.mdx
deleted file mode 100644
index b619fe8e..00000000
--- a/astro/src/pages/daily.mdx
+++ /dev/null
@@ -1,34 +0,0 @@
----
-layout: ~/layouts/PageLayout.astro
-title: Oliver's Daily Email List
-testimonials:
- - alexander-carr
- - adam-nuttall
- - mike-karthauser
- - marcos-duran
- - stephen-mulvihill
- - patty-ocallaghan
----
-
-import AboutMe from "~/components/AboutMe.astro";
-import DailyEmailForm from "~/components/DailyEmailForm.astro";
-import Markdown from "~/components/Markdown.astro";
-import Testimonials from "~/components/Testimonials.astro";
-
-
- A daily newsletter for software professionals on software development, DevOps, community, and open-source.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/astro/src/pages/diagnostic.mdx b/astro/src/pages/diagnostic.mdx
deleted file mode 100644
index f802846f..00000000
--- a/astro/src/pages/diagnostic.mdx
+++ /dev/null
@@ -1,50 +0,0 @@
----
-layout: ~/layouts/PageLayout.astro
-title: Diagnostic
-price: £3,500
-link: ~
----
-
-import Button from "~/components/Button.astro";
-import Callout from "~/components/Callout.astro";
-import Testimonials from "~/components/Testimonials.astro";
-import { numberOfYears } from '~/utils';
-
-{/* Pain */}
-
-{/* Dream */}
-
-{/* Fix */}
-
-Price: {frontmatter.price}
-
-{/* 1st call to action */}
-
-
-
-{/* Social proof */}
-
-
-
-{/* Overcome objections */}
-
-{/* Uniqueness */}
-
-## Who am I?
-
-- I'm an Acquia-certified Drupal expert with over {numberOfYears} years of professional development experience.
-- I'm a former Drupal Association employee who was responsible for improving and maintaining Drupal.org.
-- I'm a Drupal core contributor and maintain numerous Drupal projects, including the Override Node Options module, which is used on over 38,000 websites.
-- I'm a multiple-time DrupalCon speaker who regularly presents talks and workshops at conferences and meetups.
-
-{/* 2nd CTA */}
-
-
-
-
-
-{/* Urgency */}
-
-## Availability is limited
-
-TODO
diff --git a/astro/src/pages/drupal-upgrade.mdx b/astro/src/pages/drupal-upgrade.mdx
deleted file mode 100644
index 12c62a21..00000000
--- a/astro/src/pages/drupal-upgrade.mdx
+++ /dev/null
@@ -1,77 +0,0 @@
----
-layout: ~/layouts/PageLayout.astro
-title: Are you stuck on Drupal 7, 8 or 9?
-button:
- link: https://buy.stripe.com/aEU4h0gBc4ro0p27sz
- text: Book your roadmap now
----
-
-import Button from "~/components/Button.astro";
-import Testimonials from "~/components/Testimonials.astro";
-import { numberOfYears } from '~/utils';
-
-{/* Pain */}
-
-Drupal 7 will be unsupported on the **5th of January 2025**.
-Drupal 8 has been unsupported since **November 2021**.
-Drupal 9 will be unsupported in **November 2023**.
-
-* Do you need to upgrade your website before it reaches its end-of-life date and is no longer supported?
-* Are you worried about rebuilding your website and migrating your data to Drupal 10?
-* Is all of your business logic embedded within your Drupal code, making it hard to upgrade?
-* Do you rely on modules or themes that are no longer updated or don't exist for Drupal 10?
-
-{/* Dream */}
-
-## What if you had a clear path how to upgrade your website?
-
-* What if you had a recommended approach to upgrade your website to Drupal 10?
-* What if you knew about potential issues ahead of time?
-* What if you had a list of modules to use in Drupal 10, alternatives for any missing modules, and what functionality would need custom code?
-
-{/* Fix */}
-
-## Drupal upgrade roadmap
-
-An upgrade roadmap is a personalised audit of your Drupal website and includes details and actionable steps to upgrade it, including identifying potential blockers you might encounter.
-
-{/* 1st call to action */}
-
-
-
-## How does it work?
-
-* After receiving payment, we will arrange an initial call to discuss your project.
-* You share your source code and provide access to your website.
- * I'll need access to the source code for your website. Ideally, this is via GitHub, GitLab, Bitbucket, or whatever online version control you currently use, but I can also audit a zip file of your Git repository.
- * I'll need a user account to access your website to review its configuration, such as content types, user roles, etc. You can delete this once the engagement is complete.
- * Alternatively, I can use an export of the database to get a local version of your site up and running. Ideally, this would be sanitised to remove personal information such as usernames, email addresses and passwords.
-* I'll send you the document once it's complete for you to review.
-* We'll arrange a follow-up call to go through it in detail and for you to ask any questions.
-
-{/* 2nd CTA */}
-
-
-
-{/* Social proof */}
-
-
-
-{/* Overcome objections */}
-
-{/* Uniqueness */}
-
-## Who am I?
-
-* I'm an Acquia-certified Drupal expert with over {numberOfYears} years of professional development experience.
-* I'm a former Drupal Association employee who was responsible for improving and maintaining Drupal.org.
-* I'm a Drupal core contributor and maintain numerous Drupal projects, including the Override Node Options module, which is used on over 38,000 websites.
-* I'm a multiple-time DrupalCon speaker who regularly presents talks and workshops at conferences and meetups.
-
-{/* Urgency */}
-
-## Availability is limited
-
-There will be no further extensions of Drupal 7 support, and I have limited availability due to the time required, so buy now to secure your place.
-
-
diff --git a/astro/src/pages/dto.mdx b/astro/src/pages/dto.mdx
deleted file mode 100644
index 0bdfdbd8..00000000
--- a/astro/src/pages/dto.mdx
+++ /dev/null
@@ -1,67 +0,0 @@
----
-layout: ~/layouts/PageLayout.astro
-title: Introduction to Automated Testing and Test-Driven Development with Drupal
-testimonials:
- - tawny-bartlett
- - mike-karthauser
- - scott-euser
----
-
-import Button from "~/components/Button.astro";
-import Testimonials from "~/components/Testimonials.astro";
-
-export const drupalVersions = "9 and 10";
-
-export const prices = {
- early: "395.00",
- full: "495.00",
-};
-
-export const isEarlyBird = true;
-
-export const nextDate = "2022-04-04";
-
-Are you a Drupal Developer who wants to learn about automated testing and test-driven development, or do you manage a development team that you'd like to train?
-
-I've delivered large Drupal projects using automated tests and test-driven development for custom functionality, and maintain Drupal modules with thousands of installations whilst using their tests to ensure working code and prevent regressions.
-
-I offer an interactive full-day workshop (previously presented at DrupalCamp London, and remotely for DrupalCamp NYC) that provides an introduction to automated testing in Drupal and how to utilise test-driven development - which I've updated specifically for Drupal {drupalVersions}.
-
-## Contents
-
-- What is automated testing, and why write tests?
-- What types of tests are available in Drupal?
-- Outside-in vs. inside-out testing.
-- Configuring Drupal and PHPUnit to run tests locally.
-- Exercise: writing tests for existing Drupal core functionality.
-- Exercise: adding tests to an existing custom module.
-- What is test-driven development?
-- Exercise: writing a new Drupal module from scratch with test-driven development.
-- Q&A
-
-
-
-## Dates and prices
-
-The workshop is currently only available remotely, and the next available date is {new Date(nextDate).toLocaleDateString('en-GB', { day: 'numeric', month: 'long', year: 'numeric', })}.
-
-Seats are available at {isEarlyBird ? `an early bird price of £${prices.early}` : `a price of £${prices.full}`}, with a 10% discount for bulk orders of 5 or more seats.
-
-
-
-
-
-
-
-{/*
-## Not 100% sure?
-
-Here's a video where I implement some of these approaches by adding related articles to a custom blog module for Drupal 9 (narrated version coming soon).
-
-
-
-TODO: add another Buy button
-*/}
diff --git a/astro/src/pages/glossary.mdx b/astro/src/pages/glossary.mdx
deleted file mode 100644
index 192a25f2..00000000
--- a/astro/src/pages/glossary.mdx
+++ /dev/null
@@ -1,44 +0,0 @@
----
-layout: ~/layouts/PageLayout.astro
-title: Glossary
-terms:
- - - Automated Testing
-
- - - CI pipeline
-
- - - Continuous integration
- - |
- The process of continuously integrating your code with other people's code, i.e. at least once a day.
- This is done by regularly pulling and merging everyone else's code with yours and pushing yours so it's available for others to do the same. This can also refer to CI pipelines and tools like GitHub Actions and GitLab CI.
-
- - - Continuous Delivery and Deployment
-
- - - Git
-
- - - PHPStan
-
- - - Static analysis
-
- - - Test-Driven Development
-
- - - Trunk-based Development
-
- - - Version control
----
-
-import _ from "lodash";
-
-export const filteredTerms = _(frontmatter.terms).filter((term) => term[1])
-
-export const sortedTerms = _(filteredTerms).sortBy(0);
-
-{!sortedTerms.isEmpty() && (
-
- {sortedTerms.value().map((term) => (
-
-
{term[0]}
-
{term[1]}
-
- ))}
-
-)}
diff --git a/astro/src/pages/index.mdx b/astro/src/pages/index.mdx
deleted file mode 100644
index 9b83ce3e..00000000
--- a/astro/src/pages/index.mdx
+++ /dev/null
@@ -1,57 +0,0 @@
----
-layout: ~/layouts/PageLayout.astro
-title: Do you need a certified Drupal expert, core contributor and module maintainer?
-isFront: true
----
-
-import AboutMe from '~/components/AboutMe.astro';
-import DailyEmailForm from '~/components/DailyEmailForm.astro';
-import Testimonials from '~/components/Testimonials.astro';
-
-
- {/*
-
- ### Do you want to learn about automated testing with Drupal?
-
- Sign up for my free 7-day email course, "Automated Testing for Drupal Developers" or book to attend my next online workshop.
-
- */}
-
-
- ## What I can help you with
-
- If you are stuck on an unsupported version of Drupal, such as 7, 8 or 9, and don't know what's involved in upgrading, book a [Drupal upgrade consultation call][call] or a [roadmap for your website][upgrade-roadmap].
-
- If you need help or another pair of eyes on your code, book a [1-on-1 consultation call][call] or an [online pair programming session][pair] with me, with a 100% money-back guarantee.
-
- If you want to learn to write better software faster, I'm available for [development team coaching][team coaching].
-
- ### Looking for something else?
-
- Here are all of my products and services. If you still can't find what you need, send me an email, and I'll see what I can do.
-
diff --git a/astro/src/pages/now.mdx b/astro/src/pages/now.mdx
deleted file mode 100644
index 5a0d0c86..00000000
--- a/astro/src/pages/now.mdx
+++ /dev/null
@@ -1,19 +0,0 @@
----
-layout: ~/layouts/PageLayout.astro
-title: Now
----
-
-* I'm Web Development Manager at [Transport for Wales] and a [Full-Stack Software Development Consultant][services].
-* I'm working on a client project, migrating their Drupal 7 website to Drupal 10.
-* I maintain open-source software on [Drupal.org](https://www.drupal.org/u/opdavies) and [GitHub](https://github.com/opdavies).
-* I mentor software development bootcamp students for [School of Code].
-* I'm creating a [free email course][atdc] on automated testing and test-driven development in Drupal.
-* I [send daily emails][daily] about software development and delivery (register for free).
-* I host the [Beyond Blocks podcast][podcast].
-
-[atdc]: /atdc
-[daily]: /daily
-[podcast]: /podcast
-[school of code]: https://www.schoolofcode.co.uk
-[services]: /pricing
-[transport for wales]: https://www.tfw.wales
diff --git a/astro/src/pages/pair.mdx b/astro/src/pages/pair.mdx
deleted file mode 100644
index ed9660dd..00000000
--- a/astro/src/pages/pair.mdx
+++ /dev/null
@@ -1,70 +0,0 @@
----
-layout: ~/layouts/PageLayout.astro
-title: Pair program with me
-price: £499
-link: https://savvycal.com/opdavies/pair
----
-
-import Button from "~/components/Button.astro";
-import Callout from "~/components/Callout.astro";
-import Testimonials from "~/components/Testimonials.astro";
-import { numberOfYears } from '~/utils';
-
-{/* Pain */}
-
-Are you stuck adding a new feature or fixing a bug?
-
-Do you need help starting a new Drupal module or theme?
-
-Would you like another pair of eyes on your code, providing real-time suggestions and feedback rather than waiting for a code review?
-
-{/* Dream */}
-
-{/* Fix */}
-
-## Book a pair programming session
-
-What if you could have a pair programming session with a Lead Developer and Drupal Expert with {numberOfYears} years of professional experience?
-
-Book a 2-hour pair programming call, and we can work on your code together - adding new functionality, fixing bugs, writing tests for existing code, or something else.
-
-Price: {frontmatter.price}
-
-{/* 1st call to action */}
-
-
-
-{/* Social proof */}
-
-
-
-{/* Overcome objections */}
-
-## 100% money-back guarantee!
-
-If you don't find the session valuable, just let me know, and I'll refund 100% of the cost.
-
-{/* Uniqueness */}
-
-## Who am I?
-
-- I'm an Acquia-certified Drupal expert with over {numberOfYears} years of professional development experience.
-- I'm a former Drupal Association employee who was responsible for improving and maintaining Drupal.org.
-- I'm a Drupal core contributor and maintain numerous Drupal projects, including the Override Node Options module, which is used on over 38,000 websites.
-- I'm a multiple-time DrupalCon speaker who regularly presents talks and workshops at conferences and meetups.
-
-{/* 2nd CTA */}
-
-
-
-
-
You can pay and reserve your time slot straight away. There are a limited number of available slots each month. If, after the call, you decide to do a longer engagement with me, the cost of this call will be deducted from that engagement.
-
-
-{/* Urgency */}
-
-## Availability is limited
-
-I’m only available for a few pair programming sessions per month.
-
-Scheduling is first come, first served, so the sooner you book your time slot, the sooner you will have the answers you need to move your project forward.
diff --git a/astro/src/pages/podcast/[slug].astro b/astro/src/pages/podcast/[slug].astro
deleted file mode 100644
index e111b146..00000000
--- a/astro/src/pages/podcast/[slug].astro
+++ /dev/null
@@ -1,43 +0,0 @@
----
-import Markdown from "~/components/Markdown.astro";
-import Layout from "~/layouts/PodcastEpisodeLayout.astro";
-import { getCollection } from "astro:content";
-
-export async function getStaticPaths() {
- const episodes = await getCollection("podcast-episode");
- const publishedEpisodes = episodes.filter((episode) => !episode.data.draft);
-
- return publishedEpisodes.map((episode) => {
- return {
- params: { slug: episode.slug },
- props: { episode },
- };
- });
-}
-
-const { Content } = await Astro.props.episode.render();
-const { id } = Astro.props.episode;
-const { guests, links, title, topic, transistor } = Astro.props.episode.data;
----
-
-
-
-
-
- {links && (
-
Episode {episode.id.match(/^[\d+]/)} - {`${episode.data.topic} with ${episode.data.guests}`}
-
-
-
-
-
-
-
- ))}
- >
- )}
-
diff --git a/astro/src/pages/press.mdx b/astro/src/pages/press.mdx
deleted file mode 100644
index 6ac32194..00000000
--- a/astro/src/pages/press.mdx
+++ /dev/null
@@ -1,46 +0,0 @@
----
-layout: ~/layouts/PageLayout.astro
-title: Press Info
----
-
-import { numberOfYears } from "~/utils";
-
-The following information is provided as a cut-and-paste resource for conference organisers, media professionals, podcast hosts, and other interested parties.
-
-Please feel free to use anything here as-is without checking with me first. If you have additional questions, you can [email me directly][email].
-
-## Short Bio
-
-Oliver is a Software Developer and Drupal expert with over {numberOfYears} years experience. He specialises in code quality, automated testing and test-driven development.
-
-## Sample Topics
-
-* Getting started in software development, Drupal, or open-source software.
-* Building your first Drupal website.
-* Drupal module and theme development.
-* Automated testing and test-driven development (TDD).
-* Static analysis in PHP applications.
-* Utility-first styling and Tailwind CSS.
-* Git and different ways to use it (continuous integration, trunk-based development).
-* Contributing to open-source software.
-
-## Social Media and Elsewhere
-
-* [Drupal.org][drupal]
-* [GitHub][]
-* [LinkedIn][]
-* [Twitter][]
-
-## Physical Location
-
-[Caerleon, Wales](https://www.google.co.uk/maps/place/Caerleon,+Newport)
-
-## Photo
-
-
-
-[drupal]: https://www.drupal.org/u/opdavies
-[email]: mailto:oliver@oliverdavies.uk
-[github]: https://github.com/opdavies
-[linkedin]: https://www.linkedin.com/in/opdavies
-[twitter]: https://twitter.com/opdavies
diff --git a/astro/src/pages/pricing.mdx b/astro/src/pages/pricing.mdx
deleted file mode 100644
index d49a9456..00000000
--- a/astro/src/pages/pricing.mdx
+++ /dev/null
@@ -1,42 +0,0 @@
----
-layout: ~/layouts/PageLayout.astro
-title: Products and Services
----
-
-import priceFormatter from "~/price-formatter";
-import products from "~/products.yaml";
-
-
- Starting with my first talk in September 2012, I have given {talkCount} presentations
- and workshops at various conferences and meetups, in-person and remotely, on
- topics including PHP, Drupal, automated testing, Git, CSS, and systems administration.
-
-
-
diff --git a/astro/src/pages/team-coaching.mdx b/astro/src/pages/team-coaching.mdx
deleted file mode 100644
index e5796bf1..00000000
--- a/astro/src/pages/team-coaching.mdx
+++ /dev/null
@@ -1,144 +0,0 @@
----
-layout: ~/layouts/PageLayout.astro
-title: Team Coaching
-faqs:
- - - Do you only work with Drupal development teams?
- - No. While most of my background and experience is with PHP and Drupal, many things I can help with aren't specific to any language or framework.
-
- # - - TODO: money-back guarantee
-
- - - I have another question.
- - No problem! Send me an email at oliver@oliverdavies.uk.
----
-
-import AboutMe from "~/components/AboutMe.astro";
-import Button from "~/components/Button.astro";
-import Testimonials from "~/components/Testimonials.astro";
-import priceFormatter from "~/price-formatter";
-import { numberOfYears } from "~/utils";
-
-export const formUrl = "https://forms.gle/zd3Lnwe2J1sF13qJ7";
-export const price = 10000;
-
-
-
-{/*Pain*/}
-
-Do you need an experienced Software Developer or Drupal expert to upskill your in-house team? Are they new to Drupal or want to make better use of best practices, such as automated testing and test-driven development?
-
-Do you want to gain exposure by contributing to open-source software, like Drupal, but don't know where to start?
-
-{/* Dream */}
-
-{/* Fix */}
-
-I offer team coaching on an ongoing monthly basis. You can sign up for as long as you need and cancel at any time.
-
-{/* 1st call to action */}
-
-
-
-
-
-
-## What is included?
-
-- Unlimited, 24/7 access to me via email or Slack, with responses within one business day.
-- Regular 1-on-1 check-in calls and pair/mob programming sessions.
-- Reviews and feedback of relevant code, flowcharts, technical design documents, etc.
-
-## Some things I can help with
-
-- Developing custom Drupal modules and themes.
-- Drupal upgrades and migrations.
-- Automated testing and test-driven development.
-- CSS and front-end development.
-- Implementing and using component libraries, such as Fractal.
-- Continuous integration, delivery and deployment.
-- Local environment and CI pipeline setup.
-- Infrastructure automation, using tools like Terraform and Pulumi.
-- Automating and simplifying repetitive or complex tasks.
-- Contributing to open-source projects, such as Drupal.
-
-
-{/* Social proof */}
-
-{/* Overcome objections */}
-
-
-## How does it work?
-
-- The cost of team coaching is {priceFormatter.format(price)} per month, paid in advance.
-- You apply by clicking on the button below and submitting the application form, telling me about your team and what you want to achieve.
-- I'll review your application, usually within one working day.
-- If successful, you make your first payment and book your onboarding call where we can define some key objectives and metrics.
-
-
-
-
-
-If you need lighter-touch guidance and advice, I also offer one-time consulting calls and pair programming sessions.
-
-
-
-
-{/* Uniqueness */}
-
-
-## Frequently Asked Questions
-
-{frontmatter.faqs.map((faq) => (
-
-
{faq[0]}
-
-
-))}
-
-
-
-## Who am I?
-
-- I'm an Acquia-certified Drupal expert with over {numberOfYears} years of professional development experience.
-- I'm a former Drupal Association employee who was responsible for improving and maintaining Drupal.org.
-- I'm a Drupal core contributor and maintain numerous Drupal projects, including the Override Node Options module, which is used on over 38,000 websites.
-- I'm a multiple-time DrupalCon speaker who regularly presents talks and workshops at conferences and meetups.
-- I have experience working in in-house teams, such as Transport for Wales and the Drupal Association.
-- I have experience working for and with software development agencies.
-
-
-{/* 2nd CTA */}
-
-
-
-
-
-
-
-{/* Urgency */}
-
-
-## Availability is limited
-
-I'm only available for a few team coaching engagements per year.
-
-Scheduling is first come, first served, so the sooner you book your time slot, the sooner you will have the answers you need to upskill your team and deliver better software.
-
-If you have any questions, feel free to send me an email at oliver@oliverdavies.uk.
-
-
-
diff --git a/astro/src/pages/testimonials.mdx b/astro/src/pages/testimonials.mdx
deleted file mode 100644
index 1e957c16..00000000
--- a/astro/src/pages/testimonials.mdx
+++ /dev/null
@@ -1,8 +0,0 @@
----
-layout: ~/layouts/PageLayout.astro
-title: Testimonials
----
-
-import Testimonials from "~/components/Testimonials.astro";
-
-
diff --git a/astro/src/pages/things-about-php.mdx b/astro/src/pages/things-about-php.mdx
deleted file mode 100644
index 2ac4fafd..00000000
--- a/astro/src/pages/things-about-php.mdx
+++ /dev/null
@@ -1,67 +0,0 @@
----
-layout: ~/layouts/PageLayout.astro
-title: Things you should know about PHP
----
-
-export const email = "oliver@oliverdavies.uk";
-
-Thanks for attending my [Things you should know about PHP](/talks/things-you-should-know-about-php) talk.
-
-I hope that you learned some things about PHP, its ecosystem, and its communities, and if you haven't tried using PHP yet, I'd encourage you to do so.
-
-Here are links to the resources that I mention in the talk, plus a couple of extras.
-
-## Resources
-
-- [The PHP Foundation](https://thephp.foundation) - non-profit to support, advance, and develop the PHP language
-- [PHP-FIG](https://www.php-fig.org) - PHP Framework Interop Group
-- [Composer](https://getcomposer.org) - dependency manager
-- [Drupal](https://www.drupal.org) - content management system
-- [Jigsaw](https://jigsaw.tighten.co) - static site generator
-- [Laravel](https://laravel.com) - framework
-- [Nomad PHP](https://nomadphp.com) - online user group
-- [PHP official images on Docker Hub](https://hub.docker.com/_/php)
-- [PHPStan](https://phpstan.org) - static analysis tool
-- [PHPUnit](https://phpunit.de) - testing framework
-- [Pest](https://pestphp.com) - testing framework
-- [Psalm](https://psalm.dev) - static analysis tool
-- [Sculpin](khttps://sculpin.io) - static site generator
-- [WordPress](https://wordpress.org) - content management system
-- [php.net](https://www.php.net) - online documentation
-- [php[architect]](https://www.phparch.com) - online magazine
-
-## Books
-
-- [Laravel: Up & Running](https://www.oreilly.com/library/view/laravel-up/9781492041207)
-- [Symfony: The Fast Track](https://symfony.com/book)
-
-## Videos
-
-- [Codecourse](https://codecourse.com)
-- [How to Code Well](https://www.howtocodewell.net)
-- [Laracasts](https://laracasts.com)
-- [SymfonyCasts](https://symfonycasts.com)
-
-## Podcasts
-
-- [How to Code Well podcast](https://howtocodewell.fm)
-- [PHPUgly](https://www.phpugly.com)
-- [Talking Drupal](https://talkingdrupal.com)
-- [The Laravel Podcast](https://laravelpodcast.com)
-- [The PHP Roundtable](https://phproundtable.com)
-- [Voices of the elePHPant](https://voicesoftheelephpant.com)
-
-## Can I help?
-
-Do you want to introduce PHP to your company or team, or add one of these tools to your existing PHP application?
-
-I offer consulting calls and services to reduce your onboarding time and get you up and running quicker and easier.
-
-
diff --git a/astro/src/price-formatter.ts b/astro/src/price-formatter.ts
deleted file mode 100644
index ffb07063..00000000
--- a/astro/src/price-formatter.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-const priceFormatter = new Intl.NumberFormat('en-GB', {
- currency: 'GBP',
- maximumSignificantDigits: 2,
- style: 'currency',
-});
-
-export default priceFormatter;
diff --git a/astro/src/products.yaml b/astro/src/products.yaml
deleted file mode 100644
index 1d6a9c91..00000000
--- a/astro/src/products.yaml
+++ /dev/null
@@ -1,66 +0,0 @@
----
-- title: Development team coaching
- description: |
- Do you want to upskill your in-house team or have someone provide oversight and guidance as they deliver a project? Does your company want to learn to contribute to open-source software? Get unlimited 1-on-1 private Slack access to me and regular check-in calls to ensure things are on track.
- perMonth: true
- isLimited: true
- price: 10000
- remainingPlaces: 2
- link:
- text: Apply now
- href: /team-coaching
-
-- title: Drupal upgrade roadmap
- description: |
- Are you stuck on an already or soon-to-be unsupported version of Drupal? Get a personalised roadmap of your Drupal website, including details and actionable steps to upgrade it.
- price: 5000
- link:
- text: Book your roadmap now
- href: /drupal-upgrade
-
-- title: Diagnosis
- description: |
- An in-depth investigation into a single issue where I'll provide a report with my findings and advice on the next steps. Once you've purchased, you can book a Zoom call with me to discuss what you want me to investigate.
- price: 2500
- link:
- text: Book now
- href: https://buy.stripe.com/00gbJs84G2jg8Vy9AJ
-
-- title: Private talk or workshop
- description: |
- If you found one of my public speaking presentations or workshops useful, I'm available for private speaking engagements on a variety of topics to help your team succeed.
- price: 2000
- isFrom: true
- link:
- text: Schedule a talk
- href: https://buy.stripe.com/eVa4h0bgSaPM6NqcMU
-
-- title: 1-on-1 consulting call
- description: |
- Book a 1-on-1 video call, and I can help you by answering questions about software development, architecture and automation, helping you write your first automated test, or reviewing some of your code and giving advice and suggestions.
- price: 350
- link:
- text: Book your call now
- href: /call
-
-- title: Pair program with me
- description: |
- Would you like another pair of eyes on your code, providing real-time suggestions and feedback rather than waiting for a code review? Book a 2-hour pair programming call and we can work on your code together.
- price: 499
- link:
- text: Book your session now
- href: /pair
-
-- title: Introduction to automated testing in Drupal - 7-day email course
- description: |
- Register for my free upcoming email course on automated testing in Drupal.
- link:
- text: Register now
- href: /atdc
-
-- title: Drupal module template
- description: |
- If you're creating a new Drupal module, try starting with my free module template for Drupal 9 and 10.
- link:
- text: Download
- href: https://github.com/opdavies/drupal-module-template
diff --git a/astro/src/types.ts b/astro/src/types.ts
deleted file mode 100644
index dc62e906..00000000
--- a/astro/src/types.ts
+++ /dev/null
@@ -1,12 +0,0 @@
-type Episode = {
- body: string;
- data: {
- date: Date;
- draft?: boolean;
- guests: Array;
- topic: string;
- };
- id: string;
-}
-
-export type { Episode }
diff --git a/astro/src/utils.ts b/astro/src/utils.ts
deleted file mode 100644
index 35ff3f97..00000000
--- a/astro/src/utils.ts
+++ /dev/null
@@ -1,9 +0,0 @@
-import { differenceInYears } from 'date-fns';
-
-export function getSlugFromFile(file: string): string {
- const parts = file.replace('.md', '').split('/')
-
- return parts[parts.length - 1]
-}
-
-export const numberOfYears = differenceInYears(new Date(), new Date(2007, 0, 1));
diff --git a/astro/stub.md b/astro/stub.md
deleted file mode 100644
index 3fb6686e..00000000
--- a/astro/stub.md
+++ /dev/null
@@ -1,12 +0,0 @@
----
-title: >-
- {{ title }}
-pubDate: {{ date }}
-permalink: >
- {{ permalink }}
-snippet: >-
- TODO
-# tags:
-# - a
-# - b
----
diff --git a/astro/tailwind.config.cjs b/astro/tailwind.config.cjs
deleted file mode 100644
index fffefadf..00000000
--- a/astro/tailwind.config.cjs
+++ /dev/null
@@ -1,56 +0,0 @@
-const colors = require("./assets/tailwindcss/colours.cjs");
-const defaultTheme = require("tailwindcss/defaultTheme");
-const { fontFamily } = defaultTheme;
-
-/** @type {import('tailwindcss').Config} */
-module.exports = {
- mode: "jit",
- darkMode: "media",
- important: true,
- content: ['./src/**/*.{astro,html,js,jsx,md,mdx,svelte,ts,tsx,vue}'],
- theme: {
- outline: {
- black: "1px solid black",
- white: "1px solid white",
- },
- extend: {
- colors,
- fontFamily: {
- sans: [
- "Roboto Condensed",
- "Arial",
- "Helvetica Neue",
- "Helvetica",
- "sans-serif",
- ],
- mono: [
- "ui-monospace",
- "SFMono-Regular",
- "SF Mono",
- "Consolas",
- "Liberation Mono",
- ...fontFamily.mono,
- ],
- },
- spacing: {
- "2px": "2px",
- },
- borderWidth: {
- 3: "3px",
- },
- width: {
- 96: "24rem",
- },
- },
- },
- corePlugins: {
- container: false,
- },
- plugins: [
- require("./assets/tailwindcss/plugins/focus-visible.cjs"),
- require("@tailwindcss/nesting"),
- require("@tailwindcss/aspect-ratio"),
- require("@tailwindcss/forms"),
- require("@tailwindcss/typography"),
- ],
-};
diff --git a/astro/tsconfig.json b/astro/tsconfig.json
deleted file mode 100644
index 1f617ba1..00000000
--- a/astro/tsconfig.json
+++ /dev/null
@@ -1,12 +0,0 @@
-// Do not edit this file. It is automatically generated by https://www.oliverdavies.uk/build-configs.
-
-{
- "extends": "astro/tsconfigs/strict",
- "compilerOptions": {
- "baseUrl": ".",
- "paths": {
- "~/*": ["src/*"]
- },
- "strictNullChecks": true
- }
-}