Etendre #BuddyPress – partie 1 : apprivoiser le composant Activity

Crédits Photo Laundry by Joost Nuijten, on Flickr

Je vous invite à me suivre dans un voyage au coeur du composant social de WordPress!

2012/05/06 Update : i tried to translate this tutorial in english (sorry if sometimes my english looks like ‘franglish’ !)

Download the pdf file

Préambule

Enorme Merci √† l’√©quipe des core developpers du composant de r√©seau social de WordPress

BuddyPress est incontestablement mon extension WordPress pr√©f√©r√©e. ¬ę¬†Social Networking in a box¬†¬Ľ, tel est son claim, et cette promesse est bien au rendez-vous. De mon point de vue, une des dates les plus importantes est le 16/02/2010, date qui correspond √† la sortie de sa version 1.2 qui a permis de ne plus avoir besoin de WordPress Mu pour l’installer. Depuis lors, que notre configuration WordPress soit multisite ou non, nous pouvons proposer √† nos visiteurs un environnement propice √† la constitution de communaut√©s.

BuddyPress est un plugin tr√®s singulier : √† tel point qu’on parle de ¬ę¬†D√©veloppeurs BuddyPress¬†¬Ľ ! Je ne connais pas beaucoup de plugins pour lesquels on utilise un tel qualificatif pour d√©finir les personnes qui se lancent dans la conception d’extensions √† ce plugin. Et pr√©cis√©ment ce qui le singularise, c’est la multitude de hooks (de type Action ou Filter) qui sont disponibles et permettent de l’enrichir de nos cr√©ations.

Depuis que je l’ai rencontr√© en Juillet 2010, je lui ai consacr√© 25 articles pour pr√©senter des astuces ou des plugins de ma conception comme BP My Home, BP Show Friends, Bowe Codes ou encore BP Code Snippets. Aujourd’hui, mon propos n’est pas forc√©ment de vous livrer un nouveau trick ou plugin (m√™me s’il y en a un √† t√©l√©charger !!). Il s’agit plut√īt de vous donner envie de cr√©er le(s) v√ītre(s) et de rejoindre le hall of fame des concepteurs de plugin BuddyPress :).

Ainsi, je vous propose de me suivre le temps d’une s√©rie d’articles dans une exp√©dition au coeur de BuddyPress. Ce premier article nous permettra de prendre connaissance du paysage et de concevoir un plugin portant sur ce qui est pour moi le composant Majeur de BuddyPress : les Activities.

Table des mati√®res…

Let‚Äôs pack : pr√©parons notre valise !ÔĽŅ
Landing! Admirons quelques secondes le panorama.
Conception de notre plugin
Mise en jambes!
Charger un javascript sur conditions
Exemple d’identification du meilleur hook
Une petite pause pour déguster des cookies
Ready! en route pour la ‚Äúmain street‚ÄĚ de notre extension
Sachons faire preuve d’imagination et d’astuces
Petite récréation : faisons quelques loopings !
Un petit relooking s’impose..
Simplifions la vie du super Admin et ayons le souci d’effacer nos traces!!
Download du plugin temporaire..
Bilan d’√©tape : levons le nez du guidon 2s
Upgrade de notre plugin
Optimisons!
Capitalisons!
WPAjaxifions le reshare
Profitons des activity metas.
Vers l’infiniternational et au del√† !
Evolution possible de la fonction reshare
Download du plugin final..

Let’s pack : pr√©parons notre valise !

Concevoir un plugin BuddyPress n√©cessite de d’abord s’√©quiper. Voici ma trousse √† outils :

  1. WordPress (fr) 3.3.2 et BuddyPress 1.5.5.
  2. La traduction française de BuddyPress (fichiers po et mo à coller dans le répertoire bp-languages de BuddyPress)
  3. Un serveur local Apache/MySql/Php, dans mon cas j’ai choisi MAMP.
  4. Un √©diteur de texte, TextMate m’a conquis!
  5. Des favoris vers le codex de BuddyPress et plus particulièrement les conditional template tags.
  6. Un favori vers le codex de WordPress, bien entendu.
  7. Optionnel : une lecture rapide de la Prez que j’avais utilis√©e lors du WordPress Day d’Alg√©rie, l’histoire de se rafra√ģchir la m√©moire quant √† la conception de plugins WordPress
  8. PoEdit pour l’internationalisation de notre plugin
  9. Sans oublier une bonne liste de lecture. En ce moment j’√©coute RHCP ūüėČ

De la m√™me mani√®re que le slide 18 de ma pr√©sentation WordPress Day Alg√©rie insiste sur la pr√©caution de ne pas modifier le coeur de WordPress, il est indispensable de respecter cette m√™me pr√©caution s’agissant du code source de BuddyPress. Au del√† des risques pour sa stabilit√©, pensez mise √† jour ! BuddyPress se met r√©guli√®rement √† jour et si vous le modifiez, vous perdrez toutes vos modifications lors de son prochain upgrade.

Landing! Admirons quelques secondes le panorama.

BuddyPress est une extension qui s’ex√©cute sur l’ensemble du r√©seau dans le cas des configs WordPress Multisites et ses vues sont disponibles sur le blog principal du network. Notons que depuis la version 1.5, BP cr√©e √† l’install des pages WordPress pour ses diff√©rents composants.

En surlign√© bleu, j’ai indiqu√© les tables et scripts qui seront utiles dans le cadre de notre plugin. Par manque de place, je n’ai pas d√©taill√© le contenu du r√©pertoire bp-themes qui contient le th√®me par d√©faut de BuddyPress. Nous nous int√©resserons notamment √† ses templates activity (entry.php et post-form.phpÔĽŅ).

Nous disposons d’une pr√©cieuse globale $bp qui stocke un certain nombre de variables tr√®s utiles que nous pourrons r√©cup√©rer pour notre plugin. Pour l’utiliser, il suffit d’y faire r√©f√©rence au d√©but de votre fonction de cette mani√®re :

function mafonction(){
	global $bp;

	/* suite de votre fonction */
}

Voici trois des variables de $bp que j’utilise r√©guli√®rement :

  • $bp->groups->current_group->idÔĽŅ : informe sur l’id du groupe affich√©
  • $bp->displayed_user->id : informe sur l’id du membre affich√©
  • $bp->loggedin_user->id : informe sur l’id du membre connect√©

BuddyPress nous propose √©galement la classe BP_Component pour concevoir nos propres composants, sa Group API pour ajouter tr√®s simplement des ¬ę¬†apps¬†¬Ľ pour les groupes et un certain nombre de fonctions tr√®s int√©ressantes pour interagir avec ses diff√©rents composants (activit√©s, notifications, groups, forums, profiles…). Je reviendrai sur ces √©l√©ments dans un prochain article :).

Conception de notre plugin

Le besoin : permettre au super admin depuis un groupe support de poster des activit√©s qui seront automatiquement visibles sur l’int√©gralit√© des autres groupes de la communaut√©.

Commen√ßons par constituer notre environnement de test : Cr√©ons 3 groupes dont l’un sera priv√©. On r√©cup√®re l’identifiant du groupe public que nous voulons utiliser comme ¬ę¬†support¬†¬Ľ : nous le stockerons en dur dans une constante de notre plugin dans un premier temps.

Dans le r√©pertoire plugins de WordPress, nous cr√©ons un nouveau r√©pertoire bp-ads-group-update dans lequel nous allons ajouter les r√©pertoires js, css, images, includes et le fichier principal de notre plugin bp-ads-group-update.phpÔĽŅ. Editons ce dernier fichier pour faire comprendre √† WordPress qu’il s’agit d’un plugin gr√Ęce √† l’ajout de tags sp√©cifiques √† son header.

Tout comme BuddyPress, notre plugin s’ex√©cutera sur l’ensemble du Network (tag Network fix√© √† true) en cas d’installation multisite. Cela √©vitera notamment qu’il soit affich√© dans la liste des extensions disponibles des blogs fils si toutefois l’administrateur a autoris√© cet affichage. Nous retrouvons notre constante BP_AGU_GROUP_SUPPORT_IDÔĽŅ qui contient l’id de notre groupe public support (dans cet exemple 3). J’ai √©galement ajout√© un certain nombre de constantes pour plus facilement faire r√©f√©rence aux url des r√©pertoires js, css et images. La fonction plugins_url() est tr√®s pratique car selon le protocole de votre site (http ou https), elle construit la bonne url.

Mise en jambes!

Depuis l’administration des plugins ou la network administration des plugins selon votre configuration, activons le plugin. Bien entendu, √† cette √©tape de la partie rien ne se passe !! Si vous souhaitez conna√ģtre l’int√©gralit√© des variables contenues dans la global $bp, on peut s’amuser √† ajouter une premi√®re fonction qui se jouera au moment o√Ļ WordPress passera par le hook wp_head.

function bp_agu_dump_bp() {
	global $bp;
	?>

	<pre><?php var_dump($bp);?></pre>
	<?php
}
add_action('wp_head', 'bp_agu_dump_bp');

Si vous vous amusez √† rafra√ģchir le front de votre blog, vous obtenez le nec plus ultra du design ;). Plus s√©rieusement, le tout d√©but du code illustre un exemple d’interception d’un hook action.

En utilisant la fonction add_action(‘hook_a_intercepter’, ‘par_ma_fonction’, 9, 1), nous indiquons √† WordPress que d√©s qu’il passe par le ‘hook_a_intercepter’ alors il doit jouer ‘par_ma_fonction’. Les deux arguments qui suivent servent √† indiquer la priorit√© d’ex√©cution de notre fonction et le nombre d’arguments qui sont √† r√©cup√©rer du ‘hook_a_intercepter’. Supprimons cette fonction qui ne nous sera pas utile pour la suite..

Charger un javascript sur conditions

Dans notre trousse √† outils, munissons nous de notre favori ¬ę¬†conditional template tags¬†¬Ľ. Dans la mesure du possible, pour votre plugin, je vous invite √† toujours faire en sorte de charger vos javascripts ou feuilles de style uniquement au moment o√Ļ vous en avez besoin. En effet, notre besoin pr√©cise que les messages de support seront √©crits depuis le groupe support. Dans le composant groupe, le template activity/post-form.phpÔĽŅ est uniquement charg√© depuis l’accueil du groupe, ce qui correspond au conditional template tags bp_is_group_home().

function bp_agu_load_js() {
	global $bp;

	if ( bp_is_group_home() && $bp->groups->current_group->id == BP_AGU_GROUP_SUPPORT_ID ) {
		wp_enqueue_script( 'bp-agu-js', BP_AGU_PLUGIN_URL_JS . '/bp-agu.js', array('jquery') );
	}
}
add_action( 'bp_screens', 'bp_agu_load_js' );

Voici une nouvelle fonction WordPress tr√®s utile : wp_enqueue_script(‘identifiant_de_mon_js’, ‘url_de_mon_js’, array(‘scripts_de_dependance’)). WordPress recommande l’utilisation de cette fonction pour inclure nos scripts, un avantage est qu’elle permet d’inclure une seule fois un script identifi√© et de g√©rer simplement ses d√©pendances (dans notre exemple jQuery). Pour information, pour inclure un style, vous pouvez utiliser wp_enqueue_style.

Pour charger ce javascript, il faut bien choisir son moment et s’assurer que toutes les variables que l’on va tester ont √©t√© initialis√©e. Ici j’utilise le hook 'bp_screens'ÔĽŅ. Il est localis√© dans le script bp-core-hooks.php du r√©pertoire bp-core de BuddyPress. C’est le hook qui sert √† d√©finir les templates √† afficher pour les pages des composants BP. Si par exemple, j’avais choisi le hook plugins_loaded, rien ne se serait pass√© car la variable $bp->groups->current_group->id n’est pas encore initialis√©e.

En l’occurrence, comme nous n’avons pas cr√©√© le fichier javascript, rien ne se passera ūüôā Cr√©ons donc le fichier bp-agu.jsÔĽŅ dans le r√©pertoire js de notre plugin. Si vous voulez tester, ajouter lui simplement ce contenu :

jQuery(document).ready(function($){alert('chargé!')});

Exemple d’identification du meilleur hook

On revient dans quelques instants √† notre fichier js. Pour le moment, on peut facilement ajouter un checkbox au formulaire d’update d’actualit√©. Je vous invite √† parcourir le template activity/post-form.phpÔĽŅ du th√®me bp-default de BuddyPress.

L’illustration ci-dessus nous propose 3 hooks. Si, vous testez les num√©ro 1 et 3, vous vous apercevrez que le positionnement de notre checkbox est soit trop haut, soit vraiment trop bas. Donc, nous allons utiliser le hook 'bp_activity_post_form_options'ÔĽŅ. Notre fonction d’ajout du champ checkbox sera donc :

function bp_agu_checkbox(){
	global $bp;

	if ( is_super_admin() && bp_is_group_home() && $bp->groups->current_group->id == BP_AGU_GROUP_SUPPORT_ID ) {
		?>
		<span id="bp-agu-cb">
			<input type="checkbox" value="1" name="_support_message" id="support_message">Support</input>
		</span>
		<?php
	}
}
add_action('bp_activity_post_form_options', 'bp_agu_checkbox');  

En passant, la fonction is_super_admin() renvoie true si l’utilisateur connect√© est le Super Administrateur du Network ou l’administrateur si WordPress n’est pas configur√© en multisite. Si vous testez c√īt√© front, vous vous apercevrez que votre case √† cocher n’est pas juste √† c√īt√© du bouton submit comme illustr√© plus haut. C’est normal, dans la mesure o√Ļ nous enrichirons cette m√©thode gr√Ęce √† jQuery dans la version temporaire de notre plugin.

Notre checkbox va nous servir √† d√©clencher le comportement de partage du message support sur tous les groupes du r√©seau BuddyPress si elle est coch√©e. On ne sait jamais, toutes les updates de ce groupe ne seront pas forc√©ment des messages support. D√©j√† les activity recording li√©s √† la publication de nouveaux forums seraient sinon automatiquement partag√©es sur tous les groupes, et nous ne souhaitons pas ce comportement. Occupons-nous d√©sormais d’intercepter l’activit√© pour tester la valeur de cette checkbox une fois le message publi√©.

La fonction responsable des enregistrements d’activit√© est bp_activity_add()ÔĽŅ. Elle est localis√©e dans le script bp-activity/bp-activity-functions.php de BuddyPress. A la fin de cette fonction, un hook nous permet d’intercepter le moment o√Ļ elle sera publi√©e, il s’agit du marqueur do_action( 'bp_activity_add' ). N√©anmoins, si on se positionne ici, nous aurons √† tester les param√®tres associ√©s √† cette fonction pour savoir s’il s’agit bien d’une activit√© de groupe. Il y a plus simple, dans le script bp-groups/bp-groups-functions.php, la fonction groups_post_update() nous permet de nous raccrocher au hook do_action( 'bp_groups_posted_update' ) nous garantissant que l’activit√© a √©t√© post√©e depuis un groupe.

// fonction temporaire pour les besoins du test..
function bp_agu_check_support( $content, $user_id, $group_id, $activity_id ) {
	if( $group_id == BP_AGU_GROUP_SUPPORT_ID && $_REQUEST['_support_message'] ) {
		wp_die( 'la valeur du checkbox est ' . $_REQUEST['_support_message'] );
	}
}
add_action( 'bp_groups_posted_update', 'bp_agu_check_support', 9, 4);

Vous avez vu en gras, j’ai mis un 4√®me argument √† mon add_action()ÔĽŅ : j’ai indiqu√© que je voulais r√©cup√©rer les 4 arguments qui sont pass√©s via la fonction do_action( 'bp_groups_posted_update' ). Ces 4 arguments, je les sp√©cifie dans ma fonction bp_agu_check_support.

Je vous invite √† tester cette fonction en deux temps : d’abord normalement, ensuite en d√©sactivant le javascript de votre navigateur. Dans le premier cas, rien ne se passe, dans le deuxi√®me cas, vous avez bien une belle erreur WordPress affich√©e avec la valeur de notre checkbox. BuddyPress utilise r√©guli√®rement des requ√™tes AJAX pour ajouter en dynamisme, il faut donc proc√©der autrement pour passer la variable contenue dans notre checkbox, tout en envisageant le cas o√Ļ l’utilisateur a d√©sactiv√© le javascript de son navigateur.

Une petite pause pour déguster des cookies

Pour passer certaines de ses variables en AJAX, BuddyPress utilise des cookies qui dure le temps de votre session. Si vous vous amusez √† afficher l’inspecteur de votre navigateur lorsque vous avez filtr√© les activit√©s pour ne retenir que les updates, vous verrez un cookie du nom de bp-activity-filter dont la valeur est fix√©e √† activity_updateÔĽŅ. D’ailleurs, c’est ce qui explique √©galement que si vous faites un tour sur les actualit√©s d’un de vos groupes ou sur les actualit√©s de votre profil, elles seront elles-aussi filtr√©es sur les updates uniquement.

Nous allons donc profiter de ce m√©canisme pour passer la valeur de notre checkbox dans la fonction AJAX qui s’occupe de poster les activit√©s. Regardez l’extrait du fichier _inc/global.jsÔĽŅ du th√®me par d√©faut de BuddyPress, et plus particuli√®rement la ligne 67 :

G√©nial !! A chaque activit√© post√©e en AJAX, BuddyPress encode tous les cookies de session pr√©sents et les balance dans la variable $_POST['cookie']. Il ne nous reste plus qu’√† √©crire un cookie que nous appellerons bp-agu-is-support au moment o√Ļ notre checkbox sera coch√©e. Et pour ce faire, nous allons √©diter notre fichier javascript qui ne faisait qu’alerter ¬ę¬†charg√©!¬†¬Ľ pour le moment. Et pendant qu’on y est, on va r√©cup√©rer notre checkbox pour la d√©placer juste √† c√īt√© du bouton submit :). Voici donc notre tout nouveau tout beau bp-agu.jsÔĽŅ :

jQuery(document).ready(function($){
	$('#whats-new-submit').prepend($('#bp-agu-cb').html());
	$('#bp-agu-cb').html("");

	if( $.cookie("bp-agu-is-support") == 1 ) {
		$("#support_message").attr('checked', 'true');
	}

	$('#support_message').live('click', function(){
		if( $(this).attr('checked') ) {
			$.cookie("bp-agu-is-support", $(this).val());
		} else { 
			$.cookie("bp-agu-is-support", '' );
		}
	} );
} );

En bleu gras, le moment o√Ļ on affecte la valeur de notre checkbox √† notre cookie. Maintenant, il faudra tester l’existence de ce cookie pour indiquer au super Admin qu’il va o√Ļ non poster un message support. C’est la raison pour laquelle, on commence par d’abord tester cette existence et activer le cas √©ch√©ant la checkbox. Maintenant que le javascript est en place, nous pouvons nous occuper de notre fonction bp_agu_check_supportÔĽŅ pour lui faire faire autre chose que renvoyer une erreur WordPress !

Ready! en route pour la ¬ę¬†main street¬†¬Ľ de notre extension

Pour retrouver le code de cette fonction et le copier coller dans le plugin que nous avons d√©marr√©, vous pouvez √† tout moment r√©cup√©rer les sources. Maintenant analysons les 3 √©tapes de cette fonction. D’abord, nous r√©cup√©rons la valeur de notre checkbox (√©tape 1).

Nous commen√ßons par imaginer que l’utilisateur a d√©sactiv√© le javascript de son navigateur en initialisant la variable $is_support_messageÔĽŅ par la valeur de la checkbox post√©e. Si elle n’existe pas, c’est que javascript est activ√©. Il s’agit donc de parser $_POST['cookie'] pour stocker tous les cookies du document dans un tableau associatif. Ensuite, nous r√©cup√©rons tranquillement la valeur de notre cookie bp-agu-is-support pour l’affecter √† notre variable $is_support_message.

Passons √† l’√©tape 2 : si notre cookie est set et que l’id du groupe – qui nous a √©t√© pass√© en param√®tres de notre fonction via les arguments du marqueur do_action( 'bp_groups_posted_update' )ÔĽŅ – correspond √† celui de notre groupe support (que nous avons d√©fini en constante au d√©but de notre plugin), alors nous allons r√©cup√©rer les √©l√©ments de l’activit√© via la fonction bp_activity_get_specific() qui est localis√©e dans le script bp-activity/bp-activity-functions.php de BuddyPress. Comme son nom l’indique, elle permet de r√©cup√©rer des activit√©s en lui passant soit un id d’activit√© soit un tableau d’id d’activit√©s. De la m√™me mani√®re que nous avons h√©rit√© du group_id du hook intercept√©, on a cet id dans l’argument $activity_id de notre fonction. Il ne nous reste plus qu’√† pr√©parer le tableau des arguments qu’attend la fonction groups_record_activity() que vous retrouverez dans le script bp-groups/bp-groups-activity.php. On va simplement omettre intentionnellement de pr√©ciser l’index ‘item_id’ de ce tableau pour le moment. D√©tail important, notez bien qu’√† la ligne 75 nous cr√©ons un nouveau type d’activit√© : support_update

Terminons par l’√©tape 3. Rappelons nous du besoin du super Admin : permettre au super admin depuis un groupe support de poster des activit√©s qui seront automatiquement visibles sur l’int√©gralit√© des autres groupes de la communaut√©. Pour y parvenir, une boucle s’impose ūüôā C’est ce que nous allons faire en utilisant une classe WordPress hyper importante pour la communication avec la base de donn√©es : $wpdb. En passant, vous avez remarqu√© que je l’ai r√©f√©renc√©e au tout d√©but du code (ligne 56) de cette fonction ? Pour un rapide brief sur cette classe, je vous invite √† lire les slides 11 √† 15 de la pr√©sentation qui m’avait servie lors du WordPress day d’Alg√©rie. Nous r√©cup√©rons donc un tableau contenant les ids de tous les groupes du site (table wp_bp_groupsÔĽŅ), sur lequel nous bouclons pour ajouter le fameux index ‘item_id’ – en v√©rifiant bien que l’id du groupe n’est pas celui de notre groupe support – au tableau des arguments attendus par la fonction groups_record_activity() et toujours dans la boucle on la joue. R√©sultat : on a dupliqu√© l’activit√© sur nos deux groupes.

Sachons faire preuve d’imagination et d’astuces

Alors, vous allez me dire ¬ę¬†mouai pas terrible car si je vais sur les activit√©s globales du site je vais avoir 3 fois la m√™me actualit√© qui sera affich√©e¬†¬Ľ. Sauf que, dans le tableau des arguments de groups_record_activity()ÔĽŅ, nous avons pr√©cis√© qu’il fallait pr√©cis√©ment masquer ces activit√©s ('hide_sitewide' => 1) :).

Vous n’avez pas pu attendre pour tester, moi non plus !! J’ai d’abord v√©rifi√© les activit√©s globales de BuddyPress : et j’ai bien un seul message support, c’est normal car nous avons sp√©cifi√© ('hide_sitewide' => 1ÔĽŅ). Si je vais sur le groupe priv√© que nous avons cr√©√© pour nos tests, c’est bien apparent. En revanche, lorsque je vais sur le groupe public de notre environnement de test : wallou, nada !!

Alors Pourquoi tant de haine ?? √áa fait 10 minutes que vous lisez ce tuto et ¬ę¬†vlan lopamarch√©¬†¬Ľ ! En fait c’est normal que le groupe public n’affiche pas cette activit√© dans la mesure o√Ļ dans la table wp_bp_activityÔĽŅ le champ hide_sitewide de l’activit√© est fix√© √† 1 et que lui, √©tant groupe public, n’affichera que les actualit√©s dont le champ hide_sitewide est fix√© √† 0. Alors, entrons un peu plus en profondeur dans le coeur du composant Activity de BuddyPress. la fonction groups_record_activity() du script bp-groups/bp-groups-activity.php appelle la fonction bp_activity_add() du script bp-activity/bp-activity-functions.php qui elle-m√™me appelle la classe BP_Activity_Activity du script bp-activity/bp-activity-classes.php pour cr√©er l’activit√©. Vous me suivez ?

La fonction get() de cette classe cr√©e cet argument Sql WHERE "a.hide_sitewide = 0"ÔĽŅ si toutefois le groupe n’est pas priv√© : or nous avons besoin d’avoir les actualit√©s dont le champ hide_sitewide est sup√©rieur ou √©gal √† 0 !! Je vous propose une pirouette pour atteindre cet objectif. Vous avez remarqu√© que la requ√™te qui peuple $activities dispose d’un hook de type filtre ? On va donc pouvoir s’en servir. La particularit√© de ce type de hook est qu’il attend une valeur en retour. Nous allons donc utiliser un add_filter() en r√©cup√©rant la valeur de la requ√™te pour lui renvoyer une requ√™te sensiblement diff√©rente : admirez l’astuce !

function bp_agu_sql_trick_to_include_hidden( $sql ) {
	f( bp_is_group_home() ) {
		return str_replace('a.hide_sitewide = 0', 'a.hide_sitewide >= 0', $sql);
	}

	return $sql;
}
add_filter('bp_activity_get_user_join_filter', 'bp_agu_sql_trick_to_include_hidden', 99, 1); /* do not forget the count activities sql !!! */ add_filter('bp_activity_total_activities_sql', 'bp_agu_sql_trick_to_include_hidden', 99, 1);

Ainsi, si nous sommes sur l’accueil du groupe, nous allons remplacer a.hide_sitewide = 0ÔĽŅ par a.hide_sitewide >= 0 ; autrement, on retourne la requ√™te sans modification. Comme pour le hook add_action(), en sp√©cifiant apr√®s la priorit√© le nombre d’arguments attendu (ici 1), on passe la valeur de la requ√™te SQL √† notre fonction bp_agu_sql_trick_to_include_hidden($sql). Voil√† qui va satisfaire notre plugin :).

Petite récréation : faisons quelques loopings !

C’est embarassant.. Tout n’est pas tout fini : si depuis les activit√©s globales de notre site, j’active le tab My Groups ou si je vais sur mes activit√©s de profil, √©tant super Admin, sont affich√©es les 3 activit√©s. Alors, on pourrait se dire ¬ę¬†c’est pas grave, √ßa ne touche que le super Admin !!¬†¬Ľ, mais la maison essaye de soigner ses plugins. On va donc r√©soudre cette nouvelle difficult√©. Pour cela nous allons faire connaissance avec le loop des activit√©s de BuddyPress. Jetons un oeil au template activity/activity-loop.phpÔĽŅ du th√®me bp-default.

La fonction bp_has_activities() va tr√®s gentiment nous emmener d√©couvrir le script bp-activity/bp-activity-template.php lequel contient notamment la classe BP_Activity_Template. bp_has_activities() appelle cette classe et stocke son rendu dans la globale $activities_templateÔĽŅ. Cette globale servira √† BuddyPress pour retourner les diff√©rentes informations li√©es √† l’activit√© √† chaque fois que nous ferons appel aux template tags de l’activit√©. Si vous parcourez rapidement le template activity/entry.php du th√®me bp-default, vous allez rencontrer un certain nombre de ces template tags, en voici une s√©lection qui nous sera utile pour la suite :

  • bp_activity_can_comment()ÔĽŅ,
  • bp_activity_can_favorite(),
  • bp_activity_user_can_delete(),
  • bp_get_activity_type(),
  • bp_activity_user_link(),
  • bp_activity_avatar(),
  • etc..

D√©tail int√©ressant √† propos de ces template tags, c’est qu’il marche souvent en paire. Je m’explique : bp_activity_avatar()ÔĽŅ affiche le r√©sultat de bp_get_activity_avatar(). Et les bp_get_... contiennent tous des filtres √† hooker :).

Revenons sur bp_has_activities()ÔĽŅ. Si on s’int√©resse aux lignes 332 √† 371 de son code, on s’aper√ßoit qu’en fonction du ¬ę¬†scope¬†¬Ľ, BuddyPress pr√©pare des ajustements √† la requ√™te que nous avons vu plus haut. Ainsi, dans le cas des activit√©s affich√©es dans le profil de l’utilisateur connect√©, toutes les activit√©s qu’il a partag√©es seront int√©gr√©es, il en va de m√™me pour les activit√©s du tab My Groups des activit√©s globales. Et la fonction qui dirige cet aiguillage est √† la fois dans l’encadr√© bleu de notre pr√©c√©dente illustration et √† la fois (surtout d’ailleurs!) dans le script bp-core/bp-core-template.php, il s’agit de bp_ajax_querystring, et devinez quoi : cette fonction propose un filtre, nous allons donc pouvoir modifier ce comportement depuis notre plugin ;).

function bp_agu_neutralize_support_updates_in_scopes( $ajax_querystring, $object ) {
	$r = wp_parse_args( $ajax_querystring );
	extract( $r );

	if ( $scope == 'groups' || bp_is_user_activity() ) {
		$exclude_ids = array();
		$exclude_activities = bp_activity_get( array(
			'show_hidden'=>true,
			'filter' => array( 'action' => 'support_update' )
		) );

		foreach( $exclude_activities['activities'] as $exclude_id ) {
			$exclude_ids[] = $exclude_id->id;
		}

		return $ajax_querystring.'&exclude='.implode(',', $exclude_ids);
	}

	return $ajax_querystring;
}
add_filter( 'bp_ajax_querystring', 'bp_agu_neutralize_support_updates_in_scopes', 99, 2); 

Alors, pour ne pas afficher les activit√©s en triplon, on va simplement les exclure si toutefois elles ont un type support_update. On a bien fait de cr√©er ce type d’update dans notre fonction bp_agu_check_support()! Pour cela, on r√©cup√®re les activit√©s en question pour former un tableau et ajouter une variable √† l’AJAX querystring qui contiendra une liste des ids des activit√©s √† exclure s√©par√©es par des virgules.

Un petit relooking s’impose..

Impressionnant ce qu’on peut faire avec les filtres, non ? Voici l’√©tendue du relooking pour nos support_updatesÔĽŅ affich√©es dans les activit√©s des groupes :

  1. On neutralise les boutons d’action classiques (commenter, mettre en favoris ou supprimer).
  2. On change l’avatar de l’utilisateur par celui du groupe support (ainsi que le lien du profil utilisateur pour celui de l’accueil du groupe support).
  3. On supprime l’avatar secondaire, puisque nous n’en avons plus besoin.
  4. On modifie le permalien de l’activit√© pour celle du groupe support.
  5. On ajoute un bouton commentaire qui renvoie automatiquement sur l’activit√© ¬ę¬†m√®re¬†¬Ľ qui a √©t√© cr√©√©e par le groupe support, et on r√©cup√®re par la m√™me occase son nombre de commentaires.

Et toutes ces modifs en ajoutant des filtres aux template tags des activit√©s que nous avons √©voqu√©s plus t√īt. Je ne vais pas tous les illustrer, vous pourrez les retrouver en int√©gralit√© dans le fichier principal du plugin disponible en t√©l√©chargement, voici un exemple :

function bp_agu_override_activity_time_since( $content ) {
	if( 'support_update' != bp_get_activity_type() ) {
		return $content;
	}

	$parent_activity_id = bp_get_activity_secondary_item_id();

	return preg_replace( "//p/([0-9]+)//", '/p/'.$parent_activity_id.'/', $content );
}
add_filter( 'bp_activity_permalink', 'bp_agu_override_activity_time_since', 99, 1); 

Une fois le relooking achev√©, les membres ne pourront pas commenter les ‘support_update’ mais seront dirig√©s sur l’activit√© ¬ę¬†m√®re¬†¬Ľ cr√©√©e par le groupe support : ce qui permet de centraliser les commentaires √† un seul endroit. On d√©sactive le bouton de suppression dans la mesure o√Ļ on ne souhaite pas que les administrateurs des groupes puissent supprimer un message support. Enfin, on enl√®ve le bouton de mise en favoris car qui souhaite bookmarker des messages supports ?!! Il nous reste √† envisager la suppression de l’activit√© m√®re. Car si le super Admin supprime le message support, toute la logique tombe par terre : on perd la m√®re !!!! La fonction suivante se charge de cette √©ventualit√© en supprimant les activit√©s filles si toutefois la maman √©tait amen√©e √† dispara√ģtre… Triste destin√©e pour ces filles, elles sont vou√©es √† ne pas survivre √† leurs parents ūüôĀ

function bp_agu_handle_deleting( $args ) {
	bp_activity_delete( array(
		'type' => 'support_update',
		'secondary_item_id' => $args['id']
	) );
}
add_action('bp_activity_delete', 'bp_agu_handle_deleting', 9, 1 );

Simplifions la vie du super Admin et ayons le souci d’effacer nos traces!!

Voil√† qui est pas mal, on peut presque constituer notre premier package pour tests ! Avant, il faut pr√©voir une interface pour notre plugin dans le backend de WordPress, l’histoire de ne pas l’obliger √† modifier le code source du plugin pour adapter la constante BP_AGU_GROUP_SUPPORT_IDÔĽŅ √† l’id de son groupe support (qui n’est pas forc√©ment 3!).

Comme nous concevons un plugin BuddyPress, je vous invite √† rattacher cette page d’administration au menu BuddyPress du backend. En fonction de la configuration de WordPress, ce menu est soit sur l’espace WP Admin soit sur celui du Network Admin. Pour parer √† toute √©ventualit√©, il s’agit d’utiliser la fonction is_multisite()ÔĽŅ et intercepter le bon hook en fonction de son r√©sultat.

function bp_agu_backend_menu() {
	if ( !is_super_admin() ) {
		return false; 
	}

	add_submenu_page(
		'bp-general-settings',
		'Options Ads Group Update',
		'Options Ads Group Update' ,
		'manage_options', 
		'bp-agu-backend-slug',
		'bp_agu_backend_page'
	);
}
add_action( is_multisite() ? 'network_admin_menu' : 'admin_menu', 'bp_agu_backend_menu', 21); 

Pour en savoir plus sur l’ajout de page d’Administration WordPress, je vous invite √† consulter (une nouvelle fois) la pr√©sentation que j’avais utilis√©e lors du WordPress Day d’Alg√©rie et plus pr√©cis√©ment son slide 36. En gras dans le code ci-dessus, la r√©f√©rence √† la fonction qui sera jou√©e lorsque l’administrateur cliquera sur le sous menu ¬ę¬†Options Ads Group Update¬†¬Ľ du menu BuddyPress

Si on s’int√©resse au code source de la fonction bp_agu_backend_page(), on s’aper√ßoit qu’on utilise le m√©canisme de s√©curit√© wp_nonce pour s’assurer que la requ√™te provient bien de notre site. Il est important de veiller √©galement √† valider les inputs utilisateurs avant de les stocker ou les afficher. Dans notre cas, comme on attend un IDÔĽŅ de groupe, soit un entier, on utilise la fonction intval() pour s’assurer que seul un entier sera sauvegard√©.

function bp_agu_backend_page() {
	if( $_POST['_bp_agu_options'] && check_admin_referer( 'bp-agu-option', '_bp_agu_option' ) ) {
		if ( update_option('_bp_agu_group_support', intval( $_POST['_bp_agu_group_support'] ) ) !== false ) {
			echo '<div id="message" class="updated"><p>Options sauvegardées</p></div>';
		}
	}

	$group_support = intval( get_option('_bp_agu_group_support') );

	// to be continued...
}

Nous utilisons donc la table wp_options pour stocker les r√©glages globaux de notre extension. Maintenant que l’admin peut stocker son groupe ID, il ne faut pas oublier de modifier la valeur de notre constante BP_AGU_GROUP_SUPPORT_IDÔĽŅ !!

function bp_agu_define_support_group() {
	return intval( get_option('_bp_agu_group_support') );
}
define ( 'BP_AGU_GROUP_SUPPORT_ID', bp_agu_define_support_group() );

On a presque fini cette version beta de notre plugin : tenez bon !! Comme les fonctionnalit√©s de notre plugin sont susceptibles d’√©voluer, toujours dans la table wp_optionsÔĽŅ de WordPress, il peut √™tre utile de stocker sa version. Ainsi lors de mises √† jour, nous pourrons le cas √©ch√©ant pr√©voir des actions √† r√©aliser en fonction de la version utilis√©e par le site. Pour cela, nous utiliserons le registration hook de WordPress qui intervient juste apr√®s l’activation de notre extension par l’administrateur.

function bp_agu_activate() {
	if ( get_option('_bp_agu_version') != BP_AGU_PLUGIN_VERSION ) {
		update_option( '_bp_agu_version', BP_AGU_PLUGIN_VERSION );
	}
}
register_activation_hook( __FILE__, 'bp_agu_activate' );

Enfin, vite fait : on va ajouter un nouveau fichier √† la racine de notre plugin. On l’appelera uninstall.php. Ce fichier sera appel√© par WordPress au moment o√Ļ l’administrateur aura confirm√© son souhait de supprimer le plugin de son site. C’est tr√®s important, dans la mesure du possible, de tenter d’effacer toutes les traces de notre plugin notamment dans la base de donn√©es. En plus dans notre cas, on a mis en place un m√©canisme qui duplique les activit√©s. D√©s que l’admin aura supprim√© notre plugin… patatra ! tout ce que nous avons astucieusement masqu√©, r√©appara√ģtra :(. Je vous laisse d√©couvrir son contenu (suppression des options et des activit√©s de type ‘support_update’) dans la premi√®re version de notre extension disponible ci-apr√®s.. Hip Hip Hip…

Bilan d’√©tape : levons le nez du guidon 2s

Notre plugin commence √† ressembler √† quelque chose. Si on v√©rifie l’illustration du panorama, nous avons bien rencontr√© la classe ¬ę¬†CRUD¬†¬Ľ BP_Activity_ActivityÔĽŅ de la table wp_bp_activity, les fonctions d’ajout et de suppression d’activit√©s ainsi que le templating avec la classe BP_Activity_Template et les template tags filtrables. Il y a un point que nous n’avons pas abord√© : ce sont les activity metas qui sont stock√©es dans la table wp_bp_activity_meta. On va faire connaissances avec elles dans notre prochaine √©tape.

Notre plugin reste perfectible : il est important de penser √† l’internationaliser. Cela augmentera son utilisation et enrichira les feedbacks et demandes d’√©volution. Il est important √©galement de l’optimiser en s’assurant que BuddyPress est ¬ę¬†ready to rock¬†¬Ľ avant de charger l’int√©gralit√© du code de notre extension.

En passant, la fonction de duplication des activit√©s que nous avons utilis√©e pour diffuser des messages support me fait imm√©diatement penser aux tweets sponsoris√©s, c’est sans doute pour cette raison que j’ai appel√© ce plugin BP Ads Group Update..

Upgrade de notre plugin

Evolution du besoin : astucieux ce principe de duplication des activités, du coup ça serait bien si les membres pouvaient repartager des activités..

Optimisons!

√áa tombe bien, dans la fonction de reshare on peut imaginer l’int√©r√™t d’ajouter un compteur et donc d’utiliser les activity metas ūüėČ Avant de partir t√™te baiss√©e dans la conception de cette nouvelle fonctionnalit√©, r√©organisons notre plugin.

Comme vous pouvez le constater, on a cr√©√© 3 nouveaux fichiers que nous avons rang√©s dans le r√©pertoire includes de notre plugin. Toutes les fonctions li√©es √† la fonctionnalit√© support_updateÔĽŅ ont √©t√© d√©plac√©es dans le script includes/bp-agu-support.php, nous avons pr√©par√© le fichier includes/bp-agu-reshare.php pour accueillir les fonctions li√©es √† la fonctionnalit√© reshare_update et nous avons d√©plac√© les fonctions li√©es √† l’interface d’administration de notre plugin dans includes/bp-agu-admin.php.

S’agissant de la fonction bp-agu-init(), elle se d√©clenche au moment ou BuddyPress passe par le hook bp_include et commence par inclure le fichier includes/bp-agu-support.php avant de charger si les conditions sont r√©unies (fonction reshare activ√©e ou interface admin) les autres scripts. En proc√©dant ainsi, nous allons pouvoir capitaliser sur le code support_update. Si vous regardez la fonction bp_agu_reshare_is_activated()ÔĽŅ, elle se charge tout simplement de retourner le choix que nous avons fait dans l’interface d’administration de notre plugin. Il s’agit donc dans un premier temps de modifier notre code pour proposer au super Admin un radio d’activation-d√©sactivation de la fonction reshare.

Je ne d√©taille pas le code ici, vous pourrez le consulter dans le t√©l√©chargement de la version finale. Nous d√©cidons pour pouvoir mieux identifier nos ¬ę¬†retweets¬†¬Ľ d’utiliser un nouveau type d’activit√© : reshare_updateÔĽŅ.

Capitalisons!

Pour permettre au membre de repartager une activit√©, on va simplement ajouter un nouveau bouton d’action sous l’activit√© et ce de la m√™me mani√®re dont nous avions proc√©d√© pour ajouter un lien vers les commentaires de l’activit√© parente support au moment de notre relooking (point 5) D’ailleurs, on va en profiter de ce bouton qui r√©cup√®re le nombre de commentaires de l’activit√© parente et nous renvoie vers son permalien. Je pense que les commentaires seront bien mieux dans l’activit√© premi√®rement paratag√©e.

Pour cela dans le script includes/bp-agu-support.php, il s’agit de donner une priorit√© plus importante au hook qui rajoute ce bouton qu’√† celui que nous allons cr√©er pour notre bouton ¬ę¬†reshare¬†¬Ľ. Par ailleurs, il suffira de rajouter l’activit√© reshare_updateÔĽŅ √† la condition qui cr√©e ce bouton commentaire.

/* dans le fichier bp-agu-support.php */
function bp_agu_add_action_link(){
	if( ! in_array( bp_get_activity_type(), array('support_update', 'reshare_update') ) ) {
		return false; 
	}

	/* suite de la fonction */
}
// hook avec une priorité 9
add_action('bp_activity_entry_meta', 'bp_agu_add_action_link', 9 );

/* dans le fichier bp-agu-reshare.php */
function bp_agu_add_reshare_button() {
	global $bp;

	if( ! is_user_logged_in() ) {
		return false;
	}

	/**
	 * on garde toutes les activités sauf support, à part.. * si vous voyez un intérêt à repartager les messages de service
	 */
	if( 'support_update' == bp_get_activity_type() ) {
		return false;
	}

	/* suite de la fonction */
}
// hook avec une priorité 10, le bouton reshare sera affiché après le bouton commentaire
add_action('bp_activity_entry_meta', 'bp_agu_add_reshare_button', 10 );

En gras la condition ¬ę¬†si pas dans le tableau¬†¬Ľ nous servira pour √©galement profiter des points 1 et 4 du relooking des activit√©s support. Revenons √† notre bouton ¬ę¬†reshare¬†¬Ľ. Dans notre fonction bp_agu_add_reshare_button()ÔĽŅ, nous allons cr√©er un lien contenant une variable get ‘to_reshare’ √† laquelle on va ajouter un nonce pour plus de s√©curit√©. Ce lien nous servira si toutefois l’utilisateur a d√©sactiv√© le javascript de son navigateur. Car pour ajouter en dynamisme, nous allons utiliser AJAX par d√©faut! Ensuite, ce bouton sera cliquable si des conditions sont remplies :

  1. L’auteur d’une activit√© ne pourra par la repartager : aucun int√©r√™t !
  2. Si toutefois le membre a d√©j√† partag√© une activit√©, il ne pourra pas la repartager : nous aurons donc en plus du compteur de ¬ę¬†reshares¬†¬Ľ, une deuxi√®me activity meta qui stockera un tableau des user_idsÔĽŅ ayant ¬ę¬†retweet√©¬†¬Ľ

WPAjaxifions le reshare

Voil√† un nouveau m√©canisme WordPress tr√®s int√©ressant. Pour l’utiliser, il faut proc√©der en 3 √©tapes :

  • C√īt√© client (PHP -> JS) : ajouter une variable javascript pour indiquer l’url d’envoi des requ√™tes ajax.
  • C√īt√© client (JS) : pr√©voir une variable dont le nom sera ‘action‘ dans notre jQuery.post.
  • C√īt√© serveur (PHP) : ajouter un hook `wp_ajax`ÔĽŅ¬†pour intercepter cette variable ‘action‘ pass√©e et renvoyer une r√©ponse avant de stopper l’ex√©cution du code PHP.

S’agissant du premier point, dans l’environnement BuddyPress, la variable ¬ę¬†ajaxurl¬†¬Ľ est de toute fa√ßon dispo. Donc, next! On s’occupe de notre javascript. N’oublions pas de l’ajouter √† la page avec wp_euqueue_script bien entendu, vous vous souvenez comment on fait ? Ce coup-ci, on n’a pas seulement besoin que notre javascript soit charg√© pour l’activit√© d’un seul groupe, mais pour toutes les activit√©s. La condition sera donc :

function bp_agu_load_reshare_css_js(){
	if( bp_is_activity_component() || bp_is_group_home() ) {
		wp_enqueue_style('bp-agu-reshare-css', BP_AGU_PLUGIN_URL_CSS .'/reshare.css');
		wp_enqueue_script('bp-agu-reshare-js', BP_AGU_PLUGIN_URL_JS .'/reshare.js', array('jquery'), 0, 1);
	}
}
add_action('bp_actions', 'bp_agu_load_reshare_css_js');

reshare.js intercepte le click sur le bouton de reshare, envoie la requ√™te ajax qui est intercept√©e par la fonction bp_agu_handle_ajax_reshare() du script bp-agu-reshare.php. Une fois la r√©ponse re√ßue, on modifie l’affichage du bouton et on incr√©mente de 1 le nombre de ¬ę¬†repartages¬†¬Ľ. Enfin, il ne faut pas oublier de renvoyer falseÔĽŅ pour √©viter que le lien ne soit effectivement soumis.

Profitons des activity metas.

Dans l’illustration pr√©c√©dente, la fonction bp_agu_prepare_reshare() est charg√©e de constituer le tableau des arguments n√©cessaires √† l’enregistrement de l’activit√© de type reshare_update par la fonction BuddyPress bp_activity_add(). Pour ce faire on lui passe l’id de l’activit√© √† partager que l’Ajax nous a transmis et c’est √† ce moment de la partie que les activity metas entrent en sc√®ne. Dans le script bp-activity/bp-activity-functions.php, on d√©couvre les 3 outils qui nous permettent d’interagir avec la table wp_bp_activity_metaÔĽŅ.

  • bp_activity_update_meta( $activity_id, $meta_key, $meta_value )
    On ajoute ou on modifie l’information stock√©e pour une meta key d’un id d’activit√©.
  • bp_activity_get_meta( $activity_id = 0, $meta_key = "" )
    On r√©cup√®re l’information stock√©e pour la meta key d’un id d’activit√©.
  • bp_activity_delete_meta( $activity_id, $meta_key = "", $meta_value = "" )ÔĽŅ
    On supprime l’information stock√©e pour la meta key de l’id d’activit√©.

Ce qui est int√©ressant, c’est que les valeurs sont s√©rialis√©es/d√©s√©rialis√©es automatiquement en faisant appel respectivement √† bp_activity_update_meta() et bp_activity_get_meta()ÔĽŅ. Ce qui nous fait gagner du temps pour stocker des arrays PHP par exemple ūüôā

Tout d’abord, on r√©cup√®re les √©l√©ments qui composent l’activit√© √† partager. Son contenu et sa visibilit√© (hide_sitewideÔĽŅ) nous serviront pour notre reshare. Son id deviendra notre secondary id : c’est cette donn√©e qui nous permettra de cr√©er un lien de filiation entre le reshare et l’activit√© premi√®rement post√©e.

Etape 2 : on r√©cup√®re la meta ¬ę¬†compteur de reshares¬†¬Ľ attach√©e √† l’activit√© √† partager (la parente), si elle existe on incr√©mente de 1 sinon on initialise √† 1 avant de mettre √† jour cette meta. On s’occupe apr√®s du tableau des user_ids ayant ¬ę¬†reshared¬†¬Ľ l’activit√©, en lui ajoutant l’id du membre connect√© s’il n’est pas d√©j√† pr√©sent o√Ļ si toutefois le tableau n’existe pas on le cr√©e en le remplissant de l’identifiant de notre membre. On met √† jour cette deuxi√®me meta.

Enfin, on compose les arguments de notre nouvelle activit√© avant de les retourner. Vous avez vu j’ai ajout√© un filtre si toutefois un plugin tiers ou le functions.php d’un th√®me voulait l’intercepter ;). Notons que cette fonction est √©galement appel√©e dans le cas o√Ļ le navigateur a son javascript d√©sactiv√©. Dans ce dernier cas, il suffit de cr√©er une fonction de fallback qui interceptera le hook bp_actionsÔĽŅ et si la variable $_GET['to_reshare'] n’est pas vide alors, on ajoute l’activit√©, on en profite pour pr√©voir d’informer l’utilisateur du succ√®s ou non de cette action via la fonction bp_core_add_message() avant de rediriger l’utilisateur sur la m√™me page √©pur√©e des variables. Vous trouverez le code pour cette fonction (bp_agu_handle_nojs_reshare() ) de callback dans le plugin en t√©l√©chargement plus bas √† la ligne 148 du script includes/bp-agu-reshare.php

On a presque fini !! A l’instar de ce qu’on a fait pour la fonctionnalit√© de messages support, nous n’oublierons pas de cr√©er la fonction qui supprimera les activit√©s de type reshare_updateÔĽŅ si toutefois l’activit√© principale avait disparu et on veillera √† adapter notre uninstall.php.

Vers l’infiniternational et au del√† !

Permettre √† son plugin d’√™tre traduit est de mon point de vue tr√®s important car cela maximisera son utilisation au del√† de nos fronti√®res (y’en a encore ??) niveau mondial !! Pour cela WordPress utilise la librairie gettext, vous trouverez dans le codex toutes les fonctions de traduction disponibles.

Dans notre plugin, √† chaque fois o√Ļ on a indiqu√© des messages destin√©s √† √™tre affich√© en fran√ßais, il suffit de les traduire en anglais en les incluant dans des fonctions du type :

  1. __( 'Translate!', 'identifiant_de_notre_plugin') pour retourner la traduction dans une variable
  2. _e( 'Translate!', 'identifiant_de_notre_plugin' ) pour afficher la traduction dans le browser

Nous r√©f√©ren√ßons notre ¬ę¬†plugin_textdomain¬†¬Ľ en l’accrochant √† un hook intervenant suffisamment t√īt dans le chargement de BuddyPress (exemple sur fond noir dans l’illustration ci-dessus). Nous constituons un fichier .pot qui pr√©cisera les num√©ros de ligne du fichier avec les √©l√©ments √† traduire pour chaque et nous terminons en g√©n√©rant les catalogues de langue (fichiers fr_FR po et mo) √† l’aide de PoEdit.

Evolution possible de la fonction reshare

Pour les besoins du tutoriel sur les activity metas, nous stockons les user_ids des membres ayant repartag√© une activit√© dans un tableau attach√© √† l’activit√© partag√©e. Or, cette information, √©tant fortement li√©e √† l’utilisateur serait sans doute mieux dans les user_metas. Ainsi, nous pourrions plus facilement cr√©er un nouvel environnement pour les membres connect√©s sur le mod√®le de la vue ¬ę¬†My favorites¬†¬Ľ. On pourrait l’appeler ¬ę¬†My reshares¬†¬Ľ. Dans le user_meta de l’utilisateur connect√©, on stockerait un tableau des ids de ses activit√©s de type reshare_update, on aurait plus qu’√† utiliser la fonction bp_activity_get_specific()ÔĽŅ en lui passant ce tableau pour lister les reshares ūüėČ

La version finale !!

Crédit photo : Web414 Demands Your Applause! by Pete Prodoehl, on Flickr

Vous √™tes arriv√© jusqu’ici ? Enorme Bravo √† vous !! Je reconnais que ce premier tutoriel est relativement long. J’ai essay√© de vous retranscrire le plus fid√®lement possible le r√©sultat de mes explorations de BuddyPress. Il y a certainement des √©l√©ments perfectibles mais je pense que nous avons des bases int√©ressantes pour passer √† une √©tape sup√©rieure : la conception d’un composant BuddyPress √† l’aide de la classe BP_Component… A venir, tr√®s prochainement sur ce blog ūüėČ

17 commentaires sur “Etendre #BuddyPress – partie 1 : apprivoiser le composant Activity

  1. Une nouvelle fois merci et bravo pour ce super tuto!

    2 plugins en bonus qui étendent les possibilités de Buddypress.

    Super intelligent les pirouettes pour ne pas afficher les activités plusieurs fois!!

  2. Good job Imath! (comme toujours)

    Excellent tuto, tr√®s sharp. Tr√®s h√Ęte √† la 2ieme partie, en esp√©rant que tu nous apprendra comment faire √©voluer les reshare (excellente fonction afin de ne pas subtliser les id√©es des autres mais bien de les repartager).

    C’est pour quand la part 2…?

    1. Hello, pour la 2e partie, j’ai plut√īt pr√©vu de m’appuyer sur bp-checkins pour montrer comment utiliser la classe BP_Component pour cr√©er son composant BuddyPress. Ce qui en plus me permettra de passer ce plugin d’une version beta √† une 1.0 ūüėČ
      Merci pour ton commentaire & feedback ūüôā

  3. WOW.
    Je souhaite de practique mon francais (need to undust my french)

    Mon ami, you rock !

    PD: I know, I know there’s a translated PDF on top of this post

  4. Salut iMath,

    Serais-tu en mesure de me dire comment afficher mes reshare sur une nouvelle page de membre ¬ę¬†Mes Reshares¬†¬Ľ et aussi d’ajouter un bouton ¬ę¬†Supprimer¬†¬Ľ pour chacun de mes reshares.

    √áa serait grandement appr√©ci√©…

    Merci √† l’avance!
    Wcee

  5. Salut @ Wcee

    C’est tout l’objet du paragraphe ‘Evolution possible de la fonction reshare’ en fait ūüėČ

    Il faudrait modifier le code source en conséquence :
    Рids des activités partagés dans un user_meta au lieu des ids des users dans les activity_meta
    – apr√®s il suffit soit de hooker certaines actions soit de construire un composant BuddyPress (BuddyPress Skeleton component est un bon ‘boilerplate’ http://wordpress.org/extend/plugins/buddypress-skeleton-component/ ) pour ajouter la vue dans l’environnement des membres..

    Mais j’anticipe sur la partie 2 de cette s√©rie de tutos ūüėČ J’y reviendrai donc plus en d√©tail tr√®s prochainement..

    A+

  6. Great job with this plugin imath, could you point me in the right direction of adding more structure to the re share template?I want to be able to re share my custom post type along with its main picture and title/ description.

    I’ve been playing around for a while now and can only get a short excerpt of the post.

    Any help would be great!

    Thankyou

  7. Hi @ Jon,

    If you look at how BuddyPress record an activity when a new blog post is published, you’ll see that it creates an activity content with a thumbnail of an image if one is attached to post.
    If i use the reshare function, then it will take this content and you’ll have the image and description reshared.

    So i guess you first need (it will be easier) to record an activity once your custom post type is published on the same model than BuddyPress does for blog posts, and then if the activity is reshared its content will be reshared.

    Now if you want to do in an other way, then you’ll need to get the blog post id and re create the element you need :
    for example the post id is $activity->secondary_item_id in bp_agu_prepare_reshare function after line 88 of the bp-agu-reshare.php file.

    Hope it’ll help you.

  8. Rebonjour iMath!
    Je voulais te demander si tu as l’intention de revenir pour la deuxi√®me partie des reshares comme mentionn√© car j’aurais vraiment voulu pouvoir permettre aux membres d’avoir une section ¬ę¬†Mes Reshares¬†¬Ľ dans ¬ę¬†Activit√©¬†¬Ľ de leur compte ainsi que le bouton ¬ę¬†Supprimer¬†¬Ľ en dessous de l’update d’activit√© reshare pour que les membres qui ont reshar√© une activit√© puissent aussi changer d’id√©e et effacer leur reshare. √áa serait vraiment super et je crois que √ßa serait un excellent avantage √† avoir pour tout type de r√©seau social (ce que Twitter ne permet m√™me pas!) ūüėČ
    SVP!!!
    Merci et ne l√Ęche pas le bon travail.

  9. Je vais tenter de développer pour la première fois un plugin pour développer mes activités BP.

    Ce ne sera pas simple mais c’est d√©sormais possible gr√Ęce √† ton tutoriel. Il me fait bien chauffer le cerveau :D.

    Merci beaucoup.

Les commentaires sont fermés.