Время прочтения: 10 мин.

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

Расскажу немного о процессе, как статьи попадают на наш портал:

В первую очередь, после того, как автор подготовил статью, она попадает к нашему редактору. Задача редактора оценивать этику контента, и при необходимости помогать автору в редактировании статьи.  Затем редактор размещает статьи на сайте, и контент попадает к нашему читателю.

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

И так задача: автоматизировать размещение статей с сайта и исключить лишнюю работу для наших дежурных редакторов.

Разработка решения делалась для 3-х социальных сетей – ВК, Телеграмм, Facebook*, о каждом из них расскажем ниже.

Для начала добавляем хук в нашу систему СMS на изменение статуса записи

// Хук срабатывает на изменение статуса записи
add_action( 'transition_post_status' , 'sendContentToSocial' , 10,3 );

Обязательно проверяем, чтобы наш хук не срабатывал на обновление записи, а только на изменение статуса на «опубликован»

If( 'publish' === $new_status && 'publish' !== $old_status && 'post' === &post->post_type )

Вконтакте

Для начала работы с VK API, переходим по ссылке и создаем новое Singletone приложение.

Далее переходим в настройки приложения, и все что нам нужно – ID приложения.

Для получения токена доступа к методам API от имени вашей страницы, нужно сделать запрос по открытому протоколу Oauth. В строке браузера формируем строку, подобной ниже, где:

Client_id – ID вашего приложения

Scope – Разрешения, которые вы запрашиваете. Конкретно для этой задачи нам потребовались photos (загрузка фото), pages (доступ к странице), groups (доступ к группам)

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

После нажатия кнопки «Разрешить» в ответ получаем токен доступа, который позволяет нам начать работать с API.

Чтобы отправить пост на стену, нужно сформировать запрос на серверной части сайта. Все необходимые данные мы получаем из встроенного массива $post (создается в момент изменения статус записи)

Для того, чтобы добавить картинку посту, грузим вложение на сервер, а после добавляем id, полученный от сервера к запросу в API. Затем, используя метод API wall.post отправляем запрос и пост появляется группе. В ответ приходит post_id, по которому можно легко найти наш опубликованный пост!

$post_image=$_SERVER['DOCUMENTROOT'].substr($post_image, strlen($_SERVER['SERVERNAME’])+8);
// Узнаем сервер VK куда будем запивать изображение,
$photoServerName=json_decode(file_get_contents('https://api.vk.com/method/photos.getWallUploadServer?group_id=’.$vkgroup.'&v=5.37&access_token=’.$vk_token));
// Заливаем изображение на сервер.
$photoServerUpload=json_decode(curlPost($photoServerName->response->upload_url, $post_image));
// Сохраняем изображение., как фото к посту на стене.
$photoServerSave=json_decode(file_get_contents('https://api.vk.com/method/photos.saveWallPhoto?group_id='.$vk_group.'&photo='.$photoServerUpload->photo.'&server='.$photoServerUpload- -server. 'fihash=' .photoServerUpload-J-hash. ' 8v=5.37&access_token=' .fvk_token)) j
//Узнаём ID залитого изображения.
uploadedPhotoID = $photoServerSave->response[0]->id;
// Формируем запрос для отправки поста.
$st_zap='https://api.vk.com/method/wall.post?owner_id»-'.$vk_group.'&friends_only=0&from_group=l&message='.urlencode($post_text).’attachments=';
// Если изображение было загружено., то добавляем его.
if(mb_strlen($uploadedPhotoID)) { $st_zap .= 'photo'.$photoServerSave->response[0]->owner_id.'_'.uploadedPhotoID.; }
// Добавляем 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 выделяем отдельно, для отправки запроса по нужному url-у.

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

Telegram

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

Бота нужно зарегистрировать и получить его id, являющийся в том числе и токеном. Для этого в Telegram существует специальный бот — @BotFather.

Отправляем сообщение /start и в ответ получаем список его методов.
Следом пишем — /newbot — отправляем и бот попросить придумать новое имя вашему боту. Название обязательно должно оканчиваться на «bot». В случае успеха BotFather возвращает токен бота и ссылку для быстрого добавления бота в контакты. Полученных данных достаточно для начала работы с API. Подключаем VPN и начинаем читать документацию.

Не забудьте проверить полученный токен с помощью ссылки

api.telegram.org/bot<TOKEN>/getMe

Для работы с запросами нам потребуется сервер за пределами РФ. Telegram заблокирован у нас в стране, поэтому обращения к API на российских хостерах не работают. Ищем любой бесплатный хостинг, создаем там обработчик запросов от нашего сайта, и спокойно отправляем и получаем нужные данные.

Конечная функция, которая отправляет в группу сообщение, приведена ниже:

function sendMessage($chatID, $articleLink, $articleExcerpt, $articlePictureUrl, $token) 
{ $finalMessage = $articleExcerpt . " " . $articIeLink;
$bot_url = "https://api.telegram.org/bot- . $token;
$url = $bot_url . "/sendPhoto?chat_id=" . $chatID ;
$post_fields = array('chat_id' => $chatID,
'photo'	=> $articlePictureUrl
'caption'	=> $finalMessage );
$ch = curl_init();
curl_setopt($ch, CURUDPTHTTPHEADER, array (
"Content - Type: multipart/form-data"
));
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER,1); curl_setopt($ch, CURLOFT_SAFE_UPLOAD, true); curl_setopt($ch, CURLOPT_POSTFIELDS, $post_fields); $output = curl_exec($ch);
echo $output;
curl_close($ch);
return $output;

Facebook*

Для того, чтобы получить доступ к работе с Facebook* API, нам потребуется создать приложение, разработать прототип, а после уже пройти App Review.

Создаем приложение по ссылке -> Сreate new App

После создания приложения, переходим на его страницу, и видим основные параметры приложения, которые понадобятся нам в будущем (App ID и App Secret):

Так как мы разрабатываем решение для сайта, правила Facebook* требуют наличия политики конфиденциальности на сайте. Ссылку на нее вставляем в поле Privacy Policy URL. После внизу нажимаем «Добавить платформу», выбираем Web App и прописываем в полях, где написано URL, название сайта.

Приложение будет реализовать функцию «Войти через Facebook*», соответственно все те страницы, которые будут использованы в прототипе нужно обязательно внести в поля «Действительные URI для перенаправления OAuth»

После подготовки всех нужных данных, приступаем к разработке прототипа.

Facebook* предоставляет свой SDK для работы с методами, поэтому качаем его с официального аккаунта на Github и включаем в проект. Так же можно подключить с использованием composer.

Для того, чтобы пройти App Review, нам понадобилось три страницы:

Первая страница должна обрабатывать данные постера и позволять пользователю получить тот самый заветный токен страницы через свою учетку Facebook*. Cама страница состоит из простейшей разметки HTML и скрипта Javascript, который шлет POST-запросы на наш callback.php

Вторая страница (callback.php) обрабатывает действия пользователя и выводит в конце токены к тем страницам, к которым он разрешил доступ.

Третья страница (sendpostfb.php) отправляет данные поста в Facebook*.

На всех страницах всегда проверяем сессию:

If (!session_id()) {     session_start();
}
require_once _DIR_ . ‘/facebook/autoload.php'; // инклудим SDK от FACEBOOK
$fb = new Facebook\Facebook([
'app_id' => '', //Замените на ваш id приложения 
'app_secret' => '' //Ваш секрет приложения
]);

Добавляем в наш запрос к файлу callback.php разрешения, которые хотим получить от пользователя.

$helper = $fb->getRedirectLoginHelper() ;
//Добавьте разрешение publish_actions, чтобы постить от имени пользователя, а не от имени страницы $permissions = ['manage_pages','publish_pages'];
$loginUrl = $helper->getLoginUrl('https://your-url.ru/callback.php', $permissions);

Код страницы, которую покажем пользователю:

echo '<p style="color: blue;"> Текст вашего поста </p>';
echo '<span id="post-text"> ' . $postText . '</span>';
echo '<p style="color: blue;"> Ссылка на пост </p>';
echo '<p id="post-link"> ' . $postLink . '</p>';
echo '<p> Введите здесь ID страницы, куда будет размещаться пост. Он потребуется как для размещения поста, так и для получения токена доступа Facebook </p>';	
echo '<input id="pageid-fb"></br>';

echo '<a id="fb-token" href="' . htmlspecialchars($loginUrl) . '"  target="_blank">Получить токен facebook ( пользовательский и страницы ) ( при отсутствии )</a>';
echo '<p> Если у вас нет токена для вашей страницы Facebook, получите его по ссылке выше. Если у вас есть токен, просто введите его в поле ниже. </p>';
echo '<p> Впишите сюда ваш токен страницы Facebook </p>';
echo '<input id="accesstoken-fb"></br>';
echo '<button id="facebook-post"> Разместить пост в Facebook </button>';

По клику на кнопку “facebook-post” отправляем пост на страницу. В дальнейшем, после App Review, необходимость в данной странице отпала и в действии оставили только код, который отправляет пост, с некоторыми доработками.

Страница callback.php содержит в себе код, который позволяет пользователю перейдя в Facebook* дать разрешения к страницам, в которых пользователь имеет права администратора, а после возвращает в виде ответа массив с токенами (если страниц несколько). Нам в полученном ответе нужны только access_token и pageID. Их используем на предыдущей странице размещения поста.

Важный момент: сессия при получении токена не должна отличаться, иначе fb sdk вернет ошибку вместо токена.

if(!session_id()) {
    session_start();
}
require_once __DIR__ . '/facebook/autoload.php';
$fb = new Facebook\Facebook([
	  'app_id' => '', //Замените на ваш id приложения
	  'app_secret' => '' //Ваш секрет приложения
]);
$helper = $fb->getRedirectLoginHelper();
	
try { 
    $accessToken = $helper->getAccessToken();	
}

catch(Facebook\Exceptions\FacebookResponseException $e) { 
    echo 'Graph вернул ошибку: ' . $e->getMessage();
    exit;
	
}

catch(Facebook\Exceptions\FacebookSDKException $e) {	  
    echo 'Facebook SDK вернул ошибку: ' . $e->getMessage();
    exit;	
}

if (isset($accessToken))
     $_SESSION['facebook_access_token'] = (string) $accessToken;

elseif ($helper->getError())
    exit;

try {	
	$response = $fb->get('/me/accounts', $_SESSION['facebook_access_token']);
	$response = $response->getDecodedBody();		
}
		
catch (Facebook\Exceptions\FacebookResponseException $e) {		
	echo 'Graph вернул ошибку: ' . $e->getMessage();
	exit;		
}
		
catch (Facebook\Exceptions\FacebookSDKException $e) {		
	echo 'Facebook SDK вернул ошибку: ' . $e->getMessage();
	exit;		
}

//Токен страницы
print_r($response);

Ну и наконец код страницы, которая непосредственно отправляет пост в Facebook*:

$str_page = '/' . $pageID . '/feed';
$feed = array('message' => $postText , "link" => ‘');
try {	
	$response = $fb->post($str_page, $feed, $accessToken);
}		
catch (Facebook\Exceptions\FacebookResponseException $e) {	
	echo 'Graph вернул ошибку: ' . $e->getMessage();
	exit;		
}	
catch (Facebook\Exceptions\FacebookSDKException $e) {		
	echo 'Facebook SDK вернул ошибку: ' . $e->getMessage();
	exit;		
}	
$graphNode = $response->getGraphNode();
echo 'Опубликован пост, id: ' . $graphNode['id'];	
?>

После разработки и тестирования, готовим текст запроса в App Review.

При отправке запроса, мы должны предоставить:

А) Текст описания интеграции, с подробностями, зачем нам нужны эти функции и как пользователь будет ими пользоваться

Б) Видео (cкринкаст ), который явно покажет, как будет использоваться ваше приложение.

Само окно запроса выглядит так:

Важные рекомендации, следуя которым, вы сможете увеличить шанс успешного прохождения проверки:

  1. Расписывайте все подробно. Сотрудники Facebook* не будут разбираться или думать, куда им нажать лишний раз. Они выполняют ваши инструкции и, если где-то что-то идет не по плану, сразу пишут отказ без пояснения причин.
  2. Путь, по которому будет идти проверка, должен быть максимально простым. Все кнопки, переходы и ссылки должны быть на виду.
  3. Мы писали текст на русском и английском. Думаю, это тоже критично влияет.
  4. Записывая скринкаст, делайте все не в быстром темпе, и обязательно делайте остановки и показывайте места, где проверяющий может ошибиться. Либо заранее предусматривайте все подводные камни и закрывайте их.

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

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

* — Признана экстремистской организацией и запрещена на территории Российской Федерации