Пользователь
0,0
рейтинг
31 марта 2011 в 23:42

Кастомные социальные кнопки из песочницы

Недавно участвовал в разработке одного проекта — фото конкурса. По задумке, рейтинг фото альбомов должен формироваться из суммы всех публикаций в социальных сетях: Facebook, Вконтакте, Twitter. Т.е. общий рейтинг фотоальбома расчитывается:
Рейтинг фотоальбома = кол-во «Share» в Facebook + кол-во «Сохранить» в Вконтакте + кол-во «Retweet» в Twitter

На макетах, вид кнопок несколько отличался от предоставляемых социальными сетями плагинов, формируемых функциями api. В частности вид счетчиков:
image
Помимо несоответствий с дизайном, каждый плагин формирует излишний хтмл код, а хотелось бы лаконичный.

Детальнее ознакомившись с api каждой сети, окончательно убедились в отсутствии расширенных возможностей для кастомизации кнопок и этот факт понять можно, все стремятся к единоборазности своих кнопок. Решили отказаться от использования готовых плагинов и сделать свои кнопки.

Итак:
  • количество лайков будем получать от REST сервисов каждой социалки
  • кнопки рисуем свои и обрабатываем событие click


Кнопки


У каждой сети существует скрипт обработки запросов на добавление страниц с помощью Share, Сохранить, Tweet. При этом скрипту передаются определенные параметры. GET запросы выглядит так:

Facebook:
_http://www.facebook.com/sharer.php?u=<-url публикуемой страницы->&t=<-заголовок->&src=sp
Вконтакте:
_http://vkontakte.ru/share.php?url=<-url публикуемой страницы->
Twitter
_http://twitter.com/share?url=<-url публикуемой страницы->&text=<-заголовок->

Для имитации стандартного функционала, кнопки оформляем в виде ссылок с бэкграундами:

image

CSS приводить не буду, думаю с этим не должно возникнуть трудностей. У каждой кнопки-ссылки атрибут href должен содержать url в соответствии с описанными выше шаблонами.

Перед выводом, url-ы приводим в безопасный вид с помощью urlencode(). У нас код получился таким:
  1.     <div id="social_block">
  2.             <div id="vk_sharer">
  3.                 <span>53</span>
  4.                 <a id="vk_btn" href="_http://vkontakte.ru/share.php?url=http%3A%2F%2Fsite.ru%2Fklasnaya-stranitsa%2F" target="_blank" title="Сохранить Вконтакте">Сохранить</a>
  5.             </div>
  6.             <div id="fb_sharer">
  7.                 <span>116</span>
  8.                 <a id="fb_btn" href="_http://www.facebook.com/sharer.php?u=http%3A%2F%2Fsite.ru%2Fklasnaya-stranitsa%2F&t=%D0%9A%D0%BB%D0%B0%D1%81%D1%81%D0%BD%D0%B0%D1%8F+%D1%81%D1%82%D1%80%D0%B0%D0%BD%D0%B8%D1%86%D0%B0&src=sp" target="_blank" title="Мне нравится">Нравится</a>
  9.             </div>
  10.             <div id="tw_sharer" style="">
  11.                 <span>31</span>
  12.                 <a id="tw_btn" href="_http://twitter.com/share?url=http%3A%2F%2Fsite.ru%2Fklasnaya-stranitsa%2F&text=%D0%9A%D0%BB%D0%B0%D1%81%D1%81%D0%BD%D0%B0%D1%8F+%D1%81%D1%82%D1%80%D0%B0%D0%BD%D0%B8%D1%86%D0%B0" target="_blank" title="Retweet">Retweet</a>
  13.             </div>
  14.             <hr/>
  15.             <div id="total_count">200</div>
  16.     </div>


Также можно позаботиться о том как будет выглядеть «пост» в социальной сети, для этого разместим в секции <head> страницы соответсвующие мета теги.

У Facebook для этих целей есть Open Graph теги:

<meta property="og:title" content="Заголовок"/><br/>
<meta property="og:description" content="Описание"/><br/>
<meta property="og:image" content="url к картинке"/>


Вконтакте будет искать:

<meta name="title" content="Заголовок статьи" /><br/>
<meta name="description" content="Описание статьи. Это очень интересная статья." /><br/>
<link rel="image_src" href="_http://mysite.com/mypic.jpg" />


Далее обрабатываем событие click каждой кнопки, при возникновении которого, открываем новое окно браузера с url указанным в атрибуте href, при этом окно с заданными шириной и высотой, а то оно откроется как новая вкладка.

Код для кнопки Facebook (jQuery):

  1.            var click = false;
  2.            $('#fb_btn').click(function(){
  3.                // проверяем был ли уже клик по кнопке
  4.                if(!click){
  5.                    var social_box = $(this).parent('div');
  6.                    // увеличиваем значение счетчика социалки на 1
  7.                    var count = parseInt($('span', social_box).text());
  8.                    if(!isNaN(count)){
  9.                        count = count + 1;
  10.                        $('span', social_box).text(count);
  11.                    }
  12.                    // увеличиваем общий рейтинг на 1
  13.                    var total_cnt = parseInt($('#total_count').text());
  14.                    if(!isNaN(total_cnt)){
  15.                        total_cnt = total_cnt + 1;
  16.                        $('#total_count').text(total_cnt);
  17.                    }
  18.                    click = true;
  19.                }
  20.                // открываем окно
  21.                window.open($(this).attr("href"),'displayWindow', 'width=700,height=400,left=200,top=100,location=no, directories=no,status=no,toolbar=no,menubar=no');
  22.                 return false;
  23.            });
  24.  
  25.  


Аналогично для остальных. С «расшариванием» как видите все предельно просто.

Счетчики


Количество Share-ов для кажой страницы будем получать от REST сервисов социалок, после формирования страницы (событие ready). Так как в проекте повсеместно использовали jQuery, то и здесь она нам пригодится, в частности метод $.getJSON, c возможностью выполнять кроссдоменные запросы (хотя в версии jQuery 1.5 такая возможность добавлена и в $.ajax).

Код для Facebook:
  1.         var pageuri = '<-- url публикуемой страницы -->';
  2.        $.getJSON('http://api.facebook.com/restserver.php?method=links.getStats&callback=?&urls=' + pageuri + '&format=json', function(data) {
  3.                 // вставляем в DOM
  4.                 $('#fb_sharer span').text(data[0].share_count);
  5.         });


Для Вконтакте необходимо объявить два объекта: VK и VK.Share, а также callback метод VK.Share.count(index, count):
  1.         var pageuri = '<-- url публикуемой страницы -->';
  2.         VK = {};
  3.         VK.Share = {};
  4.         // объявляем callback метод
  5.         VK.Share.count = function(index, count){
  6.             // вставляем в DOM
  7.             $('#vk_sharer span').text(count);
  8.         };
  9.         $.getJSON('http://vkontakte.ru/share.php?act=count&index=1&url=' + pageuri + '&format=json&callback=?');


Для Twitter:
  1.         var pageuri = '<-- url публикуемой страницы -->';
  2.         $.getJSON('http://urls.api.twitter.com/1/urls/count.json?url=' + pageuri + '&callback=?', function(data) {
  3.             // вставляем в DOM
  4.             $('#tw_sharer span').text(data.count);
  5.         });


После получения данных добавляем их в DOM и отображаем весь блок с кнопками например:
$('#social_block').fadeIn('fast);.
Эврика!

Обновление рейтинга


В нашем случае в базе конкурса для каждого фотоальбома хранятся значения счетчиков по каждой сети и суммарный рейтинг. Поэтому после получения данных от социальных сетей, они сравниваются с данными хранимыми в базе сайта и при различии хотя бы одного значения отправляются ajax-ом для обновления. Здесь у каждого может быть свой подход, поэтому заострять внимание не буду.

Полный код получившегося jQuery плагина думаю тоже нет смысла постить, кому понадобится, оформит на свой вкус. Конечно тоже самое можно реализовать серверными скриптами и с помощью CURL например, получать эти же данные, но переложить это на клиентскую сторону нам показалось более привлекательно.

И еще один момент: Facebook перенес функционал Share в Like, но Share пока работает и надеюсь продолжит. Для получения количества «лайков» используйте в callback функции data[0].like_count.

Upd:
Архив с примером
Николай Ивлев @k0t0vsky
карма
39,0
рейтинг 0,0
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Реклама

Самое читаемое

Комментарии (58)

  • +1
    В нашем случае в базе конкурса для каждого фотоальбома хранятся значения счетчиков по каждой сети и суммарный рейтинг. Поэтому после получения данных от социальных сетей, они сравниваются с данными хранимыми в базе сайта и при различии хотя бы одного значения отправляются ajax-ом для обновления.
    Т.е. любой пользователь, немного владеющий js, может отправить на ваш сервер «обновленные» данные с угодным ему количеством голосов?
    • +1
      На этот случай, в запросе отправляется также проверочный хеш, который собственно и проверяется перед записью в базу.
      • +3
        Что мешает получить кеш со страницы и отправить запрос с ним?
        • 0
          не очень понял вопрос…
          • 0
            Хеш, который вы проверяете перед записью в базу — он отправляется вашим скриптом со страницы голосования. Явоскриптом отправляется. Значит я могу его получить и отправить с ним нужные мне данные.
            • –1
              Он уникален каждую минуту. Генерируется php и передается в js. При формировании хеша используется hh:mm:yyyy, по моему, подзабыл, как-то. А принимающий скрипт формирует свой хеш с текущим временем. Вот такой костыль придумали. Может есть более изящное решение?
              • 0
                в hh:mm:yyyy очепятка, в общем используется время до минуты и дата.
              • +1
                Не знаю как насчет изящнее, но, думаю, получать счетчики от соц. сетей на сервере, а не на клиенте, было бы как минимум надежнее. Т.е. клиент шлет запрос «обновись» серверу, а тот сам снимает показатели счетчиков и обновляет значения в базе. Да, и как себя ведет Ваш «костыль», при смене минуты? Т.е. юзер загрузил страницу (со своим уникальным хэшем, зависящим от времени вплоть до минуты), затем выпил кофе и через пять минут жмякнул like. В таком случае на сервере уже будет генерироваться новый хэш и проверка не пройдет?
                • 0
                  Логика такая:
                  — формируется хеш и присваивается глобальной переменной js прямо на странице в секции script. Что-то вроде этого:
                  ||script||data = {
                  uniq_string = '<?=хеш?>',
                  fb_count_in_db = <?=?>,
                  vk_count_in_db = <?=?>,
                  tw_count_in_db = <?=?>}||/script||
                  — по событию ready основной скрипт получает данные от социалок сравнивает их со значениями из бд и при различии хотя бы одного отправляет ajax-ом вместе с uniq_string.
                  • +2
                    Очень надеюсь, что я все еще не до конца Вас понял. В противном случае выходит, утрируя, что вы любому посетителю высылаете login-форму с заполненным полем пароля (пусть и уникальным и действительным лишь в течение минуты значением) и рассчитываете, что лишь добропорядочный пользователь нажмет кнопку «login». Проблема в том, что Вы получаете данные для формирования рейтинга от социальных сетей через клиента-посредника, проверяя подлинность данных по ключу (хэшу), который сами же только что выдали этому посреднику. Если же я все-таки правильно понял, то думаю, стоит пренебречь «привлекательностью» и все же перенести эту часть логики в укромное место на сервере.
                    • 0
                      Вы правильно поняли процесс… А мы все думы передумали, чем это может совсем страшным обернуться? Думаете могут найтись извращенцы, которые будут парсить со страницы хеш и отправлять его скрипту? Хотя наверно найдуться.
                      Может есть какой-то вариант, как-то с глобальными переменными php?
                      • –1
                        всмысле что-то хранить такое в global…
                        • 0
                          или в куку писать каждый раз
                      • 0
                        Вы даже не представляете всю ту индустрию с хакерами и взломщиками, которые кроются за обычными конкурсами с призами.
                      • 0
                        Найдутся, будьте уверены :D
                • 0
                  Т.е. клиент шлет запрос «обновись» серверу, а тот сам снимает показатели счетчиков и обновляет значения в базе.

                  А какое принципиальное отличие от того чтобы сразу клиенту данные отправить?

                  Если получать на сервере данные то писать их сразу в базу и выводить.
                  • 0
                    т. е. серверу отправить
                    • 0
                      В php можно просто использовать curl и опрашивать сервера соцсетей раз в 5 минут по cron'у и записывать ответы в базу. Страница будет загружаться быстрее у пользователей. Если сервер мощный, можно раз в минуту опрашивать.
                      Если важно отображать результат без задержек — оставьте js код, просто не отправляйте обновлённые данные с клиента на сервер.
                      • 0
                        Вот как раз и думали, что могут возникнуть глюки из-за ограничений на частоту обращений к сервису от сервера и на клиенте не всегда будет актуальная информация. Но похоже вы правы и обновление данных в базе нужно curl-ом делать.
                      • 0
                        Меня пугает ситуация с большим количество фотоальбомов (url-ов). Представьте у вас 10к страниц, если по крону опрашивать сервисы социалок по всем страницам, то у вас получится 30к запросов curl-ом. А если их будет еще больше?

                        А если организовать что-то вроде списка заданий. Т.е. клиент сообщает серверному скрипту url по которому необходимо обновить данные из социалок, на серваке создается задание и ставится в очередь. Перед добавлением в очередь:
                        — исключаем образование клонов url-ов
                        — регуляркой проверяем url на соответсвие с реальными url-ами фотоальбомов
                        — тем же curl смотрим заголовок на отсутсвие 404 ошибки
                        Также думаю можно сделать запрет на добавление в очередь не чаще выбранного времени.

                        По крону запускать скрипт, который:
                        — получает задания из очереди
                        — выполняет свое грязное дело
                        — очищает очередь

                        Таким образом на клиенте с помощью js всегда актуальные значения счетчиков, а на сервере исключается большое количество обращений к социалкам.

                        Кто что думает по этому поводу?
          • +1
            Он имеет в виду то, что запрос, будь он с хешем или без выполняется на клиентской стороне и посмотрев в том же firebug, какой запрос отправляется, можно отправить его самостоятельно.
    • +1
      Кста у фейсбука можно(и нужно) юрать данные отсюда graph.facebook.com/?ids=http://www.imdb.com/title/tt0117500/
      Вообще там много вкусняшек developers.facebook.com/docs/reference/api/, как бы гугл не ругался на закрытость фейсбука
      • 0
        да. здесь был топик об этом.
  • –4
    В будущем для многих это будет полезная вещь, а возможно уже сейчас)
    • –12
      Не могу минусовать изза маленькой кармы, но мой вам «минус один»!!! Давай ребзя, налетай-минусуй!
      • –10
        *sarcasm*
  • –1
    это уже сейчас очень полезно! Спасибо!
  • 0
    Как раз встала подобная задача, спасибо. А аналогичные возможности Одноклассников и Моего Мира исследовали?
    • 0
      Смотрел бегло, показалось, что да.
  • +2
    Поправьте, «безопастный».
    А вещь очень нужная, плюсую.
    • 0
      поправил, спасибо
      • 0
        Тогда поправьте ещё «имитацию» в «Для эмитации стандартного функционала».
  • –2
    Статья прекрасна, автор молодец!
    • 0
      спасибо
  • 0
    «share» подвержен накрутке
    • 0
      точней так — «share» контакта может быть накручен одним аккаунтом
      • –1
        Да это известно. Если url размещенный с помощью share удалить, то счетчик не уменьшается. Соответсвенно если повторно разместить, то счетчик увеличится. Но это не изменило желание заказчика использовать share потому как с его помощью постится не просто ссылка, а анонс, что более наглядно. А сам рейтинг носит заманушный характер. Победителя будет выбирать жюри.
        • 0
          Удалить у себя на странице?
          • 0
            Да, на своей страничке в социалке…
  • 0
    Поправьте в коде «Вконтакте будет искать:» — мне почему-то кажется, что br там не к месту.
  • +2
    А в правилах использования API разве не сказано, что нельзя изменять внешний вид кнопок?
    Я не утверждаю, а спрашиваю. Просто, когда тоже нужно было немного стилизовать кнопки, менеджеры сказали что менять нельзя, мол в правилах где-то откопали пункт на этот счет.
    • 0
      Вопрос актуальный, как раз эту часть документации мы пропустили. В целом наши кнопки очень похожи на оригинальные. Да кнопки картинки уже встречал и на сравнительно крупных проектах.
    • –1
      Вопрос актуальный, как раз эту часть документации мы пропустили. В целом наши кнопки очень похожи на оригинальные. Да кнопки картинки уже встречал и на сравнительно крупных проектах.
  • +4
    Изначально счетчик в Share ВКонтакте не рассчитан на конкурсы — он считает количество сохранений, а не уникальных пользователей. Для конкурсной основы гораздо лучше и правильнее использовать виджет «Мне Нравится» — он считает уникальных пользователей и его гораздо сложнее накрутить.
    • 0
      Да, но «Мне нравится» публикует только ссылку, это не так наглядно. Чуть выше ответил.
  • +2
    Было бы не плохо готовый архивчик с примером, думаю многие были бы благодарны
    • +3
      Сегодня-завтра найду время, выложу.
      • 0
        будет архивчик?
        • 0
          Будет, уезжал на выходных, не смог обеспечить.
        • 0
          Добавил ссылку в подвал топика
    • 0
      Вы интегрировали это решение в какой либо из своих проектов? Можно взглянуть? ;)
  • 0
    А для чего они разного размера? Или так задумано?
    • 0
      Дизайнер такие предоставил,
  • 0
    Спасибо всем за комменты, передумали использовать подобную механику голосования :)
    • 0
      А какую выбрали?
      • 0
        написали собственную, а в последствии ввели подтверждение аккаунтов по смс
        • 0
          К нам обращались с подобными запросами — подключаем модуль CRM и считаем.
        • 0
          У Вас есть готовое решение?

          В данный момент ищу что либо похожее для реализации голосования в конкурсе.

          Можете поделиться наработанным? Или хотя бы теорией? ;)

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.