問題描述

過去幾個小時,我一直在網路上徘徊,想知道是否有辦法讓用户通過選擇 WordPress 中的類別來構建自己的 RSS 源,然後可以通過電子郵件訂閲。似乎提出了兩個問題:

  1. 允許人們從類別中構建個性化的 Feed 。

  2. 啓用電子郵件訂閲。

任何關於如何最好地繼續下去的想法?

最佳解決辦法

這是一個很酷的主意。

我不認為 WordPress 中應該處理第 2 部分:電子郵件提供商有很多 RSS 。他們將會更好,而不是插件 (或主題) 可能會更好。

但是我們可以創建 RSS 源。

第一步:設置一個課程來包裝所有的東西。

這裏有一些類常量和變量 – 稍後我們將使用它們。只是一個單身模式。

<?php
class Per_User_Feeds
{
    // Where we'll store the user cats
    const META_KEY = '_per_user_feeds_cats';

    // Nonce for the form fields
    const NONCE = '_user_user_feeds_nonce';

    // Taxonomy to use
    const TAX = 'category';

    // The query variable for the rewrite
    const Q_VAR = 'puf_feed';

    // container for the instance of this class
    private static $ins = null;

    // container for the terms allowed for this plugin
    private static $terms = null;

    public static function init()
    {
        add_action('plugins_loaded', array(__CLASS__, 'instance'));
    }

    public static function instance()
    {
        is_null(self::$ins) && self::$ins = new self;
        return self::$ins;
    }
}

第二步:向用户個人資料頁面添加一個字段 (並保存)

您需要掛接到 show_user_profileedit_user_profile 才能執行此操作。吐出一個廢紙,一個標籤和一個字段。當用户在管理區域中查看其個人資料時,show_user_profile 將觸發。 edit_user_profile 在編輯其他人的個人資料時觸發 – 這是您的管理員用户將如何處理編輯用户的類別。

<?php
class Per_User_Feeds
{
    // snip snip

    protected function __construct()
    {
        add_action('show_user_profile', array($this, 'field'));
        add_action('edit_user_profile', array($this, 'field'));
    }

    public function field($user)
    {
        wp_nonce_field(self::NONCE . $user->ID, self::NONCE, false);

        echo '<h4>', esc_html__('Feed Categories', 'per-user-feed'), '</h4>';

        if($terms = self::get_terms())
        {
            $val = self::get_user_terms($user->ID);
            printf('<select name="%1$s[]" id="%1$s" multiple="multiple">', esc_attr(self::META_KEY));
            echo '<option value="">', esc_html__('None', 'per-user-feed'), '</option>';
            foreach($terms as $t)
            {
                printf(
                    '<option value="%1$s" %3$s>%2$s</option>',
                    esc_attr($t->term_id),
                    esc_html($t->name),
                    in_array($t->term_id, $val) ? 'selected="selected"' : ''
                );
            }
            echo '</select>';
        }
    }
}

這也介紹了我們的前兩個幫助方法:

  1. get_user_termsget_user_meta 的一個簡單的書寫器,用於調用 apply_filters – 讓其他人修改它們想要的東西!

  2. get_termsget_terms 的一個封裝,調用 apply_filters

這兩個都只是方便的事情。他們還為其他插件/主題提供了掛鈎和修改內容的方法。

<?php
/**
 * Get the categories available for use with this plugin.
 *
 * @uses    get_terms
 * @uses    apply_filters
 * @return  array The categories for use
 */
public static function get_terms()
{
    if(is_null(self::$terms))
        self::$terms = get_terms(self::TAX, array('hide_empty' => false));

    return apply_filters('per_user_feeds_terms', self::$terms);
}

/**
 * Get the feed terms for a given user.
 *
 * @param   int $user_id The user for which to fetch terms
 * @uses    get_user_meta
 * @uses    apply_filters
 * @return  mixed The array of allowed term IDs or an empty string
 */
public static function get_user_terms($user_id)
{
    return apply_filters('per_user_feeds_user_terms',
        get_user_meta($user_id, self::META_KEY, true), $user_id);
}

要保存字段,請鈎入 personal_options_update(用户保存自己的配置文件時觸發) 和 edit_user_profile_update(保存其他用户的配置文件時觸發) 。

<?php
class Per_User_Feeds
{
    // snip snip

    protected function __construct()
    {
        add_action('show_user_profile', array($this, 'field'));
        add_action('edit_user_profile', array($this, 'field'));
        add_action('personal_options_update', array($this, 'save'));
        add_action('edit_user_profile_update', array($this, 'save'));
    }

    // snip snip

    public function save($user_id)
    {
        if(
            !isset($_POST[self::NONCE]) ||
            !wp_verify_nonce($_POST[self::NONCE], self::NONCE . $user_id)
        ) return;

        if(!current_user_can('edit_user', $user_id))
            return;

        if(!empty($_POST[self::META_KEY]))
        {
            $allowed = array_map(function($t) {
                return $t->term_id;
            }, self::get_terms());

            // PHP > 5.3: Make sure the items are in our allowed terms.
            $res = array_filter(
                (array)$_POST[self::META_KEY],
                function($i) use ($allowed) {
                    return in_array($i, $allowed);
                }
            );

            update_user_meta($user_id, self::META_KEY, array_map('absint', $res));
        }
        else
        {
            delete_user_meta($user_id, self::META_KEY);
        }
    }
}

第三步:提供飼料

由於這是一個非常自定義的 Feed,我們不想劫持像作者的 Feed 來完成這個操作 (雖然這是一個選項!) 。而是讓我們添加一個重寫:yoursite.com/user-feed/{{user_id}}將呈現個性化的用户 Feed 。

要添加重寫,我們需要鈎入 init 並使用 add_rewrite_rule 。由於這使用自定義查詢變量來檢測何時使用個性化的用户 Feed,因此我們還需要掛接到 query_vars 和我們的自定義變量中,因此 WordPress 不會忽略它。

<?php
class Per_User_Feeds
{
    // snip snip

    protected function __construct()
    {
        add_action('show_user_profile', array($this, 'field'));
        add_action('edit_user_profile', array($this, 'field'));
        add_action('personal_options_update', array($this, 'save'));
        add_action('edit_user_profile_update', array($this, 'save'));
        add_action('init', array($this, 'rewrite'));
        add_filter('query_vars', array($this, 'query_var'));
    }

    // snip snip

    public function rewrite()
    {
        add_rewrite_rule(
            '^user-feed/(d+)/?$',
            'index.php?' . self::Q_VAR . '=$matches[1]',
            'top'
        );
    }

    public function query_var($v)
    {
        $v[] = self::Q_VAR;
        return $v;
    }
}

要實際呈現 Feed,我們將鈎入 template_redirect,查找我們的自定義查詢 var(如果沒有找到它),並使用個性化版本劫持全局 $wp_query

我也掛了 wp_title_rss 修改 RSS 標題,這有點怪異:它抓住了第一個類別,並顯示了飼料標題,就像看一個單一的類別。

<?php
class Per_User_Feeds
{
    // snip snip

    protected function __construct()
    {
        add_action('show_user_profile', array($this, 'field'));
        add_action('edit_user_profile', array($this, 'field'));
        add_action('personal_options_update', array($this, 'save'));
        add_action('edit_user_profile_update', array($this, 'save'));
        add_action('init', array($this, 'rewrite'));
        add_filter('query_vars', array($this, 'query_var'));
        add_action('template_redirect', array($this, 'catch_feed'));
    }

    // snip snip

    public function catch_feed()
    {
        $user_id = get_query_var(self::Q_VAR);

        if(!$user_id)
            return;

        if($q = self::get_user_query($user_id))
        {
            global $wp_query;
            $wp_query = $q;

            // kind of lame: anon function on a filter...
            add_filter('wp_title_rss', function($title) use ($user_id) {
                $title = ' - ' . __('User Feed', 'per-user-feed');

                if($user = get_user_by('id', $user_id))
                    $title .= ': ' . $user->display_name;

                return $title;
            });
        }

        // maybe want to handle the "else" here?

        // see do_feed_rss2
        load_template( ABSPATH . WPINC . '/feed-rss2.php' );
        exit;
    }
}

要實際渲染 Feed,我們依靠 wp-includes/feed-rss2.php 。你可以用更自定義的東西替代這個,但為什麼不懶呢?

這裏還有第三個幫助方法:get_user_query 。與上述幫助者相同的想法 – 抽象出一些可重用的功能並提供鈎子。

<?php
/**
 * Get a WP_Query object for a given user.
 *
 * @acces   public
 * @uses    WP_Query
 * @return  object WP_Query
 */
public static function get_user_query($user_id)
{
    $terms = self::get_user_terms($user_id);

    if(!$terms)
        return apply_filters('per_user_feeds_query_args', false, $terms, $user_id);

    $args = apply_filters('per_user_feeds_query_args', array(
        'tax_query' => array(
            array(
                'taxonomy'  => self::TAX,
                'terms'     => $terms,
                'field'     => 'id',
                'operator'  => 'IN',
            ),
        ),
    ), $terms, $user_id);

    return new WP_Query($args);
}

這是以上所有的 as a plugin 。由於使用匿名函數,該插件 (以及隨後的此答案) 需要 PHP 5.3+。

次佳解決辦法

我使用常規 WordPress Category FeedsMailChimp 來為我的電子郵件訂閲者提供只接收有興趣接收的類別的新帖子的選項。

在 MailChimp 中,您為每個 WordPress 類別創建一個組,然後在您的電子郵件訂閲表單上允許您的訂閲者選擇他們有興趣訂閲的組 (即,類別)(一組複選框可能最簡單) 。當他們訂閲時,他們的選擇將被傳遞,並將它們放在 MailChimp 上的這些組中。

然後在 MailChimp 上,您可以使用類別 Feed 為每個類別創建一個 RSS 廣告系列,並在廣告系列設置中指定只將新帖子發送到訂閲者細分 (已選擇該類別對應的組) 。

參考文獻

注:本文內容整合自 Google/Baidu/Bing 輔助翻譯的英文資料結果。如果您對結果不滿意,可以加入我們改善翻譯效果:薇曉朵技術論壇。