24 Jan 2026

feedDrupal.org aggregator

Dries Buytaert: Automatically exporting my Drupal content to GitHub

This note is mostly for my future self, in case I need to set this up again. I'm sharing it publicly because parts of it might be useful to others, though it's not a complete tutorial since it relies on a custom Drupal module I haven't released.

For context: I switched to Markdown and then open-sourced my blog content by exporting it to GitHub. Every day, my Drupal site exports its content as Markdown files and commits any changes to github.com/dbuytaert/website-content. New posts appear automatically, and so do edits and deletions.

Creating the GitHub repository

Create a new GitHub repository. I called mine website-content.

Giving your server access to GitHub

For your server to push changes to GitHub automatically, you need SSH key authentication.

SSH into your server and generate a new SSH key pair:

ssh-keygen -t ed25519 -f ~/.ssh/github -N ""

This creates two files: ~/.ssh/github (your private key that stays on your server) and ~/.ssh/github.pub (your public key that you share with GitHub).

The -N "" creates the key without a passphrase. For automated scripts on secured servers, passwordless keys are standard practice. The security comes from restricting what the key can do (a deploy key with write access to one repository) rather than from a passphrase.

Next, tell SSH to use this key when connecting to GitHub:

cat >> ~/.ssh/config << 'EOF'
Host github.com
  IdentityFile ~/.ssh/github
  IdentitiesOnly yes
EOF

Add GitHub's server fingerprint to your known hosts file. This prevents SSH from asking "Are you sure you want to connect?" when the script runs:

ssh-keyscan github.com >> ~/.ssh/known_hosts

Display your public key so you can copy it:

cat ~/.ssh/github.pub

In GitHub, go to your repository's "Settings", find "Deploy keys" in the sidebar, and click "Add deploy key". Check the box for "Allow write access".

Test that everything works:

ssh -T git@github.com

You should see: You've successfully authenticated, but GitHub does not provide shell access.

The export script

I created the following export script:

#!/bin/bash
set -e

TEMP=/tmp/dries-export

# Clone the existing repository
git clone git@github.com:dbuytaert/website-content.git $TEMP
cd $TEMP

# Clean all directories so moved/deleted content is tracked
rm -rf */

# Export fresh content older than 2 days
drush node:export --end-date="2 days ago" --destination=$TEMP

# Commit and push if there are changes
git config user.email "dries+bot@buytaert.net"
git config user.name "Dries Bot"
git add -A
git diff --staged --quiet || {
    git commit -m "Automatic updates for $(date +%Y-%m-%d)"
    git push
}

rm -rf $TEMP

The drush node:export command comes from a custom Drupal module I built for my site. I have not published the module on Drupal.org because it's specific to my site and not reusable as is. I wrote about why that kind of code is still worth sharing as adaptable modules, and I hope to share it once Drupal.org has a place for them.

The two-day delay (--end-date="2 days ago") gives me time to catch typos before posts are archived to GitHub. I usually find them right after hitting publish.

The git add -A stages everything including deletions, so if I remove a post from my site, it disappears from GitHub too (though Git's history preserves it).

Scheduling the export

On a traditional server, you'd add this script to Cron to run daily. My site runs on Acquia Cloud, which is Kubernetes-based and automatically scales pods up and down based on traffic. This means there is no single server to put a crontab on. Instead, Acquia Cloud provides a scheduler that runs jobs reliably across the infrastructure.

And yes, this note about automatically backing up my content will itself be automatically backed up.

24 Jan 2026 1:54pm GMT

23 Jan 2026

feedSymfony Blog

Twig 3.23: Introducing new operators and destructuring support

We're excited to announce the release of Twig 3.23, which has new features that enhance expressiveness and ease of use. This version introduces the assignment operator, destructuring capabilities, a null-safe operator, and strict comparison operators. Let's…

23 Jan 2026 9:28pm GMT

feedDrupal.org aggregator

Dripyard Premium Drupal Themes: How an unclosed broke Drupal’s JavaScript

Sometimes you hit a bug and your brain just goes, "huh."

That was me earlier this week while trying to figure out why Drupal's JavaScript was completely broken. But only on one page. And of course, this happened during a live demo!

You can actually see the moment it went sideways here. This is the story of how I tracked it down.

The problem

Dripyard adds a bunch of options to our theme settings pages. On one particular theme, Great Lakes, the settings page was loading with JavaScript absolutely wrecked.

23 Jan 2026 3:15pm GMT

Joachim's blog: Converting hooks to OO methods made easy

Converting hooks to OO methods made easy

Rector is a really powerful tool for making refactoring changes to your codebase. It's easy to use, but it's not obvious, and a lot of the documentation and articles about it are outdated or incomplete. For instance, when you go to the project page (https://www.drupal.org/project/rector) there's no clear indication of how to install it!

More and more of the code changes needed to keep your modules up to date with Drupal core are being written as Rector rules. I wrote recently about converting plugins to PHP attributes; the other big change in Drupal at the moment is hooks changing from procedural functions to class methods.

Here's the steps I took to convert the hooks in the Computed Field module:

  1. Install Rector in your project. As mentioned earlier, finding the installation instructions is not obvious: they're in the github project:
composer require --dev palantirnet/drupal-rector
cp vendor/palantirnet/drupal-rector/rector.php .

This puts a rector.php file in your project root. What to do with this isn't immediately obvious either, but fortunately, in the PR for OO hook conversion there is sample code. The key part is this:

  $rectorConfig->rule(\DrupalRector\Rector\Convert\HookConvertRector::class);

You can then run Rector on your code. Remember to commit any existing changes to git first: this Rector rule changes a lot, and it's good to be able to revert it cleanly if necessary.

vendor/bin/rector process path/to/my_module

This does the conversion: hook implementation code is copied to methods in new Hook classes, and the existing hook implementations are reduced to legacy wrappers.

However, the code is all formatted to ugly PHP PSR standards. Import statements in .module file for use inside hook code will also remain. So we turn to PHPCS, which can re-format the code correctly and clean up the imports. I chose to target just the .module file and the Hook classes:

vendor/bin/phpcbf --standard=Drupal --extensions=php,module path/to/my_module/src/Hook
vendor/bin/phpcbf --standard=Drupal --extensions=php,module path/to/my_module/my_module.module

At this point, you should run your tests to confirm everything works, but the conversion should be complete.

You can of course now choose to do further refactoring on your hooks class, such as splitting it into multiple classes for clarity, moving helper functions into the class, or combining multiple hooks.

joachim

23 Jan 2026 11:49am GMT

19 Jan 2026

feedSymfony Blog

SymfonyLive Paris 2026: “Édition simultanée : Facile avec Symfony UX“

SymfonyLive Paris 2026, conference in French language only, will take place from March 26 to 27! The schedule is currently being revealed as we go along. More details are available here. 🎤 Nouvelle talk annoncé à SymfonyLive Paris 2026 ! Avec…

19 Jan 2026 11:00am GMT

18 Jan 2026

feedSymfony Blog

A Week of Symfony #994 (January 12–18, 2026)

This week, Symfony development activity focused on improving the HTTP Cache attribute and making some changes to controller event attributes. Meanwhile, we published more information about the upcoming SymfonyLive Paris 2026 conference. Lastly, we introduced…

18 Jan 2026 8:18am GMT