The Evolution of a 20-Year-Old Single-Page Blog to an Automated, Scalable, Future-Proof Machine

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 single page had become much too large and difficult to maintain
  • The client did not want twenty years of bookmarked, hash-marked links to break
  • The site never benefited from SEO, as the content was a single unindexed page
  • The browser’s built-in search features would need to be matched for directory search

The Approach

The guidelines I followed and the approach I took to solve the problem ensured:

  • the single-paged hash navigation would continue working for existing content;
  • each blog would become an SEO-friendly page contained within an iframe;
  • forward and backward navigation would use PHP to generate the links;
  • a PHP-based search feature would be used for content search in the newly-created blog pages;
  • and that new files would automatically appear in the interface using PHP and JavaScript.

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:

Original HTML Input from a single table row

JSON Output:

JSON Output for processing in HTML page

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.

HTML with link formatted for iframe content

The Process

Once broad strokes were agreed, I managed to ensure the following:

  • every blog post contained required fields used to generate source JSON and page names
  • minor automatable edits regarding anchor linking and the target attribute were made
  • all of the files would live in a single directory and all assets were reachable using existing relative paths

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.

processHtmlFiles (PHP)

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:

processHtmlFiles continued (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:

inited, rewriteArticles, articlize (JS)

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:

hashChanged, updateNav (JS)

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:

pageHeader, wrapLink (JS)

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:

runSearch (JS)

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:

searchHtmlFiles (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:

findArtilcesFromData (JS)

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:

Launching PHP Server from 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.

要查看或添加评论,请登录

Kevin Ready的更多文章

社区洞察

其他会员也浏览了