Articles https://www.hashbangcode.com/ en Drupal 11: Making Interactive Elements With HTMX https://www.hashbangcode.com/article/drupal-11-making-interactive-elements-htmx <span class="field field--name-title field--type-string field--label-hidden">Drupal 11: Making Interactive Elements With HTMX</span> <p>HTMX is a JavaScript library that allows you to make ajax calls and create CSS transitions without writing any JavaScript code. It works by adding attributes to HTML elements, which it then uses to set up and perform ajax requests, swap elements, and a few other things.</p><p>It was added to Drupal in version 11.3.0* and gives developers the ability to create interactive elements using render arrays and HTML attributes. The intent is to replace the entire ajax sub-system with one built around HTMX, and there is quite a lot of work ahead to accomplish this task.</p><p>* Technically, HTMX has been in Drupal since 11.2.0, but only as an experimental library. Drupal 11.3.0 features the full HTMX library and a number of helper classes to make life easy.</p><p>In this article we will look at how HTMX is integrated into Drupal, and what services exist to help you use it within the Drupal system.&nbsp;</p><p>Since this article is quite long I have created a table of contents to assist in scrolling to the relevant sections.</p> <span class="field field--name-uid field--type-entity-reference field--label-hidden"><span>philipnorton42</span></span> <span class="field field--name-created field--type-created field--label-hidden"><time datetime="2026-03-15T19:01:54+00:00" title="Sunday, March 15, 2026 - 19:01" class="datetime">Sun, 03/15/2026 - 19:01</time> </span> Sun, 15 Mar 2026 19:01:54 +0000 philipnorton42 13817 at https://www.hashbangcode.com DrupalCamp England 2026 https://www.hashbangcode.com/article/drupalcamp-england-2026 <span class="field field--name-title field--type-string field--label-hidden">DrupalCamp England 2026</span> <p>The weekend of 28th February to the 1st March saw the second DrupalCamp England event with around 100 people attending the University of Salford, not far from Manchester, for the two day event.</p><p>I had submitted a talk and the camp organisers had accepted it and also decided to make me a featured speaker, which was an incredible honour. As such I was part of the communications being sent out in the weeks before the event.</p><p>Since this is more or less a local event for me I decided to travel in on both days rather than get a hotel or anything. The rain and wind of the previous week had abated and the Saturday morning saw some of the warmest (and driest) weather we had seen in the north west for a few months.</p><h2>Saturday</h2><p>The keynote on Saturday morning was <strong>The Augmented Future: Winning with AI</strong> with <strong>Dr. Phininder Balaghan</strong>, founder of <a href="proxy.php?url=https://traversally.ai">Traversally</a>. This was an look through the current state of AI, which Dr. Balaghan said changes every time he gives the talk.</p><p>Most companies these days have adopted an agile methodology, which has taken about 20 years to become widespread. Since the introduction of LLM AI systems a few years ago we have seen massive adoption across all industries.</p><p>Dr. Balaghan joked that we have reached the age of AI-gile, the new agile methodology.</p><p>At the moment we are using a collection of LLM agents that work together in a so-called "agentic" system to provide a coherent service. The next true advancement in AI systems will be thinking AI systems that are able to properly think about the input and respond. I think we are quite a long way from that yet and no amount of processing power or RAM is going to solve the problem that LLMs are just statistical word engines.</p> <span class="field field--name-uid field--type-entity-reference field--label-hidden"><span>philipnorton42</span></span> <span class="field field--name-created field--type-created field--label-hidden"><time datetime="2026-03-08T18:57:11+00:00" title="Sunday, March 8, 2026 - 18:57" class="datetime">Sun, 03/08/2026 - 18:57</time> </span> Sun, 08 Mar 2026 18:57:11 +0000 philipnorton42 13807 at https://www.hashbangcode.com Running An LLM With Llama.cpp Using Docker On A Raspberry Pi https://www.hashbangcode.com/article/running-llm-llamacpp-using-docker-raspberry-pi <span class="field field--name-title field--type-string field--label-hidden">Running An LLM With Llama.cpp Using Docker On A Raspberry Pi</span> <p>I've been curious about integrating AI agents into my workflow recently, and so I started looking at how this could be done using my current equipment. Data sovereignty is important to me so sending all my data to train a remote AI agent doesn't appeal. I was expecting to need to buy a new gaming rig with a couple of high end graphics cards in it, but after some research I found that this wasn't the case.</p><p>I found a system called <a href="proxy.php?url=https://github.com/ggml-org/llama.cpp">llama.cpp</a>, which is an efficient LLM engine written in C++. The idea behind llama.cpp is that you can host small, efficient AI agents without having to throw thousands at equipment to get them running. As I have a Raspberry PI model 5, with 16GB of RAM in my office I thought this was a good candidate to get running.</p><p>In this article we will look at how to get an LLM running on a Raspberry PI via a docker container, and what sort of things we might be able to do with it.</p><h2>Building The Docker Container</h2><p>The docker file here is pretty simple. We need to start from a base model of Debian, install some dependencies, and then download and compile llama.cpp. Here is my docker file.</p><pre><code class="language-plaintext">FROM debian:trixie ADD ./models /models RUN apt update &amp;&amp; apt install -y build-essential cmake git libcurl4-openssl-dev WORKDIR /opt/llama RUN git clone https://github.com/ggerganov/llama.cpp.git &amp;&amp; cd llama.cpp WORKDIR /opt/llama/llama.cpp RUN cmake -B build -DLLAMA_CURL=OFF &amp;&amp; cmake --build build --config Release ENTRYPOINT [ "/opt/llama/llama.cpp/build/bin/llama-server" ]</code></pre><p>The build option we are sending to llama.cpp is "LLAMA_CURL", which is turned off to prevent llama.cpp from being able to download models.</p> <span class="field field--name-uid field--type-entity-reference field--label-hidden"><span>philipnorton42</span></span> <span class="field field--name-created field--type-created field--label-hidden"><time datetime="2026-03-01T19:19:38+00:00" title="Sunday, March 1, 2026 - 19:19" class="datetime">Sun, 03/01/2026 - 19:19</time> </span> Sun, 01 Mar 2026 19:19:38 +0000 philipnorton42 13723 at https://www.hashbangcode.com Leaving Meetup.com And Extracting Past Event Data Without API Access https://www.hashbangcode.com/article/leaving-meetupcom-and-extracting-past-event-data-without-api-access <span class="field field--name-title field--type-string field--label-hidden">Leaving Meetup.com And Extracting Past Event Data Without API Access</span> <p>It's no secret that meetup.com have raised their prices over the last couple of years. Whilst this doesn't impact some of the larger user groups who have lots of members, it is basically killing smaller groups with no income streams.</p><p>I have no idea how tiny groups with less than 50 members can afford to pay £150+ every 6 months and pay for venues, refreshments, hosting space, and all the other things that a small group needs to pay for. That's not a fixed cost either, there's a good chance that meetup.com will increase their prices further.</p><p>The local Drupal user group I manage in Manchester is one of those groups affected. We just don't have the income or the user numbers to afford meetup.com any more. So, after 14 years we have stopped the subscription and the group will disappear from meetup within the next few weeks.</p><p>But what about those 14 years of events? They are stored in meetup.com and there is no way of getting hold of that data without API access; which costs a lot of money to get. I suppose I could just go through all those events and copy/paste the data into a CSV file, but surely there is a better way?</p><p>In this article I will show how I dug into the meetup.com site to see how the data was presented, and how I was able to MacGyver a solution in PHP to download the past data for the group as a CSV file.</p><h2>Digging Into The Data</h2><p>I can see a list of the old events on the page at <a href="proxy.php?url=https://www.meetup.com/nwdrupal/events/?type=past">https://www.meetup.com/nwdrupal/events/?type=past</a>, and as I scroll down the page the old events are loaded in as chunks. Note that this page might not exist when you read this article, but that's where the page <em>used</em> to be.</p><p>If we look at what is going on in the browser I can see that the data is loaded from the path <code class="plaintext">/gql2</code> with a payload that requests the next chunk of data from some sort of API layer.</p> <span class="field field--name-uid field--type-entity-reference field--label-hidden"><span>philipnorton42</span></span> <span class="field field--name-created field--type-created field--label-hidden"><time datetime="2026-02-15T18:51:31+00:00" title="Sunday, February 15, 2026 - 18:51" class="datetime">Sun, 02/15/2026 - 18:51</time> </span> Sun, 15 Feb 2026 18:51:31 +0000 philipnorton42 13792 at https://www.hashbangcode.com Kiwi Ears x Z Reviews Serene Wired Headphones: A Review https://www.hashbangcode.com/article/kiwi-ears-x-z-reviews-serene-wired-headphones-review <span class="field field--name-title field--type-string field--label-hidden">Kiwi Ears x Z Reviews Serene Wired Headphones: A Review</span> <p>The <a href="proxy.php?url=https://kiwiears.com/products/kiwi-ears-x-z-reviews-serene">Kiwi Ears x Z Reviews Serene</a> are a set of wired, closed back headphones that feature planar magnetic drivers. The headphones have been designed by <a href="proxy.php?url=https://kiwiears.com">Kiwi Ears</a> in collaboration with <a href="proxy.php?url=https://www.youtube.com/@ZReviews">Z Reviews</a>, hence the name.</p><p>Planar magnetic drivers are built differently to diaphragm or dynamic drivers found in most headphones.</p><p>Instead of a single diaphragm that vibrates using a coil and a fixed magnet, the planar magnetic drivers consist of a flat film that has a electrical conductor embedded in it. A set of electromagnets are used to vibrate this film, which is how it is able to produce sound.</p><p>The sound production is perhaps the most interesting aspect of planar magnetic drivers. Low frequency sounds are produced by vibrating the film at low frequencies; but high frequencies are produced by vibrating the film <em>in between</em> the vibrations of the low frequency sounds.</p><p>This means that planar magnetic drivers have very low distortion levels with a more accurate sound reproduction compared to dynamic drivers.</p><p>Whilst the film itself is lightweight the need for a field of electromagnets used to drive the film means that they tend to be a little heavier than normal drivers. They also have an increased power consumption and so aren't typically found in battery operated headphones or devices.</p><p>When Kiwi Ears approached me and asked if I wanted to review a set of planar magnetic headphones and I was intrigued. I had sampled a set of planar magnetic headphones in the past, but was keen to have a really good test of a them; especially from a company that I've come to trust with producing good quality headphones with decent audio reproduction.</p><p>In this article we will look at the Kiwi Ears x Z Reviews Serene headphones, their build quality, functionality, and how they sound.</p> <span class="field field--name-uid field--type-entity-reference field--label-hidden"><span>philipnorton42</span></span> <span class="field field--name-created field--type-created field--label-hidden"><time datetime="2026-02-08T20:22:49+00:00" title="Sunday, February 8, 2026 - 20:22" class="datetime">Sun, 02/08/2026 - 20:22</time> </span> Sun, 08 Feb 2026 20:22:49 +0000 philipnorton42 13793 at https://www.hashbangcode.com Nothing Phone (3): A Review https://www.hashbangcode.com/article/nothing-phone-3-review <span class="field field--name-title field--type-string field--label-hidden">Nothing Phone (3): A Review</span> <p>Last year I was looking around for a new phone. I had been using a Samsung Galaxy S10+ for around 6 years and whilst that was a flagship phone at the time, I was looking for a bit of an upgrade.</p><p>The S10+ was struggling to take pictures that still looked good on modern hardware and couldn't make use of the newer 5G signals. Plus, my son was off to university and was looking for a new phone that was reliable (and didn't have a cracked screen).</p><p>I had seen Nothing when they released the Phone (1) back in 2022. It looked like an interesting phone, and I quite liked what the company was doing. Their subsequent models of phones and earphones were getting good reviews, and seemed reliable.</p><p>When they announced the new Phone (3) I bought it with 15 minutes of it going on sale. I really liked the design of the phone and found the addition of a glyph matrix interface (ie. a little monochromatic screen) on the back really interesting.</p><img src="proxy.php?url=https://www.hashbangcode.com/sites/default/files/images/nothing_phone3_back.png" data-entity-uuid="2306e031-15c1-4282-b2a4-00050ff1acc4" data-entity-type="file" alt="A full shot of the back of the Nothing Phone (3). Showing the three cameras, the glyph interface, and a number of other components under the glass cover on the back." width="1000" height="1073" class="align-center" loading="lazy"><p>I went for the black version, with 16GB RAM and 512GB storage stage.</p><p>In this article I'll go through the principle features of the Nothing Phone (3) and what I think about each. There's quite a lot to look at in the phone so I instead of writing pages and pages I'll just pick the main points.</p><h2>Nothing</h2><p>Nothing as a company really impress me. In just a few years they have gone from strength to strength with their products and brand. Their CEO, Carl Pei, has said that they only have a tiny percentage of the market share, but that has only increased year on year.</p> <span class="field field--name-uid field--type-entity-reference field--label-hidden"><span>philipnorton42</span></span> <span class="field field--name-created field--type-created field--label-hidden"><time datetime="2026-02-01T18:38:27+00:00" title="Sunday, February 1, 2026 - 18:38" class="datetime">Sun, 02/01/2026 - 18:38</time> </span> Sun, 01 Feb 2026 18:38:27 +0000 philipnorton42 13676 at https://www.hashbangcode.com Drupal 11: Finding A Better Way To Display Code Examples https://www.hashbangcode.com/article/drupal-11-finding-better-way-display-code-examples <span class="field field--name-title field--type-string field--label-hidden">Drupal 11: Finding A Better Way To Display Code Examples</span> <p>I've been running this site for about 18 years now and the code I post has been in much the same format since it was started. The code is rendered onto the page using a <code class="plaintext">&lt;code&gt;</code> element and (mostly) syntax highlighted using a JavaScript plugin.</p><p>I make use of sites like <a href="proxy.php?url=https://codepen.io/">Codepen</a> and <a href="proxy.php?url=https://jsfiddle.net">JSFiddle</a> quite a bit, and often link to those sites to show examples of the code in use. Those sites got me thinking about the static nature of the code examples on this site. I have been writing more front end code recently, but static code examples aren't the best way of showing these features in action. I can (and have) uploaded images and gifs of the feature in action, but those images are many times the size of the code examples in question and serve only to bloat the page.</p><p>What I would really like to do is allow active code examples, or a code sandbox, to be injected into the page. This would allow users to interact with code examples rather than them just being static. Clearly a valuable learning tool for any site.</p><p>I know that it's possible to embed Codepen examples into a page, but not only does that require a premium subscription, it also creates a disconnect between the code and the content on the site. I wanted a solution that would allow me to write the article and the code examples all within the back end of the Drupal site.</p><p>Hosting code examples on a third party site also comes with some risk as if that site went offline then all of the code examples on my site would stop working. By self hosting I can make the editing experience better and also ensure that everything works correctly.</p><p>What I needed for the site now was some form of code sandbox that could be used to demonstrate simple JavaScript and CSS code without being tied to a third party supplier. I therefore did some searching around to find a suitable container for the code.</p> <span class="field field--name-uid field--type-entity-reference field--label-hidden"><span>philipnorton42</span></span> <span class="field field--name-created field--type-created field--label-hidden"><time datetime="2026-01-18T19:13:40+00:00" title="Sunday, January 18, 2026 - 19:13" class="datetime">Sun, 01/18/2026 - 19:13</time> </span> Sun, 18 Jan 2026 19:13:40 +0000 philipnorton42 13734 at https://www.hashbangcode.com Drupal 11: Theming The Search API Search Input https://www.hashbangcode.com/article/drupal-11-theming-search-api-search-input <span class="field field--name-title field--type-string field--label-hidden">Drupal 11: Theming The Search API Search Input</span> <p>A common request I see when theming Search API forms is to swap out the normal submit element with a magnifying glass icon. Performing this action isn't difficult, but it does require adding a couple of operations to add a suggestion so a custom template can be used.</p><p>When I set up a view to perform a search against a Search API index I normally create an exposed filter for the text content. Views shows this as a block that can be embedded into the site. The block, however, comes with a input element to act as the search button, and it isn't possible to inject SVG icons into input elements.</p><p>By changing the input element to a button we can then inject a small SVG of a magnifying glass or similar to act as the search button.</p><p>Swapping out this input element takes a couple of steps, and I although I have done this technique a few times I still need to dig into old code to figure out how I did it. So, I thought I would document it so I didn't have to go looking for the solution again.</p><p>In this article I will look at how we can use a combination of form alters and suggestion hooks to change the Search API form submit input to a button so that an SVG can be embedded inside.</p><h2>Altering The Search Form</h2><p>The first step (and perhaps the trickiest) is to alter the search form to add a couple of attributes to the search submit element.</p><p>If we add a theme suggestion alter hook for the input element, the element itself has no knowledge of the context that surrounds it. This makes it tricky to know that we are altering the correct element or even to inject a suggestion that would be unique for the search form.</p><p>The form alter hook, therefore, is used to inject an attribute into the form element so that we can read this in the suggestions hook. This gives is a bit of data we can identify and use in the suggestions hook.</p> <span class="field field--name-uid field--type-entity-reference field--label-hidden"><span>philipnorton42</span></span> <span class="field field--name-created field--type-created field--label-hidden"><time datetime="2026-01-04T18:31:53+00:00" title="Sunday, January 4, 2026 - 18:31" class="datetime">Sun, 01/04/2026 - 18:31</time> </span> Sun, 04 Jan 2026 18:31:53 +0000 philipnorton42 13719 at https://www.hashbangcode.com Drupal 11: Controlling LED Lights Using A REST Service https://www.hashbangcode.com/article/drupal-11-controlling-led-lights-using-rest-service <span class="field field--name-title field--type-string field--label-hidden">Drupal 11: Controlling LED Lights Using A REST Service</span> <p>Following on from my article looking at the <a href="proxy.php?url=https://www.hashbangcode.com/article/creating-better-led-lights-pimoroni-plasma-2350-w">Pimoroni Plasma 2350 W</a> I decided to do something interesting with the Wifi interface that would connect to a Drupal site.</p><p>The firmware of the Plasma 2350 W from Pimoroni comes with an example that connects to a free API to update the colour randomly. Once I saw this in action I realised that it shouldn't be too hard to convert that to pull the data from a Drupal REST service instead.</p><p>It is quite easy to create RESTful services in Drupal; it just needs a single class. All I would need to do is create a form to control the colour that is selected in the REST service.</p><p>In this article we will look at creating a Drupal module containing a RESTful interface, which we will connect to with the Plasma 2350 W to update the colour of the lights.</p><h2>Setting Up The Form</h2><p>In order to allow the colour of the LED lights to be set I needed to create a form that would do just that.</p><p>To save the colour to the system we will use the <code class="plaintext">state</code> service, which is a handy little key/value service that allows us to write simple values to the database. This service is a good way of storing values that aren't part of the Drupal configuration system. Ideally, you want values that can be easily recreated by the system if they don't already exist. The colour setting is therefore an ideal candidate for the state service.</p><p>Setting the form up with this service injected is simple enough, but we can also simplify the form integration by abstracting away the get and set methods for the state itself.</p><p>This is what the basic structure of the form class looks like.</p> <span class="field field--name-uid field--type-entity-reference field--label-hidden"><span>philipnorton42</span></span> <span class="field field--name-created field--type-created field--label-hidden"><time datetime="2025-12-21T18:46:34+00:00" title="Sunday, December 21, 2025 - 18:46" class="datetime">Sun, 12/21/2025 - 18:46</time> </span> Sun, 21 Dec 2025 18:46:34 +0000 philipnorton42 13727 at https://www.hashbangcode.com Creating Better LED Lights With The Pimoroni Plasma 2350 W https://www.hashbangcode.com/article/creating-better-led-lights-pimoroni-plasma-2350-w <span class="field field--name-title field--type-string field--label-hidden">Creating Better LED Lights With The Pimoroni Plasma 2350 W</span> <p>It's that time of year again (Decemberween) so I was looking around for a set of addressible LED string lights to set up.</p><p>When you get a set of LED lights from your local supermarket they will often be either a single circuit or a set of multiple circuits. This means that they are either all on, or can alternate in a set number of patterns. This is frankly rather dull.</p><p>What supermarkets don't have is addressible LED string lights. In these lights each LED on the wire can be address individually to set the colour or brightness. You can tell if the lights are addressible as they will have three cables, two for power, and one for communicating with the lights.</p><p>During my search I found the Plasma 2350 W, from <a href="proxy.php?url=https://shop.pimoroni.com/">Pimoroni</a>, which can be paired with a number of different sets of LED string lights. I picked up the <a href="proxy.php?url=https://shop.pimoroni.com/products/plasma-2350-w?variant=54829890634107">Plasma 2350 W and a set of 66 stars</a> on their store. This is probably the simplest way of getting started with the board.</p><p>Here's an image of the front of the Plasma 2350 W.</p><img src="proxy.php?url=https://www.hashbangcode.com/sites/default/files/images/plasma_2350w_chip_front.png" data-entity-uuid="8444bdce-765b-4db9-9325-850c8302534e" data-entity-type="file" alt="An image of the front of the Plasma 2350 W board. It is connected to power and the light in the top right is lit up green." width="750" height="324" class="align-center" loading="lazy"><p>And the back.</p><img src="proxy.php?url=https://www.hashbangcode.com/sites/default/files/images/plasma_2350w_chip_back.png" data-entity-uuid="014ad687-6d35-44d8-b0e9-f44a68153959" data-entity-type="file" alt="An image of the back of the 2350 W board. Showing the different pins available." width="750" height="310" class="align-center" loading="lazy"><p>Here's an image of the star shaped LED lights, taken against a wall.</p> <span class="field field--name-uid field--type-entity-reference field--label-hidden"><span>philipnorton42</span></span> <span class="field field--name-created field--type-created field--label-hidden"><time datetime="2025-12-14T20:17:31+00:00" title="Sunday, December 14, 2025 - 20:17" class="datetime">Sun, 12/14/2025 - 20:17</time> </span> Sun, 14 Dec 2025 20:17:31 +0000 philipnorton42 13717 at https://www.hashbangcode.com