One place for hosting & domains

      Plugin

      Building Your Own JavaScript Modal Plugin

      Introduction

      When starting a new project, there are two staple JavaScript UI components that you will likely require. The first is a carousel, which I’ve already taken care of with Slick. And the second is a modal. Today we are going to build out a flexible CSS3 modal plugin.

      Here’s a demo to see what we’ll be building:

      The difference between building a plugin and a project component lies in flexibility. The first thing we are going to do is take a step back and think about the requirements. Our modal plugin should:

      • Launch different modals based upon option sets
      • Allow users to define custom transitions
      • Be responsive
      • Have max/min-width points
      • Anchor to the top of the page if too tall
      • Be centered otherwise
      • Accept a HTML string for content OR a domNode
      • Have no dependencies

      See that last line? That’s right folks, we’re doing this in plain old JavaScript.

      Architecture

      Alright, let’s get our hands dirty. Our first order of business is going to be deciding on our plugin architecture and picking a design pattern. Let’s create an IIFE to create a closure we can work within. Closures can be leveraged to create a private scope, where you have control over what data you make available.

      
      (function() {
          var privateVar = "You can't access me in the console"
      }());
      

      We want to add a constructor method for our plugin, and expose it as public. Our IIFE is called globally, so our this keyword is pointing at the window. Let’s attach our constructor to the global scope using this.

      
      (function() {
        
        this.Modal = function() {
      
        }
      }());
      

      Pointing our Modal variable at a function creates a functional object, which can now be instantiated with the new keyword like so:

      var myModal = new Modal();
      

      This creates a new instance of our object. Unfortunately, our object doesn’t do much at this point, so lets do something about that.

      Options

      Taking a look back at our requirements, our first order of business is to allow user defined options. The way we are going to achieve this is to create a set of default options, and then merge it with the object the user provides.

      
      (function() {
        
        this.Modal = function() {
      
          
          this.closeButton = null;
          this.modal = null;
          this.overlay = null;
      
          
          var defaults = {
            className: 'fade-and-drop',
            closeButton: true,
            content: "",
            maxWidth: 600,
            minWidth: 280,
            overlay: true
          }
      
          
          if (arguments[0] && typeof arguments[0] === "object") {
            this.options = extendDefaults(defaults, arguments[0]);
          }
      
        }
      
        
        function extendDefaults(source, properties) {
          var property;
          for (property in properties) {
            if (properties.hasOwnProperty(property)) {
              source[property] = properties[property];
            }
          }
          return source;
        }
      }());
      

      Pause. What’s going on here? First, we create global element references. These are important so that we can reference pieces of the Modal from anywhere in our plugin. Next up, we add a default options object. If a user doesn’t provide options, we use these. If they do, we override them. So how do we know if they have provided options? The key here is in the arguments object. This is a magical object inside of every function that contains an array of everything passed to it via arguments. Because we are only expecting one argument, an object containing plugin settings, we check to make sure arguments[0] exists, and that it is indeed an object.

      If that condition passes, we then merge the two objects using a privately scoped utility method called extendDefaults. extendDefaults takes an object, loops through its properties, and if it isn’t an internal property(hasOwnProperty), assigns it to the source object. We can now configure our plugin with an options object:

      var myModal = new Modal({
          content: 'Howdy',
          maxWidth: 600
      });
      

      Public Methods

      Now that we have our Modal object, and it’s configurable, how about adding a public method? The first thing a developer is going to want to do with a modal is to open it up, so let’s make it happen.

      
      (function() {
        
        this.Modal = function() {
          ...
        }
      
        
      
        Modal.prototype.open = function() {
          
        }
      
        
      
        
        function extendDefaults(source, properties) {
          ...
        }
      }());
      

      In order to expose a public method, we attach it to our Modal object’s prototype. When you add methods to the object’s prototype, each new instance shares the same methods, rather than creating new methods for each instance. This is super performant, unless you have multi-level subclassing, in which traversing the prototype chain negates your performance boost. We have also added comments and structured our component so that we have three sections: constructor, public methods, and private methods.

      This doesn’t do anything functionally, but it keeps everything organized and readable.

      Core Functionality

      How about we take a step back? We now have a nice plugin architecture, with a constructor, options & a public method. It is time for the bread and butter, so let’s revisit what this plugin is supposed to do. Our plugin should:

      • Build a modal element and add it to the page.
      • *Add any classes specified in the className option to the modal.
      • If the closeButton option is true, add a close button.
      • If the content option is a HTML string, set it as the modal’s content.
      • If the content option is a domNode, set it’s interior content as the modal’s content.
      • Set the modal’s maxWidth and minWidth respectively.
      • Add an overlay if the overlay option is true.
      • When opened, add a scotch-open class that we can use with our CSS to define an open state.
      • When closed, remove the scotch-open class.
      • If the modal’s height exceeds the viewport’s height, also add a scotch-anchored class so that we can handle that scenario.

      Building Our Modal

      We can’t have a modal plugin without building a modal, so let’s create a private method that constructs a modal using our defined options:

      function buildOut() {
          var content, contentHolder, docFrag;
      
          
      
          if (typeof this.options.content === "string") {
            content = this.options.content;
          } else {
            content = this.options.content.innerHTML;
          }
      
          
          docFrag = document.createDocumentFragment();
      
          
          this.modal = document.createElement("div");
          this.modal.className = "scotch-modal " + this.options.className;
          this.modal.style.minWidth = this.options.minWidth + "px";
          this.modal.style.maxWidth = this.options.maxWidth + "px";
      
          
          if (this.options.closeButton === true) {
            this.closeButton = document.createElement("button");
            this.closeButton.className = "scotch-close close-button";
            this.closeButton.innerHTML = "×";
            this.modal.appendChild(this.closeButton);
          }
      
          
          if (this.options.overlay === true) {
            this.overlay = document.createElement("div");
            this.overlay.className = "scotch-overlay " + this.options.classname;
            docFrag.appendChild(this.overlay);
          }
      
          
          contentHolder = document.createElement("div");
          contentHolder.className = "scotch-content";
          contentHolder.innerHTML = content;
          this.modal.appendChild(contentHolder);
      
          
          docFrag.appendChild(this.modal);
      
          
          document.body.appendChild(docFrag);
      
        }
      

      We start by getting our target content and creating a Document Fragment. A Document Fragment is used to construct collections of DOM elements outside of the DOM, and is used to cumulatively add what we have built to the DOM. If our content is a string, we set our content variable to the option value. If our content is a domNode, we set our content variable to it’s interior HTML via innerHTML.

      Next up, we create our actual modal element, and add our className and minWidth/maxWidth properties to it. We create it with a default scotch-modal class for initial styling. Then, based upon option values, conditionally create a close button and an overlay in the same fashion.

      Finally, we add our content to a content holder div, and append it to our modal element. After appending our modal to the Document Fragment and appending our Document Fragment to the body, we now have a built modal on the page!

      Events

      This modal (hopefully) isn’t going to close itself, so providing we have a close button and/or an overlay, we need to bind events to them to make the magic happen. Below, we create a method to attach these events:

      function initializeEvents() {
          if (this.closeButton) {
            this.closeButton.addEventListener('click', this.close.bind(this));
          }
      
          if (this.overlay) {
            this.overlay.addEventListener('click', this.close.bind(this));
          }
      }
      

      We attach our events using the addEventListener method, passing a callback to a method we haven’t created yet called close. Notice we don’t just call close, but we use the bind method and pass our reference to this, which references our Modal object. This makes sure that our method has the right context when using the this keyword.

      Opening the Modal

      Let’s head back to the public open method we created earlier. Time to make it shine:

      Modal.prototype.open = function() {
          
          buildOut.call(this);
      
          
          initializeEvents.call(this);
      
          
          window.getComputedStyle(this.modal).height;
      
          
          this.modal.className = this.modal.className +
            (this.modal.offsetHeight > window.innerHeight ?
              " scotch-open scotch-anchored" : " scotch-open");
          this.overlay.className = this.overlay.className + " scotch-open";
      }
      

      When opening our modal, we first have to build it. We call our buildOut method using the call method, similarly to the way we did in our event binding with bind. We are simply passing the proper value of this to the method. We then call initializeEvents to make sure any applicable events get bound. Now, I know you are saying to yourself, what is going on with getComputedStyle? Check this out: We are using CSS3 for our transitions.

      The modal hides and shows based upon applied class names. When you add an element to the DOM and then add a class, the browser might not have interpreted the initial style, so you never see a transition from its initial state. That’s where window.getComputedStyle comes into play. Calling this forces the browser to recognize our initial state, and keeps our modal transition looking mint. Lastly, we add the scotch-open class name.

      But that’s not all. We currently have our modal centered, but if its height exceeds the viewport, that’s gonna look silly. We use a ternary operator to check the heights, and if our modal is too tall, we also add the scotch-anchored class name, to handle this situation.

      Closing the Modal

      Like anything else that is completely amazing in this world, at some point our modal must come to an end. So let’s build a method to send it to the other side:

      Modal.prototype.close = function() {
          
          var _ = this;
      
          
          this.modal.className = this.modal.className.replace(" scotch-open", "");
          this.overlay.className = this.overlay.className.replace(" scotch-open",
            "");
      
          
          this.modal.addEventListener(this.transitionEnd, function() {
            _.modal.parentNode.removeChild(_.modal);
          });
          this.overlay.addEventListener(this.transitionEnd, function() {
            if(_.overlay.parentNode) _.overlay.parentNode.removeChild(_.overlay);
          });
      }
      

      In order to have our modal transition out, we remove its scotch-open class name. The same applies to our overlay. But we aren’t finished yet. We have to remove our modal from the DOM, but it’s going to look ridiculous if we don’t wait until our animation has completed. We accomplish this by attaching an event listener to detect when our transition is complete, and when it is, it’s “Peace out, cub scout”. You may be wondering where this.transitionEnd came from. I’ll tell you. Browsers have different event names for transitions ending, so I wrote a method to detect which one to use, and called it in the constructor. See below:

      
      function transitionSelect() {
          var el = document.createElement("div");
          if (el.style.WebkitTransition) return "webkitTransitionEnd";
          if (el.style.OTransition) return "oTransitionEnd";
          return 'transitionend';
      }
      
      this.Modal = function() {
          ...
          
          this.transitionEnd = transitionSelect();
          ....
      }
      

      Wrap Up

      And there you have it. We have built out our modal javascript plugin. Comments and spacing aside,

      we did it in 100 lines of pure, sweet Vanilla JavaScript. Check out our finished product below, and then get ready to talk CSS:

      
      (function() {
      
        
        this.Modal = function() {
          
          this.closeButton = null;
          this.modal = null;
          this.overlay = null;
      
          
          this.transitionEnd = transitionSelect();
      
          
          var defaults = {
            className: 'fade-and-drop',
            closeButton: true,
            content: "",
            maxWidth: 600,
            minWidth: 280,
            overlay: true
          }
      
          
          if (arguments[0] && typeof arguments[0] === "object") {
            this.options = extendDefaults(defaults, arguments[0]);
          }
        }
      
        
      
        Modal.prototype.close = function() {
          var _ = this;
      
          this.modal.className = this.modal.className.replace(" scotch-open", "");
          this.overlay.className = this.overlay.className.replace(" scotch-open",
            "");
      
          this.modal.addEventListener(this.transitionEnd, function() {
            _.modal.parentNode.removeChild(_.modal);
          });
          this.overlay.addEventListener(this.transitionEnd, function() {
            if(_.overlay.parentNode) _.overlay.parentNode.removeChild(_.overlay);
          });
        }
      
        Modal.prototype.open = function() {
          buildOut.call(this);
          initializeEvents.call(this);
          window.getComputedStyle(this.modal).height;
          this.modal.className = this.modal.className +
            (this.modal.offsetHeight > window.innerHeight ?
              " scotch-open scotch-anchored" : " scotch-open");
          this.overlay.className = this.overlay.className + " scotch-open";
        }
      
        
      
        function buildOut() {
          var content, contentHolder, docFrag;
      
          
      
          if (typeof this.options.content === "string") {
            content = this.options.content;
          } else {
            content = this.options.content.innerHTML;
          }
      
          
          docFrag = document.createDocumentFragment();
      
          
          this.modal = document.createElement("div");
          this.modal.className = "scotch-modal " + this.options.className;
          this.modal.style.minWidth = this.options.minWidth + "px";
          this.modal.style.maxWidth = this.options.maxWidth + "px";
      
          
          if (this.options.closeButton === true) {
            this.closeButton = document.createElement("button");
            this.closeButton.className = "scotch-close close-button";
            this.closeButton.innerHTML = "×";
            this.modal.appendChild(this.closeButton);
          }
      
          
          if (this.options.overlay === true) {
            this.overlay = document.createElement("div");
            this.overlay.className = "scotch-overlay " + this.options.className;
            docFrag.appendChild(this.overlay);
          }
      
          
          contentHolder = document.createElement("div");
          contentHolder.className = "scotch-content";
          contentHolder.innerHTML = content;
          this.modal.appendChild(contentHolder);
      
          
          docFrag.appendChild(this.modal);
      
          
          document.body.appendChild(docFrag);
        }
      
        function extendDefaults(source, properties) {
          var property;
      
          for (property in properties) {
            if (properties.hasOwnProperty(property)) {
              source[property] = properties[property];
            }
          }
      
          return source;
        }
      
        function initializeEvents() {
          if (this.closeButton) {
            this.closeButton.addEventListener('click', this.close.bind(this));
          }
      
          if (this.overlay) {
            this.overlay.addEventListener('click', this.close.bind(this));
          }
        }
      
        function transitionSelect() {
          var el = document.createElement("div");
      
          if (el.style.WebkitTransition) return "webkitTransitionEnd";
          if (el.style.OTransition) return "oTransitionEnd";
      
          return 'transitionend';
        }
      
      }());
      

      This is a CSS3 modal, so JavaScript is only half the battle. To recap, we have a base class on our modal of scotch-modal, and an open class of scotch-open. Modals that exceed the viewport height have a class of scotch-anchored, and potentially have an overlay(scotch-overlay) and a close button(scotch-close). Let’s apply some base styles:

      
      .scotch-overlay
      {
          position: fixed;
          z-index: 9998;
          top: 0;
          left: 0;
      
          opacity: 0;
      
          width: 100%;
          height: 100%;
      
          -webkit-transition: 1ms opacity ease;
             -moz-transition: 1ms opacity ease;
              -ms-transition: 1ms opacity ease;
               -o-transition: 1ms opacity ease;
                  transition: 1ms opacity ease;
      
          background: rgba(0,0,0,.6);
      }
      
      .scotch-modal
      {
          position: absolute;
          z-index: 9999;
          top: 50%;
          left: 50%;
      
          opacity: 0;
      
          width: 94%;
          padding: 24px 20px;
      
          -webkit-transition: 1ms opacity ease;
             -moz-transition: 1ms opacity ease;
              -ms-transition: 1ms opacity ease;
               -o-transition: 1ms opacity ease;
                  transition: 1ms opacity ease;
      
          -webkit-transform: translate(-50%, -50%);
             -moz-transform: translate(-50%, -50%);
              -ms-transform: translate(-50%, -50%);
               -o-transform: translate(-50%, -50%);
                  transform: translate(-50%, -50%);
      
          border-radius: 2px;
          background: #fff;
      }
      
      .scotch-modal.scotch-open.scotch-anchored
      {
          top: 20px;
      
          -webkit-transform: translate(-50%, 0);
             -moz-transform: translate(-50%, 0);
              -ms-transform: translate(-50%, 0);
               -o-transform: translate(-50%, 0);
                  transform: translate(-50%, 0);
      }
      
      .scotch-modal.scotch-open
      {
          opacity: 1;
      }
      
      .scotch-overlay.scotch-open
      {
          opacity: 1;
      
      }
      
      
      .scotch-close
      {
          font-family: Helvetica,Arial,sans-serif;
          font-size: 24px;
          font-weight: 700;
          line-height: 12px;
      
          position: absolute;
          top: 5px;
          right: 5px;
      
          padding: 5px 7px 7px;
      
          cursor: pointer;
      
          color: #fff;
          border: 0;
          outline: none;
          background: #e74c3c;
      }
      
      .scotch-close:hover
      {
          background: #c0392b;
      }
      

      In a nutshell, we are making our modal and overlay just appear by default. We leave a 1ms transition on by default so that we can be sure that our transitionend event actually fires. We use the translate centering method to vertically and horizontally center our modal in the window. If scotch-anchored is applied, we center horizontally and anchor our modal 20px from the top of the window.

      This is a great starting base for adding custom animations via the className option, so why don’t we go ahead create a custom animation for the fade-and-drop default className of our plugin:

      
      
      .scotch-overlay.fade-and-drop
      {
          display: block;
          opacity: 0;
      }
      
      .scotch-modal.fade-and-drop
      {
          top: -300%;
          opacity: 1;
          display: block;
      }
      
      .scotch-modal.fade-and-drop.scotch-open
      {
          top: 50%;
      
          -webkit-transition: 500ms top 500ms ease;
             -moz-transition: 500ms top 500ms ease;
              -ms-transition: 500ms top 500ms ease;
               -o-transition: 500ms top 500ms ease;
                  transition: 500ms top 500ms ease;
      }
      
      .scotch-modal.fade-and-drop.scotch-open.scotch-anchored
      {
      
          -webkit-transition: 500ms top 500ms ease;
             -moz-transition: 500ms top 500ms ease;
              -ms-transition: 500ms top 500ms ease;
               -o-transition: 500ms top 500ms ease;
                  transition: 500ms top 500ms ease;
      }
      
      .scotch-overlay.fade-and-drop.scotch-open
      {
          top: 0;
          opacity: 1;
      
          -webkit-transition: 500ms opacity ease;
             -moz-transition: 500ms opacity ease;
              -ms-transition: 500ms opacity ease;
               -o-transition: 500ms opacity ease;
                  transition: 500ms opacity ease;
      }
      
      .scotch-modal.fade-and-drop
      {
          -webkit-transition: 500ms top ease;
             -moz-transition: 500ms top ease;
              -ms-transition: 500ms top ease;
               -o-transition: 500ms top ease;
                  transition: 500ms top ease;
      }
      
      .scotch-overlay.fade-and-drop
      {
          -webkit-transition: 500ms opacity 500ms ease;
             -moz-transition: 500ms opacity 500ms ease;
              -ms-transition: 500ms opacity 500ms ease;
               -o-transition: 500ms opacity 500ms ease;
                  transition: 500ms opacity 500ms ease;
      }
      

      For our fade-and-drop transition, we want the overlay to fade in, and the modal to drop in. We utilize the delay argument of the transition property shorthand to wait 500ms until the overlay has faded in. For our outro transition, we want the modal to fly back up out of sight and then fade the overlay out. Again, we use the delay property to wait for the modal animation to complete.

      Now we have a fully working modal plugin. Woo! So how do we actually use it? Using the new keyword, we can create a new modal and assign it to a variable:

      var myModal = new Modal();
      
      myModal.open();
      

      Without the content option set, it is going to be a pretty lame modal, so lets go ahead and pass in some options:

      var myModal = new Modal({
          content: '<p>Modals rock!</p>',
        maxWidth: 600
      });
      
      myModal.open();
      
      

      What about if we want to set up a custom animation? We should add a class to the className option that we can style with:

      var myModal = new Modal({
        className: 'custom-animation',
          content: '<p>Modals rock!</p>',
        maxWidth: 600
      });
      
      myModal.open();
      

      and then in our CSS, reference it and do your thing:

      .scotch-modal.custom-animation {
        -webkit-transition: 1ms -webkit-transform ease;
             -moz-transition: 1ms    -moz-transform ease;
              -ms-transition: 1ms     -ms-transform ease;
               -o-transition: 1ms      -o-transform ease;
                  transition: 1ms         transform ease;
        -webkit-transform: scale(0);
             -moz-transform: scale(0);
              -ms-transform: scale(0);
               -o-transform: scale(0);
                  transform: scale(0);
      }
      
      .scotch-modal-custom-animation.scotch-open {
        -webkit-transform: scale(1);
             -moz-transform: scale(1);
              -ms-transform: scale(1);
               -o-transform: scale(1);
                  transform: scale(1);
      }
      

      I know what you’re thinking:

      “Ken, what if we want to add new features to our plugin?”

      By now if you haven’t realized it, I’ll spill the beans. This article isn’t about writing a modal, it’s about writing a plugin. If you have been following along you should have the tools required to do just this. Say you want to make the plugin open automatically when instantiated. Let’s add an option for that. First, we add the option to our defaults in our constructor method.

      
        this.Modal = function() {
      
          
          this.closeButton = null;
          this.modal = null;
          this.overlay = null;
      
          
          var defaults = {
            autoOpen: false,
            className: 'fade-and-drop',
            closeButton: true,
            content: "",
            maxWidth: 600,
            minWidth: 280,
            overlay: true
          }
      
          
          if (arguments[0] && typeof arguments[0] === "object") {
            this.options = extendDefaults(defaults, arguments[0]);
          }
      
        }
      

      Next, we check if the option is true, and if so, fire our open method.

      
        this.Modal = function() {
      
          
          this.closeButton = null;
          this.modal = null;
          this.overlay = null;
      
          
          var defaults = {
            autoOpen: false,
            className: 'fade-and-drop',
            closeButton: true,
            content: "",
            maxWidth: 600,
            minWidth: 280,
            overlay: true
          }
      
          
          if (arguments[0] && typeof arguments[0] === "object") {
            this.options = extendDefaults(defaults, arguments[0]);
          }
      
          if (this.options.autoOpen === true) this.open();
        }
      

      It is as simple as that.

      I sincerely hope that after reading this, everyone learned something they didn’t know before. I personally learned a number of things during the course of writing it! We now have a fully functioning CSS3 modal plugin, but don’t stop here. Make it yours. Add features that you think would be helpful, craft some custom transitions, go absolutely bananas. You don’t even need to make a better modal. Take the plugin-building skills you acquired here today, and go build a brand new plugin. Who knows, it could be the next big thing!

      If you have made it this far, I appreciate your time and diligence and I look forward to writing more fun tutorials here in the future. In the meantime, check out some cool demos below!

      How to Build a WordPress Plugin (part 1)

      Introduction

      In this tutorial, we will go through the process of creating a plugin for WordPress. A WordPress plugin extends the WordPress core and is intended to be reusable code or functionality across multiple projects. This is one of the most interesting things about it – you can share your code or functionality on the web.

      I am sure many, if not all of you, have already searched for a plugin in the WordPress repository or any of the available market places. This is one of the reasons why WordPress is so widely used. It’s extremely extensible and has a huge community of developers around it. As of today, there are more than 39,000 publicly available free plugins on the WordPress repository.

      The plugin we are going to make in this tutorial will help automate some of the most usual functions developers do when creating a new WordPress project. By the end of this tutorial you will know how to:

      • Setup a basic WordPress plugin page
      • Create custom input fields on that plugin page
      • Validate those input fields

      You might be thinking that it would be easier and faster to just copy and paste code from your last project and not to even bother with writing a custom plugin to do this. Well, this is where you are wrong!

      This example will demonstrate the benefits of a WordPress plugin’s purpose by eliminating repetition. All you’ll need to do is add your plugin, change the options, and be on your way. You won’t need to worry that you forgot a function or anything because it’s all self-contained to a single plugin.

      The best part about building a WordPress plugin is joining the WordPress open-source community. You can share and get feedback on your work, sell it as a premium plugin, and add it to a browsable marketplace.

      Above is a screenshot of the final plugin we’re building. As mentioned earlier, it groups a handful of functions and settings you would usually add to each new project.

      Some of cool things that we’re going to be able to do are:

      • Dynamically add new images sizes
      • Customize the login page
      • Optionally clean up the head section
      • Optionally remove injected CSS for the comment widget
      • Optionally remove injected CSS for galleries
      • Optionally add a Post slug to the body class
      • Optionally load jQuery from a CDN
      • And many other useful options

      The best way to begin with a new plugin is by working on the incredibly useful WordPress Plugin Boilerplate. You might ask yourself why you would use a boilerplate instead of building from scratch. This boilerplate will get you started quick with a standardized, organized and object-oriented foundation – basically everything you want if you started from scratch.

      To get started, just go to the WordPress Plugin Boilerplate Generator and fill-out the form and click on the Build button.

      You now have just downloaded the generated plugin boilerplate as a .zip file. Now, simply unzip it and add it to your WordPress development installation in the plugins folder.

      You might want to have a dedicated local environment for testing your plugins. We recommend using either MAMP/XAMP or using a LAMP vagrant box like the awesome Scotch Box. You should also make sure to turn on the debug functionalities of WordPress by adding the following to your wp-config.php file:

          define('WP_DEBUG', true)
      

      This will help us check for any errors while coding our plugin.

      Now that the boilerplate of our plugin is ready and installed, let’s review a bit about the plugin folder structure before we begin with coding it.

      First thing you might notice, is that we have 4 main folders:

      Admin

      The folder admin is where all our admin facing code will live; including CSS, JS and partials folders and our PHP admin class file class-wp-cbf-admin.php.

      Includes

      Here you will find:

      • The main plugin PHP class class-wp-cbf.php where we will add all our actions and filters.
      • The activator file class-wp-cbf-activator.php.
      • The deactivator file class-wp-cbf-desactivator.php, the internationalization file class-wp-cbf-i18n.php
      • The loader file class-wp-cbf-loader.php which will basically call all our actions in the main class file.
      • The languages folder which is a ready to use .pot file to make your plugin in muliple languages.
      • The public folder is the same as our admin folder except for public facing functionalities.

      This leaves us with 4 files:

      • LICENCE.txt: GPL-2 license.
      • README.txt: This will include your plugin name, compatibility version, and description as seen on the plugin page in the WordPress repository. This is the first file we will edit.
      • uninstall.php: This script is called when the user clicks on the Delete link in the WordPress plugin backend.
      • wp-cbf.php: This is the main plugin bootstrap file. You will likely edit this file with the version number and the short description of your plugin.

      Now that all this is cleared, it’s time to get our hands dirty. Let’s add some code to our brand new plugin!

      If you go to the plugins page in your WordPress back-end, you will see our plugin with its title, a description, and Activate, Edit and Delete links.

      If you click on Activate, it will work thanks to the activator and deactivator classes in the includes folder. This is great, but once activated, nothing really will happen yet.

      We need to add a settings page where we will add our plugin options. You might also notice here that we still have a very generic description – let’s fix that first.

      This short description is written in the comments of the main plugin class: wp-cbf/wp-cbf.php

      Since we are at the root of our plugin, let’s update the README.txt file. You will want this to be pretty detailed explanation, especially since this is what people will see when they reach your plugin webpage. You’ll also notice installation and FAQ sections. The more you cover here, the less you might need to explain during possible support later.

      If you reload your Plugins admin page now, you will see your new description.

      Next, let’s add a setting page so we will be able to edit our plugin’s options.

      Open the admin/class-wp-cbf-admin.php where we have 3 functions already here:

      • __construct which is instantiated whenever this class is called
      • And 2 enqueueing functions: enqueue_styles and enqueue_scripts which are used where we will add our admin related CSS and JS

      After these functions, add these following 3 functions. You don’t need to add the huge comment blocks since they’re just there to help you.

          
      
          
      
          public function add_plugin_admin_menu() {
      
              
              add_options_page( 'WP Cleanup and Base Options Functions Setup', 'WP Cleanup', 'manage_options', $this->plugin_name, array($this, 'display_plugin_setup_page')
              );
          }
      
           
      
          public function add_action_links( $links ) {
              
             $settings_link = array(
              '<a href="' . admin_url( 'options-general.php?page=' . $this->plugin_name ) . '">' . __('Settings', $this->plugin_name) . '</a>',
             );
             return array_merge(  $settings_link, $links );
      
          }
      
          
      
          public function display_plugin_setup_page() {
              include_once( 'partials/wp-cbf-admin-display.php' );
          }
      

      Let’s review and explain those 3 functions:

      add_plugin_admin_menu(), as its name says, will add a menu item in the Settings sub-menu items. This is called by the add_options_page(). This function takes five arguments:

      • The page title: Here ‘WP Cleanup and Base Options Functions Setup’.
      • The menu title: Here ‘WP Cleanup’ as you might want to keep it small to span on just one line.
      • Capabilities: Who will be able to access this menu item (Admin, Editor, etc…).
      • The menu slug: Here as for mostly everything we will reference in this plugin we will use the plugin short name (we will access it with $this->plugin_name).
      • The callback function: If you look closely here, we are calling our 3rd function display_plugin_setup_page(). This is where our options will be displayed.

      This function adds a “Settings” link to the “Deactivate | Edit” list when our plugin is activated. It takes one argument, the $links array to which we will merge our new link array.

      display_plugin_setup_page()

      This one is called inside our first add_plugin_admin_menu() function. It just includes the partial file where we will add our Options. It will be mostly HTML and some little PHP logic.

      All this is great, but if you just save that file and go back to your plugin page, nothing new will appear yet. We first need to register these functions into your define_admin_hook.

      Go to the includes folder and open includes/class-wp-cbf.php. We need to add the following define_admin_hooks() private function to get this started:

          
      
          
          $this->loader->add_action( 'admin_menu', $plugin_admin, 'add_plugin_admin_menu' );
      
          
          $plugin_basename = plugin_basename( plugin_dir_path( __DIR__ ) . $this->plugin_name . '.php' );
          $this->loader->add_filter( 'plugin_action_links_' . $plugin_basename, $plugin_admin, 'add_action_links' );
      

      Each one of these lines are calling the loader file, actions, or filter hooks. From the includes/wp-cbf-loader.php file, we can get the way we have to add our arguments for example for the first action:

      • $hook ('admin_menu'), this is the action/filter hook we will add our modifications to
      • $component ($plugin_admin), this is a reference to the instance of the object on which the action is defined, more simply, if we had a hook to the admin_hooks it will be $plugin_admin on the public hooks it will be $plugin_public
      • $callback (add_plugin_admin_menu), the name of our function
      • $priority (not set here – default is 10), priority at which the function is fired with the default being 10
      • $accepted_args (not set here – default is 1), number of arguments passed to our callback function

      You can also see that we are setting up a $plugin_basename variable. It will give us the plugin main class file and is needed to add the action_links.

      Now, if you refresh your plugins admin page and activate the plugin you will now see the “Settings” link and also the menu link in there.

      Now we have a page to display our settings and that’s pretty good, but it’s empty. You can verify that by jumping on this page by either clicking on the “Settings” link on the “WP Cleanup” menu item.

      Before you go and add all your options fields, you might want to write all your plugin options on paper with the type of field you will add. For this particular plugin, most of these will be checkboxes to enable/disable functionalities, a couple of text inputs, selects that we will cover below, and some other very specific fields (color-pickers and image uploads that we will talk about in part 2.

      I would also recommend using another utility plugin to grab all the admin-specific markup that we will use. It’s not available on the WordPress repository, so you will need to get it from GitHub: WordPress Admin Style

      Now, with our list of fields and some admin related markup, we can go on and add our first inputs. For our plugin’s purpose, we will be adding 4 checkboxes to start.

      Open admin/partials/wp-cbf-admin-display.php since it’s the file that will display our settings page (as stated in our add_options_page()). Now add the following:

          <?php
          
          ?>
      
          
          <div class="wrap">
      
              <h2><?php echo esc_html(get_admin_page_title()); ?></h2>
      
              <form method="post" name="cleanup_options" action="options.php">
      
                  
                  <fieldset>
                      <legend class="screen-reader-text"><span>Clean WordPress head section</span></legend>
                      <label for="<?php echo $this->plugin_name; ?>-cleanup">
                          <input type="checkbox" id="<?php echo $this->plugin_name; ?>-cleanup" name="<?php echo $this->plugin_name; ?> [cleanup]" value="1"/>
                          <span><?php esc_attr_e('Clean up the head section', $this->plugin_name); ?></span>
                      </label>
                  </fieldset>
      
                  
                  <fieldset>
                      <legend class="screen-reader-text"><span>Remove Injected CSS for comment widget</span></legend>
                      <label for="<?php echo $this->plugin_name; ?>-comments_css_cleanup">
                          <input type="checkbox" id="<?php echo $this->plugin_name; ?>-comments_css_cleanup" name="<?php echo $this->plugin_name; ?>[comments_css_cleanup]" value="1"/>
                          <span><?php esc_attr_e('Remove Injected CSS for comment widget', $this->plugin_name); ?></span>
                      </label>
                  </fieldset>
      
                  
                  <fieldset>
                      <legend class="screen-reader-text"><span>Remove Injected CSS for galleries</span></legend>
                      <label for="<?php echo $this->plugin_name; ?>-gallery_css_cleanup">
                          <input type="checkbox" id="<?php echo $this->plugin_name; ?>-gallery_css_cleanup" name="<?php echo $this->plugin_name; ?>[gallery_css_cleanup]" value="1" />
                          <span><?php esc_attr_e('Remove Injected CSS for galleries', $this->plugin_name); ?></span>
                      </label>
                  </fieldset>
      
                  
                  <fieldset>
                      <legend class="screen-reader-text"><span><?php _e('Add Post, page or product slug to body class', $this->plugin_name); ?></span></legend>
                      <label for="<?php echo $this->plugin_name; ?>-body_class_slug">
                          <input type="checkbox" id="<?php echo $this->plugin_name;?>-body_class_slug" name="<?php echo $this->plugin_name; ?>[body_class_slug]" value="1" />
                          <span><?php esc_attr_e('Add Post slug to body class', $this->plugin_name); ?></span>
                      </label>
                  </fieldset>
      
                  
                  <fieldset>
                      <legend class="screen-reader-text"><span><?php _e('Load jQuery from CDN instead of the basic wordpress script', $this->plugin_name); ?></span></legend>
                      <label for="<?php echo $this->plugin_name; ?>-jquery_cdn">
                          <input type="checkbox"  id="<?php echo $this->plugin_name; ?>-jquery_cdn" name="<?php echo $this->plugin_name; ?>[jquery_cdn]" value="1" />
                          <span><?php esc_attr_e('Load jQuery from CDN', $this->plugin_name); ?></span>
                      </label>
                              <fieldset>
                                  <p>You can choose your own cdn provider and jQuery version(default will be Google Cdn and version 1.11.1)-Recommended CDN are <a href="https://cdnjs.com/libraries/jquery">CDNjs</a>, <a href="https://code.jquery.com/jquery/">jQuery official CDN</a>, <a href="https://developers.google.com/speed/libraries/#jquery">Google CDN</a> and <a href="http://www.asp.net/ajax/cdn#jQuery_Releases_on_the_CDN_0">Microsoft CDN</a></p>
                                  <legend class="screen-reader-text"><span><?php _e('Choose your prefered cdn provider', $this->plugin_name); ?></span></legend>
                                  <input type="url" class="regular-text" id="<?php echo $this->plugin_name; ?>-cdn_provider" name="<?php echo $this->plugin_name; ?>[cdn_provider]" value=""/>
                              </fieldset>
                  </fieldset>
      
                  <?php submit_button('Save all changes', 'primary','submit', TRUE); ?>
      
              </form>
      
          </div>
      

      This code will generate a form and a couple of checkboxes.

      If you try to check one of these checkboxes now and hit save, you will get redirected to the options.php page. This is because if you look at our form, the action attribute is linked to options.php. So let’s go on and save those options.

      At this point, you might be thinking that before saving any of these options, that we should probably be first validating and sanitizing them. Well that’s exaclty what we’re going to do.

      So let’s validate and sanitize those options:

      Let’s open admin/class-wp-cbf.php in our editor and add a new validation function. So after our display_plugin_setup_page() function jump a couple of lines and add the following:

          
          public function validate($input) {
              
              $valid = array();
      
              
              $valid['cleanup'] = (isset($input['cleanup']) && !empty($input['cleanup'])) ? 1 : 0;
              $valid['comments_css_cleanup'] = (isset($input['comments_css_cleanup']) && !empty($input['comments_css_cleanup'])) ? 1: 0;
              $valid['gallery_css_cleanup'] = (isset($input['gallery_css_cleanup']) && !empty($input['gallery_css_cleanup'])) ? 1 : 0;
              $valid['body_class_slug'] = (isset($input['body_class_slug']) && !empty($input['body_class_slug'])) ? 1 : 0;
              $valid['jquery_cdn'] = (isset($input['jquery_cdn']) && !empty($input['jquery_cdn'])) ? 1 : 0;
              $valid['cdn_provider'] = esc_url($input['cdn_provider']);
      
              return $valid;
           }
      

      As you can see here, we just created a function called validate, and we are passing it an $input argument. We then add some logic for the checkboxes to see if the input is valid.

      We’re doing this with isset and !empty which checks for us if the checkbox as been checked or not. It will assign the valid[] array the value we get from that verification. We also checked our url input field with the esc_url for a simple text field. We used a sanitize_text_field instead, but the process is the same.

      We are now going to add the saving/update function for our options.

      In the same file, right before the previous code, add:

          
           public function options_update() {
              register_setting($this->plugin_name, $this->plugin_name, array($this, 'validate'));
           }
      

      Here we use the register_setting() function which is part of the WordPress API. We are passing it three arguments:

      • Our option group: Here we will use our $plugin_name as it’s unique and safe.
      • Option name: You can register each option as a single, We will save all our options at once – so we will use the $plugin_name again.
      • A callback function: This is used to sanitize our options with the validation function we just created.

      Now that we have registered our settings, we need to add a small line of php to our form in order to get it working properly. This line will add a nonce, option_page, action, and a http_referer field as hidden inputs.

      So open up the form and update it so it look like the below code:

          <?php
          
          ?>
      
          <div class="wrap">
      
              <h2><?php echo esc_html( get_admin_page_title() ); ?></h2>
      
              <form method="post" name="cleanup_options" action="options.php">
      
              <?php settings_fields($this->plugin_name); ?>
      
              
      
              ...
      

      Great – we are almost there! We’re just missing one last step. We need to register the options_update() to the admin_init hook.

      Open includes/class-wp-cbf.php and register our new action:

          
      
          
          $this->loader->add_action('admin_init', $plugin_admin, 'options_update');
      

      Let’s try our option page now. On save, the page should refresh, and you should see a notice saying “Settings saved”.

      Victory is ours!

      But wait… If you had a checkbox checked, it’s no longer showing as checked now…

      It because we now just need to grab our “options” values and add a small condition to our inputs to reflect this.

      Open again the admin/partials/wp-cbf-admin.php file and update it as follow

              <h2 class="nav-tab-wrapper">Clean up</h2>
      
              <form method="post" name="cleanup_options" action="options.php">
      
              <?php
                  
                  $options = get_option($this->plugin_name);
      
                  
                  $cleanup = $options['cleanup'];
                  $comments_css_cleanup = $options['comments_css_cleanup'];
                  $gallery_css_cleanup = $options['gallery_css_cleanup'];
                  $body_class_slug = $options['body_class_slug'];
                  $jquery_cdn = $options['jquery_cdn'];
                  $cdn_provider = $options['cdn_provider'];
              ?>
      
              <?php
                  settings_fields($this->plugin_name);
                  do_settings_sections($this->plugin_name);
              ?>
      
              
              <fieldset>
                  <legend class="screen-reader-text">
                      <span>Clean WordPress head section</span>
                  </legend>
                  <label for="<?php echo $this->plugin_name; ?>-cleanup">
                      <input type="checkbox" id="<?php echo $this->plugin_name; ?>-cleanup" name="<?php echo $this->plugin_name; ?>[cleanup]" value="1" <?php checked($cleanup, 1); ?> />
                      <span><?php esc_attr_e('Clean up the head section', $this->plugin_name); ?></span>
                  </label>
              </fieldset>
      
              
              <fieldset>
                  <legend class="screen-reader-text"><span>Remove Injected CSS for comment widget</span></legend>
                  <label for="<?php echo $this->plugin_name; ?>-comments_css_cleanup">
                      <input type="checkbox" id="<?php echo $this->plugin_name; ?>-comments_css_cleanup" name="<?php echo $this->plugin_name; ?>[comments_css_cleanup]" value="1" <?php checked($comments_css_cleanup, 1); ?> />
                      <span><?php esc_attr_e('Remove Injected CSS for comment widget', $this->plugin_name); ?></span>
                  </label>
              </fieldset>
      
              
              <fieldset>
                  <legend class="screen-reader-text"><span>Remove Injected CSS for galleries</span></legend>
                  <label for="<?php echo $this->plugin_name; ?>-gallery_css_cleanup">
                      <input type="checkbox" id="<?php echo $this->plugin_name; ?>-gallery_css_cleanup" name="<?php echo $this->plugin_name; ?>[gallery_css_cleanup]" value="1" <?php checked( $gallery_css_cleanup, 1 ); ?>  />
                      <span><?php esc_attr_e('Remove Injected CSS for galleries', $this->plugin_name); ?></span>
                  </label>
              </fieldset>
      
              
              <fieldset>
                  <legend class="screen-reader-text"><span><?php _e('Add Post, page or product slug to body class', $this->plugin_name); ?></span></legend>
                  <label for="<?php echo $this->plugin_name; ?>-body_class_slug">
                      <input type="checkbox" id="<?php echo $this->plugin_name; ?>-body_class_slug" name="<?php echo $this->plugin_name; ?>[body_class_slug]" value="1" <?php checked($body_class_slug, 1); ?>  />
                      <span><?php esc_attr_e('Add Post slug to body class', $this->plugin_name); ?></span>
                  </label>
              </fieldset>
      
              
              <fieldset>
                  <legend class="screen-reader-text"><span><?php _e('Load jQuery from CDN instead of the basic wordpress script', $this->plugin_name); ?></span></legend>
                  <label for="<?php echo $this->plugin_name; ?>-jquery_cdn">
                      <input type="checkbox"  id="<?php echo $this->plugin_name; ?>-jquery_cdn" name="<?php echo $this->plugin_name; ?>[jquery_cdn]" value="1" <?php checked($jquery_cdn,1); ?>/>
                      <span><?php esc_attr_e('Load jQuery from CDN', $this->plugin_name); ?></span>
                  </label>
                  <fieldset>
                      <p>You can choose your own cdn provider and jQuery version(default will be Google Cdn and version 1.11.1)-Recommended CDN are <a href="https://cdnjs.com/libraries/jquery">CDNjs</a>, <a href="https://code.jquery.com/jquery/">jQuery official CDN</a>, <a href="https://developers.google.com/speed/libraries/#jquery">Google CDN</a> and <a href="http://www.asp.net/ajax/cdn#jQuery_Releases_on_the_CDN_0">Microsoft CDN</a></p>
                      <legend class="screen-reader-text"><span><?php _e('Choose your prefered cdn provider', $this->plugin_name); ?></span></legend>
                      <input type="url" class="regular-text" id="<?php echo $this->plugin_name; ?>-cdn_provider" name="<?php echo $this->plugin_name; ?>[cdn_provider]" value="<?php if(!empty($cdn_provider)) echo $cdn_provider; ?>"/>
                  </fieldset>
              </fieldset>
      
              <?php submit_button('Save all changes', 'primary','submit', TRUE); ?>
      

      So what we’re doing is basically checking to see if the value exists already, and, if it does, populating the input field with the current value.

      We do this by first grabbing all our options and assigning each one to a variable (try to keep those explicit so you know which is which).

      Then we add a small condition. We will use the WordPress built-in checked function on our inputs to get the saved value and add the “checked” attribute if the option exists and is set to 1.

      So save your file, try to save your plugin once last time, and, boom!, we have successfully finished our plugin.

      We have seen a lots of things. From the benefits of creating your own plugin and sharing it with fellow WordPress users to why you might want to make your repetitive functions into a plugin. We have reviewed the incredible WordPress Plugin Boilerplate, its structure, and why you should definitely use it.

      We put our hands in the grease and pushed ourselves in the first steps of doing a plugin, with 2 types of fields validation and sanitization, all that keeping a Oriented Object PHP process with clean and explicit code. We’re not finished yet though.

      In part 2, we will make our plugin alive, creating the functions that will actually influence your WordPress website, we will also discover more complex field types and sanitization, and, finally, get our plugin ready to be reviewed by the WordPress repository team.

      We’ll wrap this up with some additional links and sources:

      How To Create A WordPress Plugin (Beginner’s Guide)

      One of the main reasons that WordPress is so popular is its open-source nature.

      Because of that, at the time of this writing there are over 60,000 WordPress plugins that have been developed for the internet’s favorite content management system (CMS).

      And you can join in on the fun by creating your own WordPress plugin.

      Fortunately, WordPress makes the process pretty easy. Some coding knowledge will be needed, but it’s not terribly hard to learn how to create a basic plugin to add additional functionality to your website. And if it goes really well, you may even be able to sell it to others and turn your project into a side hustle!

      Ready to learn more about why you might want to create a WordPress plugin, as well as how to develop your own?

      You’re in the right place!

      A Quick Intro To WordPress Plugins

      WordPress has a market share of nearly 63% among all CMSes, making it the most popular option by a landslide.

      DreamHost Glossary

      WordPress

      WordPress is an open-source Content Management System (CMS). Since it is free and accessible, WordPress is used to power almost any type of website, from blogs to e-commerce businesses.

      Read More

      As mentioned earlier, WordPress is an open-source software platform. That means its source code, plugins, and themes are available for anyone to work with and modify as they see fit.

      Note: There’s a difference between WordPress.com and WordPress.org. The .org version is the open-source option that’s free to download and use to create a custom site. It’s the version we’ll cover in this post. The .com version is a hosted site builder with which you can create a limited site for free.

      WordPress plugins are packages of code that extend the functionality of a WordPress site. They’re created by different developers all around the world and are designed for a variety of purposes.

      For instance, in the existing plugin library you’ll find options for adding social media share buttons, adding newsletter signup forms to your sidebar, improving website search engine optimization (SEO), turning WordPress into a full-blown ecommerce site, and much more.

      The WordPress plugin ecosystem empowers those without coding knowledge to create and customize powerful websites. Additionally, it offers almost limitless opportunities for pro developers and web enthusiasts alike.

      Get Content Delivered Straight to Your Inbox

      Subscribe to our blog and receive great content just like this delivered straight to your inbox.

      Why Develop A WordPress Plugin?

      WordPress has one of the largest markets for developers. This means you’ll find plenty of resources to help you develop the exact plugin you need to optimize your website. (But don’t worry, we’ll also detail the process here soon!). You won’t find that level of support on many other website-building platforms.

      The magic of WordPress is that you can develop a solution for your own site and you don’t have to share it on the plugin market. However, many developers choose to make their plugins available to others to help them work around similar issues as those the developers encountered.

      If you do choose to offer your plugin to others, there’s some earning potential associated with WordPress plugins because of the massive user base.

      While there’s no shortage of competition, if you have a new or better solution to a common problem, you could find your plugin downloaded for thousands of sites. With a great plugin, the right pricing strategy, and some marketing efforts, a plugin could turn into a nice passiveish income stream.

      hypothetical math showing how much one could make by developing a plugin assuming 10,000 active users times 2% conversion equals 200 sales/year times $50/annual subscription equals $10K

      Lastly, WordPress is an ideal platform for learning how to code. Because it has been around for over 20 years, there’s a seemingly limitless number of resources both on and off WordPress to help you get the hang of development.

      Speaking of resources, let’s dive into everything you need to know to create your very own WordPress plugin.

      How To Create a WordPress Plugin (6 Steps)

      While different plugins will require different amounts of coding and know-how, they all tend to follow this same general development process.

      Step 1: Do Your Research And Planning

      Like we said, there are numerous tools in the WordPress plugin directory — tens of thousands of them in fact. Therefore, the first thing you’ll want to do is do some research to see if your idea already exists.

      Even if it does, you could still proceed with your plan, provided that you make some tweaks so that you’re not creating an exact replica. Explore similar plugins and find out how you might be able to improve upon them. Alternatively, you could complement what’s already available with something like your own custom post type — say, to help keep a diary of your media consumption — or additional features.

      You might also want to check the status of existing plugins. For instance, if a plugin hasn’t been updated in some time or isn’t compatible with the latest version of WordPress, there might be an opportunity to provide a better solution.

      You can also look at the number of active installations to see if there’s a big market for the type of plugin that you have in mind. This can help you decide if it’s worth the effort if you’re looking to earn money. It’s also a good idea to test the plugin on your own site to see what it does well and what could be done better.

      Finally, before diving into the build, you’ll want to read up on the WordPress Coding Standards. This is particularly important if you’re planning to share or sell your plugin. These coding standards are a set of guidelines and best practices that developers should try to adhere to when creating themes and plugins for WordPress.

      Related: Want To Learn WordPress? Start With These Resources

      Step 2: Set Up A Testing Environment

      The next step is to set up a testing environment.

      As a beginner, you’re likely to learn (and maybe break) a few things along the way. You don’t want to experiment on your live website that any internet user can see. A local environment — a staging website — will enable you to test your plugin privately as you work on it.

      We endorse using Local to create a WordPress site on your computer. It offers a straightforward, user-friendly development environment that offers powerful yet flexible tools for most people.

      You can also create an online staging environment. With DreamHost web hosting, you can easily create a staging WordPress site where you can test your plugin without breaking your live site or interrupting your visitors’ user experiences.

      Step 3: Create Your Plugin File

      Once you have your staging environment set up, it’s time to use it to create your plugin.

      The first step is to create a folder for it in your site’s directory.

      You can use an FTP/SFTP client like FileZilla to access your site’s files and folders. Or, you may be able to tap into your site via the file manager provided in your hosting account. For DreamHost users, our guide to using the website file manager will help you use our built-in file manager.

      Once you’ve connected to your site’s directory, navigate to wp-content/plugins and create a new folder for your plugin.

      Next, you’ll need to create a PHP file to add to this folder. To do this, open your preferred text editor and enter the following information:

      <?php
      /**
      * Plugin Name: test-plugin
      * Plugin URI: https://www.your-site.com/
      * Description: Test.
      * Version: 0.1
      * Author: your-name
      * Author URI: https://www.your-site.com/
      **/

      Of course, you’ll need to change the above information to match your details. When you’re ready, you can save your file. Remember to use the file extension “php” (e.g., my-first-plugin.php).

      Then, you’ll need to upload this file to the plugin folder that you just created at wp-content/plugins. Once you’ve done this, navigate to your test site’s WordPress dashboard and go to the Plugins page.

      screenshot showing the plugins option on a wordpress menu

      Here, you should be able to see your new plugin!

      This plugin won’t do anything yet if you were to activate it. However, WordPress will recognize it as a functional add-on from this point forward.

      Step 4: Add Code To Your Plugin

      Every plugin is different. However, they all share common components. For instance, all plugins use hooks to interact with WordPress.

      DreamHost Glossary

      Hook

      WordPress hooks are pieces of code that allow you to modify the CMS and add new features to it without tinkering with core files. Hooks make this possible by enabling you to “hook” custom code into pre-defined spots in WordPress.

      Read More

      A hook is how a plugin connects to the pre-existing code of WordPress’s core programming. In other words, the hook is the anchor point where a plugin inserts itself in order to add or change the functionality of a site.

      Hooks are an important part of WordPress development. There are hundreds of hooks that can be used as triggers for a plugin, and you can even create new ones if needed.

      But for now, there are two types of hooks that you’ll need to consider when creating your plugin:

      1. Actions: These add or change WordPress functionality and make up the majority of hooks.
      2. Filters: These are used to modify the functionality of actions.

      To code your plugin, you’ll need to familiarize yourself with hooks and how they work. Fortunately, the Plugin Handbook from WordPress can help you get started.

      For this guide, we’ll use the following code (source) as an example:

      
      function modify_read_more_link() {
          return '<a class="more-link" href="' . get_permalink() . '">Click to Read!</a>';
      }
      add_filter( 'the_content_more_link', 'modify_read_more_link' );
      

      As you might be able to see, this code uses a filter to modify the standard “read more” link by replacing it with a different value: “Click to Read!”

      If you add this snippet to your PHP file and activate the plugin on your site, you’ll end up seeing the following anchor text below your post excerpts:

      example of this plugin at work with a header image, some text, and a "Click to Read!" call to action

      Feel free to experiment with the code and try using a different function.

      Note that you could also add this code to your theme’s functions.php file. This file contains code that adds functionality to your site and works in a way that’s similar to how a plugin adds functionality. However, if you switch to a different theme in the future — or your theme is upgraded to a new version — you’ll lose these changes.

      This kind of code works only for Classic themes. Block themes work differently and often require no PHP code since everything is built using Blocks using only the Site Editor.

      Also note that the code in the example plugin above works only for sites utilizing classic themes. If you’ve been using the site editor built into WordPress — which has been in the core software for several years now — to lay out your site using blocks, the code above won’t do much for you.

      Related: How To Install A WordPress Theme (Tutorial)

      Step 5: Test Your Plugin

      As you continue developing your plugin, it’s important that you save your work often and test your changes on your staging or development site.

      Once you’re satisfied with your plugin, you should try it on a live site. Again, you’ll want to make sure that you’ve already thoroughly tested your plugin for any bugs and vulnerabilities.

      It’s also a good idea to create a backup of your live site before testing your plugin on it. This way, if anything does go wrong, you can restore your content.

      If you’re happy with the performance of your plugin at this point, you could offer it to other developers for them to use and test. This can earn you valuable feedback. You could also ask them to put your plugin through its paces and try to break it to prove its stability.

      To do this, you’ll want to export your plugin to a zip file for easy distribution and installation. Locate your plugin’s folder in the site’s directory, then right-click on it and follow the steps to create a zip file. For example, on Microsoft Windows select Send to > Compressed (zipped) folder.

      Choose a destination, and the files within your folder will be compiled into a zip folder that you can easily share. If you’re developing on a live site, you may need to first download the plugin folder from your SFTP client before compressing it.

      To install your plugin on a WordPress site, simply navigate to Plugins > Add New Plugin from the sidebar in your WordPress admin panel.

      screenshot of the "add new plugin" option on a wordpress navigation menu

      At the top of the page, you’ll see a button to Upload Plugin. Once selected, you’ll be prompted to choose a zip file to upload to your site.

      screenshot showing "if you have a plugin in a .zip format, you may install or update it by uploading it here" with a choose file to upload button

      Upload the compressed file you just made and select Install Now. WordPress will then unpack and install the plugin on your site.

      Once that’s complete, just click on Activate Plugin.

      Your new plugin is now live!

      Step 6: Distribute Your Plugin (2 Options)

      Now, you can start distributing the plugin you’ve created. Let’s look at the best ways to do this.

      A. Publish Your Work To The WordPress Plugin Directory

      By adding your plugin to the WordPress plugin directory, you can share your work with the community and gain exposure. You can take advantage of the WordPress user base to attract new clients.

      However, you’ll need to make sure that your plugin complies with best practices and the Detailed Plugin Guidelines before uploading it for review. Keep in mind, it might take a while for your plugin to be reviewed and accepted.

      Once your plugin is approved, you’ll need to add your files to the Subversion directory.

      When this is all done, WordPress users will be able to install your plugin on their sites.

      B. Share The Plugin On Your Own Website

      In addition to uploading your plugin to the WordPress directory, you could also create a website for it.

      You can use a site like this to market and provide more details about your plugin. You could also include documentation, tutorials, support options, links to other plugins you’ve made, and so on.

      Developers often use websites to promote their premium plugins while providing a free or “lite” version in the WordPress directory. That way, users are able to easily find and download the product via WordPress before upgrading to a paid option.

      You can lock certain advanced features behind a paywall, which can all be explained on a plugin website. Additionally, you can offer a multi-tiered membership model that offers a variety of feature sets depending on a user’s needs and budget.

      Set Yourself Up For Plugin Success With DreamHost

      As an open-source platform, WordPress enables you to develop your own plugin and share it with other users. While some coding knowledge will certainly be helpful, you can easily create a simple plugin and vastly improve your site’s functionality by following the steps above.

      Once you’ve gained enough experience, you may even want to start selling premium versions of your plugins for a rewarding and mostly passive income stream!

      But to really set yourself up for success, you need to be able to spin up an affordable plugin testing site — DreamPress can help you with that — as well as one or more marketing sites to display and sell your premium plugins. Use our AI-powered business name generator, affordable domain name finding and registration service, and WordPress-specific website builder to go from plugin idea to viable side hustle with ease!

      Do More with DreamPress

      DreamPress Plus and Pro users get access to Jetpack Professional (and 200+ premium themes) at no added cost!

      Managed WordPress Hosting - DreamPress