สร้าง WP tutorial สำหรับผู้ใช้ที่มีตัวชี้ admin โดยใช้ปุ่มถัดไปสำหรับการนำทาง


9

ฉันมุ่งมั่นที่จะสร้างการสอนเกี่ยวกับผู้ใช้ของฉันสำหรับพื้นที่ผู้ดูแลระบบ เพื่อให้บรรลุสิ่งนี้ฉันใช้พอยน์เตอร์ของผู้ดูแลระบบที่มีอยู่ใน WP core เป้าหมายของฉัน:

ป้อนคำอธิบายรูปภาพที่นี่

ฉันเกือบจะถึงแล้ว สิ่งที่ฉันได้มา ...

ลงทะเบียนสคริปต์ wp-pointer:

add_action( 'admin_enqueue_scripts', 'custom_admin_pointers_header' );

function custom_admin_pointers_header() {
    if ( custom_admin_pointers_check() ) {
        add_action( 'admin_print_footer_scripts', 'custom_admin_pointers_footer' );

        wp_enqueue_script( 'wp-pointer' );
        wp_enqueue_style( 'wp-pointer' );
    }
}

ฟังก์ชั่นตัวช่วยรวมถึงการตรวจสอบตามเงื่อนไขและสคริปต์ส่วนท้าย:

function custom_admin_pointers_check() {
    $admin_pointers = custom_admin_pointers();
    foreach ( $admin_pointers as $pointer => $array ) {
        if ( $array['active'] )
            return true;
    }
}

function custom_admin_pointers_footer() {
    $admin_pointers = custom_admin_pointers();
    ?>
    <script type="text/javascript">
        /* <![CDATA[ */
        ( function($) {
            <?php
            foreach ( $admin_pointers as $pointer => $array ) {
               if ( $array['active'] ) {
                  ?>
            $( '<?php echo $array['anchor_id']; ?>' ).pointer( {
                content: '<?php echo $array['content']; ?>',
                position: {
                    edge: '<?php echo $array['edge']; ?>',
                    align: '<?php echo $array['align']; ?>'
                },
                close: function() {
                    $.post( ajaxurl, {
                        pointer: '<?php echo $pointer; ?>',
                        action: 'dismiss-wp-pointer'
                    } );
                }
            } ).pointer( 'open' );
            <?php
         }
      }
      ?>
        } )(jQuery);
        /* ]]> */
    </script>
<?php
}

ตอนนี้เราพร้อมที่จะรวบรวมพอยน์เตอร์พอยน์เตอร์:

function custom_admin_pointers() {
    $dismissed = explode( ',', (string) get_user_meta( get_current_user_id(), 'dismissed_wp_pointers', true ) );
    $version = '1_0'; // replace all periods in 1.0 with an underscore
    $prefix = 'custom_admin_pointers' . $version . '_';

    $new_pointer_content = '<h3>' . __( 'Add New Item' ) . '</h3>';
    $new_pointer_content .= '<p>' . __( 'Easily add a new post, media item, link, page or user by selecting from this drop down menu.' ) . '</p>';

    $story_pointer_content = '<h3>' . __( 'Another info' ) . '</h3>';
    $story_pointer_content .= '<p>' . __( 'Lorem ipsum...' ) . '</p>';


    return array(
        $prefix . 'new_items' => array(
            'content' => $new_pointer_content,
            'anchor_id' => '#wp-admin-bar-new-content',
            'edge' => 'top',
            'align' => 'left',
            'active' => ( ! in_array( $prefix . 'new_items', $dismissed ) )
        ),
        $prefix.'story_cover_help' => array(
            'content' => $story_pointer_content,
            'anchor_id' => '#save-post',
            'edge' => 'top',
            'align' => 'right',
            'active' => ( ! in_array( $prefix . 'story_cover_help', $dismissed ) )
        )
    );

}

รหัสอธิบายตนเอง เราสามารถเพิ่มพอยน์เตอร์ได้ง่ายขึ้นโดยการขยายอาร์เรย์ ทุกอย่างทำงานได้ดีใน WP4

ตอนนี้ถึงปัญหา:ตัวชี้ป๊อปอัพทั้งหมดปรากฏขึ้นในเวลาเดียวกันทำให้นี่เป็นอินเทอร์เฟซที่แย่สำหรับการสอน

เป้าหมายของฉันคือการแสดงพอยน์เตอร์ทีละตัวและอนุญาตให้ผู้ใช้คลิกที่ปุ่มถัดไปเพื่อไปยังบทแนะนำ ปุ่มถัดไปควรเปิดตัวชี้ถัดไปและปิดตัวสุดท้าย

ฉันจะทำสิ่งนี้ได้อย่างไร

คำตอบ:


10

คุณกำลังเรียก.pointer( 'open' );ใช้ฟังก์ชั่นจาวาสคริปต์ในทุกวัตถุพอยน์เตอร์ดังนั้นจึงไม่แปลกใจที่พอยน์เตอร์ทั้งหมดจะปรากฏในเวลาเดียวกัน ...

ที่กล่าวว่าฉันไม่เข้าใจว่าทำไมคุณทำผลตอบแทนที่ชี้ทั้งหมด (แม้คนที่ไม่ได้ใช้งาน) จาก custom_admin_pointers()นั้นเพิ่มฟังก์ชั่นเพิ่มเติมเพื่อตรวจสอบว่ามีบางตัวชี้การใช้งานและการตรวจสอบภายในตัวชี้ห่วง ( if ( $array['active'] ) {) เพื่อเลือกที่จะเพิ่มตัวชี้จาวาสคริปต์ หรือไม่. ไม่เพียงแค่ส่งคืนเฉพาะพอยน์เตอร์ที่ใช้งานอยู่เท่านั้น?

ยิ่งกว่านั้นคุณกำลังเพิ่มจาวาสคริปต์ที่หน้าผู้ดูแลระบบทั้งหมดไม่มากเกินไป? นอกจากนี้ให้พิจารณาว่าองค์ประกอบบางอย่างเช่น "# save-post" มีเฉพาะในหน้าโพสต์ใหม่ดังนั้นจะไม่เพิ่มตัวชี้ในหน้าพ็อตใหม่เท่านั้น

ในที่สุดความยุ่งเหยิงของจาวาสคริปต์นั้นผสมผสานกับ PHP ฉันคิดว่าคุณควรพิจารณาใช้wp_localize_scriptเพื่อส่งผ่านข้อมูลไปยังจาวาสคริปต์

แผนการ:

  1. ย้ายคำจำกัดความของพอยน์เตอร์ใน PHP ไปยังไฟล์แยกด้วยวิธีนี้ง่ายต่อการแก้ไขและลบมาร์กอัพออกจากโค้ด PHP ทำให้ทุกอย่างอ่านง่ายขึ้นและบำรุงรักษาได้ดีขึ้น
  2. ในการกำหนดค่าพอยน์เตอร์เพิ่มคุณสมบัติ "ที่ไหน" ที่จะใช้ในการตั้งค่าที่หน้าผู้ดูแลระบบควรปรากฏป๊อปอัพ: post-new.php, index.php...
  3. เขียนคลาสที่จะจัดการกับการโหลดการแยกวิเคราะห์และการกรองข้อมูลพอยน์เตอร์
  4. เขียน js goodness บางอย่างที่จะช่วยให้เราเปลี่ยนปุ่ม "ลบ" เริ่มต้นเป็น "ถัดไป"

# 4กระป๋อง (อาจ) ทำได้อย่างง่ายดายรู้ตัวชี้ปลั๊กอินดี แต่มันไม่ได้เป็นกรณีของฉัน ดังนั้นฉันจะใช้รหัส jQuery ทั่วไปเพื่อให้ได้ผลลัพธ์ถ้ามีคนสามารถปรับปรุงรหัสของฉันฉันจะขอบคุณ


แก้ไข

ฉันแก้ไขโค้ด (ส่วนใหญ่ js) เพราะมีสิ่งต่าง ๆ ที่ฉันไม่ได้พิจารณา: พอยน์เตอร์บางตัวอาจถูกเพิ่มลงในสมอเดียวกันหรือสามารถเพิ่มพอยน์เตอร์เดียวกันไปยังจุดยึดที่ไม่มีอยู่หรือมองไม่เห็น ในกรณีที่รหัสก่อนหน้านี้ใช้งานไม่ได้เวอร์ชั่นใหม่ดูเหมือนว่าจะแก้ไขปัญหาได้ดี

ฉันได้ตั้งค่าส่วนสำคัญด้วยรหัสทั้งหมดที่ฉันใช้ในการทดสอบ


เริ่มจากจุดที่# 1และ# 2 : สร้างไฟล์ชื่อpointers.phpและเขียนตรงนั้น:

<?php
$pointers = array();

$pointers['new-items'] = array(
  'title'     => sprintf( '<h3>%s</h3>', esc_html__( 'Add New Item' ) ),
  'content'   => sprintf( '<p>%s</p>', esc_html__( 'Easily add a new post..' ) ),
  'anchor_id' => '#wp-admin-bar-new-content',
  'edge'      => 'top',
  'align'     => 'left',
  'where'     => array( 'index.php', 'post-new.php' ) // <-- Please note this
);

$pointers['story_cover_help'] = array(
  'title'     => sprintf( '<h3>%s</h3>', esc_html__( 'Another info' ) ),
  'content'   => sprintf( '<p>%s</p>', esc_html__( 'Lore ipsum....' ) ),
  'anchor_id' => '#save-post',
  'edge'      => 'top',
  'align'     => 'right',
  'where'     => array( 'post-new.php' ) // <-- Please note this
);

// more pointers here...

return $pointers; 

การกำหนดค่าพอยน์เตอร์ทั้งหมดอยู่ที่นี่ เมื่อคุณต้องการเปลี่ยนแปลงบางอย่างเพียงแค่เปิดไฟล์นี้และแก้ไข

หมายเหตุ: คุณสมบัติ "ที่ไหน" ที่เป็นอาร์เรย์ของเพจที่ควรใช้ตัวชี้

หากคุณต้องการแสดงพอยน์เตอร์ในหน้าที่สร้างโดยปลั๊กอินให้มองหาบรรทัดนี้ที่ระบุไว้ด้านล่างpublic function filter( $page ) {และเพิ่มเข้าไปdie($page);ข้างใต้ทันที จากนั้นเปิดหน้าปลั๊กอินที่เกี่ยวข้องและใช้สตริงนั้นในwhereคุณสมบัติ

ตกลงตอนนี้จุดที่# 3

ก่อนที่จะเขียนคลาสฉันแค่ต้องการโค้ดอินเทอร์เฟซ: ที่นั่นฉันจะใส่ข้อคิดเห็นเพื่อให้คุณสามารถเข้าใจได้ดีขึ้นว่าคลาสจะทำอะไร

<?php
interface PointersManagerInterface {

  /**
  * Load pointers from file and setup id with prefix and version.
  * Cast pointers to objects.
  */
  public function parse();

  /**
  * Remove from parse pointers dismissed ones and pointers
  * that should not be shown on given page
  *
  * @param string $page Current admin page file
  */
  public function filter( $page );

}

ฉันคิดว่าน่าจะชัดเจน ทีนี้ลองเขียนคลาสมันจะมี 2 เมธอดจากอินเตอร์เฟสบวกตัวสร้าง

<?php namespace GM;

class PointersManager implements PointersManagerInterface {

  private $pfile;
  private $version;
  private $prefix;
  private $pointers = array();

  public function __construct( $file, $version, $prefix ) {
    $this->pfile = file_exists( $file ) ? $file : FALSE;
    $this->version = str_replace( '.', '_', $version );
    $this->prefix = $prefix;
  }

  public function parse() {
    if ( empty( $this->pfile ) ) return;
    $pointers = (array) require_once $this->pfile;
    if ( empty($pointers) ) return;
    foreach ( $pointers as $i => $pointer ) {
      $pointer['id'] = "{$this->prefix}{$this->version}_{$i}";
      $this->pointers[$pointer['id']] = (object) $pointer;
    }
  }

  public function filter( $page ) {
    if ( empty( $this->pointers ) ) return array();
    $uid = get_current_user_id();
    $no = explode( ',', (string) get_user_meta( $uid, 'dismissed_wp_pointers', TRUE ) );
    $active_ids = array_diff( array_keys( $this->pointers ), $no );
    $good = array();
    foreach( $this->pointers as $i => $pointer ) {
      if (
        in_array( $i, $active_ids, TRUE ) // is active
        && isset( $pointer->where ) // has where
        && in_array( $page, (array) $pointer->where, TRUE ) // current page is in where
      ) {
       $good[] = $pointer;
      }
    }
    $count = count( $good );
    if ( $good === 0 ) return array();
    foreach( array_values( $good ) as $i => $pointer ) {
      $good[$i]->next = $i+1 < $count ? $good[$i+1]->id : '';
    }
    return $good;
  }
}

รหัสนั้นง่ายมากและทำสิ่งที่อินเตอร์เฟซคาดหวัง

อย่างไรก็ตามชั้นเรียนไม่ได้ทำอะไรด้วยตัวเองเราต้องขอที่ให้อินสแตนซ์ class nad เรียกใช้ 2 เมธอดผ่านอาร์กิวเมนต์ที่เหมาะสม

'admin_enqueue_scripts'เหมาะสำหรับขอบเขตของเรา: มีเราจะมีการเข้าถึงหน้าผู้ดูแลระบบในปัจจุบันและเรายังสามารถสคริปต์ enqueue และรูปแบบที่จำเป็น

add_action( 'admin_enqueue_scripts', function( $page ) {
  $file = plugin_dir_path( __FILE__ ) . 'pointers.php';
  // Arguments: pointers php file, version (dots will be replaced), prefix
  $manager = new PointersManager( $file, '5.0', 'custom_admin_pointers' );
  $manager->parse();
  $pointers = $manager->filter( $page );
  if ( empty( $pointers ) ) { // nothing to do if no pointers pass the filter
    return;
  }
  wp_enqueue_style( 'wp-pointer' );
  $js_url = plugins_url( 'pointers.js', __FILE__ );
  wp_enqueue_script( 'custom_admin_pointers', $js_url, array('wp-pointer'), NULL, TRUE );
  // data to pass to javascript
  $data = array(
    'next_label' => __( 'Next' ),
    'close_label' => __('Close'),
    'pointers' => $pointers
  );
  wp_localize_script( 'custom_admin_pointers', 'MyAdminPointers', $data );
} );

ไม่มีอะไรพิเศษ: เพียงแค่ใช้คลาสเพื่อรับข้อมูลพอยน์เตอร์และหากพอยน์เตอร์บางตัวผ่านรูปแบบการจัดคิวและตัวกรอง จากนั้นส่งข้อมูลพอยน์เตอร์ไปยังสคริปต์พร้อมกับป้ายกำกับ "ถัดไป" สำหรับปุ่ม

ตกลงตอนนี้ส่วน "ยากที่สุด": js อีกครั้งฉันต้องการเน้นที่ฉันไม่ทราบว่าปลั๊กอินตัวชี้ใช้ WordPress ดังนั้นสิ่งที่ฉันทำในรหัสของฉันสามารถทำได้ดีกว่าถ้ามีคนรู้ว่ามันอย่างไรก็ตามรหัสของฉันทำงานและ - พูดง่าย - มันไม่เลวเลย

( function($, MAP) {

  $(document).on( 'MyAdminPointers.setup_done', function( e, data ) {
    e.stopImmediatePropagation();
    MAP.setPlugin( data ); // open first popup
  } );

  $(document).on( 'MyAdminPointers.current_ready', function( e ) {
    e.stopImmediatePropagation();
    MAP.openPointer(); // open a popup
  } );

  MAP.js_pointers = {};        // contain js-parsed pointer objects
  MAP.first_pointer = false;   // contain first pointer anchor jQuery object
  MAP.current_pointer = false; // contain current pointer jQuery object
  MAP.last_pointer = false;    // contain last pointer jQuery object
  MAP.visible_pointers = [];   // contain ids of pointers whose anchors are visible

  MAP.hasNext = function( data ) { // check if a given pointer has valid next property
    return typeof data.next === 'string'
      && data.next !== ''
      && typeof MAP.js_pointers[data.next].data !== 'undefined'
      && typeof MAP.js_pointers[data.next].data.id === 'string';
  };

  MAP.isVisible = function( data ) { // check if anchor for given pointer is visible
    return $.inArray( data.id, MAP.visible_pointers ) !== -1;
  };

  // given a pointer object, return its the anchor jQuery object if available
  // otherwise return first available, lookin at next property of subsequent pointers
  MAP.getPointerData = function( data ) { 
    var $target = $( data.anchor_id );
    if ( $.inArray(data.id, MAP.visible_pointers) !== -1 ) {
      return { target: $target, data: data };
    }
    $target = false;
    while( MAP.hasNext( data ) && ! MAP.isVisible( data ) ) {
      data = MAP.js_pointers[data.next].data;
      if ( MAP.isVisible( data ) ) {
        $target = $(data.anchor_id);
      }
    }
    return MAP.isVisible( data )
      ? { target: $target, data: data }
      : { target: false, data: false };
  };

  // take pointer data and setup pointer plugin for anchor element
  MAP.setPlugin = function( data ) {
    if ( typeof MAP.last_pointer === 'object') {
      MAP.last_pointer.pointer('destroy');
      MAP.last_pointer = false;
    }
    MAP.current_pointer = false;
    var pointer_data = MAP.getPointerData( data );
      if ( ! pointer_data.target || ! pointer_data.data ) {
      return;
    }
    $target = pointer_data.target;
    data = pointer_data.data;
    $pointer = $target.pointer({
      content: data.title + data.content,
      position: { edge: data.edge, align: data.align },
      close: function() {
        // open next pointer if it exists
        if ( MAP.hasNext( data ) ) {
          MAP.setPlugin( MAP.js_pointers[data.next].data );
        }
        $.post( ajaxurl, { pointer: data.id, action: 'dismiss-wp-pointer' } );
      }
    });
    MAP.current_pointer = { pointer: $pointer, data: data };
    $(document).trigger( 'MyAdminPointers.current_ready' );
  };

  // scroll the page to current pointer then open it
  MAP.openPointer = function() {          
    var $pointer = MAP.current_pointer.pointer;
    if ( ! typeof $pointer === 'object' ) {
      return;
    }
    $('html, body').animate({ // scroll page to pointer
      scrollTop: $pointer.offset().top - 30
    }, 300, function() { // when scroll complete
      MAP.last_pointer = $pointer;
        var $widget = $pointer.pointer('widget');
        MAP.setNext( $widget, MAP.current_pointer.data );
        $pointer.pointer( 'open' ); // open
    });
  };

  // if there is a next pointer set button label to "Next", to "Close" otherwise
  MAP.setNext = function( $widget, data ) {
    if ( typeof $widget === 'object' ) {
      var $buttons = $widget.find('.wp-pointer-buttons').eq(0);        
      var $close = $buttons.find('a.close').eq(0);
      $button = $close.clone(true, true).removeClass('close');
      $buttons.find('a.close').remove();
      $button.addClass('button').addClass('button-primary');
      has_next = false;
      if ( MAP.hasNext( data ) ) {
        has_next_data = MAP.getPointerData(MAP.js_pointers[data.next].data);
        has_next = has_next_data.target && has_next_data.data;
      }
      var label = has_next ? MAP.next_label : MAP.close_label;
      $button.html(label).appendTo($buttons);
    }
  };

  $(MAP.pointers).each(function(index, pointer) { // loop pointers data
    if( ! $().pointer ) return;      // do nothing if pointer plugin isn't available
    MAP.js_pointers[pointer.id] = { data: pointer };
    var $target = $(pointer.anchor_id);
    if ( $target.length && $target.is(':visible') ) { // anchor exists and is visible?
      MAP.visible_pointers.push(pointer.id);
      if ( ! MAP.first_pointer ) {
        MAP.first_pointer = pointer;
      }
    }
    if ( index === ( MAP.pointers.length - 1 ) && MAP.first_pointer ) {
      $(document).trigger( 'MyAdminPointers.setup_done', MAP.first_pointer );
    }
  });

} )(jQuery, MyAdminPointers); // MyAdminPointers is passed by `wp_localize_script`

ด้วยความช่วยเหลือของความคิดเห็นรหัสควรจะชัดเจนอย่างน้อยฉันหวังว่าอย่างนั้น

โอเคเราเสร็จแล้ว PHP ของเรานั้นเรียบง่ายและจัดระเบียบได้ดีขึ้นจาวาสคริปต์ของเราอ่านได้ง่ายขึ้นตัวชี้ง่ายต่อการแก้ไขและที่สำคัญกว่านั้นทุกอย่างทำงานได้ดี


1
@ ChristineCooper แน่ใจ ตกลงปัญหาคือ 2: 1 สำหรับวิธีการทำงานของสคริปต์ตอนนี้คุณสามารถเพิ่ม 1 ตัวชี้สำหรับ 1 จุดยึด id: การใช้จุดยึดเดียวกันสำหรับตัวชี้มากกว่าหนึ่งตัวจะทำให้สคริปต์ล้มเหลว ปัญหาที่สองคือพอยน์เตอร์บางตัวใช้ anchor to id ที่อาจไม่อยู่ในหน้า เช่นตัวชี้หนึ่งใช้สำหรับ '# comment-55' ใน index.php และไม่พบ ตัวชี้บางตัวใน post.php เป้าหมาย metaboxes ที่อาจซ่อนอยู่ ... และอื่น ๆ ครั้งหนึ่งในเวอร์ชันปัจจุบันของพอยน์เตอร์ของสคริปต์คือ "ถูกล่ามโซ่" หากไม่มีใครพบว่าอนุกรมทั้งหมดจะไม่ทำงานเช่นกัน ฉันจะดูว่ามีวิธีง่ายๆในการเอาชนะปัญหาเหล่านั้นหรือไม่
gmazzap

1
@ChristineCooper ดีใจที่มันทำงาน ฉันจะคัดลอกรหัสทั้งหมดจากส่วนสำคัญกลับมาที่นี่ เงื่อนไขสามารถใส่หลังจากadd_action( 'admin_enqueue_scripts', function( $page ) {ส่งคืนได้ทันทีหากผู้ใช้ไม่มีบทบาทที่จำเป็น
gmazzap

กรุณาเปลี่ยนค่า 30 เป็น 120 ในบรรทัด: "scrollTop: $ pointer.offset (). top - 30" - เหตุผลก็เพราะแถบเครื่องมือด้านบนครอบคลุมหน้าต่างตัวชี้เป็นครั้งคราวเมื่อเลื่อน
Christine Cooper

ฉันมีปัญหาเล็กน้อยหนึ่งอย่าง หน้าฉันต้องการคำแนะนำบางส่วนปรากฏให้เห็นเป็น "admin.php page = ปลั๊กอินเส้นทาง / file.php?" - สิ่งที่ฉันจะเพิ่มไปที่อาร์เรย์? ฉันลอง "admin.php", "plugin-path / file.php", "file.php" และรูปแบบอื่น ๆ ที่ฉันนึกออก มีเหตุผลหรือไม่ที่ตรวจไม่พบหน้านี้หรือฉันทำสิ่งนี้ผิด
Christine Cooper

1
@ChristineCooper เปิดหน้าปลั๊กอินผู้ดูแลระบบและคัดลอก URL จากเบราว์เซอร์ หลังจากนั้นให้เปิดไฟล์ที่มีรหัสของฉันด้านบน ค้นหาบรรทัดpublic function filter( $page ) {ในชั้นเรียนและทันทีหลังจากวางสายว่าPointersManager die($page);เปิดเบราว์เซอร์ของคุณและวางกลับ URL ที่หน้าจะตายกับสตริง: 'where'นั่นเป็นสิ่งที่คุณต้องใช้เป็น
gmazzap

7

อ่า .. ใช่แล้ว ตัวชี้ WordPress คุณรู้ไหมว่ามันมีความรู้สึกปนกันมากมายเมื่อพูดถึงการใช้พอยน์เตอร์)

คุณกำลังติดตามถูกต้องด้วยรหัสของคุณข้างต้น แต่มีปัญหาอยู่สองสามข้อ

@GM ถูกต้องเกี่ยวกับpointer('open')คำสั่งที่เปิดตัวชี้ทั้งหมดของคุณในครั้งเดียว นอกจากนี้คุณไม่ได้ให้วิธีการล่วงหน้าผ่านตัวชี้

ฉันต่อสู้ในประเด็นเดียวกันนี้และเกิดขึ้นกับแนวทางของฉันเอง ฉันใช้ตัวแปรแบบสอบถามใน url โหลดหน้าไปยังหน้าผู้ดูแลระบบที่ฉันต้องการแสดงตัวชี้ถัดไปและให้ jQuery จัดการส่วนที่เหลือ

WP Pointers Class

ฉันตัดสินใจที่จะเขียนสิ่งนี้เป็นชั้นเรียน แต่ฉันจะแสดงทีละน้อยเพื่อช่วยให้คุณเข้าใจสิ่งที่เกิดขึ้นดีขึ้น

การเริ่มชั้นเรียน

// Create as a class
class testWPpointers {

    // Define pointer version
    const DISPLAY_VERSION = 'v1.0';

    // Initiate construct
    function __construct () {
        add_action('admin_enqueue_scripts', array($this, 'admin_enqueue_scripts'));  // Hook to admin_enqueue_scripts
    }

    function admin_enqueue_scripts () {

        // Check to see if user has already dismissed the pointer tour
        $dismissed = explode (',', get_user_meta (wp_get_current_user ()->ID, 'dismissed_wp_pointers', true));
        $do_tour = !in_array ('test_wp_pointer', $dismissed);

        // If not, we are good to continue
        if ($do_tour) {

            // Enqueue necessary WP scripts and styles
            wp_enqueue_style ('wp-pointer');
            wp_enqueue_script ('wp-pointer');

            // Finish hooking to WP admin areas
            add_action('admin_print_footer_scripts', array($this, 'admin_print_footer_scripts'));  // Hook to admin footer scripts
            add_action('admin_head', array($this, 'admin_head'));  // Hook to admin head
        }
    }

    // Used to add spacing between the two buttons in the pointer overlay window.
    function admin_head () {
        ?>
        <style type="text/css" media="screen">
            #pointer-primary {
                margin: 0 5px 0 0;
            }
        </style>
        <?php
    }
  1. เราได้กำหนดชั้นเรียน
  2. admin_enqueue_scriptsเราสร้างชั้นเรียนและเพิ่มการดำเนินการไปยัง
  3. เราพิจารณาแล้วว่าตัวชี้ของเราถูกไล่ออกไปแล้ว
  4. ถ้าไม่เราจะทำการเข้าคิวสคริปต์ที่จำเป็นต่อไป

คุณไม่จำเป็นต้องเปลี่ยนแปลงอะไรในฟังก์ชั่นแรกเหล่านี้

การตั้งค่าอาร์เรย์ของรายการตัวชี้

ขั้นตอนต่อไปคือการกำหนดพอยน์เตอร์แต่ละตัว มีห้ารายการที่เราจำเป็นต้องกำหนด (ยกเว้นสำหรับตัวชี้ล่าสุด) เราจะทำสิ่งนี้โดยใช้อาร์เรย์ ลองดูฟังก์ชั่น:

// Define footer scripts
function admin_print_footer_scripts () {

    // Define global variables
    global $pagenow;
    global $current_user;

    //*****************************************************************************************************
    // This is our array of individual pointers.
    // -- The array key should be unique.  It is what will be used to 'advance' to the next pointer.
    // -- The 'id' should correspond to an html element id on the page.
    // -- The 'content' will be displayed inside the pointer overlay window.
    // -- The 'button2' is the text to show for the 'action' button in the pointer overlay window.
    // -- The 'function' is the method used to reload the window (or relocate to a new window).
    //    This also creates a query variable to add to the end of the url.
    //    The query variable is used to determine which pointer to display.
    //*****************************************************************************************************
    $tour = array (
        'quick_press' => array (
            'id' => '#dashboard_quick_press',
            'content' => '<h3>' . __('Congratulations!', 'test_lang') . '</h3>'
                . '<p><strong>' . __('WP Pointers is working properly.', 'test_lang') . '</strong></p>'
                . '<p>' . __('This pointer is attached to the "Quick Draft" admin widget.', 'test_lang') . '</p>'
                . '<p>' . __('Our next pointer will take us to the "Settings" admin menu.', 'test_lang') . '</p>',
            'button2' => __('Next', 'test_lang'),
            'function' => 'window.location="' . $this->get_admin_url('options-general.php', 'site_title') . '"'  // We are relocating to "Settings" page with the 'site_title' query var
            ),
        'site_title' => array (
            'id' => '#blogname',
            'content' => '<h3>' . __('Moving along to Site Title.', 'test_lang') . '</h3>'
            . '<p><strong>' . __('Another WP Pointer.', 'test_lang') . '</strong></p>'
            . '<p>' . __('This pointer is attached to the "Blog Title" input field.', 'test_lang') . '</p>',
            'button2' => __('Next', 'test_lang'),
            'function' => 'window.location="' . $this->get_admin_url('index.php', 'quick_press_last') . '"'  // We are relocating back to "Dashboard" with 'quick_press_last' query var
            ),
        'quick_press_last' => array (
            'id' => '#dashboard_quick_press',
            'content' => '<h3>' . __('This concludes our WP Pointers tour.', 'test_lang') . '</h3>'
            . '<p><strong>' . __('Last WP Pointer.', 'test_lang') . '</strong></p>'
            . '<p>' . __('When closing the pointer tour; it will be saved in the users custom meta.  The tour will NOT be shown to that user again.', 'test_lang') . '</p>'
            )
        );

    // Determine which tab is set in the query variable
    $tab = isset($_GET['tab']) ? $_GET['tab'] : '';
    // Define other variables
    $function = '';
    $button2 = '';
    $options = array ();
    $show_pointer = false;

    // *******************************************************************************************************
    // This will be the first pointer shown to the user.
    // If no query variable is set in the url.. then the 'tab' cannot be determined... and we start with this pointer.
    // *******************************************************************************************************
    if (!array_key_exists($tab, $tour)) {

        $show_pointer = true;
        $file_error = true;

        $id = '#dashboard_right_now';  // Define ID used on page html element where we want to display pointer
        $content = '<h3>' . sprintf (__('Test WP Pointers %s', 'test_lang'), self::DISPLAY_VERSION) . '</h3>';
        $content .= __('<p>Welcome to Test WP Pointers admin tour!</p>', 'test_lang');
        $content .= __('<p>This pointer is attached to the "At a Glance" dashboard widget.</p>', 'test_lang');
        $content .= '<p>' . __('Click the <em>Begin Tour</em> button to get started.', 'test_lang' ) . '</p>';

        $options = array (
            'content' => $content,
            'position' => array ('edge' => 'top', 'align' => 'left')
            );
        $button2 = __('Begin Tour', 'test_lang' );
        $function = 'document.location="' . $this->get_admin_url('index.php', 'quick_press') . '";';
    }
    // Else if the 'tab' is set in the query variable.. then we can determine which pointer to display
    else {

        if ($tab != '' && in_array ($tab, array_keys ($tour))) {

            $show_pointer = true;

            if (isset ($tour[$tab]['id'])) {
                $id = $tour[$tab]['id'];
            }

            $options = array (
                'content' => $tour[$tab]['content'],
                'position' => array ('edge' => 'top', 'align' => 'left')
            );

            $button2 = false;
            $function = '';

            if (isset ($tour[$tab]['button2'])) {
                $button2 = $tour[$tab]['button2'];
            }
            if (isset ($tour[$tab]['function'])) {
                $function = $tour[$tab]['function'];
            }
        }
    }

    // If we are showing a pointer... let's load the jQuery.
    if ($show_pointer) {
        $this->make_pointer_script ($id, $options, __('Close', 'test_lang'), $button2, $function);
    }
}

โอเค .. ลองมาดูบางสิ่งที่นี่

อันดับแรก$tourอาร์เรย์ของเรา นี่คืออาร์เรย์ที่เก็บพอยน์เตอร์ทั้งหมดยกเว้นตัวชี้แรกที่แสดงต่อผู้ใช้ (เพิ่มเติมในภายหลัง) ดังนั้นคุณจะต้องเริ่มต้นด้วยตัวชี้ที่สองที่คุณต้องการแสดง .. และดำเนินการต่อจนถึงตัวชี้สุดท้าย

ต่อไปเรามีบางรายการที่สำคัญมาก

  1. $tourคีย์อาร์เรย์ต้องไม่ซ้ำกัน (quick_press, SITE_TITLE, quick_press_last นั้นเป็นตัวอย่างข้างต้น)
  2. คำสั่ง 'id' จะต้องตรงกับองค์ประกอบ html id ของรายการที่คุณต้องการแนบกับตัวชี้
  3. functionคำสั่งจะโหลด / ย้ายหน้าต่าง นี่คือสิ่งที่ใช้แสดงตัวชี้ถัดไป เราต้องโหลดหน้าต่างใหม่หรือย้ายไปที่หน้าผู้ดูแลระบบถัดไปซึ่งตัวชี้จะปรากฏขึ้น
  4. เราเรียกใช้get_admin_url()ฟังก์ชันด้วยตัวแปรสองตัว แรกคือหน้าผู้ดูแลระบบที่เราต้องการไปต่อไป; และที่สองคือคีย์อาร์เรย์ที่เป็นเอกลักษณ์ของตัวชี้ที่เราต้องการแสดง

if (!array_key_exists($tab, $tour)) {ต่อไปลงที่คุณจะเห็นรหัสที่ขึ้นต้น นี่คือที่เราตรวจสอบว่ามีการตั้งค่าตัวแปรแบบสอบถาม URL ถ้ามันไม่ได้เราต้องกำหนดตัวชี้แรกที่จะแสดง

ตัวชี้นี้ใช้id, content, button2, and functionรายการเดียวกับที่ใช้ใน$tourอาร์เรย์ด้านบน โปรดจำไว้ว่าอาร์กิวเมนต์ที่สองของget_admin_url()ฟังก์ชันจะต้องตรงกับคีย์อาร์เรย์ใน$tourตัวแปร นี่คือสิ่งที่บอกให้สคริปต์ไปที่ตัวชี้ถัดไป

ส่วนที่เหลือของฟังก์ชั่นจะใช้ถ้ามีการตั้งค่าตัวแปรแบบสอบถามไว้ใน URL แล้ว ไม่จำเป็นต้องปรับฟังก์ชั่นอีกต่อไป

การได้รับ URL ของผู้ดูแลระบบ ฟังก์ชั่นถัดไปเป็นฟังก์ชั่นตัวช่วยจริง ... ใช้เพื่อรับ URL ผู้ดูแลระบบและเลื่อนตัวชี้ไปข้างหน้า

// This function is used to reload the admin page.
// -- $page = the admin page we are passing (index.php or options-general.php)
// -- $tab = the NEXT pointer array key we want to display
function get_admin_url($page, $tab) {

    $url = admin_url();
    $url .= $page.'?tab='.$tab;

    return $url;
}

จำไว้ว่ามีสองข้อโต้แย้ง; หน้าผู้ดูแลระบบที่เรากำลังจะไป .. และแท็บ แท็บจะเป็น$tourคีย์อาร์เรย์ที่เราต้องการไปต่อไป เหล่านี้ MATCH

ดังนั้นเมื่อเราเรียกใช้ฟังก์ชันget_admin_url()และส่งผ่านตัวแปรทั้งสอง ตัวแปรแรกจะกำหนดหน้าผู้ดูแลระบบต่อไป .. และตัวแปรที่สองกำหนดตัวชี้ที่จะแสดง

สุดท้าย ... ในที่สุดเราก็สามารถพิมพ์สคริปต์ผู้ดูแลระบบไปยังส่วนท้าย

// Print footer scripts
function make_pointer_script ($id, $options, $button1, $button2=false, $function='') {

    ?>
    <script type="text/javascript">

        (function ($) {

            // Define pointer options
            var wp_pointers_tour_opts = <?php echo json_encode ($options); ?>, setup;

            wp_pointers_tour_opts = $.extend (wp_pointers_tour_opts, {

                // Add 'Close' button
                buttons: function (event, t) {

                    button = jQuery ('<a id="pointer-close" class="button-secondary">' + '<?php echo $button1; ?>' + '</a>');
                    button.bind ('click.pointer', function () {
                        t.element.pointer ('close');
                    });
                    return button;
                },
                close: function () {

                    // Post to admin ajax to disable pointers when user clicks "Close"
                    $.post (ajaxurl, {
                        pointer: 'test_wp_pointer',
                        action: 'dismiss-wp-pointer'
                    });
                }
            });

            // This is used for our "button2" value above (advances the pointers)
            setup = function () {

                $('<?php echo $id; ?>').pointer(wp_pointers_tour_opts).pointer('open');

                <?php if ($button2) { ?>

                    jQuery ('#pointer-close').after ('<a id="pointer-primary" class="button-primary">' + '<?php echo $button2; ?>' + '</a>');
                    jQuery ('#pointer-primary').click (function () {
                        <?php echo $function; ?>  // Execute button2 function
                    });
                    jQuery ('#pointer-close').click (function () {

                        // Post to admin ajax to disable pointers when user clicks "Close"
                        $.post (ajaxurl, {
                            pointer: 'test_wp_pointer',
                            action: 'dismiss-wp-pointer'
                        });
                    })
                <?php } ?>
            };

            if (wp_pointers_tour_opts.position && wp_pointers_tour_opts.position.defer_loading) {

                $(window).bind('load.wp-pointers', setup);
            }
            else {
                setup ();
            }
        }) (jQuery);
    </script>
    <?php
}
} 
$testWPpointers = new testWPpointers();

อีกครั้งไม่จำเป็นต้องเปลี่ยนแปลงอะไรข้างต้น สคริปต์นี้จะกำหนดและส่งออกสองปุ่มในหน้าต่างซ้อนทับตัวชี้ หนึ่งจะเป็นปุ่ม "ปิด" เสมอ และจะอัปเดตdismissed_pointersตัวเลือกเมตาผู้ใช้ปัจจุบัน

ปุ่มที่สอง (ปุ่มการกระทำ) จะดำเนินการฟังก์ชั่น (วิธีการย้ายหน้าต่างของเรา)

และเราปิดชั้นเรียน

นี่คือรหัสที่ครบถ้วน WP Pointer Class

คุณสามารถคัดลอก / วางที่ลงในไซต์ dev ของคุณและไปที่หน้า "แผงควบคุม" มันจะแนะนำคุณตลอดการเดินทาง

โปรดจำไว้ว่ามันสับสนเล็กน้อยที่ตัวชี้แรกถูกกำหนดครั้งสุดท้ายในรหัส นั่นคือวิธีที่มันควรจะทำงาน อาร์เรย์จะเก็บพอยน์เตอร์ที่เหลือทั้งหมดที่คุณต้องการใช้

โปรดจำไว้ว่ารายการอาร์เรย์ 'id' ต้องตรงกับอาร์กิวเมนต์ที่สองของget_admin_url()ฟังก์ชันจากคำสั่ง 'function' ของรายการอาร์เรย์ก่อนหน้า นี่คือวิธีที่พอยน์เตอร์ 'คุย' ซึ่งกันและกันและรู้วิธีก้าวหน้า

สนุก!! :)


นี่คือจอชที่น่ารักขอบคุณมาก! ฉันจะลองและดูว่ามันใช้งานได้ดีแค่ไหน ฉันควรเน้นว่ารหัสของ GM เป็นสิ่งที่ฉันจะได้รับรางวัลนี้เพราะมันมีคุณสมบัติที่สำคัญสองสามอย่างที่ฉันขอและที่ฉันเชื่อว่าเป็นสิ่งสำคัญในการสร้างคำแนะนำโดยเฉพาะอย่างยิ่งสำหรับหลาย ๆ หน้าใน wp-admin อย่างไรก็ตามมันเป็นการดีมากที่จะได้เห็นวิธีการอื่นในเรื่องนี้และจะมีประโยชน์สำหรับผู้ใช้รายอื่นที่กำลังมองหาทางออกที่ดี จากความอยากรู้อยากเห็นคุณบอกว่ามีความรู้สึกปนกันค่อนข้างมากเมื่อพูดถึงการใช้พอยน์เตอร์สนใจที่จะอธิบายอย่างละเอียด?
Christine Cooper

2
ไม่ต้องกังวล :) เอาล่ะพอยน์เตอร์สามารถ 'เข้าทาง' ได้เมื่อใช้เกิน ไม่มีใครอยากไปหน้าหนึ่งและมีตัวชี้สามหรือสี่ตัวแสดง ... โดยเฉพาะอย่างยิ่งหากไม่เกี่ยวข้อง สมมติว่าอีกสองปลั๊กอินกำลังแสดงพอยน์เตอร์จากนั้นเราเพิ่มพอยน์เตอร์มากขึ้น คนส่วนใหญ่พูดว่าใช้เท่าที่จำเป็น ... แต่สำหรับแต่ละคนก็เป็นของตัวเอง :) ดีใจที่คุณได้ทำงานอย่างถูกต้อง
josh

1
นี่คือ Josh ที่ยอดเยี่ยมฉันขอแนะนำ 1 ข้อเพื่อให้มีความยืดหยุ่นมากขึ้นและมีที่ที่คุณสามารถส่งผ่านไปยังอาร์เรย์ในฟังก์ชั่นสาธารณะแทนที่จะเก็บไว้ในรหัสเรียน ประการที่สองตัวชี้แรกแยกกันอย่างไรปรับเปลี่ยนเพื่อให้สามารถเป็นคีย์ / ค่าของแถวลำดับแรกในอาร์เรย์ตัวชี้ แค่ความคิดสองสามข้อเพื่อให้คลาสนี้สามารถเรียกใช้จากสคริปต์อื่นและส่งต่อไปยังอาร์เรย์ของตัวชี้ ฉันยังคงชอบมันมากขอบคุณที่แบ่งปันฉันจะใช้สิ่งนี้!
JasonDavis

ขอบคุณ @jasondavis ฉันดึงรหัสนั้นมาจากปลั๊กอินอื่นที่ฉันพัฒนาขึ้นเพื่อใครบางคน ฉันสนใจที่จะทำให้มันทำงานได้อย่างถูกต้องเท่านั้น แต่ใช่ฉันเห็นด้วยอย่างยิ่งกับคุณ ... ต้องได้รับการทำความสะอาด บางทีฉันจะหยุดทีหลังวันนี้แล้วไปยุ่งกับมันอีกครั้ง :)
Josh

มันเจ๋งจริง ๆ แล้วฉันไม่เคยมีความตั้งใจที่จะใช้ Admin Pointers เพราะพวกเขาดูเหมือนฝันร้ายและที่สองเพราะฉันไม่ได้ใช้จริงสำหรับพวกเขา แต่ชั้นเรียนของคุณทำให้พวกเขาดูง่ายต่อการใช้งานตอนนี้ที่ฉันรู้สึกว่าฉัน ต้องใช้พวกมันเพราะมันง่ายมากกับคลาสนั้น! ฉันชอบโครงการ / ห้องสมุดเล็ก ๆ เช่นนั้นสิ่งดีๆ
JasonDavis
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.