Tải có điều kiện JavaScript / CSS cho Shortcodes


37

Tôi đã phát hành một plugin tạo ra một mã ngắn và yêu cầu tệp JavaScript và tệp CSS để tải trên bất kỳ trang nào có chứa mã ngắn đó. Tôi chỉ có thể tải tập lệnh / kiểu trên tất cả các trang, nhưng đó không phải là cách thực hành tốt nhất. Tôi chỉ muốn tải các tập tin trên các trang gọi shortcode. Tôi đã tìm thấy hai phương pháp để làm điều này, nhưng cả hai đều có vấn đề.

Phương pháp 1 đặt cờ thành đúng bên trong hàm xử lý shortcode, sau đó kiểm tra giá trị đó bên trong một wp_footercuộc gọi lại. Nếu nó đúng, nó sử dụng wp_print_scripts()để tải JavaScript. Vấn đề với điều này là nó chỉ hoạt động cho JavaScript chứ không phải CSS, vì CSS nên được khai báo bên trong <head>, điều mà bạn chỉ có thể thực hiện trong thời gian đầu như hook inithay wp_head.

Phương pháp 2 kích hoạt sớm và "liếc về phía trước" để xem liệu shortcode có tồn tại trong nội dung trang hiện tại không. Tôi thích phương pháp này tốt hơn nhiều so với phương pháp đầu tiên, nhưng vấn đề với nó sẽ không phát hiện được nếu mẫu gọi do_shortcode().

Vì vậy, tôi đang nghiêng về việc sử dụng phương thức thứ hai và sau đó cố gắng phát hiện nếu một mẫu được gán, và nếu vậy, hãy phân tích nó cho mã ngắn. Tuy nhiên, trước khi tôi làm điều đó, tôi muốn kiểm tra xem có ai biết phương pháp nào tốt hơn không.

Cập nhật: Tôi đã tích hợp giải pháp vào plugin của mình. Nếu bất cứ ai tò mò muốn xem nó xuất hiện trong môi trường sống, bạn có thể tải xuống hoặc duyệt nó .

Cập nhật 2: Kể từ WordPress 3.3, giờ đây có thể gọi wp_enqueue_script()trực tiếp bên trong một cuộc gọi lại mã ngắn và tệp JavaScript sẽ được gọi trong phần chân trang của tài liệu. Về mặt kỹ thuật cũng có thể áp dụng cho các tệp CSS, nhưng nên được coi là một thực tiễn xấu vì việc đưa CSS ra ngoài <head>thẻ vi phạm thông số kỹ thuật của W3C, có thể là trường hợp FOUC và có thể buộc trình duyệt hiển thị lại trang.


Tôi đã sử dụng một biến thể của Phương pháp 1 trong quá khứ. Tải JS cho shortcode ở chân trang, tải CSS cho shortcode in-line. Nó hoạt động, nhưng là hackish. Mong chờ một giải pháp tốt hơn.
EAMann

Vấn đề chính với CSS nội tuyến là rất khó ghi đè với các kiểu khác và nó không sử dụng phương thức wp_enqueue_styles ().
Ian Dunn

Bạn có bao nhiêu css?
Mfield

Có bao nhiêu dòng javascript?
Mfield

2
Các javascript là phần dễ dàng. Tốt nhất để làm điều này là dưới "Jedi" ở đây: scribu.net/wordpress/optimal-script-loading.html
mfields

Câu trả lời:


11

Dựa trên kinh nghiệm của bản thân, tôi đã sử dụng kết hợp phương pháp 1 & 2 - các tập lệnh kiến ​​trúc và chân trang của 1 và kỹ thuật 'nhìn về phía trước' của 2.

Đối với cái nhìn phía trước, tôi sử dụng regex thay cho stripos; sở thích cá nhân, nhanh hơn và có thể kiểm tra mã ngắn 'không đúng định dạng';

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

Nếu bạn lo lắng về các tác giả sử dụng do_shortcodethủ công, tôi sẽ chọn hướng dẫn họ sử dụng lệnh gọi hành động để thu hút phong cách đã đăng ký trước của bạn theo cách thủ công.

CẬP NHẬT : Đối với tác giả lười biếng không bao giờ RTFM, hãy xuất một thông báo để làm nổi bật lỗi theo cách của họ;)

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;
}

Đó là một điểm hay. Lý tưởng nhất là tôi muốn nó hoạt động mà không cần họ phải làm gì thêm - bởi vì một nửa thời gian họ có thể sẽ không đọc Câu hỏi thường gặp trước, vì vậy họ sẽ cho rằng nó bị hỏng - nhưng tôi có thể sẽ làm điều đó. Tôi có thể đăng ký các tập lệnh trên mỗi trang, nhưng chỉ ghi lại chúng nếu tôi phát hiện ra một shortcode. Sau đó, người dùng có thể kết nối với init và gọi các hàm enqueue trong các mẫu cụ thể khi cần, giả sử vẫn chưa quá muộn trong quá trình thực thi tại thời điểm đó. Ngoài ra, WP có tích hợp get_shortcode_regex ().
Ian Dunn

3
Nếu người dùng có kinh nghiệm trong việc triển khai do_shortcode(), có hợp lý không khi cho rằng họ cũng lão luyện theo các hướng dẫn sau đây để ghi lại phong cách shortcode?
Chip Bennett

1
Đúng, nhưng nó sẽ nhận được regex cho tất cả các mã ngắn, không chỉ của bạn;) "Tôi có thể đăng ký các tập lệnh trên mỗi trang" Có lẽ cũng là phương pháp tốt hơn! Lưu ý rằng họ không cần phải nối vào init, bất cứ nơi nào trước đây wp_head. Đối với nhà phát triển lười biếng, hãy kiểm tra wp_style_is( 'my_style_handle', 'done' )bên trong shortcode của bạn. Nếu đó là sai, hãy in ra một lỗi có thể nhìn thấy để hướng dẫn họ phải làm gì.
TheDeadMote

@Chip - Tôi không lo lắng rằng họ không có khả năng làm theo hướng dẫn, chỉ là họ sẽ không biết họ phải làm gì, vì 99% thời gian bạn không cần phải làm gì thêm.
Ian Dunn

1
@ Tôi nghĩ rằng việc thêm do_shortcode()vào mẫu đã "làm [thêm] một cái gì đó thêm" - và người dùng sẽ làm điều gì đó thêm sẽ biết về nhu cầu chinh phục phong cách, nếu không sẽ sẵn sàng hơn / có thể để làm theo hướng dẫn đặc biệt.
Chip Bennett

8

Tôi trả lời câu hỏi này muộn nhưng vì Ian đã bắt đầu chủ đề này trong danh sách tin tặc wp hôm nay nên tôi nghĩ rằng nó đáng để trả lời, đặc biệt là khi tôi dự định thêm một tính năng như vậy vào một số plugin tôi đang làm việc.

Một cách tiếp cận để xem xét là kiểm tra tải trang đầu tiên để xem liệu shortcode có thực sự được sử dụng hay không và sau đó lưu trạng thái sử dụng shortcode vào khóa meta post. Đây là cách thực hiện:

Từng bước làm thế nào

  1. Đặt $shortcode_usedcờ thành 'no'.
  2. Trong hàm shortcode, chính nó đặt $shortcode_usedcờ thành 'yes'.
  3. Đặt 'the_content'mức độ ưu tiên hook 12sau khi WordPress đã xử lý shortcodes và kiểm tra meta post để ''sử dụng khóa "_has_{$shortcode_name}_shortcode". (Giá trị ''được trả về khi khóa meta bài đăng không tồn tại cho ID bài đăng.)
  4. Sử dụng một 'save_post'cái móc để xóa meta post xóa cờ liên tục cho bài đăng đó trong trường hợp người dùng thay đổi cách sử dụng shortcode.
  5. Ngoài ra, trong 'save_post'hook sử dụng wp_remote_request()để gửi HTTP GET không chặn đến permalink của chính bài đăng để kích hoạt tải trang đầu tiên và cài đặt cờ liên tục.
  6. Cuối cùng thiết lập một 'wp_print_styles'và kiểm tra bài meta cho một giá trị 'yes', 'no'hoặc ''sử dụng phím "_has_{$shortcode_name}_shortcode". Nếu giá trị 'no'không phục vụ bên ngoài. Nếu giá trị là 'yes'hoặc ''đi trước và phục vụ bên ngoài.

Và rằng nên làm điều đó. Tôi đã viết và thử nghiệm một plugin ví dụ để cho thấy tất cả những thứ này hoạt động như thế nào.

Mã Plugin ví dụ

Plugin thức dậy trên một [trigger-css]shortcode đặt các <h2>thành phần trên trang thành màu trắng trên đỏ để bạn có thể dễ dàng thấy nó hoạt động. Nó giả sử một cssthư mục con chứa style.csstệp có CSS ​​này trong đó:

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

Và dưới đây là mã trong một plugin hoạt động:

<?php
/**
 * Plugin Name: CSS on Shortcode
 * Description: Shows how to conditionally load a shortcode
 * Author: Mike Schinkel <mike@newclarity.net>
 */
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();

Ví dụ Ảnh chụp màn hình

Dưới đây là một loạt các ảnh chụp màn hình

Trình chỉnh sửa bài cơ bản, không có nội dung

Hiển thị bài đăng, không có nội dung

Trình chỉnh sửa bài cơ bản với [trigger-css]Shortcode

Hiển thị bài đăng với [trigger-css]Shortcode

Không chắc chắn nếu đó là 100%

Tôi tin rằng những điều trên sẽ hoạt động trong hầu hết các trường hợp nhưng vì tôi mới viết mã này nên tôi không thể chắc chắn 100%. Nếu bạn có thể tìm thấy các tình huống mà nó không hoạt động tôi thực sự muốn biết vì vậy tôi có thể sửa mã trong một số plugin tôi vừa thêm vào. Cảm ơn trước.


Vì vậy, năm plugin sử dụng phương pháp của bạn sẽ kích hoạt năm yêu cầu từ xa mỗi khi bài đăng được lưu? Tôi muốn sử dụng một regex trên post_content. Và những gì về shortcodes trong widget?
fuxia

@toscho Việc kích hoạt tải bài thực sự là tùy chọn; nó chỉ ở đó để đảm bảo người dùng không phải xem tải trang đầu tiên với các phần bên ngoài được tải. Đây cũng là một cuộc gọi không chặn vì vậy theo lý thuyết bạn không nên chú ý đến nó. Đối với mã của chúng tôi, chúng tôi đang thực hiện trong một lớp cơ sở để lớp cơ sở có thể xử lý việc đó chỉ một lần. Chúng tôi có thể kết 'pre_http_request'nối hook và vô hiệu hóa nhiều cuộc gọi đến cùng một URL trong khi 'save_post'hook đang hoạt động, nhưng tôi muốn đợi cho đến khi w thực sự thấy cần điều đó, phải không? Đối với Widgets, nó có thể được tăng cường để xử lý nhưng nó không phải là trường hợp sử dụng mà tôi đã xem xét.
MikeSchinkel

1
@toscho - Ngoài ra, bạn không thể chắc chắn rằng shortcode ở đó vì một hook khác có thể xóa nó. Cách duy nhất bạn có thể chắc chắn là nếu chức năng shortcode thực sự kích hoạt. Vì vậy, phương pháp regex không đáng tin cậy 100%.
MikeSchinkel

Tôi biết. Không có cách chống đạn để tiêm CSS cho các mã ngắn (trừ khi sử dụng <style>).
fuxia

Tôi đang làm việc với một triển khai dựa trên giải pháp này và tôi chỉ muốn chỉ ra rằng phương pháp này sẽ không gây ra sự xem trước cho bài đăng / trang.
mor7ifer

5

Googling tìm cho tôi một câu trả lời tiềm năng . Tôi nói "tiềm năng" vì nó có vẻ tốt, nên hoạt động, nhưng tôi không tin chắc 100% đó là cách tốt nhất để làm điều đó:

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;
    }
}

Điều này sẽ có thể kiểm tra xem bài đăng hiện tại có đang sử dụng shortcode hay không và thêm biểu định kiểu vào <head>phần tử một cách thích hợp. Nhưng tôi không nghĩ rằng nó sẽ hoạt động cho một chỉ mục (tức là nhiều bài đăng trong vòng lặp) ... Nó cũng từ một bài đăng blog cũ 2 năm, vì vậy tôi thậm chí không chắc nó sẽ hoạt động với WP 3.1.X .


Điều này sẽ không hoạt động nếu shortcode có đối số. Nếu bạn thực sự muốn đi theo con đường này chậm, hãy sử dụng WP get_shortcode_regex()để tìm kiếm.
onetrickpony

Như tôi đã nói, câu trả lời "tiềm năng" mà tôi chưa thử nghiệm ... :-)
EAMann

Về cơ bản giống như phương thức 2, nhưng nó vẫn không kiểm tra mẫu cho các cuộc gọi do_shortcode ().
Ian Dunn

Tại sao nó cần phải làm điều đó? Nếu bạn gọi do_shortcode()thủ công trong mẫu thì bạn đã biết bạn sẽ chạy shortcode
onetrickpony

Tôi không phải là người gọi shortcode, người dùng là. Đây là một plugin phân tán, không phải là một plugin riêng tư.
Ian Dunn

2

Sử dụng kết hợp câu trả lời của TheDeadMedic và tài liệu get_shortcode_regex () (mà thực sự không tìm thấy mã ngắn của tôi), tôi đã tạo ra một hàm đơn giản được sử dụng để liệt kê các tập lệnh cho nhiều mã ngắn. Vì wp_enqueue_script () trong shortcodes chỉ thêm vào phần chân trang, điều này có thể hữu ích vì nó có thể xử lý cả tập lệnh đầu trang và chân trang.


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' );

1

Cuối cùng tôi cũng tìm thấy một giải pháp cho việc tải css có điều kiện, hoạt động cho plugin của tôi www.mapsmarker.com và tôi dùng để chia sẻ với bạn. Nó kiểm tra xem shortcode của tôi có được sử dụng trong tệp mẫu hiện tại và tiêu đề / footer.php hay không và nếu có, hãy liệt kê biểu định kiểu cần thiết trong tiêu đề:

  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' );

hơi lệch sang một bên nhưng điều này không cho rằng mọi người đang sử dụng header.php và footer.php. Điều gì về các phương thức gói chủ đề như được mô tả bởi scribu.net/wordpress/theme-wrappers.html ? hoặc chủ đề như rễ giữ các phần mẫu của họ ở nơi khác?
orionrush

1

Đối với plugin của tôi, tôi thấy rằng đôi khi người dùng có trình tạo chủ đề có mã ngắn được lưu trữ trong dữ liệu bài đăng . Đây là những gì tôi đang sử dụng để phát hiện xem shortcode plugin của tôi có trong dữ liệu meta bài đăng hoặc bài đăng hiện tại hay không :

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' );

0

bởi vì CSS nên được khai báo bên trong <head>

Đối với các tệp CSS, bạn có thể tải chúng trong đầu ra shortcode của mình:

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

Đặt một hằng số hoặc một cái gì đó sau này, như MY_CSS_LOADED(chỉ bao gồm CSS nếu hằng số không được đặt).

Cả hai phương pháp của bạn đều chậm hơn so với cách này.

Đối với các tệp JS, bạn có thể làm tương tự nếu tập lệnh bạn đang tải là duy nhất và không có bất kỳ phụ thuộc bên ngoài nào. Nếu đây không phải là trường hợp tải nó bên trong chân trang, nhưng sử dụng hằng số để xác định xem có cần tải hay không ...


3
Tải CSS bên ngoài <head>phần tử không phải là đánh dấu thích hợp. Đúng, xác thực chỉ là một hướng dẫn, nhưng nếu chúng ta cố gắng tuân theo hướng dẫn đó, thì việc tải biểu định kiểu trong đầu ra mã ngắn là một ý tưởng tồi.
EAMann

Các khối CSS nội tuyến là đánh dấu hợp lệ, ngay cả trong XHTML từ những gì tôi nhớ. Không có lý do gì để không sử dụng chúng khi bạn không có lựa chọn nào khác được chấp nhận
onetrickpony

1
Theo công cụ xác nhận của W3C : <style type="text/css"> The element named above was found in a context where it is not allowed. This could mean that you have incorrectly nested elements -- such as a "style" element in the "body" section instead of inside "head". Vì vậy, kiểu nội tuyến ( <element style="..."></element>) là hợp lệ, nhưng các <style>phần tử nội tuyến thì không.
EAMann

1
làm cho nó có thể lọc và bất kỳ plugin hoặc chủ đề nào khác có thể làm như họ muốn với nó. Nếu họ định cấu hình bộ lọc để trả về một chuỗi trống - sẽ không có gì được in.
Mfields

1
Bạn đã không đề cập đến bất kỳ lý do khách quan chống lại thực hành này. Dù sao nó không thành vấn đề; Tôi chỉ thấy hai tùy chọn ở đây: Luôn tải CSS / script (tối ưu hóa kích thước) hoặc kiểu nội tuyến có điều kiện
onetrickpony

0

Script Logic là một plugin WordPress cung cấp cho bạn toàn quyền kiểm soát tất cả các tệp JavaScript và CSS. Sử dụng plugin này, bạn chỉ có thể tải tệp CSS và JS một cách có điều kiện trên các trang cần thiết.

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


Điều đó không thực sự liên quan đến câu hỏi này, đó là về việc kiểm soát sự mê hoặc từ chính plugin. Cách tiếp cận của bạn sẽ yêu cầu người dùng cài đặt một plugin khác, và sau đó hiểu cách cấu hình đúng.
Ian Dunn
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.