Coconut Tickets WordPress to Laravel Migration – part 3

Part 3 – Technical Migration
In the last 2 parts of
we explored the motivation behind taking the risk of migrating the successfully working Coconut Tickets platform from WordPress to Laravel and the strategy that was used. In this part we dive deeper into the technology and look at the big technical decisions that were taken. Identifying the boundaries between the Coconut Tickets plugin and WordPress itself was critical to making the migration technical decisions. Using a combination of knowledge of our software and performing text searches for common WordPress function names (mainly starting wp) we analysed the use of the WordPress API with our plugin. This is where the yearly subscription to PHP Storm really delivered because we could find WordPress functions, and then (using PHP Storm) track their usage across the classes of the plugin which is more valuable than a simple text search. We identified the following areas that use WordPress directly and would need to be re-developed to work with Laravel.
Laravel has its own login functionality which can easily replace the WordPress login functionality. Unfortunately the plugin also relied on knowing which role the user had in the system and this is not standard behaviour in Laravel 5.7 so we needed to plan to add it. WordPress has a thin database layer (WPDB) that allows raw SQL commands and simple CRUD commands to be executed on WordPress native or custom tables. Our plugin already had its own thin database layer implemented on top of WPDB. Coconut Tickets is a transactional system with reporting (like many business applications) and therefore makes a lot of use of the MySQL database in WordPress. To rewrite the complete database layer to the Eloquent ORM in Laravel would take hundreds of man-hours. The use of WPDB is closer to the PHP standard PDO database service than it is to Eloquent and Laravel also supports PDO. Therefore, it was decided to rewrite our own thin database layer to use PDO directly rather than to use Eloquent. That would save time when bulk migrating source code from the WordPress plugin and still left open the possibility that any new modules could be written to use the Eloquent ORM. Coconut Tickets uses the WordPress subscription management plugin PMPro. Even though the plugin is open source it is tightly integrated with WordPress, and we thought there would be little value in migrating it to Laravel. Luckily there is a Laravel package called “Cashier” for building subscription management functionality. Cashier provides a good back-end for subscription management but doesn’t have any user facing functionality (not even a page for the user to enter his subscription request) therefore we needed to plan to build that ourselves. Also, the services an event manager would have access to in Coconut Tickets is dependent on the subscription plan he has signed up for, this was more functionality that needed to be built. The main class in the WordPress plugin receives notifications of WordPress hooks and actions and then decides which modules to call within the plugin. This class is effectively a controller and would be replaced by a single Controller class in Laravel. This was cheating a little because it would have been better to refactor this into several controllers but the overall strategy of getting something working first took precedence. The main class file is also responsible for loading CSS and JS files into the application at run time, this were easily replaced with link and script statements in Laravel blade files. WordPress offers an easy way to make admin pages for a plugin but it is very specific to WordPress. These pages were used by Coconut Tickets to help the operations team manage the application and manage the subscribed users. All this functionality needed to be re-written for Laravel. The many JavaScript modules in Coconut Tickets communicate with the WordPress plugin via Ajax calls. In WordPress, it is necessary to register which Ajax calls a plugin wishes to allow and which functions will be called by the plugin as a result. These Ajax calls can be either privileged (i.e. the user must be logged in first) or non-privileged (i.e. free public access). Laravel also supports receiving Ajax calls but doesn’t implement the same access management as WordPress. Again in the spirit of getting something to work, it was decided to build a Controller class in Laravel that would emulate the WordPress Ajax functionality and therefore avoid disrupting the existing JavaScript code. Our research told us that to do this would require adding an API token to each user in Laravel to provide the security for privileged Ajax calls as this is not present in standard Laravel. WordPress has good functionality for storing and retrieving image and document media. This includes processing a raw image to produce images in different sizes such as thumbnails. An equivalent is not available in a standard Laravel 5.7 implementation. There are a number of Laravel media management packages but they are quite complicated compared to the WordPress model and it would have been difficult to migrate the data from thousands of images already stored on WordPress. Once again it was decided to build a replacement in Laravel. This would be a module that would offer a similar API to the WordPress media manager but would use Laravel features (e.g. controllers and Eloquent ORM) to deliver the service. We also needed to write a migration tool to convert the WordPress media data into our new format. A real compromise was reached for the Coconut Tickets blog and tutorial pages. WordPress is a good CMS and although there are equally good CMS tools built with Laravel, it was decided to simply leave the blog and tutorial pages on WordPress for the first release. There would not have been any major advantage in migrating these pages to Laravel. One other important change was identified by knowing about Laravel applications rather than by analysis of the WordPress plugin. All the output to the page in Laravel should be part of the result returned by the route controller which would preferably involve a view implemented with a Laravel blade. To restructure the existing classes to call a blade for each page would have been a big change. Instead, we decided to create a few very basic views that would have an object passed to them that would do all the page rendering within the blade. In this way the “view” like classes from the WordPress plugin were passed to a blade and these were used to displayed pages with the minimum of re-development.
In the next post in this series we discuss how we migrated the WordPress plugins and theme.
Find out more about