Свой плагин WordPress для автопостинга ВКонтакте

Дмитрий Корнев
23 октября 2015

Существует немало разных плагинов для WordPress, которые могут обеспечить автоматизированное добавление записей сайта в социальную сеть ВКонтакте. Если вы не нашли себе подходящего, то можете сделать свой! Эта статья поможет.

Зачем свой плагин?

Многие существующие плагины довольно сложны. Причина — попытка их авторов сделать универсальную вещь. В итоге, некоторых пользователей такие «комбайны» устраивают, а кому-то всё равно не хватает функций. Однако, в любом случае, плагины приобретают слишком много кода, который вполне может глючить. Свой плагин можно сделать очень простым, чтобы весь код в нём был, как на ладони. Он будет делать только то, что необходимо именно вам, и в том виде, каком нужно. Без всяких компромиссов!

Социальная сеть ВКонтакте имеет удобный API и великолепную документацию по нему. Глупо этим не пользоваться. В статье рассмотрен довольно простой пример плагина под WordPress, а также совсем простецкая универсальная заготовка. Измените код немного под себя и пользуйтесь на здоровье.

Что нужно для автопостов?

Нужно знать ID-номер «стены» ВКонтакте, на которую вы хотите автоматически добавлять записи.

Без разницы, какой это будет тип стены — ваша персональная, либо сообщества. Для персональной номер смотрим в «Мои Настройки». Здесь есть «Адрес Вашей страницы» и «Номер страницы». Это как раз то, что нам требуется:

ID-номер стены ВКонтакте

Для сообщества номер смотрим в самом сообществе. Зайдите в него. Если у вас есть соответствующие права, то здесь можно увидеть ссылку «Управление сообществом», а ещё «Статистика сообщества». В составе последней ссылки можно увидеть цифры, которые не спрятаны, даже если сообществу назначен красивый адрес. Цифры — это требуемый нам ID-номер сообщества. Пример:

http://vk.com/stats?gid=36440041

Посты на стену в ВКонтакте будут публиковаться с использованием API и специального приложения ВКонтакте. Одного приложения достаточно, чтобы отправлять посты с нескольких сайтов.

Создать приложение можно здесь. В процессе этого задайте название, пример, «Автопосты с сайтов» и выберите тип «Standalone-приложение». В результате, приложение будет создано и вы получите его ID-номер.

Пример настроек приложения:

Приложение для API ВКонтакте

Чтобы API-запросы от вашего сайта (плагина) к этому приложению обрабатывались вам обязательно в этих запросах надо будет указывать так называемый access_token. Это специальный секретный ключ — строка из 85 символов. Его достаточно получить для своего приложения один раз. Информация на официальном сайте.

Получить access_token можно, открыв в веб-браузере ссылку:

https://oauth.vk.com/authorize?client_id=[id_приложения]&scope=offline,group,photos,wall&display=page&response_type=token&redirect_uri=https://oauth.vk.com/blank.html

Здесь, вместо [id_приложения] указывается ID-номер приложения.

Содержание автопостов

Что нам вообще требуется? Мы хотим, чтобы при размещении статьи на сайте автоматически создавался пост с анонсом на стене ВКонтакте. Причём нормального вида, наподобие тех, что создаются вручную. Для каждого такого анонса оптимально передавать:

  1. Небольшой текст, например, заголовок и/или вводную часть статьи.
  2. Картинку статьи, желательно НЕ миниатюру.
  3. Ссылку на статью на сайте.

Пример автопостов в сообществе ВКонтакте без картинок:

Автопост в ВКонтакте

Здесь передавался текст — заголовок и анонс, разделённые просто двойным переводом строки.

Других способов как-то выделить заголовок я не знаю, никакое форматирование текста в социальной сети использовать нельзя. Наверное, совсем идеально было бы, если не просто суммировать заголовок и анонс, а готовить для этих дел специальные цельные куски текста.

При наведении курсора мыши на ссылку в посте можно видеть картинку и описание статьи, взятые с сайта автоматически непосредственно в момент просмотра. См. статью по теме.

На следующем примере автопостов всё тоже самое, только дополнительно передавалась картинка:

Автопост в ВКонтакте

Картинка большая. Я предпочитаю для этих целей использовать картинки с шириной, порядка, 800-1200 пикс. Думаю, этого достаточно, слишком увлекаться тоже не стоит.

Зачем именно большая картинка? На мой взгляд, так посты выглядят более естественно. Обычно, создавая вручную пост на стене, пользователи прикрепляют фотку или другую довольно крупную картинку. Миниатюры при ручном размещении никто не использует.

Универсальный код

Начну с обратного, — сначала совсем простой пример, так проще показать основу, плагин для WordPress ниже. Итак, задаём исходные данные:

// ID-номер стены юзера или сообщества, куда надо постить.
$vk_user = $vk_group = 12345678;
// Секретный ключ, который был получен для приложения VK.
$vk_token = '12345qwerty...';

// Информация для поста: анонс, изображение, ссылка.
$post_text = 'Здесь заголовок и может какой-то ещё текст';
$post_image = 'https://d1mon.com/att/img.jpg';
$post_url = 'https://d1mon.com/n/1069';

// Преобразуем ссылку на изображение, нужен вид типа /var/www/d1mon.com/att/img.jpg
$post_image = $_SERVER['DOCUMENT_ROOT'].substr($post_image, strlen($_SERVER['SERVER_NAME'])+7);

Далее два варианта кодов, предназначенные для отправки постов на стену пользователя и сообщества ВКонтакте. Отличаются они незначительно, но отличаются! Используйте какой-то один.

Код для отправки поста на стену пользователя:

// Узнаем сервер VK, куда будем заливать изображение.
$ph_ser = json_decode(file_get_contents('https://api.vk.com/method/photos.getWallUploadServer?v=5.37&access_token='.$vk_token));
// Заливаем изображение на сервер.
$ph_upl = json_decode(curlPost($ph_ser->response->upload_url, $post_image));
// Сохраняем изображение, как фото к посту на стене.
$ph_sav = json_decode(file_get_contents('https://api.vk.com/method/photos.saveWallPhoto?user_id='.$vk_user.'&photo='.$ph_upl->photo.'&server='.$ph_upl->server.'&hash='.$ph_upl->hash.'&v=5.37&access_token='.$vk_token));
// Узнаём ID залитого изображения.
$ph_id = $ph_sav->response[0]->id;

// Формируем запрос для отправки поста.
$st_zap = 'https://api.vk.com/method/wall.post?owner_id='.$vk_user.'&friends_only=0&message='.urlencode($post_text).'&attachments=';
// Если изображение было загружено, то добавляем его.
if(mb_strlen($ph_id)) { $st_zap .= 'photo'.$ph_sav->response[0]->owner_id.'_'.$ph_id.','; }
// Добавляем URL и завершаем формировать запрос.
$st_zap .= $post_url.'&v=5.37&access_token='.$vk_token;

// Отправляем сформированный запрос.
$st_res = json_decode(file_get_contents(str_replace(' ', '%20', $st_zap)));
// Узнаём ID опубликованного ВКонтакте поста.
$st_id = $st_res->response->post_id;

Вариант кода для отправки поста на стену сообщества:

// Узнаем сервер VK, куда будем заливать изображение.
$ph_ser = json_decode(file_get_contents('https://api.vk.com/method/photos.getWallUploadServer?group_id='.$vk_group.'&v=5.37&access_token='.$vk_token));
// Заливаем изображение на сервер.
$ph_upl = json_decode(curlPost($ph_ser->response->upload_url, $post_image));
// Сохраняем изображение, как фото к посту на стене.
$ph_sav = json_decode(file_get_contents('https://api.vk.com/method/photos.saveWallPhoto?group_id='.$vk_group.'&photo='.$ph_upl->photo.'&server='.$ph_upl->server.'&hash='.$ph_upl->hash.'&v=5.37&access_token='.$vk_token));
// Узнаём ID залитого изображения.
$ph_id = $ph_sav->response[0]->id;

// Формируем запрос для отправки поста.
$st_zap = 'https://api.vk.com/method/wall.post?owner_id=-'.$vk_group.'&friends_only=0&from_group=1&message='.urlencode($post_text).'&attachments=';
// Если изображение было загружено, то добавляем его.
if(mb_strlen($ph_id)) { $st_zap .= 'photo'.$ph_sav->response[0]->owner_id.'_'.$ph_id.','; }
// Добавляем URL и завершаем формировать запрос.
$st_zap .= $post_url.'&v=5.37&access_token='.$vk_token;

// Отправляем сформированный запрос.
$st_res = json_decode(file_get_contents(str_replace(' ', '%20', $st_zap)));
// Узнаём ID опубликованного ВКонтакте поста.
$st_id = $st_res->response->post_id;

И завершение — общий кусок — вспомогательная функция:

// Функция cURL.
function d1_vk_curlPost($url, $img)
{
  if(!isset($url) || !isset($img))
  {
    return false;
  }
  $ch = curl_init();
  curl_setopt($ch, CURLOPT_USERAGENT, $_SERVER['HTTP_USER_AGENT']);
  curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
  curl_setopt($ch, CURLOPT_TIMEOUT, 10);
  curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
  curl_setopt($ch, CURLOPT_URL, $url);
  curl_setopt($ch, CURLOPT_POST, true);
  curl_setopt($ch, CURLOPT_POSTFIELDS, ['file1' => new CurlFile($img)]);
  $response = curl_exec($ch);
  curl_close($ch);
  return $response;
}

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

Плагин под WordPress

Здесь всё тоже самое, только есть дополнительные фишки, дабы это был уже законченный рабочий инструмент под WordPress. Для использования, здесь просто надо вписать свои параметры. С настройками через админ-панель движка я не стал заморачиваться, чтобы не усложнять. Да и для того плагина, который пишется именно под себя и используется на одном сайте так удобнее. Обратите внимание, что этот вариант кода реализует отправку постов на стену пользователя, а не сообщества.

<?php

/**
 * Plugin Name: d1mon_vk_autopost
 * Description: Автопостинг на стену юзера в VK.
 */

// Запуск автопостинга при публикации нового WP-поста.
add_action('publish_post', 'd1mon_vk_publish_new');
// Запуск автопостинга по команде.
add_action('wp_ajax_d1mon_vk', 'd1mon_vk_ajax');
// Добавление диалога плагина в редактирование WP-поста.
add_action('admin_init', 'd1mon_vk_box', 1);

// Функция автопостинга.
function d1mon_vk($wp_post_id)
{
  // ID-номер стены юзера, куда надо постить.
  $vk_user = 12345678;
  // Секретный ключ, который был получен для приложения VK.
  $vk_token = '12345qwerty...';

  // Получаем информацию по WP-посту.
  $wp_post_url = get_permalink($wp_post_id);
  $wp_post_arr = get_post($wp_post_id);
  $wp_post_title = $wp_post_arr->post_title;
  $wp_post_content_arr = get_extended($wp_post_arr->post_content);
  $wp_post_desc = strip_tags($wp_post_content_arr['main']);

  // Формируем текст VK-поста.
  $vk_text = $wp_post_title.'

'.$wp_post_desc;

  // Если у WP-поста есть миниатюра.
  if(($wp_post_image = get_post_thumbnail_id($wp_post_id)) > 0)
  {
    // Пытаемся получить массив для этой же картинки в большом размере.
    if(is_array($wp_post_image = wp_get_attachment_image_src($wp_post_image, 'large' )))
    {
      // Получили, фомируем URL для этой картинки до нужного вида.
      $wp_post_image = $_SERVER['DOCUMENT_ROOT'].substr($wp_post_image[0], strlen($_SERVER['SERVER_NAME'])+7);
    }
    else { unset($wp_post_image); }
  }
  // Иначе пробуем взять картинку из аттачей WP-поста.
  elseif($wp_post_image = get_attached_media('image', $wp_post_id))
  {
    // Сокращаем массив, берем лишь первую картинку.
    $wp_post_image = array_shift($wp_post_image);
    if(mb_strlen($wp_post_image = $wp_post_image->guid))
    {
      // Взяли, фомируем URL для этой картинки до нужного вида.
      $wp_post_image = $_SERVER['DOCUMENT_ROOT'].substr($wp_post_image, strlen($_SERVER['SERVER_NAME'])+7);
    }
    else { unset($wp_post_image); }
  }
  else { unset($wp_post_image); }

  // Если изображение нашлось.
  if(mb_strlen($wp_post_image))
  {
    // Узнаем VK-сервер, куда будем заливать изображение.
    $ph_ser = json_decode(file_get_contents('https://api.vk.com/method/photos.getWallUploadServer?v=5.37&access_token='.$vk_token));
    // Заливаем изображение на VK-сервер.
    $ph_upl = json_decode(curlPost($ph_ser->response->upload_url, $wp_post_image));
    // Сохраняем изображение, как фото к VK-посту на стене.
    $ph_sav = json_decode(file_get_contents('https://api.vk.com/method/photos.saveWallPhoto?user_id='.$vk_user.'&photo='.$ph_upl->photo.'&server='.$ph_upl->server.'&hash='.$ph_upl->hash.'&v=5.37&access_token='.$vk_token));
    // Узнаём id залитого изображения.
    $ph_id = $ph_sav->response[0]->id;
  }

  // Начинаем формировать запрос для отправки VK-поста.
  $st_zap = "https://api.vk.com/method/wall.post?owner_id=".$vk_user."&friends_only=0&message=".urlencode($vk_text)."&attachments=";
  // Если изображение было загруженно, то добавляем его в запрос.
  if(mb_strlen($ph_id)) { $st_zap .= 'photo'.$ph_sav->response[0]->owner_id.'_'.$ph_id.','; }
  // Добавляем URL на WP-пост.
  $st_zap .= $wp_post_url;
  // Дополнительный постинг в другие социальные сети.
  //$st_zap .= '&services=twitter,facebook';
  // Завершаем формировать запрос.
  $st_zap .= '&v=5.37&access_token='.$vk_token;

  // Отправляем сформированный запрос в VK.
  $st_res = json_decode(file_get_contents(str_replace(' ', '%20', $st_zap)));
  // Узнаём ID опубликованного VK-поста.
  $st_id = $st_res->response->post_id;

  // Если все ок.
  if(mb_strlen($st_id)>1)
  {
    // Добавяем в WP ссылку на VK-пост.
    add_post_meta($wp_post_id, 'd1mon_vk_link', $vk_user.'_'.$st_id);
    // Добавяем в WP ссылку на изображение VK-поста.
    add_post_meta($wp_post_id, 'd1mon_vk_photo', $ph_id);
  }
}

// Функция запуска автопостинга при публикации в WP нового поста.
function d1mon_vk_publish_new($wp_post_id)
{
  // Если WP-пост опубликован.
  if(($_POST['post_status'] == 'publish') && ($_POST['original_post_status'] != 'publish'))
  {
    // Пытаемся получить из WP ссылку на VK-пост.
    $test = get_post_meta($wp_post_id, 'd1mon_vk_link');
    // Если ссылка не найдена.
    if(count($test) == 0)
    {
      // Получаем Unix-метку времени WP-поста с поправкой на временную зону GTM.
      $wp_post_time = get_post_time('U', true, $wp_post_id);
      $wp_post_time_plus = $wp_post_time + 60*60*24*2; // двое суток.

      // Если WP-пост новый. WP-посты, публикуемые задним числом, игнорируем.
      if($wp_post_time_plus > current_time('timestamp'))
      {
        // Запуск автопостинга.
        d1mon_vk($wp_post_id);
      }
    }
  }
}

// Функция запуска автопостинга по команде.
function d1mon_vk_ajax()
{
  // Берем ID редактируемого WP-поста.
  $wp_post_id = $_REQUEST['post_id'];
  // Если WP-пост опубликован.
  if(get_post_status($wp_post_id) == 'publish')
  {
    // Запуск автопостинга.
    d1mon_vk($wp_post_id);
  }
  header("Location: http://".$_SERVER['HTTP_HOST']."/wp-admin/post.php?post=".$wp_post_id."&action=edit");
  exit;
}

// Функции диалога плагина в редактирование WP-поста.
function d1mon_vk_box()
{
  add_meta_box('d1mon_vk_box', 'd1mon_vk_autopost', 'd1mon_vk_box_inner', 'post', 'side');
}
function d1mon_vk_box_inner($post)
{
  $d1mon_vk_box_link = get_post_meta($post->ID, 'd1mon_vk_link');
  $d1mon_vk_box_image = get_post_meta($post->ID, 'd1mon_vk_photo');
  if(count($d1mon_vk_box_link) > 0)
  {
    echo '<p>Существующие VK-записи <strong>('.count($d1mon_vk_box_link).'):</strong></p>';
    $i=0;
    while($i < count($d1mon_vk_box_link))
    {
      echo '<p><a target="_blank" href="//vk.com/wall'.$d1mon_vk_box_link[$i].'">Пост</a>';
      if(mb_strlen($d1mon_vk_box_image[$i]>1))
      {
        echo ' (<a target="_blank" href="//vk.com/photo'.get_option('d1mon_vk_opt_gid').'_'.$d1mon_vk_box_image[$i].'">изображение</a>)';
      }
      echo '</p>';
      $i++;
    }
  }
  else
  {
    echo '<p>Постов в VK не было!</p>';
  } 
  $link = admin_url('admin-ajax.php?action=d1mon_vk&post_id='.$post->ID);
  if(get_post_status($post->ID)=='publish')
  {
    echo '<a href="'.$link.'" id="d1monvk" class="button button-primary button-large">Запостить в VK!</a>';
  }
}

// Функция cURL (вспомогательная)
function curlPost($url, $img)
{
  if(!isset($url) || !isset($img))
  {
    return false;
  }
  $ch = curl_init();
  curl_setopt($ch, CURLOPT_USERAGENT, $_SERVER['HTTP_USER_AGENT']);
  curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
  curl_setopt($ch, CURLOPT_TIMEOUT, 10);
  curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
  curl_setopt($ch, CURLOPT_URL, $url);
  curl_setopt($ch, CURLOPT_POST, true);
  curl_setopt($ch, CURLOPT_POSTFIELDS, ['file1' => new CurlFile($img)]);
  $response = curl_exec($ch);
  curl_close($ch);
  return $response;
}

?>

Другие социальные сети

В последнем примере, на этапе формирования запроса, имеется один интересный закоментированный параметр: «Дополнительный постинг в другие социальные сети». При необходимости вы можете его включить. Функция актуальна для Facebook и Twitter. Я когда узнал, что такое можно заодно делать, то весьма обрадовался. Ну а как же. Ведь интересная же перспектива — делаешь всего один небольшой плагин и отправляешь автопосты сразу в несколько социальных сетей.

Однако, радость была преждевременной. ВКонтакте не пожелал этого делать нормально. Нет, автопосты он, конечно, отправляет. Но при этом он ставит в них свои ссылки! То есть, пользователи других социальных сетей отправятся за подробностями именно вконтакт. И не важно, что вы изначально для поста передавали ссылку на свой сайт. В общем, тупо! Не понимаю, кому тогда эта функция вообще нужна. Если вы вдруг решите использовать у себя эту дополнительную возможность, то имейте в виду, что для её работы нужно зайти в свои настройки ВКонтакте и активировать там связи с этими социальными сетями. Сделать это несложно:

Настройка экспорта из ВКонтакте

11 комментариев

tw
Супер, я надеюсь ещё работает через АПИ! Осталось как-то прикрутить к своей цмс!!!
id
Не получилось. Хотя использовал приложения, уже задействованные в других плагинах автопостинга. Т.е. приложение 100% создано верно. Этот код ещё рабочий?
На двух сайтах работает, код на основе этого. Если API поменялся, то либо версию выбирайте, либо вносите соответсвующие изменения в код.
id
Кстати, да. Сталкивался. Например на хостингах, где РНР 5.3 работает. А на Бегете, где РНР 5.6 - не работает.
У меня PHP Version 5.6.19. Дело не в этом. Просто смотрите что за ошибка у вас, ищите соответствующее решение, а иначе гадать можно долго.
Кстати, сейчас вспомнил, возникала проблема, когда пытался отправлять слишком большие куски текста. В остальном проблем с кодом не было. Для больших текстов надо менять сильно код, не стал заморачиваться, просто добавил проверку длины и обрезаю когда надо.
id
А где версию API выбирать? При создании приложения?
Версия в самих запросах к api, типа v=5.37.
ch
Здравствуйте, отмечу, скрипт рабочий до сих пор, НО не грузит фото. как исправить?
ch
если можно, то продублируйте ответ в мой вк
ch
нашел проблему, в скрипте $post_image а нужно $wp_post_image