{"id":21340286,"url":"https://github.com/mnestorov/wp-plugin-boilerplate","last_synced_at":"2026-03-11T01:01:35.759Z","repository":{"id":111493554,"uuid":"437046774","full_name":"mnestorov/wp-plugin-boilerplate","owner":"mnestorov","description":"A standardized, organized, object-oriented foundation for building WordPress Plugins.","archived":false,"fork":false,"pushed_at":"2023-05-14T18:19:29.000Z","size":77,"stargazers_count":2,"open_issues_count":0,"forks_count":2,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-08-22T14:54:11.956Z","etag":null,"topics":["php","plugin-boilerplate","wordpress","wordpress-plugin","wp","wp-plugin"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":false,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mnestorov.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2021-12-10T16:39:17.000Z","updated_at":"2023-05-26T07:18:43.000Z","dependencies_parsed_at":"2024-07-20T11:15:44.892Z","dependency_job_id":null,"html_url":"https://github.com/mnestorov/wp-plugin-boilerplate","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/mnestorov/wp-plugin-boilerplate","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mnestorov%2Fwp-plugin-boilerplate","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mnestorov%2Fwp-plugin-boilerplate/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mnestorov%2Fwp-plugin-boilerplate/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mnestorov%2Fwp-plugin-boilerplate/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mnestorov","download_url":"https://codeload.github.com/mnestorov/wp-plugin-boilerplate/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mnestorov%2Fwp-plugin-boilerplate/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30364599,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-10T21:41:54.280Z","status":"ssl_error","status_checked_at":"2026-03-10T21:40:59.357Z","response_time":106,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["php","plugin-boilerplate","wordpress","wordpress-plugin","wp","wp-plugin"],"created_at":"2024-11-22T00:49:58.170Z","updated_at":"2026-03-11T01:01:35.704Z","avatar_url":"https://github.com/mnestorov.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\u003ca href=\"https://laravel.com\" target=\"_blank\"\u003e\u003cimg src=\"https://raw.githubusercontent.com/github/explore/80688e429a7d4ef2fca1e82350fe8e3517d3494d/topics/wordpress/wordpress.png\" width=\"100\" alt=\"Laravel Logo\"\u003e\u003c/a\u003e\u003c/p\u003e\n\n# WordPress Plugin Boilerplate\n\n[![Licence](https://img.shields.io/github/license/Ileriayo/markdown-badges?style=for-the-badge)](./LICENSE)\n\n\n## Overview\n\nA standardized, organized, object-oriented foundation for building WordPress Plugins.\n\n## Contents\n\nThe WordPress Plugin Boilerplate includes the following files:\n\n- **.gitignore** - used to exclude certain files from the repository.\n- **CHANGELOG.md** - the list of changes to the core project.\n- **README.md** - the file that you’re currently reading.\n- **my-plugin-name** - directory that contains the source code\n\n## Features\n\n- The WordPress Plugin Boilerplate is based on the [Plugin API](http://codex.wordpress.org/Plugin_API), [Coding Standards](https://developer.wordpress.org/coding-standards/), and [Documentation Standards](https://developer.wordpress.org/coding-standards/inline-documentation-standards/php/).\n- All classes, functions, and variables are documented so that you know what you need to change.\n- The WordPress Plugin Boilerplate uses a strict file organization scheme and that makes it easy to organize the files that compose the plugin.\n- The plugin includes a **'.pot'** file as a starting point for internationalization.\n\n## Installation\n\nThe WordPress Plugin Boilerplate can be installed directly into your plugins folder \"as-is\". You will want to rename it and the classes inside of it to fit your needs. \n\nTerms like **'plugin-name'** and other variations are spread all throughout the file contents as well. You can use VS Code, Sublime Text, Atom.io or other capable text editors to mass-replace within multiple files. \n\n**Note:** *Here is a list of what you should replace (make sure to do case-sensitive search-replaces).*\n\nFor example, if your plugin is named **'my-example-plugin'** then:\n\n- rename files from **my-plugin-name** to **my-example-plugin**\n- **my-plugin-name** should become **my-example-plugin**\n- **My_Plugin_Name** should become **My_Example_Plugin**\n- **MY_PLUGIN_NAME_** should become **MY_EXAMPLE_PLUGIN_**\n\nIt's safe to activate the plugin at this point. Because the WordPress Plugin Boilerplate has no real functionality there will be no menu items, meta boxes, or custom post types added until you write the code.\n\n## Recommended Tools\n\n### i18n Tools\n\nThe WordPress Plugin Boilerplate uses a variable to store the text domain used when internationalizing strings throughout the Boilerplate. To take advantage of this method, there are tools that are recommended for providing correct, translatable files:\n\n- [Poedit](http://www.poedit.net/)\n- [i18n](https://codex.wordpress.org/I18n_for_WordPress_Developers)\n\nAny of the above tools should provide you with the proper tooling to internationalize the plugin.\n\n## Important Notes\n\n### Includes\n\nNote that if you include your own classes, or third-party libraries, there are four locations in which said files may go:\n\n- **my-plugin-name/includes/functions.php** is where general functions, shortcodes, etc. of the site reside\n- **my-plugin-name/includes/classes** is where functionality shared between the admin area and the public area parts of the site reside\n- **my-plugin-name/assets/src/admin** is for all admin-specific scripts and styles\n- **my-plugin-name/assets/src/public** is for all public-specific scripts and styles\n\n**Note:** *We have the **Loader** class for registering the hooks.*\n\n### The 'Loader' class\n\nThe goal of this class is to encapsulate the registration of hooks and then execute both actions and filters at the appropriate time when the plugin is loaded.\n\n#### How to you use the 'Loader' class to hook actions and filters\n\nIn order to understand how to use the loader, we should look at the source for the core plugin class, **Plugin_Name** in **class-plugin-name.php**.\n\nThe first block of code in this class declares the private container `$loader`:\n\n```php\nprotected $loader;\n```\n\nNext, we see within the `__construct()` method that the functions `load_dependencies()` and `define_public_hooks()` are called:\n\n```php\npublic function __construct() {\n\tif ( defined( 'PLUGIN_NAME_VERSION' ) ) {\n\t\t$this-\u003eversion = PLUGIN_NAME_VERSION;\n\t} else {\n\t\t$this-\u003eversion = '1.0.0';\n\t}\n\n\t$this-\u003eplugin_name = 'plugin-name';\n\t$this-\u003eload_dependencies();\n\t$this-\u003eset_locale();\n\t$this-\u003edefine_admin_hooks();\n\t$this-\u003edefine_public_hooks();\n}\n```\n\nFollowing the construct, we see the function `load_dependencies()` defined. Here is where the resource files for classes used by the plugin are called. The first class resource file we see being required here is `class-plugin-name-loader.php`.\n\n```php\nrequire_once plugin_dir_path( dirname( __FILE__ ) ) . 'classes/class-plugin-name-loader.php';\n```\n\n**Example**\n\nIf we have defined a class called **Plugin_Name_CPT** in the file **class-plugin-name-cpt.php** located in the includes directory of the plugin, we require it by adding this line to `load_dependencies()`:\n\n```php\nrequire_once plugin_dir_path( dirname( __FILE__ ) ) . 'classes/class-plugin-name-cpt.php';\n```\n\n**Note:** *Require any additional class files the plugin relies on within the `load_dependencies()` function*.\n\nSo now, the first step is done.\n\n---\n\nContinuing our examination, we see that at the end of this function, our earlier declared container called `$loader` is now defined as a **new object** of the class **Plugin_Name_Loader**, which it can do now because it was just required earlier in this function:\n\n```php\n$this-\u003eloader = new Plugin_Name_Loader();\n```\n\nNow let's skip down and take a look at `define_public_hooks()`. This is another function that was called from the `__construct()` method earlier. This is a great place to organize hooks used by the plugin. Here's how it looks:\n\n```php\nprivate function define_public_hooks() {\n    // Instantiates a new object of the class Plugin_Name_Public.\n    $plugin_public = new Plugin_Name_Public( $this-\u003eget_plugin_name(), $this-\u003eget_version() );\n    // This is where the loader's add_action() hooks the callback function of the class object. \n    $this-\u003eloader-\u003eadd_action( 'wp_enqueue_scripts', $plugin_public, 'enqueue_styles' );\n    // Another action is passed to the class object.\n    $this-\u003eloader-\u003eadd_action( 'wp_enqueue_scripts', $plugin_public, 'enqueue_scripts' );\n}\n```\n\n**You can see two important things going on here:**\n\n- An object of a class is instantiated.\n\n- The loader custom version of add_action() is performed which accepts the object as an argument.\n\nThis is where the loader becomes useful for us. Instead of passing just the hook and callback function to `add_action()`, the loader uses it's own custom `add_action()` and `add_filter()` functions which allow us to pass three arguments: *hook*, *class*, and *callback* function. This way it knows how to find the function in your class.\n\nFor reference, here are [all of the arguments](https://github.com/mnestorov/my-plugin-boilerplate/blob/main/my-plugin-name/includes/classes/class-plugin-name-loader.php) accepted by the loader's version of `add_action()`:\n\n```php\npublic function add_action( $hook, $component, $callback, $priority = 10, $accepted_args = 1 ) {\n\t$this-\u003eactions = $this-\u003eadd( $this-\u003eactions, $hook, $component, $callback, $priority, $accepted_args );\n}\n```\n\nSo now, the second step is done.\n\n---\n\nWhile there are ways to pass a class function to the WordPress `add_action()` or `add_filter()`, this is how we do it through the boilerplate's loader.\n\n**Example**\n\nWithin the function `define_public_hooks()`, we will repeat the two steps we just examined above. \n\nRemember, we can only do this because earlier we required our class file for **Plugin_Name_CPT**.\n\n1. Instantiate an object of our class:\n\n```php\n$plugin_cpt = new Plugin_Name_CPT();\n```\n\n2. Use the loader's `add_action()` to hook a function of `$plugin_cpt`:\n\n```php\n$this-\u003eloader-\u003eadd_action( 'init', $plugin_cpt, 'my_cpt_alert_function' );\n```\n\nThat's all. \n\n---\n\nHere is a final checklist to make sure we've done everything we need to:\n\n1. Create our class. In the above example it was defined as **Plugin_Name_CPT** at **includes/class-plugin-name-cpt.php**. Here is a very simple class we can use for testing which we'll use to display an message every time WordPress initializes our CPT class:\n\n```php\n\u003c?php\nclass Plugin_Name_CPT {\n    public function my_cpt_alert_function() { ?\u003e \n        \u003cscript\u003ealert(\"CPT IS WORKING!\");\u003c/script\u003e \u003c?php\n    }\n}\n```\n\n2. Require our class within the `load_dependencies()` method in the **class-plugin-name.php**. \n\n\n```php\nrequire_once plugin_dir_path( dirname( __FILE__ ) ) . 'classes/class-plugin-name-cpt.php';\n```\n\n3. Instantiate an object of our class within the method `define_public_hooks()` in the **class-plugin-name.php**.\n\n```php\n$plugin_cpt = new Plugin_Name_CPT();\n```\n\n4. Lastly, hook the method from our class to an action or filter. We do this within `define_public_hooks()` in the **class-plugin-name.php**.\n\n```php\n$this-\u003eloader-\u003eadd_action( 'init', $plugin_cpt, 'my_cpt_alert_function' );\n```\n\n---\n\n**Note:** In retrospect of all of the above, this `Loader` class helps to easily manage hooks throughout the plugin as we're working on our code, and we can trust that everything will be registered with WordPress just as we would expect.**\n\n---\n\n## License\n\n\nThis project is licensed under the MIT License.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmnestorov%2Fwp-plugin-boilerplate","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmnestorov%2Fwp-plugin-boilerplate","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmnestorov%2Fwp-plugin-boilerplate/lists"}