首页 > 解决方案 > wordpress收藏系统无插件学习方法

问题描述

下午好开发人员,我使用 Wordpress 和 php 开发了一个最喜欢的系统,它的工作原理如下,单击添加收藏夹图标我向 php 发送一个 ajax 请求,其中包含最喜欢的 id 和登录的用户 id。php 通过保存在 user_meta 中来处理这个包含收藏用户数量的信息以及登录用户中包含收藏夹 ID 的数组。无论如何,问题是,系统正在工作,但是每当我开发一些东西时,我一直想知道是否有办法改进代码,如果有办法以更好的方式来做,我会把我的代码留在这里。

这一切都是为了学习好吗?

HTML

<div class="stats -favorites">
    <a class="icon -click <?php echo is_favorite(get_current_user_id(), $user_ID) ? 'fa' : 'far' ?> fa-heart" data-js="favorite" data-favorite="<?php echo $user_ID; ?>" data-user="<?php echo get_current_user_id(); ?>"></a>
    <span class="label" data-js="favorite_label">
        <?php echo get_favorites_num( $user_ID ); ?>
    </span>
    <span class="value">favoritos</span>
</div>

JS

 function setFavorite(userid, favoriteid) {

    var favorite_field = $('[data-js="favorite"]');
    var favorite_label = $('[data-js="favorite_label"]');

    $.ajax({
        url        : appmeninas_ajax_params.ajaxurl,
        data       : {
                        'action'     : 'setfavorite',
                        'userid'     : userid,
                        'favoriteid' : favoriteid,
                    },
        dataType   : 'json',
        type       : 'POST',
        cache      : false,

        beforeSend : function( xhr ) {
            favorite_field.removeClass('far fa fa-heart').addClass('fas fa-circle-notch fa-spin');
        },

        success : function( data ) {

            var icon = (data.is_favorite) ? 'fa fa-heart' : 'far fa-heart';

            favorite_field.removeClass('fas fa-circle-notch fa-spin');
            favorite_field.addClass(icon);

            favorite_label.html('');
            favorite_label.append(data.favorites_num);

        }
    });

};

$('[data-js=favorite]').click(function() {
    var favoriteid = $(this).data('favorite');
    var userid = $(this).data('user');
    setFavorite(userid, favoriteid);
});

PHP

function setfavorite() {

    $userid = $_POST['userid'];
    $favoriteid = $_POST['favoriteid'];

    // user require favorite
    $favorites_list = get_field( 'favorites_list', 'user_' .$userid );
    $favorites_num = get_field( 'favorites', 'user_' .$favoriteid );

    if ( !$favorites_list ) {
        $favorites_list = [];
    }

    // profile favorite
    if ( in_array( $favoriteid, $favorites_list ) ) {

        $favorites_num--;
        $tmp = array_search( $userid, $favorites_list );
        array_splice( $favorites_list, $tmp, 1 );
        $is_favorite = false;

    } else {

        $favorites_num++;
        $favorites_list[] = $favoriteid;
        $is_favorite = true;

    }


    // set favorite counter
    update_user_meta( $favoriteid, 'favorites', $favorites_num );

    // set favorite list
    update_user_meta( $userid, 'favorites_list', $favorites_list );


    echo json_encode( array(
        'favorites_num'  => $favorites_num,
        'favorites_list' => $favorites_list,
        'is_favorite'    => $is_favorite,
    ) );

    die();

}

function is_favorite($userid, $favoriteid) {
    $favorites_list = get_field( 'favorites_list', 'user_' .$userid );
    return in_array( $favoriteid, $favorites_list );
}
function get_favorites_num( $userid ) {
    if ( get_field( 'favorites', 'user_' .$userid ) ) {
        return get_field( 'favorites', 'user_' .$userid );
    } else {
        return '0';
    }
}


add_action('wp_ajax_setfavorite', 'setfavorite');
add_action('wp_ajax_nopriv_setfavorite', 'setfavorite');

标签: javascriptphpwordpress

解决方案


我可能会在接下来的 2 个月内实现相同的功能。我已经开始研究插件,但正如你的问题所述,它似乎并不难。

我试着回来,但首先我需要一个前端个人资料页面,我可以在其中列出收藏夹。

到目前为止,第一印象看起来不错,但首先我会注意$_POST数组并清理并可能验证值,因为有时不仅您的 ajax 会调用。

if ( isset($_POST['userid']) && isset($_POST['favoriteid']) ) { // Both $_POST values exist

  $userid = filter_var($_POST['userid'], FILTER_SANITIZE_NUMBER_INT);
  $favoriteid = filter_var($_POST['favoriteid'], FILTER_SANITIZE_NUMBER_INT);

  if ( filter_var($userid, FILTER_VALIDATE_INT) && filter_var($favoriteid, FILTER_VALIDATE_INT) ) {
    // $_POST was save, both values are Integers
  }
}

第二个与get_field哪个是ACF Plugin提供的功能有关。因此,在停用它或将其替换为 JCF 时,可能会导致错误。

您可以通过使用来避免这种情况if ( function_exists('get_field') ) {。然后,您的代码仅在 ACF 被停用时才停止工作。

否则似乎没有必要使用 ACF 函数,您可以使用 WP 原生函数get_user_meta代替:

function is_favorite($userid, $favoriteid){
  $favorites_list = get_user_meta($userid, 'favorites_list', true);
  // check the new output instead of get_field
  return in_array( $favoriteid, $favorites_list );
}

然后所有的呼吁get_field('favorites', 'user_' .$favoriteid)似乎都是错误的。ACF Docs 说get_fieldist 的第二个参数是一个帖子 ID,所以我不知道“user_”是什么意思。我会打电话给:

function get_favorites_num($favoriteid){
  return get_user_meta($favoriteid, 'favorites', true) || 0;
}

我现在准备好了我自己最喜欢的系统,用户可以在其中收藏来自特定 post_type 的帖子

HTML

    <?php while ( have_posts() ) : the_post() ?>
      <?php 

        $customPostsMeta = get_post_custom();
        $favorite_class = 'favorite-me disabled';
        $fav_count = isset($customPostsMeta['_favorites']) ? intval($customPostsMeta['_favorites'][0]) : 0;
        $fav_count_text = $fav_count > 0 ? '(' . $fav_count . ')' : '';
        $fav_count = ' <span class="fav-count clearfix">' . $fav_count_text . '</span>';
        $favorite_title = '';

        if ( is_user_logged_in() ) {
          $user = wp_get_current_user();
          $favorites = get_user_meta($user->ID, '_favorite_posts', true);
          $fav_key = array_search($post_id, $favorites);
          $is_favorite = ( $fav_key !== false );
          if ( $is_favorite ) {
            $favorite_class .= ' is-favorite';
            $favorite_title = ' title="' . get_the_title() . ' ' . __('favorisieren', 'myTheme') . '"';
          } else {
            $favorite_title = ' title="' . get_the_title() . ' ' . __('nicht mehr favorisieren', 'myTheme') . '"';
          }
        }
    ?>
    <a class="<?php echo $favorite_class; ?>" href="#post-<?php the_ID() ?>"<?php echo $favorite_title; ?>><?php echo __('Favorit', 'myTheme')?><?php echo $fav_count; ?></a>
  <?php endwhile; ?>

JS

// i use a small self written JS module frame where this is included as module
// favorite.setup() is fired imediatly, favorite.ready() fires on document ready
// you can see a full version here: https://dev.alphabetisierung.at/wp-content/themes/sandbox_2017/js/actions.js
// line 732

    /**
     * Favorites ajax system
     * =====================
     * https://stackoverflow.com/questions/60468237
     */
    favorite: {
      options: {
        selectors: {
          link: '.favorite-me',
          fav_count: '.fav-count'
        },
        classNames: {
          disabled: 'disabled',
          is_favorite: 'is-favorite',
        }
      },
      events: function(){
        var options = this.options,
            selectors = options.selectors,
            classNames = options.classNames,
            info = this.info;

        this.$favorites.on('click', function(event){
          var post_id = this.hash.replace('#post-', ''),
              $favorite_link = $(this).addClass(classNames.disabled),
              $fav_count = $favorite_link.children(selectors.fav_count),
              $favorite = $.ajax({
                url: myTheme.page.urls.ajax,
                type: 'post',
                data: {
                  action: info.name, // derived from the module name "favorite"
                  verify: myTheme.page.verify, // https://developer.wordpress.org/reference/functions/check_ajax_referer/
                  post_id: post_id
                  // user_id of user who takes the action is not necessary
                }
              });

          $favorite.done(function(data){
            var fav_count = data.hasOwnProperty('fav_count') ? parseInt(data.fav_count) : 0,
                fav_count_text = '',
                is_favorite = data.hasOwnProperty('is_favorite') ? data.is_favorite : false;

            if ( fav_count > 0 ) {
              fav_count_text = '(' + fav_count + ')';
            }
            $fav_count.html(fav_count_text);

            if ( is_favorite && !$favorite_link.is('.' + classNames.is_favorite) ) {
              $favorite_link.addClass(classNames.is_favorite);
            } else {
              $favorite_link.removeClass(classNames.is_favorite);
            }
            $favorite_link.removeClass(classNames.disabled);
          });
          event.preventDefault();
        });
      },
      ready: function ready(){
        var selectors = this.options.selectors,
            classNames = this.options.classNames;

        this.$favorites = $(selectors.link).removeClass(classNames.disabled);
        this.events();
      },
      setup: function setup(){
        var setup = myTheme.info.is_user_logged_in && myTheme.info.post_type === 'my_custom_post_type';
        return setup; // only for my post_type
      }

PHP

add_action('wp_enqueue_scripts', 'myTheme_enqueue_scripts');
add_action('wp_ajax_favorite', 'myTheme_set_favorite');
// wp_ajax_nopriv_{action} is not necessary when feature is only for logged in users


  function myTheme_enqueue_scripts(){
    $data = array(
      'id' => get_the_ID(),
      'urls' => array(
        'ajax' => admin_url('admin-ajax.php'),
        'template' => get_stylesheet_directory_uri(),
      ),
      'verify' => wp_create_nonce('myThemeOrAction_ajax_call'), // used for check_ajax_referer()
      // ...
      'info' => array(
        // ...
        'is_user_logged_in' => is_user_logged_in(),
        'post_type' => get_post_type(),
      ),
    );
    // ...
    wp_localize_script('actions', 'myTheme_data', $data );
  }


function myTheme_set_favorite(){
  check_ajax_referer('myThemeOrAction_ajax_call', 'verify');

  if ( isset($_POST['post_id']) ) {
    $user = wp_get_current_user(); // here we get the user ID of the current user
    $post_id = filter_var($_POST['post_id'], FILTER_SANITIZE_NUMBER_INT);
    $post = get_post($post_id);
    // $fav_id = filter_var($_POST['fav_id'], FILTER_SANITIZE_NUMBER_INT);
    // $fav_user = get_userdata($fav_id); // WP_User
    $is_favorite = false;

    if ( $post instanceof WP_Post ) { // post ID is valid
    // for user favorites it would be
    // if ( $fav_user instanceof WP_User ) {
      $fav_count = intval(get_post_meta($post->ID, '_favorites', true));
      $favorites = get_user_meta($user->ID, '_favorite_posts', true);
      if ( !filter_var($fav_count, FILTER_VALIDATE_INT) ) {
        $fav_count = 0;
      }
      if ( !is_array($favorites) || empty($favorites) ) {
        $favorites = array();
      }
      $fav_key = array_search($post->ID, $favorites);

      if ( $fav_key !== false ) { // is favorite, remove it
        $fav_count--;
        unset($favorites[$fav_key]);
      } else { // is no favorite, add it
        $fav_count++;
        $favorites[] = $post->ID;
        $is_favorite = true;
      }

      // set favorite counter
      update_post_meta($post->ID, '_favorites', $fav_count);

      // set favorite list
      update_user_meta($user->ID, '_favorite_posts', $favorites);

      // Output
      $json = array(
        'fav_count'  => $fav_count,
        'favorites' => $favorites,
        'error' => false,
        'is_favorite' => $is_favorite,
      );
    } else {
      $json = array('is_favorite' => $is_favorite, 'error' => true, 'message' => 'Invalid Post ID');
    }
  } else {
    $json = array('is_favorite' => $is_favorite, 'error' => true, 'message' => 'No post_id Post ID sent');
  }
  // wp_send_json sets the http header and ends the request
  wp_send_json($json);
}

这是我在路上注意到的事情:

  • wp_create_nonce()使用和验证推荐人check_ajax_referer()
  • 检查 JSON 结果数据键是否存在data.hasOwnProperty('key')以避免可能的 JS 错误
  • 检查有效WP_UserWP_Post反对
  • 当前用户 ID 不需要通过 POST 发送
  • wp_ajax_nopriv_{action}当功能仅适用于登录用户时,不需要
  • 用于wp_send_json()结束响应

亲切的问候汤姆


推荐阅读