[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"blog-content-publish-a-plugin-to-the-wordpress-store-2":3},"\u003Cp>Have you ever wanted to publish your own plugin to the official \u003Ca href=\"https:\u002F\u002Fde-at.wordpress.org\u002Fplugins\u002F\" rel=\"noreferrer\">WordPress plugin store\u003C\u002Fa>? The process of developing your own WordPress plugin can be cumbersome and exhausting, as some things are proprietary to WordPress and need to be done in specific ways, but don't worry, I'm here to help 😄\u003C\u002Fp>\u003Cp>I recently had the pleasure of developing and publishing a WordPress-Plugin for our innovative, ai-driven image cropping software \u003Ca href=\"https:\u002F\u002Fcroppy.at\u002F\" rel=\"noreferrer\">Croppy\u003C\u002Fa>. You can check it out here: \u003Ca href=\"https:\u002F\u002Fwordpress.org\u002Fplugins\u002Fcroppy-ai-assisted-image-cropper\u002F\" rel=\"noreferrer\">WordPress-Plugin-Store: Croppy\u003C\u002Fa>\u003C\u002Fp>\u003Ch2 id=\"things-to-consider-even-before-starting\">Things to consider, even before starting\u003C\u002Fh2>\u003Cp>Some things should be considered very carefully, before writing a single line of code. Otherwise, you might end up failing the review process of WordPress and need to adapt your code. (it happened to me, so learn from my mistakes)\u003C\u002Fp>\u003Col>\u003Cli>\u003Cstrong>Your code must define a GPL-compatible License\u003C\u002Fstrong>\u003Col>\u003Cli>how you do that? Well I will explain that later on in the blog but just think about which license you would like to use\u003C\u002Fli>\u003C\u002Fol>\u003C\u002Fli>\u003Cli>\u003Cstrong>Every piece of code you write in functions, classes etc. must be generic and with a custom slug in front of it\u003C\u002Fstrong>\u003Col>\u003Cli>this is due to the fact that WordPress hosts millions of plugins and there is the chance that someone has the same method as you, if there would be no slug, you would overwrite his method or vice versa\u003C\u002Fli>\u003C\u002Fol>\u003C\u002Fli>\u003Cli>\u003Cstrong>All data, that your plugin uses must be sanitized, escaped and validated before being used\u003C\u002Fstrong>\u003Col>\u003Cli>WordPress offers a variety of sanitation methods, you must use them, details can be found later on\u003C\u002Fli>\u003C\u002Fol>\u003C\u002Fli>\u003Cli>\u003Cstrong>No Iframe, no creation of users, no saving of files directly  into the Plugin directory\u003C\u002Fstrong>\u003Col>\u003Cli>generally not allowed\u003C\u002Fli>\u003C\u002Fol>\u003C\u002Fli>\u003C\u002Fol>\u003Cp>Those were among the things that broke my neck when submitting the plugin for the first time. To be honest: If I had read the \u003Ca href=\"https:\u002F\u002Fdeveloper.wordpress.org\u002Fplugins\u002Fwordpress-org\u002Fdetailed-plugin-guidelines\u002F\" rel=\"noreferrer\">documentation\u003C\u002Fa> thoroughly beforehand, it  would have been easier :)\u003C\u002Fp>\u003Cfigure class=\"kg-card kg-image-card\">\u003Cimg src=\"\u002Fimages\u002Fblog\u002Fpublish-a-plugin-to-the-wordpress-store-2-seadev_studios_a_car_being_ready_to_start_in_a_race_comic_style.webp\" class=\"kg-image\" alt=\"a racing car, that just startet the race\" loading=\"lazy\" width=\"1154\" height=\"647\" srcset=\"\u002Fimages\u002Fblog\u002Fpublish-a-plugin-to-the-wordpress-store-2-seadev_studios_a_car_being_ready_to_start_in_a_race_comic_style.webp 600w, \u002Fimages\u002Fblog\u002Fpublish-a-plugin-to-the-wordpress-store-2-seadev_studios_a_car_being_ready_to_start_in_a_race_comic_style.webp 1000w, \u002Fimages\u002Fblog\u002Fpublish-a-plugin-to-the-wordpress-store-2-seadev_studios_a_car_being_ready_to_start_in_a_race_comic_style.webp 1154w\" sizes=\"(min-width: 720px) 720px\">\u003C\u002Ffigure>\u003Ch2 id=\"ready-set-go\">Ready,  set, go!\u003C\u002Fh2>\u003Cp>As you have now considered the most important things and thought about what your plugin should and should not do, it is time to start our development process.\u003C\u002Fp>\u003Ch3 id=\"the-first-steps-when-developing\">The first steps when developing\u003C\u002Fh3>\u003Cp>Create a directory for your plugin. The name you choose will be the plugin-slug, so be careful and choose one that you can use later on in the store as well.\u003C\u002Fp>\u003Cp>When you have your directory, create a \u003Cem>LICENSE.txt\u003C\u002Fem> in it and copy the content of your preferred GPL-compatible license in it.\u003C\u002Fp>\u003Cp>Then create a PHP file, that serves as entry point for your plugin. Your directory structure should now look like that:\u003C\u002Fp>\u003Cfigure class=\"kg-card kg-image-card kg-card-hascaption\">\u003Cimg src=\"\u002Fimages\u002Fblog\u002Fpublish-a-plugin-to-the-wordpress-store-2-image.png\" class=\"kg-image\" alt=\"a directory structure\" loading=\"lazy\" width=\"345\" height=\"85\">\u003Cfigcaption>\u003Cspan style=\"white-space: pre-wrap;\">You must change the slug to your desired name\u003C\u002Fspan>\u003C\u002Ffigcaption>\u003C\u002Ffigure>\u003Cp>Now open your PHP file and start is with\u003C\u002Fp>\u003Cpre>\u003Ccode class=\"language-php\">&lt;?php\n\u002F**\n * Plugin Name: Blog Plugin\n * Plugin URI: https:\u002F\u002FXXXX.com\n * Description: Perfect description of the blog plugin.\n * Version: 1.0.0\n * Author: Kilian\n * Author URI: https:\u002F\u002Fseadev-studios.com\n * Text Domain: blog-plugin\n * Domain Path: \u002Flanguages\n * Requires at least: 6.4\n * Requires PHP: 7.0\n * Tested up to: 6.5\n * License: GPLv2 or later\n * License URI: http:\u002F\u002Fwww.gnu.org\u002Flicenses\u002Fgpl-2.0.html\n**\u002F\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cul>\u003Cli>The plugin name is self-explanatory. \u003C\u002Fli>\u003Cli>The Plugin URI is the website of your plugin (if existent)\u003C\u002Fli>\u003Cli>the text domain is the domain of your plugin, it should always match your plugin slug.\u003C\u002Fli>\u003Cli>The domain path is the path where WordPress can find your translations for your strings (if  you do not translate, just delete this line)\u003C\u002Fli>\u003Cli>The requirements are basically the versions of WordPress and PHP that your plugin needs\u003C\u002Fli>\u003Cli>the tested up to states up to which version your plugin has been tested. \u003C\u002Fli>\u003Cli>Then specify your license again, and you are set.\u003C\u002Fli>\u003C\u002Ful>\u003Ch3 id=\"the-readme\">The README\u003C\u002Fh3>\u003Cp>The README is basically the description, that is being rendered into the plugin store when you click onto a plugin. It is important to note that this will be one of the first things a potential user sees, so try to be as specific as possible when choosing what to write here.\u003C\u002Fp>\u003Cp>It is written in Markdown. So you can make headers, lists, etc. Important to note is, that it must consist of four sections:\u003C\u002Fp>\u003Col>\u003Cli>Title of your plugin (yet again)\u003C\u002Fli>\u003C\u002Fol>\u003Cpre>\u003Ccode class=\"language-txt\">=== Blog Plugin ===\nContributors: kilian\nTags: blog, development\nStable tag: 1.0.0\nRequires at least: 6.0\nRequires PHP: 7.0\nTested up to: 6.6\nLicense: GPLv2 or later\nLicense URI: http:\u002F\u002Fwww.gnu.org\u002Flicenses\u002Fgpl-2.0.html\n\nThe best WordPress plugin to exist.\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Col start=\"2\">\u003Cli>Description\u003C\u002Fli>\u003C\u002Fol>\u003Cpre>\u003Ccode class=\"language-txt\">== Description ==\n# Description of the Blog plugin.\n...\n...\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Col start=\"3\">\u003Cli>Installation\u003C\u002Fli>\u003C\u002Fol>\u003Cpre>\u003Ccode class=\"language-txt\">== Installation ==\n\nGeneral Information  on what is needed to run your plugin (external accounts for example)\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Col start=\"4\">\u003Cli>FAQ\u003C\u002Fli>\u003C\u002Fol>\u003Cpre>\u003Ccode class=\"language-txt\">== Frequently Asked Questions ==\n\n= Question 1 =\n\nAnswer 1\n\n= Question 2 =\n\nAnswer 2\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Great job. That's it. Per definition, you have your own WordPress plugin. It doesn't do anything yet other than look good in the store ;), but we can change that.\u003C\u002Fp>\u003Cfigure class=\"kg-card kg-image-card kg-card-hascaption\">\u003Cimg src=\"\u002Fimages\u002Fblog\u002Fpublish-a-plugin-to-the-wordpress-store-2-seadev_studios_a_programmer_that_just_starts_coding_comic_style-1.webp\" class=\"kg-image\" alt=\"a programmer that is focused on his work\" loading=\"lazy\" width=\"1154\" height=\"647\" srcset=\"\u002Fimages\u002Fblog\u002Fpublish-a-plugin-to-the-wordpress-store-2-seadev_studios_a_programmer_that_just_starts_coding_comic_style-1.webp 600w, \u002Fimages\u002Fblog\u002Fpublish-a-plugin-to-the-wordpress-store-2-seadev_studios_a_programmer_that_just_starts_coding_comic_style-1.webp 1000w, \u002Fimages\u002Fblog\u002Fpublish-a-plugin-to-the-wordpress-store-2-seadev_studios_a_programmer_that_just_starts_coding_comic_style-1.webp 1154w\" sizes=\"(min-width: 720px) 720px\">\u003Cfigcaption>\u003Cspan style=\"white-space: pre-wrap;\">Let's start coding.\u003C\u002Fspan>\u003C\u002Ffigcaption>\u003C\u002Ffigure>\u003Ch3 id=\"the-coding\">The Coding\u003C\u002Fh3>\u003Cp>I will not tell you what to program and how.  I will just tell you some things to consider and some things to do so that it works properly.\u003C\u002Fp>\u003Cp>The first lines of code should be:\u003C\u002Fp>\u003Cpre>\u003Ccode class=\"language-php\">\u002F\u002F Exit if accessed directly\nif (!defined('ABSPATH')) {\n    exit;\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>This ensures that your plugin  file cannot be accessed via the browser.\u003C\u002Fp>\u003Cp>Create a PHP function now, that initializes a menu item so that your plugin  is accessible via the menu:\u003C\u002Fp>\u003Cpre>\u003Ccode class=\"language-php\">\u002F\u002F Add menu item to left sidebar\nfunction blog_plugin_add_menu_item() {\n    \u002F\u002F Add menu page with icon\n    add_menu_page(\n        'Blog Plugin',              \u002F\u002F Page title\n        'Blog Plugin',              \u002F\u002F Menu title\n        'manage_options',      \u002F\u002F Capability required to access the page\n        'blog_plugin',     \u002F\u002F Menu slug\n        'blog_plugin_page',\u002F\u002F Callback function to render the page\n        'dashicons-format-image',\n        10                      \u002F\u002F Position in the menu\n    );\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Notice the consistent usage of the plugin slug 😃\u003C\u002Fp>\u003Cp>And the function to render the page is defined right away:\u003C\u002Fp>\u003Cpre>\u003Ccode class=\"language-php\">function blog_plugin_page() {\n    ?&gt;\n        &lt;div&gt;\n            &lt;h1&gt;\n                Some HTML Content to render!\n            &lt;\u002Fh1&gt;\n        &lt;\u002Fdiv&gt;\n    &lt;?php\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>You can return any HTML you like and style the page as you wish. This is the component of your plugin that will be seen and interacted with by the user directly. So style it to be appealing.\u003C\u002Fp>\u003Cp>And to trigger the creation of the menu item, add the following code somewhere into the PHP file.\u003C\u002Fp>\u003Cpre>\u003Ccode class=\"language-php\">add_action('admin_menu', 'blog_plugin_add_menu_item');\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>This tells WordPress to render your menu item as soon as the admin menu action is triggered.\u003C\u002Fp>\u003Cp>That's basically  it. I will now tell you a few things you can use if you would like to, but the general blog is now finished!\u003C\u002Fp>\u003Ch2 id=\"good-to-know\">Good to know\u003C\u002Fh2>\u003Cp>Some things are good to know but not mandatory to use, under this category falls everything that I will explain now:\u003C\u002Fp>\u003Ch3 id=\"add-css-and-jquery-code-to-your-plugin\">Add CSS and JQuery Code to your plugin\u003C\u002Fh3>\u003Cp>First things first, add the following code snippet:\u003C\u002Fp>\u003Cpre>\u003Ccode class=\"language-php\">add_action('admin_enqueue_scripts', 'blog_plugin_custom_scripts');\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Then create the correlating function:\u003C\u002Fp>\u003Cpre>\u003Ccode class=\"language-php\">function blog_plugin_custom_scripts() {\n    wp_enqueue_style('blog-plugin-custom-style', plugins_url('css\u002Fstyling.css', _FILE__), array(), '1.0.0');\n    wp_enqueue_script('blog-plugin-custom-script', plugins_url('js\u002Fscript.js', __FILE__), array('jquery'), '1.0.0');\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Of course, you would need to create both the style.css and the script.js file in the corresponding directory within your plugin directory.\u003C\u002Fp>\u003Ch3 id=\"sanitize-input-escape-input-validate-input\">Sanitize Input, Escape Input, Validate Input\u003C\u002Fh3>\u003Cp>WordPress offers some cool methods to do those things completely  automated.\u003C\u002Fp>\u003Cul>\u003Cli>esc_html_e()\u003Cul>\u003Cli>displays translated text and escapes it for safe use in HTML output\u003C\u002Fli>\u003C\u002Ful>\u003C\u002Fli>\u003Cli>sanitize_text_field()\u003Cul>\u003Cli>sanitizes user input from a text field on your plugin page\u003C\u002Fli>\u003C\u002Ful>\u003C\u002Fli>\u003Cli>wp_unslash()\u003Cul>\u003Cli>removes slashes from a string (recursively)\u003C\u002Fli>\u003C\u002Ful>\u003C\u002Fli>\u003C\u002Ful>\u003Cp>Whenever your application deals with dynamic user data, remember to sanitize, escape and validate this data before doing anything with it.\u003C\u002Fp>\u003Ch3 id=\"translating-your-strings\">Translating your Strings\u003C\u002Fh3>\u003Cp>Translating your plugin provides you with certainty, that no auto-translation misinterprets your plugin and that all users around the world see the correct translations.\u003C\u002Fp>\u003Ch4 id=\"the-po-files\">The .po Files\u003C\u002Fh4>\u003Cp>Those files are used to define all the messages and translations that you have.\u003C\u002Fp>\u003Cp>The structure is as easy as could be:\u003C\u002Fp>\u003Cpre>\u003Ccode class=\"language-po\">msgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: \\n\"\n\"POT-Creation-Date: \\n\"\n\"PO-Revision-Date: \\n\"\n\"Last-Translator: \\n\"\n\"Language-Team: \\n\"\n\"Language: de_AT\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text\u002Fplain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\nmsgid \"Logout\"\nmsgstr \"Ausloggen\"\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Define your message IDs and your message strings. Before all the strings, change the language tag to your actual language. The rest should be good to go.\u003C\u002Fp>\u003Cp>Then save the file with the following name:\u003C\u002Fp>\u003Cp>\u003Cstrong>blog-plugin-de_DE.po\u003C\u002Fstrong>\u003C\u002Fp>\u003Cp>The locale and the slug of course change, but the syntax is important. Also, the locale must match the language tag within the .po file.\u003C\u002Fp>\u003Ch4 id=\"the-mo-files\">The .mo Files\u003C\u002Fh4>\u003Cp>Are actually binary representation of your .po files and are the translated, interpretable version of your translations so that WordPress can use them.\u003C\u002Fp>\u003Cp>Creating the .mo Files is easy:\u003C\u002Fp>\u003Cpre>\u003Ccode class=\"language-bash\">msgcat yourFile.po | msgfmt -o generatedFile.mo -\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>That's it. \u003C\u002Fp>\u003Ch4 id=\"usage-of-the-translation-in-the-plugin-code\">Usage of the translation in the plugin code\u003C\u002Fh4>\u003Cp>Important is, that the text-domain matches your plugin slug (in my case blog-plugin) and that the .mo files have the name blog-plugin-LOCALE.mo so that WordPress can find them.\u003C\u002Fp>\u003Cp>Now you can just translate any string with:\u003C\u002Fp>\u003Cpre>\u003Ccode class=\"language-js\">esc_html_e('Logout', 'blog-plugin');\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Finished.\u003C\u002Fp>\u003Cfigure class=\"kg-card kg-image-card\">\u003Cimg src=\"\u002Fimages\u002Fblog\u002Fpublish-a-plugin-to-the-wordpress-store-2-seadev_studios_a_new_software_is_being_deployed_to_a_global_CDN-1.webp\" class=\"kg-image\" alt=\"interconnected world, driven by technology\" loading=\"lazy\" width=\"1456\" height=\"816\" srcset=\"\u002Fimages\u002Fblog\u002Fpublish-a-plugin-to-the-wordpress-store-2-seadev_studios_a_new_software_is_being_deployed_to_a_global_CDN-1.webp 600w, \u002Fimages\u002Fblog\u002Fpublish-a-plugin-to-the-wordpress-store-2-seadev_studios_a_new_software_is_being_deployed_to_a_global_CDN-1.webp 1000w, \u002Fimages\u002Fblog\u002Fpublish-a-plugin-to-the-wordpress-store-2-seadev_studios_a_new_software_is_being_deployed_to_a_global_CDN-1.webp 1456w\" sizes=\"(min-width: 720px) 720px\">\u003C\u002Ffigure>\u003Ch2 id=\"publishing-your-form\">Publishing your form\u003C\u002Fh2>\u003Cp>Go to this page here and submit the submission form: \u003Ca href=\"https:\u002F\u002Fwordpress.org\u002Fplugins\u002Fadd\u002F\">https:\u002F\u002Fwordpress.org\u002Fplugins\u002Fadd\u002F\u003C\u002Fa>\u003C\u002Fp>\u003Cp>They will test and review your plugin code thoroughly, but if you stuck to this blog, that will be no problem. \u003Cbr>As soon as the review process is done, you can upload the plugin code to SVN. These steps are already well documented.\u003C\u002Fp>\u003Cp>If you have got any questions about any step that I have explained on how to publish a WordPress plugin, do not hesitate to leave a comment!\u003C\u002Fp>\u003Cp>Thank you for reading and I wish you all the best.\u003C\u002Fp>"]