INF 270: WordPress — Week 14: Creating a Shortcode Plugin

Review: What is a WordPress Plugin?

A plugin is a folder of files WordPress loads when you activate it — independent of the theme.

  • Lives in wp-content/plugins/your-plugin-name/
  • Survives theme switches; can be reused on other sites
  • Requires one PHP file with a plugin header comment so WordPress recognizes it
  • Our plugin: one PHP file + the CSS and JS you already wrote

What is a Shortcode?

A tag in square brackets that WordPress replaces with HTML when the page loads — no code editing required for the person publishing content.

You can enter a shortcode in any page by using the "Shortcode" block in the block editor. You then enter the actual shortcode text:

[store-calculator]

In our plugin's PHP file, we will register the shortcode like this:

add_shortcode( 'store-calculator', 'store_calculator_render' )
  • The first argument is the shortcode tag, the second is the name of the function that renders the HTML.
  • The render function must return HTML — never echo it.

Plugin File Structure

Folder name and main PHP filename should match.

wp-content/
  plugins/
    store-calculator/         ← your plugin folder
      store-calculator.php    ← main plugin file (required)
      index.html              ← the HTML from your local project
      style.css               ← the CSS from your local project
      script.js               ← the JS from your local project

Plugin Header

Without Plugin Name, WordPress won't recognize the file. ABSPATH prevents the file from being loaded directly in a browser.

<?php
/**
 * Plugin Name: Store Calculator
 * Description: A shortcode-powered price calculator widget.
 * Version:     1.0.0
 * Author:      Your Name
 */

// Exit if accessed directly — a standard WordPress safety check
if ( ! defined( 'ABSPATH' ) ) {
    exit;
}

Enqueueing CSS and JavaScript

Don't inline <link>/<script> tags in your shortcode output. Use WordPress's enqueue system so assets load in the right place and order.

WordPress manages all CSS and JS through a dependency queue. Instead of printing raw tags, you register each file with a handle (a unique string ID), and WordPress decides when and where to output the actual tag — deduplicating assets if multiple plugins request the same library.

  • wp_enqueue_style( handle, url ) — queues a stylesheet. WordPress outputs it in <head> via wp_head().
  • wp_enqueue_script( handle, url, deps, version, in_footer ) — queues a script. Passing true for in_footer places the tag just before </body>, which is usually what you want so the script doesn't block page rendering.
  • add_action( 'wp_enqueue_scripts', ... ) — hooks your function into the point in the WordPress load cycle where front-end assets are collected. Never call enqueue functions outside a hook.
<?php
function store_calculator_enqueue_assets() {
    wp_enqueue_style(
        'store-calculator-style',
        plugin_dir_url( __FILE__ ) . 'style.css'
    );

    wp_enqueue_script(
        'store-calculator-script',
        plugin_dir_url( __FILE__ ) . 'script.js',
        array(), // no dependencies
        '1.0.0',
        true     // load in the footer, after the HTML
    );
}
add_action( 'wp_enqueue_scripts', 'store_calculator_enqueue_assets' );

plugin_dir_url( __FILE__ ) gives the correct URL to your plugin folder regardless of where WordPress is installed. plugin_dir_path( __FILE__ ) is the server file-system path equivalent — used when you need to include a file rather than link to it.

Simplify your index.html

When you developed locally, you had to create a complete index.html file. For the shortcode, the HTML will be inserted into an existing page. So you can remove the outer html, head and body elements, as well as the script tag.

The Shortcode Callback

ob_start() captures everything that include outputs; ob_get_clean() returns it as a string.

<?php
function store_calculator_render() {
    ob_start();
    include plugin_dir_path( __FILE__ ) . 'index.html';
    return ob_get_clean();
}
add_shortcode( 'store-calculator', 'store_calculator_render' );

Complete Plugin File

<?php
/**
 * Plugin Name: Store Calculator
 * Description: A shortcode-powered price calculator widget.
 * Version:     1.0.0
 * Author:      Your Name
 */

if ( ! defined( 'ABSPATH' ) ) {
    exit;
}

function store_calculator_enqueue_assets() {
    wp_enqueue_style(
        'store-calculator-style',
        plugin_dir_url( __FILE__ ) . 'style.css'
    );
    wp_enqueue_script(
        'store-calculator-script',
        plugin_dir_url( __FILE__ ) . 'script.js',
        array(),
        '1.0.0',
        true
    );
}
add_action( 'wp_enqueue_scripts', 'store_calculator_enqueue_assets' );

function store_calculator_render() {
    ob_start();
    include plugin_dir_path( __FILE__ ) . 'index.html';
    return ob_get_clean();
}
add_shortcode( 'store-calculator', 'store_calculator_render' );

Next Steps

Your plugin's CSS is probably interfering with the rest of your site's styles. Adjust your CSS so it only applies to the elements inside your widget.

It would be good practice to wrap your JavaScript inside a DOMContentLoaded event listener to ensure it runs after the page has fully loaded:

document.addEventListener('DOMContentLoaded', function() {
	// Your existing JavaScript code here
});

Make sure you are committing and pushing your changes to GitHub!