问题描述

过去几个小时,我一直在网路上徘徊,想知道是否有办法让用户通过选择 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 辅助翻译的英文资料结果。如果您对结果不满意,可以加入我们改善翻译效果:薇晓朵技术论坛。