• Skip to main content
  • Skip to primary sidebar
Martin Taylor

Martin Taylor

PHP, CSS, MySQL and WordPress tips and techniques

Populating Alpine data in a PHP page (part 2)

Posted on March 16, 2024

In my previous post on this topic, I described a way to transfer data into an Alpine component, if the page has been rendered by PHP on the server.

This is often going to be the situation when I’m using Alpine JS to add some interactivity to the page. For example, Alpine might need the data in an x-show condition, in an x-model input field, or to drive dynamic CSS with x-bind.

An alternative, of course, is to fetch the data from an API after the page has loaded. But this would be duplicating time and effort. PHP has already rendered the page, including the data I need, so it’s just a matter of getting the data over into the Alpine variables.

The solution I’ve devised is x-json, an Alpine custom directive. The code for the directive is in my previous post, and now I just want to give a bit more detail on its usage.

The directive is applied to a JS script element, containing JSON data, that PHP must first render into the page. Again, my previous post gave an example of how this is done, but you would end up with something like this in your page. One important note – this script must be inside the x-data scope that you want to populate.

<script type="application/json">
{"student":{"name":"Sue","age":32"},"locations":["Paris","London"]}
</script>

In this case the data is an object, consisting of two named objects. One is an object with student data, the other an array of locations. I want to put all of that data into this Alpine component:

  Alpine.data('mydata',() => ({
    student: {},
    locations: [],
  }))

Note that the names of the Alpine properties must match the names in the JSON object. I don’t see this as a serious constraint, and it keeps things simple.

Now to connect things up, I simply add the directive to the script tag:

<script type="application/json" x-json>

Now the directive will copy the JSON data into the Alpine component. Remember that the script must be placed inside the x-data scope for the component.

If for some reason I don’t want to copy all the data – say just the student object, then I add a modifier to the directive.

<script type="application/json" x-json.student>

Maybe the locations array has to go in an Alpine store, so I add another x-json directive, this time with the store name (prefixed by a colon) and a modifier.

<script type="application/json" x-json.student x-json:mystore.locations>

I can chain several modifiers together, so (if the JSON also contained a ‘lessons’ object for the Alpine store), I could do this:

<script type="application/json" x-json.student x-json:mystore.locations.lessons>

One last thing – the directive runs after the x-init and init() functions. If you need to do some processing after the JSON data arrives in the component or store, you can nominate a callback function. Maybe something like this:

<script type="application/json" x-json.student="switch()">

The ‘switch()’ function in the Alpine component will now be called after the student data is copied in. Note that if you want to use a function in an Alpine store, you have to supply the fully qualified function name. If you just supply a function name, it refers to a function in the current data component.

<script type="application/json" x-json:mystore.locations="$store.mystore.storeLoaded()">

And that’s it … for now. If I develop any new features, I’ll post them here.

Filed under: Alpine

Thoughts on Tailwind CSS

Posted on March 15, 2024

While following YouTube tutorials on frameworks such as Vue.js, I’d often find that the presenter was using Tailwind CSS. Of course, the tutorial focus wasn’t on styling, but it seemed to me that Tailwind was worth a deeper dive. Now I’ve had the chance to do that.

This isn’t a full review of Tailwind, let alone a tutorial – just some thoughts and opinions. Bear in mind that I’m primarily a PHP developer, although I’ve recently acquired a keen interest in using Alpine JS to spice up the web front end. So the majority of my pages are server-side rendered, with some styling changes applied dynamically by JS.

It took me a while to understand how to use Tailwind in a conventional web project. Although there is a CDN version, it’s intended only for experimentation, and they even label it “Play CDN”. The only other alternative appeared to be to use npm to install and control Tailwind, which (wrongly) led me to the conclusion that it was designed for use with a compiled framework such as Vue.js.

Eventually, though, I found and followed the instructions to install and use the Tailwind CLI without Node.js. I did this in the Linux container on my Chromebook, where I use VS Code, and to be fair, it was pretty straightforward. As a note, the VS Code extension for Tailwind is well worth installing, too.

Tailwind is a huge library of low-level CSS classes – almost all the classes contain just one declaration. So the Tailwind class ‘block’ is simply ‘display:block’, and Tailwind class ‘p-1’ is just ‘padding: 0.25rem’. Incidentally, this is why the CDN version weighs in at 111KB – all those classes add up.

Because the classes are so low-level, you have to combine them on each element. Here’s a typical example.

<h4 class="font-bold mt-12 pb-2 border-b border-gray-200">

I’ll be honest, I don’t like this much. It isn’t far removed from using inline styles, and poses a real risk to reuse. If I have five or six h4 elements on a page, with this approach, the chances are that I’ll get one of them slightly wrong; and if they all need changing to a different shade of grey, that’s more work than I want.

To counter this, Tailwind has an @apply directive, that can be used to map a conventional CSS selector to a list of Tailwind classes.

h4 {
  @apply font-bold mt-12 pb-2 border-b border-gray-200;
}

OK, this answers the reuse question, but it’s a bit of a hybrid that dilutes the Tailwind approach, and in fact the Tailwind docs argue that you should avoid it wherever possible. For me, I would just use standard CSS in this situation anyway.

So I’ve already seen enough to tell me that I won’t be using Tailwind, but what features did I like?

As you add classes to your HTML, Tailwind generates a CSS file that exactly matches. There are no redundant classes, no awkwardly named classes, and there’s no risk of conflicting rules. I recognise all three of these situations.

I also quite liked the Tailwind approach to responsive styling, using a simple modifier on a class to have it apply only at a given breakpoint. So using an example from the docs:

<!-- Width of 16 by default, 32 on medium screens, and 48 on large screens -->
<img class="w-16 md:w-32 lg:w-48" src="...">

I’ve ended up wondering if Tailwind is best for people who prefer not to get their hands dirty with CSS, and for whom the busy HTML class lists are not an issue.

And finally, I do have one use case where I might just get a benefit from Tailwind. If I’m mocking up a page and don’t want to go to the effort of defining my own CSS rules, Tailwind does have an advantage over inline styles. But that’s as far as I would go with it. Otherwise, it’s a sledgehammer / walnut situation as far as I’m concerned.

Filed under: CSS

Understanding JavaScript assignments

Posted on March 3, 2024

I’ve recently been using JavaScript a lot, while trying out Vue JS and Alpine JS in particular.

Something that often led to confusion was the result of assigning one variable to another. It sounds stupidly simple, but when it involves objects, it can lead to problems if it’s not done carefully.

After some research, during which I came across other people with misunderstandings, different interpretations and terminology, I know what’s going on.

Let’s start with a simple assignment of a string to a variable.

let Foo = "abc"

So JS creates a new value “abc” in memory. Then it creates a new variable “Foo”, and it connects the two. We can say that variable “Foo” is a pointer to the value “abc”.

Moving on, we’ll involve another variable.

Let Bar = Foo

Now JS creates variable “Bar”, but here’s the important bit … it doesn’t connect it with “Foo”. Instead, it makes “Bar” a pointer to the value “abc”. It’s a subtle difference, and in practice it doesn’t affect very much, but it’s important when we come on to considering objects rather than strings.

So now, in memory, we have one value “abc” and two variables “Foo” and “Bar”, both pointing to it.

On to the next step:

Foo = "xyz"

JS creates a new value “xyz” in memory, and changes “Foo” so that it points to this new value. Our other variable “Bar” is still pointing to “abc”, so it’s unaffected by this change to “Foo”. No surprises from a practical viewpoint – everything will work as expected. Let’s just finish off this section:

Bar = "efg"

This is familiar territory – JS creates a new value “efg” in memory, and changes “Bar” so that it points to this new value. The additional thing to note here, though, is that the value “abc” still exists in memory. But it has nothing pointing to it, and the JS garbage collector will be along at some point soon to get rid of it.

Now that’s clear, let’s move on to object assignment.

Let Foo = { name: "Joe", age: 32 } 

Under the covers, this actually results in several values being created, but let’s keep it simple and say that this object now exists in memory with “Foo” pointing to it.

Let Bar = Foo

Just as with the string example earlier, we now have “Foo” and “Bar” both pointing to the same object value. Don’t misunderstand – “Bar” is not pointing to “Foo” as such.

Bar.name = "Amy"

Now, this is the bit that can cause problems for the unwary. We just changed the “name” property of the object value that is shared by “Foo” and “Bar”.

console.log (Foo.name) 

This displays “Amy” in the console. So it looks like “Foo” has been changed as well as “Bar”. And for practical purposes, that’s the effect. But we know that it’s because they are both pointing to the same object value.

Just to prove the point, let’s reassign “Foo” and make it a string again.

Foo = "abc"

We already know what happens – a new value “abc” is created, and “Foo” is changed so that it points to it. But what about “Bar” – won’t that be affected? No – because “Bar” is still pointing to the object value with the name and age properties.

You regularly see mention of objects being assigned “by reference” and variables being somehow bound together. It’s not altogether true. Sure, variables can share values, but if we understand what goes on within JS, it helps us to maximise quality and develop better code.

Filed under: JavaScript

Populating Alpine data in a PHP page (part 1)

Posted on March 2, 2024

In a traditional PHP page, the server-side code gathers the data (e.g. from a database) and inserts it into the HTML. The browser needs to do nothing more than render the HTML it receives.

Now introduce Alpine JS to the page. Let’s say we have our data state defined like this:

 Alpine.data('mydata',() => ({
    student: {name: null, age: null},
    course: {name: null, location: null},
 }))

OK, but we want these two objects to be initialised with the student and course data from the server, so that it can be used, for example in x-show or x-bind.

We certainly don’t want to go back to the server, maybe to get the data from an API. We already got the data while the page was being built. So we need to put that data in the page somewhere that Alpine can use.

One way to do it would be for PHP to generate the data … something like:

 Alpine.data('mydata',() => ({
    student: <?php echo $student_object; ?>,
    course: <?php echo $course_object; ?>,
 }))

That would work, but often enough the data isn’t defined inline. It’s held in a standalone JS file, so it’s awkward to use PHP to fill in the gaps.

An effective solution is to provide the data as JSON, in a script element on the page. Then we just have to parse the JSON data and copy it into the Alpine data properties.

So – step 1: Generate the script element.

<?php
$student = get_student();
$course = get_course();
$jdata = [
  'student' => $student,
  'course' => $course,
];
?>
<script type="application/json">
<?php echo json_encode($jdata); ?>
</script>

Step 2 is to grab the script element, parse the JSON and copy over to the Alpine properties. There are plenty of ways to do this, but I wanted something I could reuse, so I put together a custom Alpine ‘x-json’ directive.

To use it, we just add x-json to the script element. In this most basic usage, the directive takes the objects it finds in the script element, and copies them over to the same-named objects in the Alpine data.

<script type="application/json" x-json>
<?php echo json_encode($jdata), PHP_EOL; ?>
</script>

In our example, this will take the student and course objects from the script, and copy them to the student and course properties in Alpine data.

The directive is capable of rather more than that, but I’ll describe it in full in Part 2.

Meantime, here’s the directive code.

document.addEventListener('alpine:init', () => {
  Alpine.directive('json', (el, { expression, modifiers, value }, { evaluate }) => {
    const jdata = JSON.parse(el.innerText)
    if (!modifiers.length) modifiers = Object.keys(jdata)
    const dest = value ? Alpine.store(value) : Alpine.$data(el)
    for (let m of modifiers) {
      dest[m] = jdata[m]
    }
    if (expression) evaluate (expression)
  })
})

Filed under: Alpine, PHP

Alpine JS

Posted on March 2, 2024

I’ve recently been trying out a number of JavaScript frameworks. My goal is to liven up the front-end user experience on a couple of the sites that I work on.

I got a fair way down the track with Vue.js, and was impressed with what it can do. Ultimately, though, I decided that it was slightly over the top for what I needed. I didn’t need to go to a full SPA, but Vue was leading me towards that. I could of course just use Vue’s CDN script to plug in to existing pages, but you get the best out of Vue if it’s compiled and that was getting too complicated.

I then discovered Alpine JS, which is a lightweight JS framework that delivers reactivity on the client. Alpine claims that its objective is only to supplement server-side-rendered pages, and not to replace them. In my case, having the pages built mainly in PHP and then having Alpine added to them made sense, and it works really well.

Alpine comes with a range of directives that you add to your HTML elements, and they provide a high percentage of the needs. Many of these are similar to Vue or Angular. For example, adding the x-show attribute to this div means that it will only be shown if the loginError variable is true.

<div x-show="loginError">Your user name / password were not recognised</div>

A bonus with Alpine is its extensibility, so if the out-of-box directives are not enough, it’s straightforward to define new ones with custom functionality.

I plan to post some Alpine examples, extensions and experiences here.

Filed under: Alpine

PHP Calendar Class using relative dates

Posted on July 16, 2021

After correcting the error in my calendar class (see PHP Calendar Class revisited), I’d been wondering whether the code could be further simplified. Some of the calculations were a bit on the arcane side, even if they now worked OK.

The solution lay in PHP’s relative date formats, which can be used when instantiating or modifying a DateTime object.

Given that we always display full weeks (Monday to Sunday), the two key dates needed for the calendar are the first Monday to display, and the last Sunday to display. It’s more than likely that these are in the previous / next months, rather than the month in focus. For a July 2021 calendar, for example, the first Monday is June 28; and the last Sunday is August 1.

It turns out that PHP is eyebrow-raisingly helpful at deriving these two dates.

For the first Monday, what we need is the Monday that precedes the second day in the month. The first day of the month might itself be a Monday, so we allow for that by starting at the second day. Here’s an example, which shows how straightforward it is, and also that we can chain the function calls on a single line of code:

$year = 2021;
$month = 7;
$start = new DateTime();
$start->setDate($year, $month, 2)->modify('previous Monday');

$start is now set to June 28; and exactly as you’d hope, when we try it for November, $start is set to November 1. I’ve no idea what machinations are going on behind the scenes but the point is that my code is radically more simple and understandable. If there is a performance hit, it’s negligible, given that I’m only incurring it once per page.

Here’s how we get the last Sunday to be displayed. We need the first Sunday after the last-but-one day in the month. Note that setDate() conveniently allows you to have negative days, so we first add 1 to the month, and then use -1 as the day number, which steps back two days from day 1 of that month.

$end = new DateTime();
$end->setDate($year, $month + 1, -1)->modify('first Sunday');

Note that PHP uses “first” here to get the first Sunday after the date, which is perfect for our needs.

I’ll be updating my calendar class to use this new approach.

Filed under: PHP

PHP Calendar Class revisited

Posted on July 14, 2021

I found today that my PHP Calendar Class didn’t cope at all well with months that span more than five weeks. August 2021 is a good example – it covers six Monday-to-Sunday weeks, and my code was assuming that it would only need to worry about four or five such weeks.

I’ve now updated the code in the original post.

Filed under: PHP

Wildcard subdomains in XAMPP

Posted on June 15, 2020

For some time now I’ve been using subdomains in XAMPP, here on my own Win10 PC, for a few of my test sites. It obviously makes things much more realistic when testing functionality.

What I didn’t realise until recently, though, was how much easier this can be made by implementing wildcard subdomains. Any folder inside the web document root is automatically available as a subdomain. You just open a browser to ‘foldername.localhost’ and it’s done.

Not sure why I did, but I chanced upon http://www.sintesisdigital.com.mx/dashboard/docs/configure-wildcard-subdomains.html which gives all the details of how to achieve this.

Incidentally, I found that I didn’t even need to update the hosts file, and while I’d have been OK with doing that, it saves even more time.

Filed under: General

MySQL – retrieving rows with one column as key

Posted on June 13, 2020

Getting results back from MySQL as an array is of course easy enough, using fetch_all in MySQLi or fetchAll in PDO. You get back an array of rows, and you can loop through it as necessary.

This result array is numerically indexed, from element 0 upwards, reflecting the ORDER BY clause in the query.

Element 0 = array of columns from first row
Element 1 = array of columns from second row, and so on

Fair enough, and often that’s exactly what you want, but what if you want to use the array as a lookup? I’ve encountered that situation several times, where I have a table with key / value pairs, for example, and I want to bring it into memory so that I can use it in my PHP code. Something like this, for example:

Region IDRegion name
EUEurope
USUnited States of America
APAsia Pacific

PDO provides a really useful option to handle this. The code is something like this:

$sql = 'SELECT region_id, region_name FROM regions';
$result = $this->db->query($sql)->fetchAll(PDO::FETCH_KEY_PAIR);

Note the PDO::FETCH_KEY_PAIR option – it causes the array of rows to be a perfectly formed key/value structure:

[
“EU” => “Europe”
“US” => “United States of America”
“AP” => “Asia Pacific”
]

And now I can use the array as a lookup.

Just recently, though, I came up against a need to have several columns in the lookup array. The situation was a query using GROUP BY, returning counts and sums from a database table based on a number of criteria.

So I wanted a lookup array with a key (as above), but with several columns in each element. For simplicity, let’s say we have a third column (Manager) in the region table, so the query is this:

SELECT region_id, region_name, manager FROM regions

Now, FETCH_KEY_PAIR can’t do this. It will only handle a query with two columns – one to be the key and one to be the value. Well, maybe it could … you might use CONCAT_WS, so that there are only two fields:

SELECT region_id, CONCAT_WS(‘,’ region_name, manager) FROM regions

But let’s stick with the original query. I’d started out by looping through the result and building a second indexed array. It worked, but it looked untidy so I looked around for a more concise approach. The answer, it turns out, is PHP’s array_column() function, which includes an option to reindex an array by one of its columns. Perfect for this situation!

So we code things like this:

$sql = 'SELECT region_id, region_name, manager FROM regions';
$result = $this->db->query($sql)->fetchAll(PDO::FETCH_ASSOC);
$regions = array_column($result, null, 'region_id');

And the resulting $regions array is structured like this:

[
“EU” => [“region_id”=>”EU”, “region_name”=>”Europe”, “manager”=>”Alicia”]
“US” => [“region_id”=>”US”, “region_name”=>”United States of America”, “manager”=>”Tony”]
“AP” => [“region_id”=>”AP”, “region_name”=>”Asia Pacific”, “manager”=>”Leanne”]
]

Note how the region id remains in the array of columns on each row, but that’s a minor inconvenience – the result is what I needed.

Filed under: MySQL, PHP

CSS-only menus in WordPress

Posted on May 26, 2020

I recently set myself the challenge of building a CSS-only menu (including sub-menu dropdowns) for a WordPress site. Why? Partly as an academic exercise, but partly in an attempt to reduce what appeared to be a too-busy combination of CSS, JS and PHP in the site and theme as it stood.

All this of course in contravention of the well-established KISS principle, but hey … we’re in lockdown and it’s good to have something to occupy the little grey cells.

One thing I soon discovered is that if you need a dropdown menu, you’ll be relying on the so-called “CSS Checkbox Hack”. The term “hack” isn’t quite fair, because the HTML and CSS used are perfectly legitimate and have valid use cases of their own. It’s just that there’s a no-doubt unintended way to use this particular feature of CSS.

There are scores of explanations of the checkbox hack on the web, so I’ll be brief. The idea is that you set up your HTML like this:

<label for="menu-toggle" class="menu-toggle-label">Menu</label>
<input type="checkbox" id="menu-toggle" class="menu-toggle">
<ul class="menu">
    <li>Blah</li>
</ul>

The label will be visible. The checkbox has to be hidden because it’s only there to trigger the action we need (and that’s the “hack”). The <ul> will initially be invisible.

Now, in HTML, if you click the label for a checkbox, it will toggle the checkbox’s “checked” state. And we can use that as a selector in CSS to drive a change in another element – for example to change the visibility of that <ul>. Here’s the relevant part of the CSS:

.menu, .menu-toggle {
    display: none;
}
.menu-toggle:checked + ul {
    display: block;
}

That second rule says that when menu-toggle is checked, find an adjacent <ul> and make it visible. Simple enough. So using the checkbox’s label effectively as a button causes the <ul> to appear and disappear.

The next challenge was to find a way to arrange WP’s menu HTML with the necessary labels and checkboxes. I think the only way to do this is to generate the HTML yourself, and the usual suggestion is to create an extension to the Walker_Nav_Menu class, where you can set up your own start/end HTML for the items and levels in the menu.

But that seemed like a tad too much complexity, so I went for a custom approach based on WP’s wp_get_nav_menu_items function. This brings back a sorted list of the menu items, each with a value defining its parent item, so you can work out what the submenu hierarchy is. By the way, I’d not realised until using this that the menu items are saved as posts in WP’s database.

The first bit of code here is where we grab the menu items and create an array of objects that reflect the hierarchy.

$menu_items = wp_get_nav_menu_items('primary-menu');
// Construct menu hierarchy
$menu = [];
foreach ($menu_items as $index=>$menu_item) {
	$parent = $menu_item->menu_item_parent;
	$menu_obj = new stdClass();
	$menu_obj->url = $menu_item->url;
	$menu_obj->title = $menu_item->title;
	if ($parent) { // Add submenu to parent object
		$menu[$lvl_index]->submenus[] = $menu_obj;		
	} else { // Make new parent object
		$menu[$index] = $menu_obj;
		$menu[$index]->submenus = [];
		$lvl_index = $index;
	}
}

We end up with an array of objects for the top-level menu items, each with an array of its submenu objects. Armed with this, we can generate the HTML. In my case, it looked like this. It’s a pretty straightforward iteration through the array and sub-menu arrays, shoving those labels and checkboxes in where necessary.

echo '<nav class="nav-primary">';
echo '<label for="menu-toggle" class="menu-toggle-label top-menu-toggle-label">Menu</label>';
echo '<input type="checkbox" id="menu-toggle" class="menu-toggle">';
echo '<ul class="menu menu-primary">';
foreach ($menu as $index=>$menu_item) {
	$has_submenu = count($menu_item->submenus);
	$classes = 'menu-item '.'menu-item'.$index;
	if ($has_submenu) $classes .= ' menu-item-has-children';
	echo '<li class="',$classes,'">';
	echo '<a class="menu-link" href="',$menu_item->url,'">';
	echo '<span>',$menu_item->title,'</span>';
	echo '</a>';
	if ($has_submenu) {
		echo '<label for="menu-toggle-',$index,'" class="menu-toggle-label">+</label>';
		echo '<input type="checkbox" id="menu-toggle-',$index,'" class="menu-toggle">';
		echo '<ul class="sub-menu">';
		foreach ($menu_item->submenus as $submenu_item) {
			echo '<li class="menu-item submenu-item">';
			echo '<a class="menu-link submenu-link" href="',$submenu_item->url,'">';
			echo '<span>',$submenu_item->title,'</span>';
			echo '</a>';
			echo '</li>';
		}
		echo '</ul>';
	}
	echo '</li>';
}
echo '</ul>';
echo '</nav>';

And hey, it works. But I decided against using it.

A few reasons for that.

First – it uses an unintended consequence of a CSS feature, and it puts checkboxes into a page that no user will ever see. That’s not what checkboxes are for.

Second – I still hold to the principle that CSS is for styling and JS is for functionality. This approach blurs that line.

Third – a JS approach allows me to do more with the HTML, like adding classes to dropdowns when they are visible … I can’t see a way to do this with CSS alone.

So all-in-all, a good exercise with some useful lessons.

Filed under: CSS, PHP, WordPress

  • Page 1
  • Page 2
  • Go to Next Page »

Primary Sidebar

Recent Posts

  • Populating Alpine data in a PHP page (part 2)
  • Thoughts on Tailwind CSS
  • Understanding JavaScript assignments
  • Populating Alpine data in a PHP page (part 1)
  • Alpine JS

Copyright Martin Taylor © 2025