GeoPal Notes

Random stuff

WordPress shortcode για HTML, CSS και Javascript

Έστω πως επιθυμούμε την κατασκευή ενός WordPress shortcode το οποίο όταν καλείται επιστρέφει html, css και javascript.

Θα μπορούσαμε να ενσωματώσουμε όλα τα παραπάνω σε κάτι του τύπου:

function content_hcj_function() {
  $buff = '
  <style>
    .ozzy {
      background: #0A0A0A;
      color: #FAFAFA }
  </style>
  
  <script>
    document.querySelector('.ozzy p').style.borderBottom = '3px solid';
  </script>

  <div class="ozzy">
    <p>No more tears</p>
  </div>';
  
  return $buff;
}
add_shortcode('listen-to', 'content_hcj_function');

Οπότε κατά την κλήση του το shortcode θα παράγει αυτό.

Υπάρχουν όμως τα εξής ζητήματα:

  1. Αν το shortcode κληθεί πολλές φορές, τότε επίσης και το ίδιο το css θα επιστραφεί κάθε φορά και μην ξεχνάμε πως θα μπορούσε να πρόκειται για πολλές γραμμές, όχι όπως στο παράδειγμα. Αυτό δεν είναι ούτε σωστό, ούτε αποδοτικό.
  2. Οι ειδικοί χαρακτήρες που περιέχονται στην javascript (π.χ. $, &, #), θα μετατραπούν από τα φίλτρα περιεχομένου του WordPress (content filters) σε HTML entities, οπότε ο κώδικας δεν θα λειτουργήσει.

Προτεινόμενη Υλοποίηση

Η βασική στρατηγική είναι πως θα διαχωριστούν τα επιστρεφόμενα δεδομένα ανά τύπο. Η html θα παραχθεί από το shortcode, ενώ τα τμήματα css και javascript θα ενσωματωθούν σε ξεχωριστά .css και .js αρχεία τα οποία και θα κληθούν με κατάλληλο τρόπο.

Αρχικά κατασκευάζω το shortcode με τη συνάρτηση κλήσης του, εντός ενός πρόσθετου (plugin), συμπεριλαμβανομένου της html που θέλω να επιστραφεί κατά την κλήση.

/**
 * Plugin Name: HTML, CSS, JS Shortcode
 * Description: Display custom content
 * Version: 1.0
 * Author: geopal
 */

/** Exit if accessed directly */
if (!defined('ABSPATH')) exit;

function content_hcj_function() {

    $buff = '
    <div class="ozzy">
    <p>No more tears</p>
    </div>';
    
    return $buff;

}
add_shortcode('listen-to', 'content_hcj_function');

Στη συνέχεια και προκειμένου να γνωρίζω αν το shortcode έχει κληθεί τουλάχιστον μία φορά, χρησιμοποιώ το τέχνασμα της συνάρτησης add_filter(). Η ίδια λογική θα μπορούσε να υλοποιηθεί με τη δημιουργία μιας global μεταβλητής, το αποφεύγω όμως εσκεμμένα.

/**
 * Plugin Name: HTML, CSS, JS Shortcode
 * Description: Display custom content
 * Version: 1.0
 * Author: geopal
 */

/** Exit if accessed directly */
if (!defined('ABSPATH')) exit;

function content_hcj_function() {
 
    // Declare that shortcode has been used (only once per pageload)
    if (!has_filter('shortcode_hcj_used', '__return_true')) {
        add_filter('shortcode_hcj_used', '__return_true');
    }

    $buff = '
    <div class="ozzy">
    <p>No more tears</p>
    </div>';
    
    return $buff;

}
add_shortcode('listen-to', 'content_hcj_function');

Εν συνεχεία καταχωρώ (register) χωρίς να φορτώσω τα assets μου (css, js), χρησιμοποιώντας τις συναρτήσεις wp_register_style(), wp_register_script() και το wp_enqueue_scripts() hook.

/**
 * Plugin Name: HTML, CSS, JS Shortcode
 * Description: Display custom content
 * Version: 1.0
 * Author: geopal
 */

/** Exit if accessed directly */
if (!defined('ABSPATH')) exit;

function content_hcj_function() {
 
    // Declare that shortcode has been used (only once per pageload)
    if (!has_filter('shortcode_hcj_used', '__return_true')) {
        add_filter('shortcode_hcj_used', '__return_true');
    }

    $buff = '
    <div class="ozzy">
    <p>No more tears</p>
    </div>';
    
    return $buff;

}
add_shortcode('listen-to', 'content_hcj_function');

// Register assets
function register_hcj_assets_function() {
    wp_register_style(
        'hcj-style',
        plugin_dir_url(__FILE__) . 'assets/style.css',
        array(),
        '1.0.0',
        'all'
    );
    wp_register_script(
        'hcj-script',
        plugin_dir_url(__FILE__) . 'assets/script.js',
        array(),
        '1.0.0',
        true
    );
}
add_action( 'wp_enqueue_scripts', 'register_hcj_assets_function' );

Στο τελευταίο βήμα, χρησιμοποιώντας τις wp_enqueue_style() και wp_enqueue_script() φορτώνω (enqueue) τα assets μου υπο την προϋπόθεση πως το shortcode έχει κληθεί, οπότε προκύπτει και η τελική έκδοση του κώδικα.

/**
 * Plugin Name: HTML, CSS, JS Shortcode
 * Description: Display custom content
 * Version: 1.0
 * Author: geopal
 */

/** Exit if accessed directly */
if (!defined('ABSPATH')) exit;

function content_hcj_function() {
 
    // Declare that shortcode has been used (only once per pageload)
    if (!has_filter('shortcode_hcj_used', '__return_true')) {
        add_filter('shortcode_hcj_used', '__return_true');
    }

    $buff = '
    <div class="ozzy">
    <p>No more tears</p>
    </div>';
    
    return $buff;

}
add_shortcode('listen-to', 'content_hcj_function');

// Register assets
function register_hcj_assets_function() {
    wp_register_style(
        'hcj-style',
        plugin_dir_url(__FILE__) . 'assets/style.css',
        array(),
        '1.0.0',
        'all'
    );
    wp_register_script(
        'hcj-script',
        plugin_dir_url(__FILE__) . 'assets/script.js',
        array(),
        '1.0.0',
        true
    );
}
add_action( 'wp_enqueue_scripts', 'register_hcj_assets_function' );

// Enqueue assets if the shortcode is used
add_action('wp_enqueue_scripts', 'load_hcj_assets');
function load_hcj_assets() {
    if (apply_filters('shortcode_hcj_used', false)) {
        wp_enqueue_style('hcj-style');
        wp_enqueue_script('hcj-script');
    }
}