it-swarm.com.de

Bedingtes Laden von JavaScript/CSS für Shortcodes

Ich habe ein Plugin veröffentlicht, das einen Shortcode erstellt und eine JavaScript-Datei und eine CSS-Datei benötigt, um auf jede Seite geladen zu werden, die diesen Shortcode enthält. Ich könnte das Skript/den Stil einfach auf alle Seiten laden lassen, aber das ist nicht die beste Vorgehensweise. Ich möchte nur die Dateien auf Seiten laden, die den Shortcode aufrufen. Ich habe zwei Methoden gefunden, aber beide haben Probleme.

Methode 1 setzt ein Flag in der Shortcode-Handler-Funktion auf true und überprüft diesen Wert dann in einem wp_footer-Rückruf. Wenn dies zutrifft, wird zum Laden des JavaScript wp_print_scripts() verwendet. Das Problem dabei ist, dass es nur für JavaScript und nicht für CSS funktioniert, da CSS in <head> deklariert werden sollte, was Sie nur während eines frühen Hooks wie init oder wp_head tun können.

Methode 2 startet früh und "späht voraus", um zu sehen, ob der Shortcode im aktuellen Seiteninhalt vorhanden ist. Ich mag diese Methode viel besser als die erste, aber das Problem damit wird nicht erkannt, ob die Vorlage do_shortcode() aufruft.

Daher tendiere ich dazu, die zweite Methode zu verwenden und dann zu ermitteln, ob eine Vorlage zugewiesen ist, und wenn ja, den Shortcode zu analysieren. Zuvor wollte ich jedoch überprüfen, ob jemand eine bessere Methode kennt.

Update: Ich habe die Lösung in mein Plugin integriert. Wenn jemand neugierig ist, es in einer Live-Umgebung zu sehen, kann er es herunterladen oder es durchsuchen .

Update 2: Ab WordPress 3.3 ist es jetzt möglich, wp_enqueue_script() direkt in einem Shortcode-Callback aufzurufen und die JavaScript-Datei in der Fußzeile des Dokuments aufzurufen. Dies ist auch für CSS-Dateien technisch möglich, sollte jedoch als schlechte Praxis angesehen werden, da die Ausgabe von CSS außerhalb des <head> -Tags gegen die W3C-Spezifikationen verstößt, unter Umständen FOUC verursacht und den Browser zum erneuten Rendern der Seite zwingt.

37
Ian Dunn

Aufgrund meiner eigenen Erfahrung habe ich eine Kombination aus Methode 1 und 2 verwendet - die Architektur und die Fußzeilenskripte von 1 und die Vorausschau-Technik von 2.

Für die Vorausschau benutze ich jedoch Regex anstelle von stripos; persönliche Präferenz, schneller, und kann nach falschem Shortcode suchen;

preg_match( '#\[ *shortcode([^\]])*\]#i', $content );

Wenn Sie Bedenken haben, dass Autoren do_shortcode manuell verwenden, würde ich diese anweisen verwenden Sie einen Aktionsaufruf Stellen Sie Ihren vorregistrierten Stil manuell in eine Warteschlange.

UPDATE: Für den faulen Autor, der nie RTFM verwendet, wird eine Meldung ausgegeben, um den Fehler ihrer Wege hervorzuheben;)

function my_shortcode()
{
    static $enqueued;
    if ( ! isset( $enqueued ) )
        $enqueued = wp_style_is( 'my_style', 'done' ); // cache it so we don't repeat if called over and over

    // do shortcode
    $output = '';

    if ( ! $enqueued )
        // you can output the message on first occurence only by wrapping it in the previous if
        $output .= <<<HTML
<p>Attention! You must enqueue the shortcode stylesheet yourself if calling <code>do_shortcode()</code> directly!</p>
<p>Use <code>wp_enqueue_style( 'my_style' );</code> before your <code>get_header()</code> call inside your template.</p>
HTML;

    return $output;
}
11
TheDeadMedic

Ich beantworte diese Frage zu spät, aber seit Ian diesen Thread auf der Liste der WP-Hacker heute gestartet hat, war es mir ein Anliegen, sie zu beantworten, insbesondere in Anbetracht der Tatsache, dass ich geplant habe, einigen Plugins, die ich bisher hatte, eine solche Funktion hinzuzufügen arbeiten an.

Ein zu berücksichtigender Ansatz besteht darin, beim Laden der ersten Seite zu überprüfen, ob der Shortcode tatsächlich verwendet wird, und dann den Shortcode-Verwendungsstatus in einem Post-Metaschlüssel zu speichern. Hier ist wie:

Schritt-für-Schritt-Anleitung

  1. Setzen Sie ein $shortcode_used-Flag auf 'no'.
  2. Setzen Sie in der Shortcode-Funktion selbst das Flag $shortcode_used auf 'yes'.
  3. Legen Sie eine 'the_content' Hook-Priorität 12 fest, nachdem WordPress Shortcodes verarbeitet hat, und überprüfen Sie das Post-Meta mit der Taste '' auf einen "_has_{$shortcode_name}_shortcode". (Der Wert '' wird zurückgegeben, wenn für die Beitrags-ID kein Beitrags-Metaschlüssel vorhanden ist.)
  4. Verwenden Sie einen 'save_post'-Hook, um das Post-Meta zu löschen und das persistente Flag für diesen Post zu löschen, falls der Benutzer die Verwendung des Shortcodes ändert.
  5. Verwenden Sie wp_remote_request() auch im Hook 'save_post', um ein nicht blockierendes HTTP-GET an den eigenen Permalink des Posts zu senden, um das Laden der ersten Seite und das Setzen des beständigen Flags auszulösen.
  6. Stellen Sie zuletzt einen 'wp_print_styles' ein und überprüfen Sie das Post-Meta mit dem Schlüssel 'yes' auf den Wert 'no', '' oder "_has_{$shortcode_name}_shortcode". Wenn der Wert 'no' ist, bedienen Sie nicht die externe. Wenn der Wert 'yes' oder '' ist, fahren Sie fort und bedienen Sie das externe Gerät.

Und das sollte es tun. Ich habe ein Beispiel-Plugin geschrieben und getestet, um zu zeigen, wie das alles funktioniert.

Beispiel Plugin Code

Das Plugin wird mit einem [trigger-css]-Shortcode aktiviert, der die <h2>-Elemente auf der Seite auf Weiß-Rot setzt, damit Sie leicht sehen können, wie sie funktionieren. Es wird davon ausgegangen, dass ein css-Unterverzeichnis style.css-Datei mit diesem CSS enthält:

/*
 * Filename: css/style.css
 */
h2 {
  color: white;
  background: red;
}

Und unten ist der Code in einem funktionierenden Plugin:

<?php
/**
 * Plugin Name: CSS on Shortcode
 * Description: Shows how to conditionally load a shortcode
 * Author: Mike Schinkel <[email protected]>
 */
class CSS_On_Shortcode {

  /**
   * @var CSS_On_Shortcode
   */
  private static $_this;

  /**
   * @var string 'yes'/'no' vs. true/false as get_post_meta() returns '' for false and not found.
   */
  var $shortcode_used = 'no';

  /**
   * @var string
   */
  var $HAS_SHORTCODE_KEY = '_has_trigger-css_shortcode';
  /**
   *
   */
  function __construct() {
    self::$_this = $this;
    add_shortcode( 'trigger-css', array( $this, 'do_shortcode' ) );
    add_filter( 'the_content', array( $this, 'the_content' ), 12 ); // AFTER WordPress' do_shortcode()
    add_action( 'save_post', array( $this, 'save_post' ) );
    add_action( 'wp_print_styles', array( $this, 'wp_print_styles' ) );
  }

  /**
   * @return CSS_On_Shortcode
   */
  function this() {
    return self::$_this;
  }

  /**
   * @param array $arguments
   * @param string $content
   * @return string
   */
  function do_shortcode( $arguments, $content ) {
    /**
     * If this shortcode is being used, capture the value so we can save to post_meta in the 'the_content' filter.
     */
    $this->shortcode_used = 'yes';
    return '<h2>THIS POST WILL ADD CSS TO MAKE H2 TAGS WHITE ON RED</h2>';
  }

  /**
   * Delete the 'has_shortcode' meta value so that it can be regenerated
   * on first page load in case shortcode use has changed.
   *
   * @param int $post_id
   */
  function save_post( $post_id ) {
    delete_post_meta( $post_id, $this->HAS_SHORTCODE_KEY );
    /**
     * Now load the post asynchronously via HTTP to pre-set the meta value for $this->HAS_SHORTCODE_KEY.
     */
    wp_remote_request( get_permalink( $post_id ), array( 'blocking' => false ) );
  }

  /**
   * @param array $args
   *
   * @return array
   */
  function wp_print_styles( $args ) {
    global $post;
    if ( 'no' != get_post_meta( $post->ID, $this->HAS_SHORTCODE_KEY, true ) ) {
      /**
       * Only bypass if set to 'no' as '' is unknown.
       */
      wp_enqueue_style( 'css-on-shortcode', plugins_url( 'css/style.css', __FILE__ ) );
    }
   }

  /**
   * @param string $content
   * @return string
   */
  function the_content( $content ) {
    global $post;
    if ( '' === get_post_meta( $post->ID, $this->HAS_SHORTCODE_KEY, true ) ) {
      /**
       * This is the first time the shortcode has ever been seen for this post.
       * Save a post_meta key so that next time we'll know this post uses this shortcode
       */
      update_post_meta( $post->ID, $this->HAS_SHORTCODE_KEY, $this->shortcode_used );
    }
    /**
     * Remove this filter now. We don't need it for this post again.
     */
    remove_filter( 'the_content', array( $this, 'the_content' ), 12 );
    return $content;
  }

}
new CSS_On_Shortcode();

Beispiel-Screenshots

Hier ist eine Reihe von Screenshots

Basic Post Editor, kein Inhalt

Nachanzeige, kein Inhalt

Basic Post Editor mit [trigger-css] Shortcode

Post Display mit [trigger-css] Shortcode

Nicht sicher, ob es 100% ist

Ich glaube, dass das oben Genannte in fast allen Fällen funktionieren sollte, aber da ich gerade diesen Code geschrieben habe, kann ich nicht 100% sicher sein. Wenn Sie Situationen finden, in denen es nicht funktioniert, würde ich gerne wissen, ob ich den Code in einigen Plugins korrigieren kann, die ich soeben hinzugefügt habe. Danke im Voraus.

8
MikeSchinkel

Googeln fand mich ein Potential Antwort . Ich sage "Potenzial", wie es gut aussieht, sollte funktionieren, aber ich bin nicht zu 100% davon überzeugt, dass es der beste Weg ist, dies zu tun:

add_action( 'wp_print_styles', 'yourplugin_include_css' );
function yourplugin_include_css() {
    // Check if shortcode exists in page or post content
    global $post;

    // I removed the end ' ] '... so it can accept args.
    if ( strstr( $post->post_content, '[yourshortcode ' ) ) {
        echo $csslink;
    }
}

Dies sollte in der Lage sein, zu überprüfen, ob der aktuelle Beitrag einen Shortcode verwendet, und dem <head> -Element ein Stylesheet entsprechend hinzuzufügen. Aber ich denke nicht, dass es für eine Indexseite (dh mehrere Posts in der Schleife) funktionieren wird ... Es stammt auch aus einem 2-jährigen Blog-Post, daher bin ich nicht einmal sicher, ob es mit WP 3.1.X.

5
EAMann

Unter Verwendung einer Kombination aus der Antwort von TheDeadMedic und der get_shortcode_regex () Dokumentation (die meine Shortcodes tatsächlich nicht gefunden hat) habe ich eine einfache Funktion erstellt, mit der Skripts für mehrere Shortcodes in die Warteschlange gestellt werden. Da das wp_enqueue_script () in Shortcodes nur zur Fußzeile hinzugefügt wird, kann dies hilfreich sein, da es sowohl Kopf- als auch Fußzeilenskripts verarbeiten kann.


function add_shortcode_scripts() {
    global $wp_query;   
    $posts = $wp_query->posts;
    $scripts = array(
        array(
            'handle' => 'map',
            'src' => 'http://maps.googleapis.com/maps/api/js?sensor=false',
            'deps' => '',
            'ver' => '3.0',
            'footer' => false
        ),
        array(
            'handle' => 'contact-form',
            'src' => get_template_directory_uri() . '/library/js/jquery.validate.min.js',
            'deps' => array( 'jquery' ),
            'ver' => '1.11.1',
            'footer' => true
        )   
    );

    foreach ( $posts as $post ) {
        foreach ( $scripts as $script ) {
            if ( preg_match( '#\[ *' . $script['handle'] . '([^\]])*\]#i', $post->post_content ) ) {
                // enqueue css and/or js
                if ( wp_script_is( $script['handle'], 'registered' ) ) {
                    return;
                } else {
                    wp_register_script( $script['handle'], $script['src'], $script['deps'], $script['ver'], $script['footer'] );
                    wp_enqueue_script( $script['handle'] );
                }
            }
        }
    }
}
add_action( 'wp', 'add_shortcode_scripts' );
2
Sean Michaud

Für mein Plugin habe ich festgestellt, dass Benutzer manchmal einen Theme Builder haben, dessen Shortcode in Metadaten posten gespeichert ist. Hier ist, was ich verwende, um festzustellen, ob mein Plugin-Shortcode in aktuellen Post- oder Post-Metadaten vorhanden ist:

function abcd_load_my_shorcode_resources() {
       global $post, $wpdb;

       // determine whether this page contains "my_shortcode" shortcode
       $shortcode_found = false;
       if ( has_shortcode($post->post_content, 'my_shortcode') ) {
          $shortcode_found = true;
       } else if ( isset($post->ID) ) {
          $result = $wpdb->get_var( $wpdb->prepare(
            "SELECT count(*) FROM $wpdb->postmeta " .
            "WHERE post_id = %d and meta_value LIKE '%%my_shortcode%%'", $post->ID ) );
          $shortcode_found = ! empty( $result );
       }

       if ( $shortcode_found ) {
          wp_enqueue_script(...);
          wp_enqueue_style(...);
       }
}
add_action( 'wp_enqueue_scripts', 'abcd_load_my_shorcode_resources' );
1
zdenekca

Schließlich habe ich auch eine Lösung für das bedingte Laden von CSS gefunden, die für mein Plugin www.mapsmarker.com funktioniert und die ich gerne mit Ihnen teilen möchte. Es wird geprüft, ob mein Shortcode in der aktuellen Vorlagendatei und in der Datei "header/footer.php" verwendet wird. Wenn ja, wird das benötigte Stylesheet in die Kopfzeile eingefügt:

  function prefix_template_check_shortcode( $template ) {
    $searchterm = '[mapsmarker';
    $files = array( $template, get_stylesheet_directory() . DIRECTORY_SEPARATOR . 'header.php', get_stylesheet_directory() . DIRECTORY_SEPARATOR . 'footer.php' );
    foreach( $files as $file ) {
        if( file_exists($file) ) {
            $contents = file_get_contents($file);
            if( strpos( $contents, $searchterm )  ) {
                wp_enqueue_style('
leafletmapsmarker', LEAFLET_PLUGIN_URL . 'leaflet-dist/leaflet.css');
                  break; 
            }
        }
    }
  return $template;
  }  
  add_action('template_include','prefix_template_check_shortcode' );
1
robertharm

Script Logic ist ein WordPress-Plugin, mit dem Sie die volle Kontrolle über alle JavaScript- und CSS-Dateien haben. Mit diesem Plugin können Sie CSS- und JS-Dateien nur auf Seiten laden, auf denen dies erforderlich ist.

http://wordpress.org/plugins/script-logic/

0
Tahir Yasin

weil CSS in <head> deklariert werden sollte

Für CSS-Dateien können Sie diese in Ihre Shortcode-Ausgabe laden:

<style type="text/css">
  @import "path/to/your.css"; 
</style>

Legen Sie eine Konstante oder etwas anderes fest, wie MY_CSS_LOADED (schließen Sie das CSS nur ein, wenn die Konstante nicht festgelegt ist).

Beide Methoden sind langsamer als auf diese Weise.

Für JS-Dateien können Sie dasselbe tun, wenn das Skript, das Sie laden, eindeutig ist und keine externen Abhängigkeiten aufweist. Wenn dies nicht der Fall ist, laden Sie es in die Fußzeile, aber verwenden Sie die Konstante, um zu bestimmen, ob geladen werden muss oder nicht ...

0
onetrickpony