{"id":308,"date":"2017-09-29T14:59:32","date_gmt":"2017-09-29T20:59:32","guid":{"rendered":"https:\/\/laubsterboy.com\/blog\/?p=308"},"modified":"2018-12-07T13:00:45","modified_gmt":"2018-12-07T20:00:45","slug":"php-framework-wordpress-plugin","status":"publish","type":"post","link":"https:\/\/www.johnrussell.dev\/blog\/2017\/09\/php-framework-wordpress-plugin\/","title":{"rendered":"Using a PHP Framework or Library in WordPress Plugins and Themes"},"content":{"rendered":"<p>Anyone who has spent a fair amount of time creating WordPress Plugins or Themes has likely also come across the need to package a PHP framework or library inside a plugin or theme. On the surface this is a fairly routine thing to do &#8211; simply copy the file into your plugin or theme, or use composer. There are lots of plugins out there using various PHP libraries and frameworks.<\/p>\n<h2>The Problems Begin<\/h2>\n<p>I&#8217;ve personally started including a PHP framework that I&#8217;ve created to help make development easier and add some features that I repeatedly use from project to project. At first this is great, and development is humming along, but eventually you&#8217;ll likely run into some problems, like I did. When WordPress loads it loads each activated plugin alphabetically (based on the plugin directory), so let&#8217;s say we have two plugins &#8211; one called &#8220;Analytics&#8221; and one called &#8220;Cache&#8221; and both include the same &#8220;Utilities&#8221; framework. When&nbsp;<em>Analytics<\/em> is loaded it will load the&nbsp;<em>Utilities<\/em> framework, and when&nbsp;<em>Cache<\/em> is loaded (depending on how the <em>Utilities<\/em> framework is built)&nbsp;it will either skip loading&nbsp;<em>Utilities<\/em> because it&#8217;s already been loaded or everything will come crashing down due to &#8220;Fatal error: Cannot redeclare class\/function&#8221;. Assuming everything loaded properly, without any fatal errors, the&nbsp;<em>Utilities<\/em> framework is now loaded and available for use by&nbsp;<em>Analytics<\/em> and&nbsp;<em>Cache<\/em>, and you move on with development.<\/p>\n<p>In a closed system where you control the entire stack, all dependencies, plugins, and themes this isn&#8217;t a problem. However, with WordPress the idea is that any number of plugins or themes may be installed by the end user, and in this case the developer of a plugin or theme doesn&#8217;t have control over what other dependencies, plugins, or themes get installed. So, back to the example from above, what if&nbsp;<em>Analytics<\/em> needs version 1.0.0 of the&nbsp;<em>Utilities<\/em> framework and&nbsp;<em>Cache<\/em> needs version 2.1.0 of the&nbsp;<em>Utilities<\/em> framework? Knowing the order in which plugins are loaded we know that the&nbsp;<em>Analytics<\/em>&nbsp;plugin will successfully load the 1.0.0 version of&nbsp;<em>Utilities<\/em> that is packaged with it, but&nbsp;<em>Cache<\/em> will be stuck with version 1.0.0 as well.<\/p>\n<p>Assuming that the framework is just a simple class, one way around this problem is to rename the class based on it&#8217;s version, or namespace the framework based on it&#8217;s version. The problem with this solution is the implementation within your plugin or theme &#8211; each time the framework updates you have to update the calls to the framework, which makes maintenance a complete mess (not only for your plugin or theme but also for the developer of the framework). Making things worse, what if the framework is a package in itself, containing dozens of interface and class files?<\/p>\n<p>As a quick side note, one could argue that the chances of this exact situation happening is quite unlikely. However, I think there&#8217;s a strong case to be made for plugin developers who make multiple plugins that are relevant to the same audience actually running into this problem. Especially if the plugin end-users happen to update one plugin (that includes a framework) but not another plugin (thus leaving one of the plugins with an outdated framework).<\/p>\n<h2>WordPress Hooks Are Our Friend<\/h2>\n<p>The solution that I came up with is similar to what the <a href=\"https:\/\/github.com\/CMB2\/CMB2\" target=\"_blank\" rel=\"noopener\">CMB2<\/a> toolkit uses, but is instantiated in a different way and uses namespacing as part of the solution. In my specific situation (using my own framework) I had the following requirements:<\/p>\n<ul>\n<li>Ability load two separate version of the framework simultaneously.<\/li>\n<li>Allow for the newest version to load in a way that guaranteed backwards compatibility.<\/li>\n<li>No need for changing the framework namespace or class names with each version.<\/li>\n<\/ul>\n<p>What I ended up with is a framework that adheres to the following versioning scheme:<\/p>\n<ul>\n<li>Major version (1.0.0 to 2.0.0) releases are namespaced by including \/v1\/ or \/v2\/ in the namespace to allow for major version releases to run side-by-side with no conflicts. This allows one plugin to use version 1 while another uses version 2.<\/li>\n<li>Minor version (1.0.0 to 1.1.0) releases only add new features (never remove) and do not change the interface of existing classes and methods to guarantee backwards compatibility. This allows plugins that expect an old version of the framework to still run properly with a newer version of the framework.<\/li>\n<li>Dot version (1.0.0. to 1.0.1) releases only fix bugs and security issues and never change functionality.<\/li>\n<\/ul>\n<h2>The Code<\/h2>\n<p>This addresses version dependency issues, but in order to force the highest version of the framework to load I needed to add an init file. So, in the section of my plugin where all other dependencies are loaded I simply add a line such as this:<\/p>\n<pre class=\"theme:github lang:php decode:true \">require_once 'includes\/laubsterboy-sdk\/v1\/init.php';\n<\/pre>\n<p>Which loads the init.php:<\/p>\n<pre class=\"theme:github tab-convert:true lang:php decode:true\" title=\"Laubsterboy SDK init\">&lt;?php\n\nnamespace laubsterboy_sdk\\v1;\n\nif (!class_exists('\\laubsterboy_sdk\\v1\\Laubsterboy_SDK_Init_1_0_0')) {\n\t\/**\n\t * Laubsterboy SDK Init class\n\t *\n\t * This class is responsible for loading the latest minor version of the SDK.\n\t * This is needed since there is a possibility for multiple plugins including\n\t * the SDK and the first plugin activated may not include the newest version.\n\t * Anything that breaks backwards compatibility must be placed into a new\n\t * major version, and namespaced as such, to allow for multiple versions to\n\t * run side by side.\n\t *\/\n\tclass Laubsterboy_SDK_Init_1_0_0 {\n\t\tprotected static $instance = null;\n\t\tprotected $version = '1.0.0';\n\n\t\t\/**\n\t\t * Laubsterboy SDK Init Constructor\n\t\t *\n\t\t * Is responsible for comparing its version versus the global version and modifying as necessary\n\t\t *\n\t\t * @since 1.0.0\n\t\t *\/\n\t\tprotected function __construct() {\n\t\t\tglobal $laubsterboy_sdk_v1_version;\n\n\t\t\tif (empty($laubsterboy_sdk_v1_version) || version_compare($laubsterboy_sdk_v1_version, $this-&gt;version, '&lt;')) {\n\t\t\t\t$laubsterboy_sdk_v1_version = $this-&gt;version;\n\t\t\t}\n\n\t\t\tadd_action('after_setup_theme', array($this, 'load'), 1);\n\t\t}\n\n\n\n\t\t\/**\n\t\t * Laubsterboy SDK Init Singleton\n\t\t *\n\t\t * Retrieves an instance of this Laubsterboy SDK Init class\n\t\t *\n\t\t * @since 1.0.0\n\t\t *\n\t\t * @return Laubsterboy_SDK_Init_1_0_0\n\t\t *\/\n\t\tpublic static function get_instance() {\n\t\t\tif (is_null(static::$instance)) {\n\t\t\t\tstatic::$instance = new static();\n\t\t\t}\n\n\t\t\treturn static::$instance;\n\t\t}\n\n\n\n\t\t\/**\n\t\t * load\n\t\t *\n\t\t * Performs various checks to see if this version of the SDK should be loaded or skipped\n\t\t *\n\t\t * @since 1.0.0\n\t\t *\n\t\t * @return void\n\t\t *\/\n\t\tpublic function load() {\n\t\t\tglobal $laubsterboy_sdk_v1_version;\n\n\t\t\t\/\/ Check to make sure this load method is being called via the after_setup_theme action\n\t\t\tif (!doing_action('after_setup_theme')) return;\n\n\t\t\t\/\/ Check if the global version is the same as this version\n\t\t\tif ($laubsterboy_sdk_v1_version !== $this-&gt;version) return;\n\n\t\t\t\/\/ Check if this version has already been loaded\n\t\t\tif (defined(__NAMESPACE__ . '\\LAUBSTERBOY_SDK_LOADED')) return;\n\n\t\t\t\/\/ Define the version\n\t\t\tdefine(__NAMESPACE__ . '\\LAUBSTERBOY_SDK_LOADED', $this-&gt;version);\n\n\t\t\t\/\/ Load the Laubsterboy_SDK class\n\t\t\trequire_once 'laubsterboy-sdk.php';\n\t\t}\n\t}\n\n\tLaubsterboy_SDK_Init_1_0_0::get_instance();\n}<\/pre>\n<p>Lastly, in order to actually use the framework all I need to do is hook into the &#8216;after_setup_theme&#8217; action, such as this:<\/p>\n<pre class=\"theme:github tab-convert:true lang:php decode:true \">function my_plugin_after_setup_theme() {\n\t\/\/ Create SDK instance\n\t$sdk = new \\laubsterboy_sdk\\v1\\Laubsterboy_SDK();\n}\nadd_action('after_setup_theme', 'my_plugin_after_setup_theme');<\/pre>\n<p>The way all of this works is by each plugin or theme loading the framework init.php file which creates an instance of itself, using the singleton pattern. In the constructor it checks for the existence of a full version global number to compare against. If the current version of the framework is greater than the global version then it hooks into the &#8216;after_setup_theme&#8217; action and sets the global version to be the same as its version. Lastly the callback for the &#8216;after_setup_theme&#8217; performs a few checks to make sure that it&#8217;s attempting to load the highest version number and that the framework hasn&#8217;t been loaded yet, and then finally loads the main framework class.<\/p>\n<p>Ultimately, it&#8217;s a fairly simple setup for using a PHP framework or library in a WordPress plugin that&#8217;s easy to implement and maintain. This is the solution that worked for me, but I&#8217;m sure there are other solutions out there so please share your thoughts, and what you&#8217;ve done, in the comments.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Anyone who has spent a fair amount of time creating WordPress Plugins or Themes has likely also come across the need to package a PHP framework or library inside a plugin or theme. On the surface this is a fairly routine thing to do &#8211; simply copy the file into your plugin or theme, or [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":311,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[2],"tags":[99,96,100,101,97,98,49,95,60,64],"class_list":["post-308","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-code-snippet","tag-after_setup_theme","tag-framework","tag-hook","tag-init","tag-library","tag-php","tag-plugin","tag-sdk","tag-theme","tag-wordpress"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.1.1 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Using a PHP Framework or Library in WordPress Plugins and Themes - John Russell Blog<\/title>\n<meta name=\"description\" content=\"A simple method for packaging a PHP framework or library in WordPress plugins and themes, while avoiding version and naming collisions.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.johnrussell.dev\/blog\/2017\/09\/php-framework-wordpress-plugin\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Using a PHP Framework or Library in WordPress Plugins and Themes - John Russell Blog\" \/>\n<meta property=\"og:description\" content=\"A simple method for packaging a PHP framework or library in WordPress plugins and themes, while avoiding version and naming collisions.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.johnrussell.dev\/blog\/2017\/09\/php-framework-wordpress-plugin\/\" \/>\n<meta property=\"og:site_name\" content=\"John Russell Blog\" \/>\n<meta property=\"article:published_time\" content=\"2017-09-29T20:59:32+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2018-12-07T20:00:45+00:00\" \/>\n<meta name=\"author\" content=\"John Russell\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:image\" content=\"https:\/\/www.johnrussell.dev\/blog\/wp-content\/uploads\/2017\/09\/blog-post-featured-image.png\" \/>\n<meta name=\"twitter:creator\" content=\"@laubsterboy\" \/>\n<meta name=\"twitter:site\" content=\"@laubsterboy\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"John Russell\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"7 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/www.johnrussell.dev\/blog\/2017\/09\/php-framework-wordpress-plugin\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/www.johnrussell.dev\/blog\/2017\/09\/php-framework-wordpress-plugin\/\"},\"author\":{\"name\":\"John Russell\",\"@id\":\"https:\/\/www.johnrussell.dev\/blog\/#\/schema\/person\/296c0c6bd1deeeb20834393e1e16325c\"},\"headline\":\"Using a PHP Framework or Library in WordPress Plugins and Themes\",\"datePublished\":\"2017-09-29T20:59:32+00:00\",\"dateModified\":\"2018-12-07T20:00:45+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/www.johnrussell.dev\/blog\/2017\/09\/php-framework-wordpress-plugin\/\"},\"wordCount\":1017,\"commentCount\":0,\"image\":{\"@id\":\"https:\/\/www.johnrussell.dev\/blog\/2017\/09\/php-framework-wordpress-plugin\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.johnrussell.dev\/blog\/wp-content\/uploads\/2017\/09\/blog-post-featured-image.png\",\"keywords\":[\"after_setup_theme\",\"framework\",\"hook\",\"init\",\"library\",\"PHP\",\"Plugin\",\"sdk\",\"Theme\",\"WordPress\"],\"articleSection\":[\"Code Snippet\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/www.johnrussell.dev\/blog\/2017\/09\/php-framework-wordpress-plugin\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.johnrussell.dev\/blog\/2017\/09\/php-framework-wordpress-plugin\/\",\"url\":\"https:\/\/www.johnrussell.dev\/blog\/2017\/09\/php-framework-wordpress-plugin\/\",\"name\":\"Using a PHP Framework or Library in WordPress Plugins and Themes - John Russell Blog\",\"isPartOf\":{\"@id\":\"https:\/\/www.johnrussell.dev\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/www.johnrussell.dev\/blog\/2017\/09\/php-framework-wordpress-plugin\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/www.johnrussell.dev\/blog\/2017\/09\/php-framework-wordpress-plugin\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.johnrussell.dev\/blog\/wp-content\/uploads\/2017\/09\/blog-post-featured-image.png\",\"datePublished\":\"2017-09-29T20:59:32+00:00\",\"dateModified\":\"2018-12-07T20:00:45+00:00\",\"author\":{\"@id\":\"https:\/\/www.johnrussell.dev\/blog\/#\/schema\/person\/296c0c6bd1deeeb20834393e1e16325c\"},\"description\":\"A simple method for packaging a PHP framework or library in WordPress plugins and themes, while avoiding version and naming collisions.\",\"breadcrumb\":{\"@id\":\"https:\/\/www.johnrussell.dev\/blog\/2017\/09\/php-framework-wordpress-plugin\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.johnrussell.dev\/blog\/2017\/09\/php-framework-wordpress-plugin\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.johnrussell.dev\/blog\/2017\/09\/php-framework-wordpress-plugin\/#primaryimage\",\"url\":\"https:\/\/www.johnrussell.dev\/blog\/wp-content\/uploads\/2017\/09\/blog-post-featured-image.png\",\"contentUrl\":\"https:\/\/www.johnrussell.dev\/blog\/wp-content\/uploads\/2017\/09\/blog-post-featured-image.png\",\"width\":1200,\"height\":600},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.johnrussell.dev\/blog\/2017\/09\/php-framework-wordpress-plugin\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/www.johnrussell.dev\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Using a PHP Framework or Library in WordPress Plugins and Themes\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.johnrussell.dev\/blog\/#website\",\"url\":\"https:\/\/www.johnrussell.dev\/blog\/\",\"name\":\"John Russell Blog\",\"description\":\"\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/www.johnrussell.dev\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\/\/www.johnrussell.dev\/blog\/#\/schema\/person\/296c0c6bd1deeeb20834393e1e16325c\",\"name\":\"John Russell\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.johnrussell.dev\/blog\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/00ce0f258fcc5e5d29897a5e81316009713e9104cfaf49f481c5bce3f81c7cb1?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/00ce0f258fcc5e5d29897a5e81316009713e9104cfaf49f481c5bce3f81c7cb1?s=96&d=mm&r=g\",\"caption\":\"John Russell\"},\"url\":\"https:\/\/www.johnrussell.dev\/blog\/author\/laubsterboy\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Using a PHP Framework or Library in WordPress Plugins and Themes - John Russell Blog","description":"A simple method for packaging a PHP framework or library in WordPress plugins and themes, while avoiding version and naming collisions.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.johnrussell.dev\/blog\/2017\/09\/php-framework-wordpress-plugin\/","og_locale":"en_US","og_type":"article","og_title":"Using a PHP Framework or Library in WordPress Plugins and Themes - John Russell Blog","og_description":"A simple method for packaging a PHP framework or library in WordPress plugins and themes, while avoiding version and naming collisions.","og_url":"https:\/\/www.johnrussell.dev\/blog\/2017\/09\/php-framework-wordpress-plugin\/","og_site_name":"John Russell Blog","article_published_time":"2017-09-29T20:59:32+00:00","article_modified_time":"2018-12-07T20:00:45+00:00","author":"John Russell","twitter_card":"summary_large_image","twitter_image":"https:\/\/www.johnrussell.dev\/blog\/wp-content\/uploads\/2017\/09\/blog-post-featured-image.png","twitter_creator":"@laubsterboy","twitter_site":"@laubsterboy","twitter_misc":{"Written by":"John Russell","Est. reading time":"7 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.johnrussell.dev\/blog\/2017\/09\/php-framework-wordpress-plugin\/#article","isPartOf":{"@id":"https:\/\/www.johnrussell.dev\/blog\/2017\/09\/php-framework-wordpress-plugin\/"},"author":{"name":"John Russell","@id":"https:\/\/www.johnrussell.dev\/blog\/#\/schema\/person\/296c0c6bd1deeeb20834393e1e16325c"},"headline":"Using a PHP Framework or Library in WordPress Plugins and Themes","datePublished":"2017-09-29T20:59:32+00:00","dateModified":"2018-12-07T20:00:45+00:00","mainEntityOfPage":{"@id":"https:\/\/www.johnrussell.dev\/blog\/2017\/09\/php-framework-wordpress-plugin\/"},"wordCount":1017,"commentCount":0,"image":{"@id":"https:\/\/www.johnrussell.dev\/blog\/2017\/09\/php-framework-wordpress-plugin\/#primaryimage"},"thumbnailUrl":"https:\/\/www.johnrussell.dev\/blog\/wp-content\/uploads\/2017\/09\/blog-post-featured-image.png","keywords":["after_setup_theme","framework","hook","init","library","PHP","Plugin","sdk","Theme","WordPress"],"articleSection":["Code Snippet"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.johnrussell.dev\/blog\/2017\/09\/php-framework-wordpress-plugin\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.johnrussell.dev\/blog\/2017\/09\/php-framework-wordpress-plugin\/","url":"https:\/\/www.johnrussell.dev\/blog\/2017\/09\/php-framework-wordpress-plugin\/","name":"Using a PHP Framework or Library in WordPress Plugins and Themes - John Russell Blog","isPartOf":{"@id":"https:\/\/www.johnrussell.dev\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.johnrussell.dev\/blog\/2017\/09\/php-framework-wordpress-plugin\/#primaryimage"},"image":{"@id":"https:\/\/www.johnrussell.dev\/blog\/2017\/09\/php-framework-wordpress-plugin\/#primaryimage"},"thumbnailUrl":"https:\/\/www.johnrussell.dev\/blog\/wp-content\/uploads\/2017\/09\/blog-post-featured-image.png","datePublished":"2017-09-29T20:59:32+00:00","dateModified":"2018-12-07T20:00:45+00:00","author":{"@id":"https:\/\/www.johnrussell.dev\/blog\/#\/schema\/person\/296c0c6bd1deeeb20834393e1e16325c"},"description":"A simple method for packaging a PHP framework or library in WordPress plugins and themes, while avoiding version and naming collisions.","breadcrumb":{"@id":"https:\/\/www.johnrussell.dev\/blog\/2017\/09\/php-framework-wordpress-plugin\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.johnrussell.dev\/blog\/2017\/09\/php-framework-wordpress-plugin\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.johnrussell.dev\/blog\/2017\/09\/php-framework-wordpress-plugin\/#primaryimage","url":"https:\/\/www.johnrussell.dev\/blog\/wp-content\/uploads\/2017\/09\/blog-post-featured-image.png","contentUrl":"https:\/\/www.johnrussell.dev\/blog\/wp-content\/uploads\/2017\/09\/blog-post-featured-image.png","width":1200,"height":600},{"@type":"BreadcrumbList","@id":"https:\/\/www.johnrussell.dev\/blog\/2017\/09\/php-framework-wordpress-plugin\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.johnrussell.dev\/blog\/"},{"@type":"ListItem","position":2,"name":"Using a PHP Framework or Library in WordPress Plugins and Themes"}]},{"@type":"WebSite","@id":"https:\/\/www.johnrussell.dev\/blog\/#website","url":"https:\/\/www.johnrussell.dev\/blog\/","name":"John Russell Blog","description":"","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.johnrussell.dev\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/www.johnrussell.dev\/blog\/#\/schema\/person\/296c0c6bd1deeeb20834393e1e16325c","name":"John Russell","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.johnrussell.dev\/blog\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/00ce0f258fcc5e5d29897a5e81316009713e9104cfaf49f481c5bce3f81c7cb1?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/00ce0f258fcc5e5d29897a5e81316009713e9104cfaf49f481c5bce3f81c7cb1?s=96&d=mm&r=g","caption":"John Russell"},"url":"https:\/\/www.johnrussell.dev\/blog\/author\/laubsterboy\/"}]}},"_links":{"self":[{"href":"https:\/\/www.johnrussell.dev\/blog\/wp-json\/wp\/v2\/posts\/308","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.johnrussell.dev\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.johnrussell.dev\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.johnrussell.dev\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.johnrussell.dev\/blog\/wp-json\/wp\/v2\/comments?post=308"}],"version-history":[{"count":14,"href":"https:\/\/www.johnrussell.dev\/blog\/wp-json\/wp\/v2\/posts\/308\/revisions"}],"predecessor-version":[{"id":342,"href":"https:\/\/www.johnrussell.dev\/blog\/wp-json\/wp\/v2\/posts\/308\/revisions\/342"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.johnrussell.dev\/blog\/wp-json\/wp\/v2\/media\/311"}],"wp:attachment":[{"href":"https:\/\/www.johnrussell.dev\/blog\/wp-json\/wp\/v2\/media?parent=308"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.johnrussell.dev\/blog\/wp-json\/wp\/v2\/categories?post=308"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.johnrussell.dev\/blog\/wp-json\/wp\/v2\/tags?post=308"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}