Кросспостинг из Drupal в ВК своими руками

Главные вкладки

Аватар пользователя edhel edhel 12 апреля 2013 в 19:50
  1. Создаём группу в ВК, допустим её id будет 111.
  2. Регистрируем приложение в ВК типа standalone (http://vk.com/editapp?act=create), допустим id его будет 222.
  3. Получаем токен для доступа к API: в браузере открываем ссылку http://oauth.vk.com/authorize?client_id=222&scope=offline,wall&redirect_.... Берём токен из адресной строки после редиректа, допустим AABBCC.
  4. Добавляем в нужный тип материала (допустим news) cck-поле с чекбоском (репостить ноду в ВК или нет). Можно и без чекбокса, если надо репостить все материалы.
  5. Создаём таблицу в БД для сохранения соответствий между нодами и постами в ВК:
    CREATE TABLE IF NOT EXISTS vk_node (
      nid int(10) unsigned NOT NULL,
      post_id int(10) unsigned NOT NULL,
      PRIMARY KEY  (nid)
    )
  6. Создаём модуль на drupal (ниже примеры кода для drupal 6). Минимальный состав функций: хук nodeapi и две функции, код которых ниже.
  7. В хук nodeapi добавляем вызов функции _vk_post, который будет делать синхронизацию с ВК:
    
    	if ($node->type=='news' && ($op=='insert' || $op=='delete' || $op=='update')) {
    		_vk_post($node);
    	}
    
    
  8. Функция для вызова API ВК:
    
    function _vk_invoke($name, array $params = array()) {
    	$params['access_token'] = 'AABBCC';
    	$params['owner_id'] = -111; // группа
    	foreach ($params as $key => $value) {
    		$q[] = "$key=" . urlencode($value);
    	}
    	$q = join("&", $q);
    	$content = file_get_contents("https://api.vk.com/method/$name?$q");
    	$result  = json_decode($content);
    	return $result->response;
    }
    
    
  9. И основная функция синхронизации с ВК:
    
    function _vk_post($node) {
    	$post_id = db_result(db_query("SELECT post_id FROM {vk_node} WHERE nid = %d", $node->nid));
    	$vk_on = $node->status && $node->field_news_vk[0]['value'] && ($node->language == '' || $node->language == 'ru');
    
    	if ($vk_on) {
    		$message = "$node->title:\n\n" . preg_replace("/\s+/ms", " ", node_view($node, TRUE, TRUE, FALSE));
    		$message = preg_replace("|</p>|ims", "</p>\n\n", $message);
    		$message = preg_replace("|<br ?/?>|ims", "<br/>\n", $message);
    		$message = html_entity_decode(strip_tags($message), ENT_QUOTES, "utf-8");
    		$attachments = url("node/$node->nid", array('absolute' => TRUE));
    	}
    
    	// нужно добавить
    	if (!$post_id && $vk_on) {
    		$response = _vk_invoke('wall.post', array(
    			'friends_only' => 0, 
    			'from_group' => 1, 
    			'message' => $message,
    			'attachments' => $attachments,
    		));
    		if ($response && $response->post_id) {
    			db_query("INSERT INTO {vk_node} (nid, post_id) VALUES (%d, %d)", $node->nid, $response->post_id);
    			drupal_set_message('Новость добавлена ВКонтакте.');
    		}
    		else {
    			drupal_set_message('Не удалось добавить новость ВКонтакте.', 'warning');
    		}
    	}
    	// нужно обновить
    	elseif ($post_id && $vk_on) {
    		$response = _vk_invoke('wall.edit', array(
    			'post_id' => $post_id, 
    			'message' => $message,
    			'attachments' => $attachments,
    		));
    		if ($response) {
    			drupal_set_message('Новость обновлена ВКонтакте.');
    		}
    		else {
    			drupal_set_message('Не удалось обновить новость ВКонтакте.', 'warning');
    		}
    	}
    	// нужно удалить
    	elseif ($post_id && !$vk_on) {
    		$response = _vk_invoke('wall.delete', array(
    			'post_id' => $post_id, 
    		));
    		if ($response) {
    			drupal_set_message('Новость удалена ВКонтакте.');
    		}
    		else {
    			drupal_set_message('Не удалось удалить новость ВКонтакте.', 'warning');
    		}
    		db_query("DELETE FROM {vk_node} WHERE nid=%d", $node->nid);
    	}
    
    }
    
    

    Во второй строчке тела — проверка чекбокса. Если не нужна, то надо убрать $node->field_news_vk[0]['value'].

    В строке, где вызывается node_view, можно поменять формат вывода текста в ВК, состав выводимых полей и т. п. У меня она выглядит так (выводится конкретное текстовое cck-поле):

    $message = "$node->title:\n\n" . preg_replace("/\s+/ms", " ", check_markup($node->field_news_text[0]['value'], $node->field_news_text[0]['format'], FALSE));

Пример работы: отсюда http://news.sfu-kras.ru/ репост сюда http://vk.com/sfu_news.

Комментарии

Аватар пользователя edhel edhel 12 апреля 2013 в 20:47

Чтобы сделать задержку, надо вместо nodeapi выполнять вызов _vk_post в хуке cron для всех нод, которые были изменены с последнего запуска. Это строчек 5-10.

Аватар пользователя Lotar Lotar 12 апреля 2013 в 22:31

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

Аватар пользователя edhel edhel 13 апреля 2013 в 4:20

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

А я не расстроен и видел этот модуль) У готовых модулей зачастую есть недостатки: 1) они избыточны, 2) они не всегда могут сделать именно точно так, как хочется.

Например, в данном случае, судя по исходникам (по правде не тестил в живую): посты не удаляются при удалении или снятии с публикации, нельзя выбрать для отправки конкретное cck-поле, вроде посты не обновляются при изменении ноды. Кстати не вижу ничего такого в коде, чтобы говорило об отложенном кросспостинге. Из плюсов: прикрепляет фото к посту, если нужно.

Мне, как программисту, иногда проще написать самому, чем вешать 100 модулей и потом спрашивать на форумах как заставить их работать так, как хочется)

Аватар пользователя est est 4 июня 2013 в 12:16

"Lotar" wrote:
Не хочу вас расстраивать уважаемый автор, но есть хороший модуль написанный участником нашего сообщества. И он именно так называется и именно это делает.

"Lotar" wrote:
Я же сказал так и называется http://drupal.org/project/vkxp[/quote]
Комментарий автора насчет D6.

Аватар пользователя est est 4 июня 2013 в 13:05

"qwiste" wrote:
во первых о кросспостинге:
вариант крайне спорный, людей возможно не интересуют такие сообщения
если вы отдаете вконтакту без задержки содержимое сайта поисковик думает что вы воруете у вконтакта (как итог санкции от ПС)
кросспост вообще неоднозначное дело.

Вряд ли, ведь с VK ссылка ведет на ваш сайт, а не наоборот.

Аватар пользователя Atonyk Atonyk 11 октября 2013 в 2:09

edhel, большое спасибо за модуль. Долго не мог найти ничего подходящего. Все работает отлично!

Единственно, я поменял функцию:

<?php
function _vk_repost_is_proper_type($node) {
    
$content_type variable_get('vk_repost_content_type''');
    
$types explode(','$content_type);
    foreach(
$types as $type){
        if(
$node->type == trim($type)){
            return 
true;
        }
    }
    return 
$content_type == '';
}
?>

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

И поменял:
<?php$message = preg_replace("/\s+/ms", " ", node_view($node, TRUE, TRUE, FALSE));?>
на
<?php$message = preg_replace("/\s+/ms", " ", $node->teaser);?>
Чтобы не полные статьи публиковались, а только анонсы.

Аватар пользователя est est 25 октября 2013 в 17:00

Где-то с неделю как прекратился перепост на VK. Полез разбираться - токен изменился. Знает кто-нибудь, в связи с чем его меняют? Можно ли управлять длительностью жизни токена?

Аватар пользователя reddiamond reddiamond 18 декабря 2013 в 23:28

"reddiamond" wrote:

А как для 7 получить токен? по ссылке когда переходишь открывается страница с ошибкой


Разобрался со своей проблемой, т.к. на сайте стоял редирект уводило ссылку на http://my-site.ru/go/6328?client_id=4066765&scope=wall%2Cgroups%2Cphotos...
В начале поменял http://my-site.ru/go/6328 на https://oauth.vk.com/authorize? и все заработало