Je flâne sur le Web depuis quelques heures en me demandant s'il est possible de permettre aux utilisateurs de créer leur propre flux RSS en sélectionnant des catégories dans WordPress, auxquelles on pourrait ensuite s'abonner par courrier électronique. Semble présenter deux problèmes:
Des idées sur la meilleure façon de procéder avec l'un ou l'autre?
C'est une très bonne idée.
Je ne pense pas que la partie 2 doive être traitée dans WordPress: il existe de nombreux flux RSS pour les fournisseurs de messagerie. Ils seront bien meilleurs qu’un plugin (ou un thème).
MAIS nous pouvons créer des flux RSS.
Première étape: configurez une classe pour tout envelopper.
Il y a quelques constantes et variables de classe ici - nous les utiliserons plus tard. Juste un motif singleton.
<?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;
}
}
Deuxième étape: ajoutez un champ aux pages de profil de l'utilisateur (et enregistrez-le)
Pour ce faire, vous devrez vous connecter à show_user_profile
et edit_user_profile
. Crachez un nonce, une étiquette et le champ. show_user_profile
se déclenche lorsque les utilisateurs affichent leur profil dans la zone d'administration. edit_user_profile
se déclenche lorsqu’ils modifient le profil d’un autre - c’est ainsi que votre utilisateur admin se classera dans les catégories d’un utilisateur modifié.
<?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>';
}
}
}
Cela introduit également nos deux premières méthodes d'assistance:
get_user_terms
, un simple wrapper autour de get_user_meta
avec un appel à apply_filters
- laissez les autres modifier les choses s'ils le souhaitent!get_terms
un wrapper autour de get_terms
avec un appel à apply_filters
.Les deux ne sont que des choses de commodité. Ils fournissent également des moyens pour que d'autres plugins/thèmes se connectent et modifient des choses.
<?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);
}
Pour enregistrer les champs, connectez-vous à personal_options_update
(se déclenche lorsque l'utilisateur enregistre son propre profil) et à edit_user_profile_update
(se déclenche lors de la sauvegarde du profil d'un autre utilisateur).
<?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);
}
}
}
Troisième étape: fournir un flux
Comme il s’agit bien d’un flux personnalisé, nous ne voulons pas détourner quelque chose comme les flux d’auteurs pour y parvenir (bien que ce soit une option!). Au lieu de cela, ajoutons une réécriture: yoursite.com/user-feed/{{user_id}}
restituera le flux utilisateur personnalisé.
Pour ajouter la réécriture, nous devons accrocher init
et utiliser add_rewrite_rule
. Comme cela utilise une variable de requête personnalisée pour détecter lorsque nous sommes sur un flux utilisateur personnalisé, nous devons également connecter query_vars
et notre variable personnalisée afin que WordPress ne l'ignore pas.
<?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;
}
}
Pour rendre le flux, nous allons nous connecter à template_redirect
, rechercher notre variable personnalisée var (si nous ne le trouvons pas) et pirater le $wp_query
global avec une version personnalisée.
J'ai également eu recours à wp_title_rss
pour modifier le titre RSS, ce qui était un peu bizarre: il saisissait la première catégorie et affichait le titre du flux comme s'il regardait une seule catégorie.
<?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;
}
}
Pour rendre réellement le flux, nous nous appuyons sur wp-includes/feed-rss2.php
. Vous pouvez remplacer ceci par quelque chose de plus personnalisé, mais pourquoi ne pas être paresseux?
Il existe également une troisième méthode d'assistance ici: get_user_query
. Même idée que les assistants ci-dessus - supprimez certaines fonctionnalités réutilisables et créez des points d'ancrage.
<?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);
}
Voici tout ce qui précède sous forme de plugin . Le plugin (et par la suite cette réponse) nécessite PHP 5.3+ en raison de l'utilisation de fonctions anonymes.
Je le fais en utilisant le WordPress Category Feeds classique et MailChimp pour donner à mes abonnés par courrier électronique la possibilité de recevoir de nouveaux messages uniquement pour les catégories qui les intéressent.
Dans MailChimp, vous créez un groupe pour chaque catégorie WordPress, puis vous autorisez vos abonnés à sélectionner les groupes (c.-à-d. Les catégories) auxquels ils souhaitent s’abonner (un ensemble de cases à cocher est probablement plus facile). Lors de leur inscription, leurs sélections seront transmises et elles seront placées dans ces groupes sur MailChimp.
Ensuite, sur MailChimp, vous créez une campagne RSS pour chaque catégorie à l'aide du fil de catégorie et indiquez dans les paramètres de campagne d'envoyer uniquement de nouvelles publications à un segment de vos abonnés (le segment qui a sélectionné le groupe correspondant à cette catégorie).
Le plus simple serait d'ajouter une série de deux très courts plugins (mu-). Cela ajoute également des routes pour page/2
, etc.:
http://example.com/u/%author%
<?php
/** Plugin Name: (WPSE) #46074 Add /u/%author% routes */
register_activation_hook( __FILE__, function() { flush_rewrite_rules(); } );
register_deactivation_hook( __FILE__, function() { flush_rewrite_rules(); } );
add_action( 'init', function()
{
// Adds `/u/{$author_name}` routes
add_rewrite_rule(
'u/([^/]+)/?',
'index.php?author_name=$matches[1]',
'top'
);
add_rewrite_rule(
'u/([^/]+)/page/?([0-9]{1,})/?',
'index.php?author_name=$matches[1]&paged=$matches[2]',
'top'
);
}
http://example.com/p/%postname%
<?php
/** Plugin Name: (WPSE) #46074 Add /u/%author% routes */
register_activation_hook( __FILE__, function() { flush_rewrite_rules(); } );
register_deactivation_hook( __FILE__, function() { flush_rewrite_rules(); } );
add_action( 'init', function()
{
// Adds `/p/{$postname}` routes
add_rewrite_rule(
'p/([^/]+)/?',
'index.php?p=$matches[1]',
'top'
);
add_rewrite_rule(
'p/([^/]+)/page/?([0-9]{1,})/?',
'index.php?p=$matches[1]&paged=$matches[2]',
'top'
);
}
WordPress fournit déjà des flux RSS pour chaque catégorie, voici l'article du codex expliquant leur structure:
http://codex.wordpress.org/WordPress_Feeds#Categories_and_Tags
Pour que l'abonnement aux courriels fonctionne, je configure généralement Feedburner avec l'abonnement aux courriels activé (après avoir réclamé un fil, allez à Publier> Abonnements aux courriels). Cela nécessiterait que vous preniez vos flux de catégories et que vous les configuriez dans Feedburner, puis que vous ajoutiez ces liens vers votre site aux endroits appropriés. Si vous avez affaire à une tonne de catégories, cela peut représenter un gros travail. J'espère que d'autres personnes ici auront des suggestions.
Bonne chance!