Je partage mes liens sur Instagram, YouTube, LinkedIn et TikTok depuis Nomade sur Rails . Comme tout le monde, j’utilisais Linktree. Et comme tout développeur, ça me dérangeait de dépendre d’un service tiers pour quelque chose d’aussi simple qu’une page de liens.
J’ai décidé de construire mon propre plugin WordPress. Le résultat : BioLinks , un plugin gratuit et open source qui crée une page link in bio auto-hébergée avec 5 templates visuels, tracking des clics et détection automatique de Google Analytics.
Pourquoi un plugin plutôt qu’une simple page ?
Une page WordPress classique avec une liste de liens fait le job. Mais il manque :
- Le tracking des clics, pour savoir quel lien performe sans installer un outil externe
- Le design dédié, une page standalone sans header/footer du thème, optimisée pour mobile
- La gestion facile, pour ajouter et réordonner des liens sans toucher au code
Un plugin encapsule tout ça proprement et peut être distribué à d’autres utilisateurs.
Architecture
Le plugin suit une structure classique WordPress avec 3 classes PHP :
biolinks/
├── biolinks.php # Point d'entrée, constantes, hooks
├── includes/
│ ├── class-biolinks-db.php # CRUD config + liens + logs + stats
│ ├── class-biolinks-admin.php # Page admin (3 onglets)
│ ├── class-biolinks-front.php # Template loader + AJAX handler
│ └── icons.php # SVG inline (10 réseaux + 9 icônes)
├── assets/
│ ├── admin.css / admin.js # Dashboard admin
│ └── front.js # Click tracking (sendBeacon)
└── templates/
├── page.php # Template HTML commun
└── dark.css / light.css / ... # 5 thèmes CSS
Base de données
Trois tables custom :
wp_biolinks_config: table key/value pour la configuration (photo, titre, bio, slug, template, couleur d’accent, réseaux sociaux en JSON)wp_biolinks_links: les liens avec nom, URL, icône, position et compteur de clicswp_biolinks_logs: historique des clics avec horodatage et user-agent
Le choix d’une table key/value pour la config (plutôt que wp_options) isole complètement les données du plugin. À la désinstallation, un simple DROP TABLE nettoie tout.
Page standalone via template_include
La page link in bio ne doit pas afficher le header/footer du thème. Le plugin crée automatiquement une page WordPress à l’activation et intercepte son rendu via le filtre template_include :
public function load_template(string $template): string
{
$page_id = (int) BioLinks_DB::get_config('page_id');
if ($page_id > 0 && is_page($page_id)) {
return BIOLINKS_PATH . 'templates/page.php';
}
return $template;
}
Le template page.php est une page HTML complète qui charge le CSS du template sélectionné et injecte la couleur d’accent via une variable CSS :
<style>:root { --accent: #0a7286; }</style>
Chaque template CSS utilise var(--accent) pour les boutons, hovers et bordures. Changer la couleur dans l’admin met à jour toute la page.
Templates visuels
5 CSS files, chacun avec son propre style :
| Template | Approche |
|---|---|
| Dark | Dégradé sombre, boutons semi-transparents, texte blanc |
| Light | Fond clair, boutons bordés, texte sombre |
| Minimal | Fond uni couleur d’accent, boutons outline blancs |
| Colorful | Fond d’accent vif, boutons blancs avec texte accent |
| Glass | Glassmorphism avec backdrop-filter: blur() |
Le choix de séparer les templates en fichiers CSS distincts (plutôt qu’un seul fichier avec des classes conditionnelles) simplifie la maintenance et réduit le poids : seul le CSS du template actif est chargé.

L’onglet Apparence : sélection du template et color picker WordPress natif.
Tracking des clics avec sendBeacon
Le tracking utilise navigator.sendBeacon plutôt que fetch :
link.addEventListener('click', function () {
var data = new URLSearchParams();
data.append('action', 'biolinks_click');
data.append('link_id', this.getAttribute('data-id'));
data.append('nonce', biolinksData.nonce);
var blob = new Blob([data.toString()], {
type: 'application/x-www-form-urlencoded'
});
navigator.sendBeacon(biolinksData.ajax_url, blob);
});
sendBeacon est plus fiable que fetch pour le tracking : la requête est envoyée même si l’utilisateur quitte la page immédiatement (ce qui arrive systématiquement sur une page de liens). Le lien s’ouvre via target="_blank", le beacon part en parallèle.
Côté serveur, un rate limiting via les transients WordPress empêche le spam (1 clic par IP/lien/minute).
Détection automatique de Google Analytics
Plutôt que de demander à l’utilisateur de coller son ID GA, le plugin le détecte depuis les plugins SEO courants :
public static function detect_ga_id(): ?string
{
$seopress = get_option('seopress_google_analytics_option_name');
if (!empty($seopress['google_analytics_ga4'])) {
return $seopress['google_analytics_ga4'];
}
// Yoast, MonsterInsights...
}
Si un ID est trouvé, le script gtag.js est injecté dans le <head> du template. Sinon, rien, pas de tracking externe par défaut.
Sécurité
Le plugin étant distribué publiquement, l’audit de sécurité est critique :
- Nonces sur tous les formulaires admin et endpoints AJAX
current_user_can('manage_options')sur toutes les actions adminsanitize_text_field,esc_url_raw,sanitize_hex_colorsur tous les inputsesc_html,esc_attr,esc_urlsur toutes les sorties HTML- Rate limiting sur le tracking public (1 clic/IP/lien/minute via transients)
- Allowlist pour les templates (validé à l’écriture ET à la lecture)
- Allowlist pour les icônes (validé contre
BIOLINKS_GENERIC_LABELS) $wpdb->prepare()sur toutes les requêtes SQL paramétrées
Admin WordPress
L’interface admin est organisée en 3 onglets :
- Ma page : profil (photo via Media Library, titre, bio), réseaux sociaux (10 champs URL), liens (drag & drop avec SortableJS, CRUD avec formulaire)
- Apparence : grille de 5 templates avec preview miniature + color picker natif WordPress
- Statistiques : 4 cartes stats + graphiques Chart.js (clics/jour + clics/lien)

L’onglet Ma page : gestion des liens avec drag & drop SortableJS.

L’onglet Statistiques : graphique Chart.js des clics par jour et par lien.
Le résultat
Ma page link in bio est en ligne : nomadesurrails.fr/linkedtree
Le plugin est gratuit et open source sur GitHub : github.com/JeremieSamson/biolinks
Il se configure en 2 minutes, fonctionne avec n’importe quel thème WordPress, et ne nécessite aucun service externe. Si tu cherches une alternative à Linktree pour ton site WordPress, c’est fait pour ça.
Plus d’infos et téléchargement sur la page dédiée BioLinks .
