When creating a WordPress plugin, one the most important step is to pre-install very important knowledge, making sure the plugin operates easily from the get-go. Take, as an example, an occasions supervisor plugin. Upon set up, it’s immensely advisable if the plugin mechanically generates a web page titled Upcoming Occasions, exhibiting an inventory of long run occasions.

This pre-configured web page, embedded with a shortcode like [event_list number="10" scope="future" status="publish"], permits customers to straight away leverage the plugin’s functions with out studying via its documentation.

Putting in knowledge is useful now not simplest when first putting in the plugin, but in addition when due to this fact updating it. For example, if an replace introduces a calendar view characteristic, the plugin can mechanically create a brand new web page, Occasions Calendar, showcasing this addition via a shortcode akin to [event_calendar status="publish"].

Normally, the scope of information set up spans more than a few wishes:

  • Producing new pages with explicit titles and contents.
  • Including entries for customized publish sorts (CPTs) created through the plugin.
  • Placing default settings into the wp_options desk
  • Assigning new functions to consumer roles
  • Assigning metadata to customers, for brand spanking new or up to date options supplied through the plugin (e.g. customers may alternate the development date layout, and a default price is first added for all customers)
  • Developing classes repeatedly used inside the plugin’s context, akin to “meetings” or “sports activities.”

Putting in knowledge will have to be an incremental procedure, in a different way shall we create reproduction entries.

As an example, if a plugin model 1.1 introduces an Upcoming Occasions web page and a consumer updates from model 1.0, simplest the brand new knowledge related to model 1.1 must be put in. This incremental replace guarantees that after model 1.2 rolls out with the calendar characteristic, simplest the brand new Occasions Calendar web page is added, keeping off any duplication of the Upcoming Occasions web page.

Therefore, when up to date, the plugin will have to retrieve what earlier model used to be put in, and set up the information that corresponds to the brand new model(s) simplest.

This text explains the way to set up preliminary knowledge, and stay including new knowledge with additional updates, in our WordPress plugins.

Offering the present model

To take care of the incremental procedure, the plugin will have to monitor its present model, most often declared within the header of the plugin’s major document. However in fact, we will be able to’t reference it immediately from there, as it’s within a PHP remark. So we additionally outline this price in a variable and supply it to a Plugin magnificence chargeable for initialization and configuration:

setup();

The Plugin magnificence, leveraging PHP 8.0’s Constructor assets promotion characteristic, retail outlets this model, so we will be able to reference it afterward:

Realize how the good judgment to initialize and configure the plugin is added to the setup approach, now not the constructor. That’s for the reason that constructor will have to keep away from generating unwanted side effects; in a different way, shall we produce insects when extending or composing the Plugin magnificence.

Let’s see how that might occur. Let’s say we sooner or later upload a BetterPlugin magnificence that composes capability from the Plugin magnificence:

magnificence BetterPlugin {

  public serve as printSomething(): string
  {
    $pluginVersion = '1.0';
    $plugin = new Plugin($pluginVersion);
    go back '
' . $plugin->printSomething() . '
'; } }

On every occasion executing new Plugin() within printSomething, a brand new example of Plugin is created. If the configuration good judgment have been added to the constructor, it will be accomplished each and every time we create a brand new Plugin object. In our case, we wish to create the Upcoming Occasions web page simplest as soon as, now not a couple of occasions. Via including the good judgment to the setup approach, we will be able to keep away from this drawback.

Monitoring the former model

WordPress does now not supply a handy method to retrieve the model of the plugin being changed. Therefore, we will have to retailer this price through ourselves within the wp_options desk of the database.

Retailer the model beneath access "myplugin_version", the place myplugin_ is the identify of the plugin (e.g. eventsmanager_version). It’s necessary to at all times prepend all our settings with myplugin_, to keep away from possible conflicts, as we will be able to’t ensure that every other plugin gained’t upload a model possibility.

When loading the plugin on every request, Plugin will already know what the present model (from assets $pluginVersion previous on), and can retrieve the ultimate kept model from the database. This comparability determines the plugin’s standing:

  • New set up: detects if the database lacks a model access for the plugin, indicating first-time setup (i.e. $storedPluginVersion is null)
  • Replace: Recognized when the present model exceeds the database-stored model, signaling an improve requirement.
  • Differently, there’s no alternate

On every occasion there's a alternate, we name prepareAndInstallPluginSetupData to put in the best knowledge, whether or not for a brand new set up (wherein case it will have to set up all knowledge for all variations) or an replace (set up knowledge just for all of the new variations). The nullable $previousVersion variable signifies which state of affairs it's ($previousVersion is null => new set up).

After calling this system, we will have to additionally retailer the present plugin model at the database, turning into the brand new “ultimate kept” model. This will have to be performed after calling prepareAndInstallPluginSetupData in order that if this system produces an error (e.g., throwing a RuntimeException) and knowledge isn't put in, the former model continues to be kept at the database, and a brand new spherical of putting in knowledge will probably be tried at the subsequent request.

managePluginDataVersioning();
  }

  /**
   * If the plugin has simply been newly-installed + activated
   * or up to date, set up the best knowledge.
   */
  safe serve as managePluginDataVersioning(): void
  {
    $myPluginVersionOptionName = 'myplugin_version';
    $storedPluginVersion = get_option($myPluginVersionOptionName, null);

    // Take a look at if the principle plugin has been activated or up to date
    $isPluginJustFirstTimeActivated = $storedPluginVersion === null;
    $isPluginJustUpdated = !$isPluginJustFirstTimeActivated && $storedPluginVersion !== $this->pluginVersion;

    // If there have been no adjustments, not anything to do
    if (!$isPluginJustFirstTimeActivated && !$isPluginJustUpdated) {
      go back;
    }

    add_action(
      'init',
      serve as () use ($myPluginVersionOptionName, $storedPluginVersion): void {
        $this->prepareAndInstallPluginSetupData($storedPluginVersion);

        // Replace at the DB
        update_option($myPluginVersionOptionName, $this->pluginVersion);
      }
    );
  }

  safe serve as prepareAndInstallPluginSetupData(?string $previousVersion): void
  {
    // Set up good judgment...
  }
}

Realize that prepareAndInstallPluginSetupData (and the following DB replace) is accomplished at the init motion hook. That is to be sure that all knowledge from the CMS is in a position for retrieval and manipulation.

Specifically, taxonomies (tags and classes) can't be accessed ahead of the init hook. If the plugin’s set up procedure had to create a CPT access and assign a customized class to it, this procedure may simplest run from the init hook onwards.

Gaining access to the ultimate kept model from the DB on each and every request isn't very best from a efficiency stance. To fortify this, mix all of the choices wanted through the plugin into an array, retailer them in one access, after which get right of entry to all of them with a unmarried name to the DB.

For example, if the plugin additionally had to retailer a myplugin_date_format technique to show the development date, we will be able to create a unmarried access myplugin_options with houses model and date_format.

To get right of entry to the ultimate kept model, the PHP code will have to be then tailored like this:

pluginVersion;
        update_option($myPluginOptionsOptionName, $myPluginOptions);
      }
    );
  }
}

Averting concurrent requests putting in reproduction knowledge

There's the chance that the set up procedure is also precipitated greater than as soon as if two or extra customers get right of entry to the wp-admin at precisely the similar time. To keep away from the similar knowledge being put in two times or extra, we use a temporary as a flag to permit simplest the primary request to put in knowledge:

  • Take a look at if temporary myplugin_installing_plugin_setup_data exists (as soon as once more, this identify will have to be prepended with myplugin_); if that is so, do not anything (as any other procedure is putting in the information)
  • Differently, retailer the temporary within the database for a cheap most period of time to put in the information (e.g., 30 seconds)
  • Set up the information
  • Delete the temporary

Here's the code:

installPluginSetupData($previousVersion);
    delete_transient($transientName);
  }

  safe serve as installPluginSetupData(?string $previousVersion): void
  {
    // Do one thing...
  }
}

Putting in knowledge for all variations

As discussed previous, if updating the plugin, we will have to simplest set up the information for the brand new variations, now not they all. That signifies that we want to arrange what knowledge to put in model through model.

Within the code underneath, array $versionCallbacks signifies what serve as to execute for every model with the serve as executing the good judgment to put in the information. We iterate the record of them all, evaluate every towards the former model the use of version_compare and, whether it is better, execute the corresponding serve as to put in the corresponding knowledge.

Realize that if $previousVersion is null (i.e., it’s a brand new set up), then all purposes are accomplished.

magnificence Plugin {
  /**
   * Give you the set up in phases, model through model, to
   * be capable of execute it each when putting in/activating the plugin,
   * or updating it to a brand new model with setup knowledge.
   *
   * The plugin's setup knowledge will probably be put in if:
   *
   * - $previousVersion = null => Activating the plugin for first time
   * - $previousVersion < someVersion => Updating to a brand new model that has knowledge to put in
   */
  safe serve as installPluginSetupData(?string $previousVersion): void
  {
    $versionCallbacks = [
      '1.1' => $this->installPluginSetupDataForVersion1Dot1(...),
      '1.2' => $this->installPluginSetupDataForVersion1Dot2(...),
      // ... Add more versions
    ];
    foreach ($versionCallbacks as $model => $callback) {
      /**
       * If the former model is supplied, take a look at if the corresponding replace
       * has already been carried out, then skip
       */
      if ($previousVersion !== null && version_compare($previousVersion, $model, '>=')) {
        proceed;
      }
      $callback();
    }
  }

  safe serve as installPluginSetupDataForVersion1Dot1(): void
  {
    // Do one thing...
  }

  safe serve as installPluginSetupDataForVersion1Dot2(): void
  {
    // Do one thing...
  }
}

Putting in knowledge for every explicit model

After all, we will have to set up the true knowledge (create a web page, a CPT access, upload an possibility, and so forth) for every model.

On this code, we upload the Upcoming Occasions web page for the occasions supervisor plugin, for v1.1:

magnificence Plugin {
  
  // ...

  safe serve as installPluginSetupDataForVersion1Dot1(): void
  {
    wp_insert_post([
      'post_status' => 'publish',
      'post_type' => 'page',
      'post_title' => __('Upcoming Events', 'myplugin'),
      'post_content' => '[event_list number="10" scope="future"]',
    ]);
  }

  // ...
}

Then, we create the Occasions Calendar web page for v1.2 (on this case, the use of Gutenberg blocks at the web page, including a customized block referred to as event-calendar):

magnificence Plugin {
  
  // ...

  safe serve as installPluginSetupDataForVersion1Dot2(): void
  {
    wp_insert_post([
      'post_status' => 'publish',
      'post_type' => 'page',
      'post_title' => __('Events Calendar', 'myplugin'),
      'post_content' => serialize_blocks([
        [
          'blockName' => 'myplugin/event-calendar',
          'attrs' => [
            'status' => 'publish',
          ],
          'innerContent' => [],
        ],
      ]),
    ]);
  }
}

All code in combination

We're performed! The entire PHP code for the Plugin magnificence, containing the good judgment to trace the plugin model and set up the best knowledge, is the next:

managePluginDataVersioning();
  }

  /**
   * If the plugin has simply been newly-installed + activated
   * or up to date, set up the best knowledge.
   */
  safe serve as managePluginDataVersioning(): void
  {
    $myPluginVersionOptionName = 'myplugin_version';
    $storedPluginVersion = get_option($myPluginVersionOptionName, null);

    // Take a look at if the principle plugin has been activated or up to date
    $isPluginJustFirstTimeActivated = $storedPluginVersion === null;
    $isPluginJustUpdated = !$isPluginJustFirstTimeActivated && $storedPluginVersion !== $this->pluginVersion;

    // If there have been no adjustments, not anything to do
    if (!$isPluginJustFirstTimeActivated && !$isPluginJustUpdated) {
      go back;
    }

    add_action(
      'init',
      serve as () use ($myPluginVersionOptionName, $storedPluginVersion): void {
        $this->prepareAndInstallPluginSetupData($storedPluginVersion);

        // Replace at the DB
        update_option($myPluginVersionOptionName, $this->pluginVersion);
      }
    );
  }

  /**
   * Use a temporary to be sure that just one example
   * will set up the information. Differently, two requests
   * going down concurrently may each execute
   * this good judgment
   */
  safe serve as prepareAndInstallPluginSetupData(?string $previousVersion): void
  {
    $transientName = 'myplugin_installing_plugin_setup_data';
    $temporary = get_transient($transientName);
    if ($temporary !== false) {
      // Some other example is executing this code at the moment
      go back;
    }

    set_transient($transientName, true, 30);
    $this->installPluginSetupData($previousVersion);
    delete_transient($transientName);
  }

  /**
   * Give you the set up in phases, model through model, to
   * be capable of execute it each when putting in/activating the plugin,
   * or updating it to a brand new model with setup knowledge.
   *
   * The plugin's setup knowledge will probably be put in if:
   *
   * - $previousVersion = null => Activating the plugin for first time
   * - $previousVersion < someVersion => Updating to a brand new model that has knowledge to put in
   */
  safe serve as installPluginSetupData(?string $previousVersion): void
  {
    $versionCallbacks = [
      '1.1' => $this->installPluginSetupDataForVersion1Dot1(...),
      '1.2' => $this->installPluginSetupDataForVersion1Dot2(...),
      // ... Add more versions
    ];
    foreach ($versionCallbacks as $model => $callback) {
      /**
       * If the former model is supplied, take a look at if the corresponding replace
       * has already been carried out, then skip
       */
      if ($previousVersion !== null && version_compare($previousVersion, $model, '>=')) {
        proceed;
      }
      $callback();
    }
  }

  safe serve as installPluginSetupDataForVersion1Dot1(): void
  {
    wp_insert_post([
      'post_status' => 'publish',
      'post_type' => 'page',
      'post_title' => __('Upcoming Events', 'myplugin'),
      'post_content' => '[event_list number="10" scope="future" status="publish"]',
    ]);
  }

  safe serve as installPluginSetupDataForVersion1Dot2(): void
  {
    wp_insert_post([
      'post_status' => 'publish',
      'post_type' => 'page',
      'post_title' => __('Events Calendar', 'myplugin'),
      'post_content' => serialize_blocks([
        [
          'blockName' => 'myplugin/event-calendar',
          'attrs' => [
            'status' => 'publish',
          ],
          'innerContent' => [],
        ],
      ]),
    ]);
  }
}

Abstract

WordPress plugins frequently want to set up knowledge upon set up. As well as, as more recent variations of the plugin supply new options, the plugin may additionally want to set up knowledge when up to date.

On this article, we discovered the way to monitor variations and set up the best knowledge for our plugins.

Do you might have a WordPress plugin that may have the benefit of putting in knowledge? Tell us within the feedback.

The publish Putting in setup knowledge for a WordPress plugin gave the impression first on Kinsta®.

WP Hosting

[ continue ]