Content Management Systems are great for managing content, with means to create, modify, and delete pages/posts easily. However, sometimes as developers we need to leverage the displaying of content outside of the normal system (read: user facing system). For example, Ninja Forms, the Drag and Drop Form Builder for WordPress, has a feature for previewing forms as they would be displayed in your theme. In order to display a preview of the form on the front end of the website we created a page, using the WordPress page post type, then filtered the content of that page with the contents of the form. This worked great during in-house development, however there are complications when deployed to 200,000+ user websites.
The problem with creating a new page for displaying our preview is that we are creating content within a user’s site that they may not want. While Ninja Forms relied on a CMS page for the form previews, website owners were deleting the page. Using the page post type to manage the preview page was giving users access to delete our functionality. As plugin developers it is our responsibility to architect solutions in a way that this does not happen.
If the process of creating a page inherently allows for that page to be deleted, and we must rely on the existence of that page for our plugin to function correctly, we have two options to consider.
The First Option
If the problem is the page being deleted, then it would be simple enough to add a check to see if that page exists, and if not, then re-create it. While this solves the issue of the page being deleted, it creates to problem of being counter intuitive for our customers. For a website owner, their deliberate action of deleting a page is being ignored which creates the concern of something being broken, as their CMS seems to be NOT deleting pages.
The Second Option
If creating a page is causing problems, then how can we create a page without actually creating a page? WordPress provides many hooks for interacting with the request cycle of a page. Leveraging these hooks allows us to dynamically modify content as needed; specifically, the filter
template_include allows us to override WordPress’ default template behavior. Using this filter, we can modify the page output with our preview page then filter the content with our preview content.
This solution requires at least two filters:
the_content. With these filters we are able to fallback to a compatible theme template and filter the content with our preview content.
The important part about the
template_include filters is that we need to ensure that we load an available theme template. We do not know what templates any given theme provides. However, we should be safe to assume that either
index.php (final fallback) will be available.
Additionally, I filter
the_title (for labeling) and
get_the_excerpt (as a fallback for content, as some pages may not have content but rather only an excerpt).
Now that we have a means for displaying our preview page, we need to make sure that our filters run intentionally and not on every page. A simple solution is to check for a query string variable in the URL:
Finally, an updated example: https://gist.github.com/kjohnson/b7877b886663a7e2c280