The Evolution of a 20-Year-Old Single-Page Blog to an Automated, Scalable, Future-Proof Machine
Or, Integrating Business Logic of PHP and JavaScript to Migrate a Ginormous Single Page App into a Single Page App with Nested Content
The Challenge
A client came to me with a request to modernize a single-page, two-decades-old blog that had grown unwieldy in size. The blog was a single HTML page with hundreds of internal links, each leading to a blog entry that consistently had a date, a title, an image, and an anchor link. The client wanted to maintain the hash navigation while removing the internal content and creating a scalable, future-proof solution.
The Problem
There were a few items to resolve to meet the client’s requirements:
The Approach
The guidelines I followed and the approach I took to solve the problem ensured:
When I received the files, no JavaScript or PHP existed. The machine where the content resided was mysql-php, so my typical node approach was not applicable here. After looking over the existing code and questioning the client about its formatting, it was noticed that the placement of the title, image, and date, following the anchor link, would enable the creation of a JSON Schema to support its inclusion in the client-side JavaScript.
Code Sample
From source code similar to this at the top of each blog post page, the following JSON output was created:
HTML Input:
JSON Output:
Within the original index.php file, the date values were used to create the names for the files generated from the blog posts. We decided on the format ‘date-yyyy-mm-dd.html’ to facilitate sorting. Using this approach, most of the original document was portioned into over 300 uniquely dated posts (i.e., date-2005-05-05.html, date-2024-11-21.html, etc.).
Each of these child blog pages shares styling and scripting assets. The way that they link to other blog content is by targeting _top in the anchor elements. In this case, the href would trigger the inclusion of the HTML page ‘date-2024-02-29.html’, as it is the filename referenced by anchorname.
The Process
Once broad strokes were agreed, I managed to ensure the following:
After ensuring the availability of the required content from the client, it was time to integrate PHP and JavaScript to provide a much friendlier and easier-to-manage interface.
The Code
Near the top of the document, PHP was required to search the directory and look up all of the HTML files that began with the ‘date-‘ prefix. These would be printed in reverse-chronological order, most recent first, within a SCRIPT element of the HTML page. PHP is used to generate the array that JavaScript uses later in the page.
Once I had an idea of what I wanted to do, it was time to get AI involved. I began by commenting out the description of the code that I was about to code in my IDE. Even if the AI does not help auto-generate code, documenting the code is generally appreciated. PHP is a language that I have used many times, but I was very appreciative of AI assistance when coding its occasionally unfamiliar syntax.
The PHP Block
The PHP block was used at the top of the page to scan the directory for HTML files.
Next, the specific HTML was vetted to ensure each file could be included in the navigation. For this to be the case, the preg_match functions find the anchorName, headerImage, and itemTitle in the HTML. Files must begin with ‘date-‘ to be included.
The regular expressions were challenging, but AI helped me iterate to get this to the version here. When I say, AI, I refer to several possible AI assistants I use. I have not differentiated whether CoPilot, Claude, or ChatGPT was used. The details in the output code came from prompts I created, and I ensured that the chosen AI helped author code that fit my requirements.
PHP:
In the code above, the results array is populated by JSON structures representing individual blog posts. The last line, written within the SCRIPT element of the HTML file defines the constant all_articles as an array of JSON objects. That echo statement puts the code into the purview of JavaScript.
领英推荐
The Handoff
Once PHP has created the JSON objects for JavaScript to use, due to the naming convention of the files (date-alphabetical order), both ordered and indexed methods of working with the content are available. The pages are still referenced and accessible through their hashmarked location (“anchorname”), and we can locate its fileName through its all_articles[anchorname][fileName] reference.
Loading the Page
The inited function is called after the PHP block defines all_articles. It uses rewriteArticles without a subset parameter, which means that all of the blog items will be used to generate li elements. Later, the subset parameter is used to provide a search return from a second PHP file.
JavaScript:
Helper Functions
The hashChanged function controls the presentation of individual blog pages and the entire or partial view of navigation elements. The updateNav function manages the available navigation items (previous, next, and search).
JavaScript:
Generating the Supporting HTML
The updateNav function has a timer to prevent delayed asset availability from affecting the navigation. In one-tenth of a second, the pageHeader is called and the revised navigation is available. The pageHeader includes the previous and next navigation elements, wrapped within wrapLink functions.
JavaScript:
Beyond Navigation: Searching for text within pages
When I first suggested the approach that I was taking and how it would achieve the same functionality as the existing page, I had not considered searching within the page. The client pointed out that in the browser, I could simply use Command+F within the single page to find text in any blog post. So the new quandary I faced was how to give that feature to the several hundred pages without using Node.js or server-side JavaScript. Again, it was time to use PHP in addition to vanilla JavaScript. First, the setup in JavaScript.
The JavaScript
In the pageHeader script above, is a form input labeled “searchText”. When the Search button is clicked, the runSearch function is called. This triggers a simple search for a text fragment in the searchHtmlFiles php page. If nothing is found, an alert advises the user. If one or more files contain the text fragment, a JSON array of matching files are found.
JavaScript:
The PHP
On the server, searchHtmlFiles.php processes the JavaScript request by searching each file for a case-insensitive match of the textFrag argument. It searches in reverse order so that the most recent blogs are at the top of the returned items. The results array is populated with each matching file name, and the json_encode function converts the text output to JSON.
PHP:
Back to JavaScript
In the runSearch function above, rewriteArticles is called with the array of URLs as the subset argument. That results in each element being processed with the findArticlesFromData function, which looks through all_articles to find if any have the URL as a fileName property.
JavaScript:
The Deliverable
Once the PHP and JavaScript were integrated, the client could navigate the blog posts the same way as before. The search feature was a welcome addition, and the client was pleased with the results. The client could add new content to the directory, and it would appear in the interface, no edits required. The client can search for text within the pages, and the search results are displayed as a list of blog posts. To ensure a known working record of the project, I created a docker image from the project that could be run on any machine with docker installed. The client was able to download the image and run it on their local machine to see the project in action.
Simple Dockerfile:
Debrief
When asked about the feasibility of doing what my client requested, keeping the hash-navigation while removing the internal content, I raised an eyebrow and said “It’s possible.” My intonation did not deter my client from pushing the request to its execution. My familiarity with PHP and ability to work with AI to fill in the gaps where my knowledge was insufficient ensured that it could be done cost-effectively. The project is live, and users enjoy the benefits of its fast load time, device support, and ease of use.
Kevin Ready is a coder, writer, and AI enthusiast working at remote and hybrid locations worldwide.