WordPress functions.php ile Paylaşım Sayacı ve Sosyal Medya Butonu Ekleme

WordPress sitenizde sosyal medya paylaşım butonları eklemek istediğinizde aklınıza ilk gelen şey büyük ihtimalle bir eklenti kurmak oluyor. Ama functions.php dosyasına birkaç satır kod ekleyerek hem daha hafif hem de tamamen özelleştirilebilir bir çözüme ulaşabilirsiniz. Bu yazıda, gerçek paylaşım sayacıyla birlikte çalışan sosyal medya butonlarını sıfırdan nasıl kuracağınızı adım adım göstereceğim.

Neden Eklenti Yerine functions.php?

Sık karşılaştığım bir senaryo şu: Müşteri sitesi var, 15-20 eklenti yüklü, sayfa hızı berbat. İnceliyorsunuz, sadece paylaşım sayacı için 2 eklenti kurulmuş. Birisi aktif değil ama kaldırılmamış, diğeri her sayfada gereksiz CSS ve JavaScript yüklüyor.

functions.php yaklaşımının avantajları şunlar:

  • Performans: Ekstra HTTP isteği yok, gereksiz asset yüklenmiyor
  • Kontrol: Tam olarak istediğiniz yerde, istediğiniz şekilde görünüyor
  • Bakım kolaylığı: Kodunuz temanızda, başka bir bağımlılık yok
  • Özelleştirme: Tasarımı istediğiniz gibi değiştirebilirsiniz

Dezavantajı da var tabii ki: Tema güncellendiğinde kodunuz gidebilir. Bu yüzden mutlaka bir child tema kullanmanızı öneririm.

Temel Yapıyı Anlamak

Paylaşım sayacı sistemi birkaç parçadan oluşuyor. Önce bu parçaları anlayalım:

  • Paylaşım sayacı: Her gönderi için kaç kez paylaşıldığını tutan bir meta veri
  • Sosyal medya URL’leri: Twitter, Facebook, LinkedIn gibi platformlara yönlendiren linkler
  • Buton HTML’i: Görsel kısım
  • AJAX handler: Sayacı güncelleyen arka plan işlemi
  • Shortcode veya hook: Butonları sayfaya yerleştiren mekanizma

Adım 1: Paylaşım Sayacı Altyapısı

İlk olarak paylaşım sayısını saklayacak ve okuyacak fonksiyonları yazalım. WordPress’in post meta sistemi bu iş için biçilmiş kaftan.

// functions.php

// Paylaşım sayısını getir
function get_share_count($post_id, $platform = 'total') {
    $count = get_post_meta($post_id, '_share_count_' . $platform, true);
    return $count ? intval($count) : 0;
}

// Paylaşım sayısını artır
function increment_share_count($post_id, $platform) {
    $current = get_share_count($post_id, $platform);
    $new_count = $current + 1;
    update_post_meta($post_id, '_share_count_' . $platform, $new_count);
    
    // Toplam sayacı da güncelle
    $total = get_share_count($post_id, 'total');
    update_post_meta($post_id, '_share_count_total', $total + 1);
    
    return $new_count;
}

// Tüm platform sayaçlarını sıfırla (admin işlemi için)
function reset_share_counts($post_id) {
    $platforms = array('facebook', 'twitter', 'linkedin', 'whatsapp', 'total');
    foreach ($platforms as $platform) {
        delete_post_meta($post_id, '_share_count_' . $platform);
    }
}

Adım 2: AJAX Handler Kurulumu

Kullanıcı butona tıkladığında sayacın güncellenmesi için AJAX kullanacağız. Hem giriş yapmış hem de misafir kullanıcılar için handler tanımlamamız gerekiyor.

// AJAX handler - giriş yapan kullanıcılar için
add_action('wp_ajax_track_share', 'handle_share_tracking');

// AJAX handler - misafir kullanıcılar için
add_action('wp_ajax_nopriv_track_share', 'handle_share_tracking');

function handle_share_tracking() {
    // Nonce güvenlik kontrolü
    if (!isset($_POST['nonce']) || !wp_verify_nonce($_POST['nonce'], 'share_tracking_nonce')) {
        wp_send_json_error('Güvenlik doğrulaması başarısız.');
        return;
    }
    
    $post_id = isset($_POST['post_id']) ? intval($_POST['post_id']) : 0;
    $platform = isset($_POST['platform']) ? sanitize_text_field($_POST['platform']) : '';
    
    // Geçerli platform kontrolü
    $allowed_platforms = array('facebook', 'twitter', 'linkedin', 'whatsapp');
    if (!$post_id || !in_array($platform, $allowed_platforms)) {
        wp_send_json_error('Geçersiz parametreler.');
        return;
    }
    
    // Post'un varlığını kontrol et
    if (!get_post($post_id)) {
        wp_send_json_error('Gönderi bulunamadı.');
        return;
    }
    
    $new_count = increment_share_count($post_id, $platform);
    $total = get_share_count($post_id, 'total');
    
    wp_send_json_success(array(
        'platform_count' => $new_count,
        'total_count' => $total,
        'platform' => $platform
    ));
}

Adım 3: JavaScript ve CSS Varlıklarını Yüklemek

Butonların çalışması için gerekli JavaScript ve stil dosyalarını doğru şekilde sıraya koyalım.

add_action('wp_enqueue_scripts', 'enqueue_share_button_assets');

function enqueue_share_button_assets() {
    // Sadece tekil yazılarda yükle, performans için önemli
    if (!is_single() && !is_page()) {
        return;
    }
    
    // Inline CSS ekle (küçük olduğu için ayrı dosya açmaya gerek yok)
    $custom_css = '
        .share-buttons-wrapper {
            display: flex;
            align-items: center;
            gap: 10px;
            flex-wrap: wrap;
            margin: 25px 0;
            padding: 15px;
            background: #f8f9fa;
            border-radius: 8px;
        }
        .share-btn {
            display: inline-flex;
            align-items: center;
            gap: 6px;
            padding: 8px 16px;
            border: none;
            border-radius: 5px;
            cursor: pointer;
            font-size: 14px;
            font-weight: 600;
            text-decoration: none;
            color: #fff;
            transition: opacity 0.2s ease;
        }
        .share-btn:hover { opacity: 0.85; color: #fff; }
        .share-btn-facebook { background-color: #1877f2; }
        .share-btn-twitter { background-color: #1da1f2; }
        .share-btn-linkedin { background-color: #0a66c2; }
        .share-btn-whatsapp { background-color: #25d366; }
        .share-count-total {
            margin-left: auto;
            font-size: 13px;
            color: #666;
        }
        .share-btn .btn-count {
            background: rgba(255,255,255,0.25);
            border-radius: 3px;
            padding: 1px 5px;
            font-size: 12px;
        }
    ';
    wp_add_inline_style('wp-block-library', $custom_css);
    
    // Inline JavaScript
    $share_js = '
    document.addEventListener("DOMContentLoaded", function() {
        document.querySelectorAll(".share-btn[data-platform]").forEach(function(btn) {
            btn.addEventListener("click", function(e) {
                e.preventDefault();
                var platform = this.dataset.platform;
                var postId = this.dataset.postId;
                var shareUrl = this.dataset.shareUrl;
                var countEl = this.querySelector(".btn-count");
                
                // Paylaşım penceresini aç
                window.open(shareUrl, "_blank", "width=600,height=400");
                
                // AJAX ile sayacı güncelle
                var formData = new FormData();
                formData.append("action", "track_share");
                formData.append("post_id", postId);
                formData.append("platform", platform);
                formData.append("nonce", shareButtonData.nonce);
                
                fetch(shareButtonData.ajaxUrl, {
                    method: "POST",
                    body: formData
                })
                .then(function(response) { return response.json(); })
                .then(function(data) {
                    if (data.success && countEl) {
                        countEl.textContent = data.data.platform_count;
                        var totalEl = document.querySelector(".share-count-total span");
                        if (totalEl) {
                            totalEl.textContent = data.data.total_count;
                        }
                    }
                });
            });
        });
    });
    ';
    
    wp_add_inline_script('jquery', $share_js);
    
    // JavaScript değişkenlerini localize et
    wp_localize_script('jquery', 'shareButtonData', array(
        'ajaxUrl' => admin_url('admin-ajax.php'),
        'nonce' => wp_create_nonce('share_tracking_nonce')
    ));
}

Adım 4: Buton HTML Oluşturucu

Şimdi asıl görsel kısmı, yani butonların HTML’ini oluşturacak fonksiyonu yazalım.

function generate_share_buttons($post_id = null) {
    if (!$post_id) {
        $post_id = get_the_ID();
    }
    
    if (!$post_id) return '';
    
    $post_url = urlencode(get_permalink($post_id));
    $post_title = urlencode(get_the_title($post_id));
    
    // Platform URL'leri
    $platforms = array(
        'facebook' => array(
            'label' => 'Facebook',
            'url' => 'https://www.facebook.com/sharer/sharer.php?u=' . $post_url,
            'icon' => 'f',
            'color_class' => 'share-btn-facebook'
        ),
        'twitter' => array(
            'label' => 'Twitter',
            'url' => 'https://twitter.com/intent/tweet?url=' . $post_url . '&text=' . $post_title,
            'icon' => 't',
            'color_class' => 'share-btn-twitter'
        ),
        'linkedin' => array(
            'label' => 'LinkedIn',
            'url' => 'https://www.linkedin.com/sharing/share-offsite/?url=' . $post_url,
            'icon' => 'in',
            'color_class' => 'share-btn-linkedin'
        ),
        'whatsapp' => array(
            'label' => 'WhatsApp',
            'url' => 'https://api.whatsapp.com/send?text=' . $post_title . '%20' . $post_url,
            'icon' => 'wa',
            'color_class' => 'share-btn-whatsapp'
        )
    );
    
    $total_count = get_share_count($post_id, 'total');
    
    $html = '<div class="share-buttons-wrapper">';
    $html .= '<strong>Paylaş:</strong>';
    
    foreach ($platforms as $platform_key => $platform) {
        $count = get_share_count($post_id, $platform_key);
        $html .= sprintf(
            '<a href="%s" class="share-btn %s" data-platform="%s" data-post-id="%d" data-share-url="%s" rel="nofollow" target="_blank">
                <span class="btn-icon">%s</span>
                <span class="btn-label">%s</span>
                %s
            </a>',
            esc_url($platform['url']),
            esc_attr($platform['color_class']),
            esc_attr($platform_key),
            $post_id,
            esc_attr($platform['url']),
            esc_html($platform['icon']),
            esc_html($platform['label']),
            $count > 0 ? '<span class="btn-count">' . $count . '</span>' : ''
        );
    }
    
    if ($total_count > 0) {
        $html .= '<div class="share-count-total">Toplam paylaşım: <span>' . $total_count . '</span></div>';
    }
    
    $html .= '</div>';
    
    return $html;
}

Adım 5: İçeriğe Otomatik Ekleme

Butonları her yazının altına otomatik eklemek için the_content filtresini kullanalım.

add_filter('the_content', 'auto_append_share_buttons');

function auto_append_share_buttons($content) {
    // Sadece ana döngüde, tekil yazılarda çalış
    if (!is_single() || !in_the_loop() || !is_main_query()) {
        return $content;
    }
    
    // Belirli kategorileri hariç tutmak isteyebilirsiniz
    $excluded_categories = array(); // Örnek: array(5, 12)
    if (!empty($excluded_categories)) {
        $post_categories = wp_get_post_categories(get_the_ID());
        if (array_intersect($excluded_categories, $post_categories)) {
            return $content;
        }
    }
    
    $share_buttons = generate_share_buttons(get_the_ID());
    
    // İçeriğin altına ekle
    return $content . $share_buttons;
}

Adım 6: Shortcode Desteği

Bazen otomatik ekleme yerine, butonları tam istediğiniz yere koymak istersiniz. Bunun için bir shortcode tanımlayalım.

add_shortcode('share_buttons', 'share_buttons_shortcode');

function share_buttons_shortcode($atts) {
    $atts = shortcode_atts(array(
        'post_id' => get_the_ID(),
        'show_total' => 'yes'
    ), $atts, 'share_buttons');
    
    $post_id = intval($atts['post_id']);
    
    if (!$post_id) return '';
    
    return generate_share_buttons($post_id);
}

// Kullanım: [share_buttons] veya [share_buttons post_id="123"]

Bu shortcode’u Gutenberg editöründe “Shortcode” bloğuna ya da klasik editörde doğrudan yazı içine ekleyebilirsiniz.

Adım 7: Admin Panelinde Paylaşım İstatistikleri

Yönetim panelinde yazı listesinde paylaşım sayılarını görmek, içerik performansını takip etmek için çok işe yarıyor.

// Yazı listesine özel sütun ekle
add_filter('manage_posts_columns', 'add_share_count_column');

function add_share_count_column($columns) {
    $columns['share_count'] = 'Paylaşım';
    return $columns;
}

// Sütun verisini doldur
add_action('manage_posts_custom_column', 'display_share_count_column', 10, 2);

function display_share_count_column($column, $post_id) {
    if ($column === 'share_count') {
        $total = get_share_count($post_id, 'total');
        $facebook = get_share_count($post_id, 'facebook');
        $twitter = get_share_count($post_id, 'twitter');
        $linkedin = get_share_count($post_id, 'linkedin');
        $whatsapp = get_share_count($post_id, 'whatsapp');
        
        echo '<strong>' . $total . '</strong><br>';
        echo '<small style="color:#999;">';
        echo 'FB:' . $facebook . ' | ';
        echo 'TW:' . $twitter . ' | ';
        echo 'LI:' . $linkedin . ' | ';
        echo 'WA:' . $whatsapp;
        echo '</small>';
    }
}

// Sütunu sıralanabilir yap
add_filter('manage_edit-post_sortable_columns', 'make_share_count_sortable');

function make_share_count_sortable($columns) {
    $columns['share_count'] = 'share_count';
    return $columns;
}

// Sıralama sorgusunu ayarla
add_action('pre_get_posts', 'share_count_orderby');

function share_count_orderby($query) {
    if (!is_admin() || !$query->is_main_query()) return;
    
    if ($query->get('orderby') === 'share_count') {
        $query->set('meta_key', '_share_count_total');
        $query->set('orderby', 'meta_value_num');
    }
}

Gerçek Dünya Senaryoları

Bu sistemi kurarken karşılaştığım birkaç gerçek dünya durumundan bahsedeyim.

Senaryo 1: Haber Sitesi

Bir haber sitesinde paylaşım sayısını yazının üst kısmında, başlığın hemen altında göstermek istediler. the_content filtresini değiştirip içeriğin başına koydum. Ama sorun şu ki, bazı makalelerde excerpt kullanılıyordu ve excerpt’lerde de butonlar çıkıyordu.

Çözüm basitti:

add_filter('the_content', 'conditional_share_buttons');

function conditional_share_buttons($content) {
    // Excerpt içinde çalışmasın
    if (doing_filter('get_the_excerpt')) {
        return $content;
    }
    
    if (!is_single() || !in_the_loop() || !is_main_query()) {
        return $content;
    }
    
    // Belirli yazı tipleri için çalış
    $allowed_post_types = array('post', 'haber');
    if (!in_array(get_post_type(), $allowed_post_types)) {
        return $content;
    }
    
    $share_buttons = generate_share_buttons(get_the_ID());
    return $share_buttons . $content; // İçeriğin ÜSTÜNE ekle
}

Senaryo 2: WooCommerce Ürün Sayfaları

E-ticaret sitelerinde ürünlerin sosyal medyada paylaşılması satışları artırıyor. WooCommerce ürün sayfaları için özel bir hook noktası kullanmak daha temiz bir çözüm sunuyor:

// WooCommerce ürün sayfasına paylaşım butonu ekle
add_action('woocommerce_single_product_summary', 'add_product_share_buttons', 35);

function add_product_share_buttons() {
    global $product;
    
    if (!$product) return;
    
    $post_id = $product->get_id();
    echo generate_share_buttons($post_id);
}

Senaryo 3: Cache Sistemiyle Uyumluluk

WP Rocket veya W3 Total Cache kullanan sitelerde AJAX tabanlı sayaç güncellemesi sorun çıkarmıyor çünkü AJAX istekleri genellikle cache’lenmez. Ama sayacın sayfa yüklendiğinde doğru değeri göstermesi için dinamik içerik ayarlarına dikkat edin.

Cache eklentilerinin “cache bypass” kurallarına AJAX endpoint’i eklemek de iyi bir pratik:

  • WP Rocket’te: “Never Cache URL(s)” bölümüne /wp-admin/admin-ajax.php eklemeyin, zaten hariç tutulmuş olmalı
  • Nginx’te statik cache kullanıyorsanız, AJAX POST isteklerini cache dışında tuttuğunuzdan emin olun

Font Awesome Olmadan İkon Eklemek

Birçok geliştirici Font Awesome için ekstra bir bağımlılık istemez. SVG ikonları inline olarak kullanmak çok daha temiz:

function get_platform_svg_icon($platform) {
    $icons = array(
        'facebook' => '<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor"><path d="M24 12.073c0-6.627-5.373-12-12-12s-12 5.373-12 12c0 5.99 4.388 10.954 10.125 11.854v-8.385H7.078v-3.47h3.047V9.43c0-3.007 1.792-4.669 4.533-4.669 1.312 0 2.686.235 2.686.235v2.953H15.83c-1.491 0-1.956.925-1.956 1.874v2.25h3.328l-.532 3.47h-2.796v8.385C19.612 23.027 24 18.062 24 12.073z"/></svg>',
        'twitter' => '<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor"><path d="M23.953 4.57a10 10 0 01-2.825.775 4.958 4.958 0 002.163-2.723c-.951.555-2.005.959-3.127 1.184a4.92 4.92 0 00-8.384 4.482C7.69 8.095 4.067 6.13 1.64 3.162a4.822 4.822 0 00-.666 2.475c0 1.71.87 3.213 2.188 4.096a4.904 4.904 0 01-2.228-.616v.06a4.923 4.923 0 003.946 4.827 4.996 4.996 0 01-2.212.085 4.936 4.936 0 004.604 3.417 9.867 9.867 0 01-6.102 2.105c-.39 0-.779-.023-1.17-.067a13.995 13.995 0 007.557 2.209c9.053 0 13.998-7.496 13.998-13.985 0-.21 0-.42-.015-.63A9.935 9.935 0 0024 4.59z"/></svg>',
        'linkedin' => '<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor"><path d="M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433a2.062 2.062 0 01-2.063-2.065 2.064 2.064 0 112.063 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.222 0h.003z"/></svg>',
        'whatsapp' => '<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor"><path d="M17.472 14.382c-.297-.149-1.758-.867-2.03-.967-.273-.099-.471-.148-.67.15-.197.297-.767.966-.94 1.164-.173.199-.347.223-.644.075-.297-.15-1.255-.463-2.39-1.475-.883-.788-1.48-1.761-1.653-2.059-.173-.297-.018-.458.13-.606.134-.133.298-.347.446-.52.149-.174.198-.298.298-.497.099-.198.05-.371-.025-.52-.075-.149-.669-1.612-.916-2.207-.242-.579-.487-.5-.669-.51-.173-.008-.371-.01-.57-.01-.198 0-.52.074-.792.372-.272.297-1.04 1.016-1.04 2.479 0 1.462 1.065 2.875 1.213 3.074.149.198 2.096 3.2 5.077 4.487.709.306 1.262.489 1.694.625.712.227 1.36.195 1.871.118.571-.085 1.758-.719 2.006-1.413.248-.694.248-1.289.173-1.413-.074-.124-.272-.198-.57-.347m-5.421 7.403h-.004a9.87 9.87 0 01-5.031-1.378l-.361-.214-3.741.982.998-3.648-.235-.374a9.86 9.86 0 01-1.51-5.26c.001-5.45 4.436-9.884 9.888-9.884 2.64 0 5.122 1.03 6.988 2.898a9.825 9.825 0 012.893 6.994c-.003 5.45-4.437 9.884-9.885 9.884m8.413-18.297A11.815 11.815 0 0012.05 0C5.495 0 .16 5.335.157 11.892c0 2.096.547 4.142 1.588 5.945L.057 24l6.305-1.654a11.882 11.882 0 005.683 1.448h.005c6.554 0 11.89-5.335 11.893-11.893a11.821 11.821 0 00-3.48-8.413z"/></svg>'
    );
    
    return isset($icons[$platform]) ? $icons[$platform] : '';
}

Bu SVG’leri generate_share_buttons fonksiyonundaki icon kısmında kullanarak ekstra font bağımlılığından kurtulabilirsiniz.

Güvenlik Notları

Bu sistemi canlıya alırken dikkat etmeniz gereken birkaç nokta var:

  • Nonce doğrulaması: Her AJAX isteğinde nonce kontrolü yapıyoruz, bu XSS ve CSRF saldırılarına karşı koruma sağlıyor
  • Sanitizasyon: sanitize_text_field ve intval kullanarak gelen verileri temizliyoruz
  • Whitelist kontrolü: Sadece izin verilen platformların işleneceğinden emin oluyoruz
  • Rate limiting: Aynı kullanıcının kısa sürede çok fazla sayaç artırmasını engellemek için bir oturum kontrolü ekleyebilirsiniz

Sonuç

functions.php ile paylaşım sayacı sistemi kurmak başta karmaşık görünse de parçalara ayırınca oldukça yönetilebilir. Eklenti kurmanın cazibesine kapılmak kolay, ama bu yaklaşım size tam kontrol ve daha iyi performans veriyor. Özellikle çok sayfalı, yüksek trafikli sitelerde gereksiz eklentilerden kurtulmak büyük fark yaratıyor.

Kodu kendi ihtiyaçlarınıza göre uyarlayın: Belki sadece Facebook ve Twitter yeterli, belki WhatsApp yerine Telegram lazım. Temel yapı aynı, sadece platform dizisini güncellemeniz yeterli. Child tema kullandığınızı da unutmayın, yoksa bir sonraki tema güncellemesinde bu çalışmanın hepsini kaybedebilirsiniz.

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir