<?php
/**
* Plugin Name: Africa Market Homepage Builder
* Description: Adds a premium multi-product homepage shortcode for WooCommerce stores targeting African markets.
* Version: 1.0.0
* Author: ChatGPT
*/
if (!defined('ABSPATH')) {
exit;
}
final class Africa_Market_Homepage_Builder {
const OPTION_KEY = 'afh_settings';
public function __construct() {
add_action('init', [$this, 'register_shortcodes']);
add_action('admin_menu', [$this, 'register_admin_page']);
add_action('admin_init', [$this, 'register_settings']);
add_action('wp_enqueue_scripts', [$this, 'register_assets']);
}
public function register_shortcodes(): void {
add_shortcode('afh_homepage', [$this, 'render_homepage']);
add_shortcode('afh_hero', [$this, 'render_hero']);
add_shortcode('afh_categories', [$this, 'render_categories']);
add_shortcode('afh_products', [$this, 'render_products']);
add_shortcode('afh_trust', [$this, 'render_trust']);
add_shortcode('afh_testimonials', [$this, 'render_testimonials']);
add_shortcode('afh_cta', [$this, 'render_cta']);
}
public function register_assets(): void {
wp_register_style('afh-styles', false, [], '1.0.0');
wp_enqueue_style('afh-styles');
$css = '
.afh-wrap{font-family:Arial,sans-serif;color:#121212}
.afh-container{max-width:1200px;margin:0 auto;padding:0 16px}
.afh-btn{display:inline-block;background:#111827;color:#fff!important;padding:14px 22px;border-radius:999px;text-decoration:none;font-weight:700;transition:.2s ease}
.afh-btn:hover{transform:translateY(-1px);opacity:.95}
.afh-btn.alt{background:#fff;color:#111827!important;border:1px solid #d1d5db}
.afh-section{padding:42px 0}
.afh-title{font-size:32px;line-height:1.15;margin:0 0 12px;font-weight:800}
.afh-subtitle{font-size:16px;color:#4b5563;margin:0 0 18px}
.afh-hero{background:linear-gradient(135deg,#f8fafc 0%,#eef2ff 100%);padding:54px 0;border-radius:24px;overflow:hidden}
.afh-hero-grid{display:grid;grid-template-columns:1.2fr .8fr;gap:28px;align-items:center}
.afh-badges{display:flex;flex-wrap:wrap;gap:10px;margin:18px 0}
.afh-badge{background:#fff;border:1px solid #e5e7eb;border-radius:999px;padding:8px 12px;font-size:13px;font-weight:700}
.afh-image-card{background:#fff;border-radius:24px;padding:18px;box-shadow:0 18px 50px rgba(15,23,42,.08)}
.afh-image-card img{width:100%;height:auto;border-radius:18px;display:block}
.afh-grid{display:grid;gap:18px}
.afh-grid-4{grid-template-columns:repeat(4,1fr)}
.afh-grid-3{grid-template-columns:repeat(3,1fr)}
.afh-card{background:#fff;border:1px solid #e5e7eb;border-radius:22px;padding:18px;box-shadow:0 8px 22px rgba(15,23,42,.05)}
.afh-card h3{margin:0 0 8px;font-size:20px}
.afh-card p{margin:0;color:#4b5563}
.afh-icon{font-size:24px;margin-bottom:10px}
.afh-section-head{display:flex;justify-content:space-between;align-items:end;gap:16px;margin-bottom:18px}
.afh-products .products{display:grid;grid-template-columns:repeat(4,1fr);gap:18px;margin:0;padding:0;list-style:none}
.afh-products .product{background:#fff;border:1px solid #e5e7eb;border-radius:22px;padding:14px;box-shadow:0 8px 22px rgba(15,23,42,.05);position:relative}
.afh-products .woocommerce-loop-product__title{font-size:16px!important;min-height:44px}
.afh-products .price{font-weight:800;color:#111827!important}
.afh-products a.button,.afh-products a.add_to_cart_button,.afh-products a.product_type_simple{background:#111827!important;color:#fff!important;border-radius:999px!important;padding:10px 14px!important;font-weight:700!important}
.afh-trustbar{display:grid;grid-template-columns:repeat(4,1fr);gap:14px}
.afh-trustbox{background:#f9fafb;border:1px solid #e5e7eb;border-radius:18px;padding:16px;font-weight:700}
.afh-quote{background:#fff;border:1px solid #e5e7eb;border-radius:22px;padding:20px;box-shadow:0 8px 22px rgba(15,23,42,.05)}
.afh-quote p{font-size:15px;color:#374151;margin:0 0 12px}
.afh-quote strong{display:block}
.afh-cta{background:linear-gradient(135deg,#111827 0%,#1f2937 100%);color:#fff;border-radius:26px;padding:34px}
.afh-cta .afh-title,.afh-cta .afh-subtitle{color:#fff}
.afh-whatsapp-float{position:fixed;right:20px;bottom:20px;z-index:9999;background:#25D366;color:#fff!important;padding:14px 18px;border-radius:999px;text-decoration:none;font-weight:800;box-shadow:0 12px 30px rgba(37,211,102,.28)}
.afh-note{font-size:13px;color:#6b7280;margin-top:10px}
@media (max-width: 1024px){
.afh-grid-4,.afh-products .products,.afh-trustbar{grid-template-columns:repeat(2,1fr)}
.afh-grid-3{grid-template-columns:repeat(2,1fr)}
}
@media (max-width: 767px){
.afh-hero-grid,.afh-grid-4,.afh-grid-3,.afh-products .products,.afh-trustbar{grid-template-columns:1fr}
.afh-title{font-size:28px}
.afh-section-head{display:block}
}';
wp_add_inline_style('afh-styles', $css);
}
public function register_admin_page(): void {
add_menu_page(
'Africa Homepage',
'Africa Homepage',
'manage_options',
'afh-homepage',
[$this, 'render_admin_page'],
'dashicons-store',
56
);
}
public function register_settings(): void {
register_setting('afh_group', self::OPTION_KEY, [$this, 'sanitize_settings']);
}
public function sanitize_settings(array $input): array {
$defaults = $this->get_defaults();
$output = [];
foreach ($defaults as $key => $value) {
$raw = $input[$key] ?? $value;
if (in_array($key, ['hero_title', 'hero_subtitle', 'hero_cta_text', 'hero_cta_link', 'hero_secondary_text', 'hero_secondary_link', 'hero_image', 'market_label', 'whatsapp_number', 'trust_1', 'trust_2', 'trust_3', 'trust_4', 'testimonial_1_text', 'testimonial_1_name', 'testimonial_2_text', 'testimonial_2_name', 'testimonial_3_text', 'testimonial_3_name', 'cta_title', 'cta_text', 'cta_button_text', 'cta_button_link'], true)) {
$output[$key] = sanitize_text_field($raw);
} elseif ($key === 'featured_categories') {
$output[$key] = sanitize_text_field($raw);
} elseif ($key === 'products_limit') {
$output[$key] = max(4, min(24, absint($raw)));
} else {
$output[$key] = sanitize_text_field($raw);
}
}
return $output;
}
private function get_settings(): array {
return wp_parse_args(get_option(self::OPTION_KEY, []), $this->get_defaults());
}
private function get_defaults(): array {
return [
'hero_title' => 'Produits tendances pour toute l\'Afrique',
'hero_subtitle' => 'Cosmétiques, nutraceutiques, vêtements, chaussures et produits gagnants avec une présentation moderne, rassurante et orientée conversion.',
'hero_cta_text' => 'Voir les produits',
'hero_cta_link' => '/shop',
'hero_secondary_text' => 'Commander sur WhatsApp',
'hero_secondary_link' => '#whatsapp',
'hero_image' => '',
'market_label' => 'Paiement à la livraison disponible selon le pays',
'featured_categories' => 'cosmetiques,nutriments,vetements,chaussures',
'products_limit' => 8,
'whatsapp_number' => '212600000000',
'trust_1' => 'Paiement à la livraison',
'trust_2' => 'Support WhatsApp rapide',
'trust_3' => 'Produits tendance',
'trust_4' => 'Livraison multi-pays',
'testimonial_1_text' => 'Très bon service, livraison rapide et produit conforme.',
'testimonial_1_name' => 'Client satisfait',
'testimonial_2_text' => 'Le site est clair et le paiement à la livraison rassure vraiment.',
'testimonial_2_name' => 'Acheteur COD',
'testimonial_3_text' => 'Commande confirmée facilement et suivi sérieux.',
'testimonial_3_name' => 'Client récurrent',
'cta_title' => 'Commandez en quelques clics',
'cta_text' => 'Découvrez nos meilleures offres et contactez-nous rapidement sur WhatsApp pour confirmer votre commande.',
'cta_button_text' => 'Acheter maintenant',
'cta_button_link' => '/shop',
];
}
public function render_admin_page(): void {
if (!current_user_can('manage_options')) {
return;
}
$settings = $this->get_settings();
?>
<div class="wrap">
<h1>Africa Market Homepage Builder</h1>
<p>Configure les textes du template. Ensuite utilise le shortcode <code>[afh_homepage]</code> dans ta page d'accueil.</p>
<form method="post" action="options.php">
<?php settings_fields('afh_group'); ?>
<table class="form-table" role="presentation">
<tr><th scope="row"><label for="hero_title">Titre principal</label></th><td><input name="<?php echo esc_attr(self::OPTION_KEY); ?>[hero_title]" id="hero_title" type="text" class="regular-text" value="<?php echo esc_attr($settings['hero_title']); ?>"></td></tr>
<tr><th scope="row"><label for="hero_subtitle">Sous-titre</label></th><td><input name="<?php echo esc_attr(self::OPTION_KEY); ?>[hero_subtitle]" id="hero_subtitle" type="text" class="large-text" value="<?php echo esc_attr($settings['hero_subtitle']); ?>"></td></tr>
<tr><th scope="row"><label for="hero_cta_text">Texte bouton principal</label></th><td><input name="<?php echo esc_attr(self::OPTION_KEY); ?>[hero_cta_text]" id="hero_cta_text" type="text" class="regular-text" value="<?php echo esc_attr($settings['hero_cta_text']); ?>"></td></tr>
<tr><th scope="row"><label for="hero_cta_link">Lien bouton principal</label></th><td><input name="<?php echo esc_attr(self::OPTION_KEY); ?>[hero_cta_link]" id="hero_cta_link" type="text" class="regular-text" value="<?php echo esc_attr($settings['hero_cta_link']); ?>"></td></tr>
<tr><th scope="row"><label for="hero_secondary_text">Texte bouton secondaire</label></th><td><input name="<?php echo esc_attr(self::OPTION_KEY); ?>[hero_secondary_text]" id="hero_secondary_text" type="text" class="regular-text" value="<?php echo esc_attr($settings['hero_secondary_text']); ?>"></td></tr>
<tr><th scope="row"><label for="hero_secondary_link">Lien bouton secondaire</label></th><td><input name="<?php echo esc_attr(self::OPTION_KEY); ?>[hero_secondary_link]" id="hero_secondary_link" type="text" class="regular-text" value="<?php echo esc_attr($settings['hero_secondary_link']); ?>"></td></tr>
<tr><th scope="row"><label for="hero_image">URL image hero</label></th><td><input name="<?php echo esc_attr(self::OPTION_KEY); ?>[hero_image]" id="hero_image" type="text" class="large-text" value="<?php echo esc_attr($settings['hero_image']); ?>"></td></tr>
<tr><th scope="row"><label for="market_label">Bandeau marché</label></th><td><input name="<?php echo esc_attr(self::OPTION_KEY); ?>[market_label]" id="market_label" type="text" class="large-text" value="<?php echo esc_attr($settings['market_label']); ?>"></td></tr>
<tr><th scope="row"><label for="featured_categories">Catégories à afficher</label></th><td><input name="<?php echo esc_attr(self::OPTION_KEY); ?>[featured_categories]" id="featured_categories" type="text" class="large-text" value="<?php echo esc_attr($settings['featured_categories']); ?>"><p class="description">Slug séparés par des virgules. Exemple: cosmetiques,nutriments,vetements,chaussures</p></td></tr>
<tr><th scope="row"><label for="products_limit">Nombre de produits</label></th><td><input name="<?php echo esc_attr(self::OPTION_KEY); ?>[products_limit]" id="products_limit" type="number" min="4" max="24" value="<?php echo esc_attr((string) $settings['products_limit']); ?>"></td></tr>
<tr><th scope="row"><label for="whatsapp_number">Numéro WhatsApp</label></th><td><input name="<?php echo esc_attr(self::OPTION_KEY); ?>[whatsapp_number]" id="whatsapp_number" type="text" class="regular-text" value="<?php echo esc_attr($settings['whatsapp_number']); ?>"></td></tr>
<tr><th scope="row">Blocs de confiance</th><td>
<input name="<?php echo esc_attr(self::OPTION_KEY); ?>[trust_1]" type="text" class="regular-text" value="<?php echo esc_attr($settings['trust_1']); ?>"><br><br>
<input name="<?php echo esc_attr(self::OPTION_KEY); ?>[trust_2]" type="text" class="regular-text" value="<?php echo esc_attr($settings['trust_2']); ?>"><br><br>
<input name="<?php echo esc_attr(self::OPTION_KEY); ?>[trust_3]" type="text" class="regular-text" value="<?php echo esc_attr($settings['trust_3']); ?>"><br><br>
<input name="<?php echo esc_attr(self::OPTION_KEY); ?>[trust_4]" type="text" class="regular-text" value="<?php echo esc_attr($settings['trust_4']); ?>">
</td></tr>
<tr><th scope="row">Témoignages</th><td>
<input name="<?php echo esc_attr(self::OPTION_KEY); ?>[testimonial_1_text]" type="text" class="large-text" value="<?php echo esc_attr($settings['testimonial_1_text']); ?>"><br>
<input name="<?php echo esc_attr(self::OPTION_KEY); ?>[testimonial_1_name]" type="text" class="regular-text" value="<?php echo esc_attr($settings['testimonial_1_name']); ?>"><br><br>
<input name="<?php echo esc_attr(self::OPTION_KEY); ?>[testimonial_2_text]" type="text" class="large-text" value="<?php echo esc_attr($settings['testimonial_2_text']); ?>"><br>
<input name="<?php echo esc_attr(self::OPTION_KEY); ?>[testimonial_2_name]" type="text" class="regular-text" value="<?php echo esc_attr($settings['testimonial_2_name']); ?>"><br><br>
<input name="<?php echo esc_attr(self::OPTION_KEY); ?>[testimonial_3_text]" type="text" class="large-text" value="<?php echo esc_attr($settings['testimonial_3_text']); ?>"><br>
<input name="<?php echo esc_attr(self::OPTION_KEY); ?>[testimonial_3_name]" type="text" class="regular-text" value="<?php echo esc_attr($settings['testimonial_3_name']); ?>">
</td></tr>
<tr><th scope="row"><label for="cta_title">Titre final</label></th><td><input name="<?php echo esc_attr(self::OPTION_KEY); ?>[cta_title]" id="cta_title" type="text" class="regular-text" value="<?php echo esc_attr($settings['cta_title']); ?>"></td></tr>
<tr><th scope="row"><label for="cta_text">Texte final</label></th><td><input name="<?php echo esc_attr(self::OPTION_KEY); ?>[cta_text]" id="cta_text" type="text" class="large-text" value="<?php echo esc_attr($settings['cta_text']); ?>"></td></tr>
<tr><th scope="row"><label for="cta_button_text">Bouton final</label></th><td><input name="<?php echo esc_attr(self::OPTION_KEY); ?>[cta_button_text]" id="cta_button_text" type="text" class="regular-text" value="<?php echo esc_attr($settings['cta_button_text']); ?>"></td></tr>
<tr><th scope="row"><label for="cta_button_link">Lien bouton final</label></th><td><input name="<?php echo esc_attr(self::OPTION_KEY); ?>[cta_button_link]" id="cta_button_link" type="text" class="regular-text" value="<?php echo esc_attr($settings['cta_button_link']); ?>"></td></tr>
</table>
<?php submit_button('Enregistrer'); ?>
</form>
</div>
<?php
}
public function render_homepage(): string {
$html = '<div class="afh-wrap">';
$html .= $this->render_hero();
$html .= $this->render_categories();
$html .= $this->render_products();
$html .= $this->render_trust();
$html .= $this->render_testimonials();
$html .= $this->render_cta();
$html .= $this->render_whatsapp_button();
$html .= '</div>';
return $html;
}
public function render_hero(): string {
$s = $this->get_settings();
$image = $s['hero_image'] ? esc_url($s['hero_image']) : esc_url('https://images.unsplash.com/photo-1521572163474-6864f9cf17ab?auto=format&fit=crop&w=1000&q=80');
ob_start();
?>
<section class="afh-section">
<div class="afh-container">
<div class="afh-hero">
<div class="afh-container afh-hero-grid">
<div>
<div class="afh-badge"><?php echo esc_html($s['market_label']); ?></div>
<h1 class="afh-title"><?php echo esc_html($s['hero_title']); ?></h1>
<p class="afh-subtitle"><?php echo esc_html($s['hero_subtitle']); ?></p>
<div class="afh-badges">
<span class="afh-badge">🚚 Livraison rapide</span>
<span class="afh-badge">💬 WhatsApp</span>
<span class="afh-badge">🛍️ Multi-catégories</span>
<span class="afh-badge">🌍 Marché africain</span>
</div>
<div style="display:flex;gap:12px;flex-wrap:wrap;">
<a class="afh-btn" href="<?php echo esc_url($s['hero_cta_link']); ?>"><?php echo esc_html($s['hero_cta_text']); ?></a>
<a class="afh-btn alt" href="<?php echo esc_url($s['hero_secondary_link']); ?>"><?php echo esc_html($s['hero_secondary_text']); ?></a>
</div>
<div class="afh-note">Conseil: ajoute WooCommerce, tes catégories et tes produits pour exploiter le template au maximum.</div>
</div>
<div>
<div class="afh-image-card">
<img src="<?php echo $image; ?>" alt="Boutique africaine moderne">
</div>
</div>
</div>
</div>
</div>
</section>
<?php
return (string) ob_get_clean();
}
public function render_categories(): string {
$s = $this->get_settings();
$slugs = array_filter(array_map('trim', explode(',', $s['featured_categories'])));
$items = [];
foreach ($slugs as $slug) {
$term = get_term_by('slug', $slug, 'product_cat');
if ($term && !is_wp_error($term)) {
$items[] = [
'name' => $term->name,
'link' => get_term_link($term),
'count' => (int) $term->count,
];
} else {
$items[] = [
'name' => ucfirst(str_replace('-', ' ', $slug)),
'link' => home_url('/shop'),
'count' => 0,
];
}
}
if (empty($items)) {
return '';
}
ob_start();
?>
<section class="afh-section">
<div class="afh-container">
<div class="afh-section-head">
<div>
<h2 class="afh-title">Nos univers</h2>
<p class="afh-subtitle">Un site pensé pour vendre plusieurs gammes de produits sur un seul domaine.</p>
</div>
</div>
<div class="afh-grid afh-grid-4">
<?php foreach ($items as $item) : ?>
<a class="afh-card" href="<?php echo esc_url(is_string($item['link']) ? $item['link'] : home_url('/shop')); ?>" style="text-decoration:none;color:inherit;">
<div class="afh-icon">🛒</div>
<h3><?php echo esc_html($item['name']); ?></h3>
<p><?php echo esc_html($item['count'] > 0 ? $item['count'] . ' produits disponibles' : 'Catégorie prête à remplir'); ?></p>
</a>
<?php endforeach; ?>
</div>
</div>
</section>
<?php
return (string) ob_get_clean();
}
public function render_products(): string {
if (!class_exists('WooCommerce')) {
return '<section class="afh-section"><div class="afh-container"><div class="afh-card"><h3>WooCommerce requis</h3><p>Installe et active WooCommerce pour afficher tes produits automatiquement.</p></div></div></section>';
}
$s = $this->get_settings();
$shortcode = sprintf('[products limit="%d" columns="4" visibility="visible" orderby="date" order="DESC"]', (int) $s['products_limit']);
ob_start();
?>
<section class="afh-section afh-products">
<div class="afh-container">
<div class="afh-section-head">
<div>
<h2 class="afh-title">Produits populaires</h2>
<p class="afh-subtitle">Affichage automatique des produits les plus récents pour garder la page vivante.</p>
</div>
<a class="afh-btn alt" href="<?php echo esc_url(home_url('/shop')); ?>">Voir la boutique</a>
</div>
<?php echo do_shortcode($shortcode); ?>
</div>
</section>
<?php
return (string) ob_get_clean();
}
public function render_trust(): string {
$s = $this->get_settings();
$items = [$s['trust_1'], $s['trust_2'], $s['trust_3'], $s['trust_4']];
ob_start();
?>
<section class="afh-section">
<div class="afh-container">
<div class="afh-section-head">
<div>
<h2 class="afh-title">Pourquoi acheter chez nous ?</h2>
<p class="afh-subtitle">Une structure pensée pour rassurer les clients et améliorer la conversion.</p>
</div>
</div>
<div class="afh-trustbar">
<?php foreach ($items as $item) : ?>
<div class="afh-trustbox">✅ <?php echo esc_html($item); ?></div>
<?php endforeach; ?>
</div>
</div>
</section>
<?php
return (string) ob_get_clean();
}
public function render_testimonials(): string {
$s = $this->get_settings();
$quotes = [
['text' => $s['testimonial_1_text'], 'name' => $s['testimonial_1_name']],
['text' => $s['testimonial_2_text'], 'name' => $s['testimonial_2_name']],
['text' => $s['testimonial_3_text'], 'name' => $s['testimonial_3_name']],
];
ob_start();
?>
<section class="afh-section">
<div class="afh-container">
<div class="afh-section-head">
<div>
<h2 class="afh-title">Ils nous font confiance</h2>
<p class="afh-subtitle">Ajoute de vrais témoignages clients par pays pour encore plus de crédibilité.</p>
</div>
</div>
<div class="afh-grid afh-grid-3">
<?php foreach ($quotes as $quote) : ?>
<div class="afh-quote">
<p>“<?php echo esc_html($quote['text']); ?>”</p>
<strong><?php echo esc_html($quote['name']); ?></strong>
</div>
<?php endforeach; ?>
</div>
</div>
</section>
<?php
return (string) ob_get_clean();
}
public function render_cta(): string {
$s = $this->get_settings();
ob_start();
?>
<section class="afh-section">
<div class="afh-container">
<div class="afh-cta">
<h2 class="afh-title"><?php echo esc_html($s['cta_title']); ?></h2>
<p class="afh-subtitle"><?php echo esc_html($s['cta_text']); ?></p>
<a class="afh-btn alt" href="<?php echo esc_url($s['cta_button_link']); ?>"><?php echo esc_html($s['cta_button_text']); ?></a>
</div>
</div>
</section>
<?php
return (string) ob_get_clean();
}
private function render_whatsapp_button(): string {
$s = $this->get_settings();
$number = preg_replace('/\D+/', '', (string) $s['whatsapp_number']);
if ($number === '') {
return '';
}
$message = rawurlencode('Bonjour, je souhaite commander un produit sur votre site.');
$link = 'https://wa.me/' . $number . '?text=' . $message;
return '<a class="afh-whatsapp-float" id="whatsapp" href="' . esc_url($link) . '" target="_blank" rel="noopener">WhatsApp</a>';
}
}
new Africa_Market_Homepage_Builder();