Using Liquid it is easy to access the chronologically previous/next page through a page attribute (see this example). But some articles will have a custom previous/next page that differs from the chronological one.

As of today, the solution I have applied to this is the following:

Custom Next/Previous Page in Front Matter

First, I add in the front matter the custom relative URL.

<!-- this markdown file -->
---
<!-- ... -->
previous_page_url : /2024/02/analytics-referral-spam
<!-- ... -->
---

Previous/Next Page Assignment in Post Layout

Then, I add to the layout code that assigns the correct page to consider in each case into the variables previous_page and next_page. All the code added after that point for links and titles will simply use these two variables.

<!-- _layouts/post.html -->
{% comment %}
  This is the assignment of the next/previous post variable 
  (if explicit in the front matter, use it, otherwise use the chronological one)
{% endcomment %}
{% if page.previous_page_url %}
  {% assign previous_page = site.posts | where: "url", page.previous_page_url | first %}
{% else %}
  {% assign previous_page = page.previous %}
{% endif %}
{% if page.next_page_url %}
  {% assign next_page = site.posts | where: "url", page.next_page_url | first %}
{% else %}
  {% assign next_page = page.next %}
{% endif %}

Conclusion

I still have to enter the correct relative paths in the front matter of each post. Something that isn’t convenient is that the front matter has to be modified for both the “next article” and the “previous one”, so for each “link” between articles we have to manually modify two files.

In the future, I might either change the setup and figure out a completely different approach, or maintain this approach but write a script that fills the front matter for me.