Главная > Сайт > Кросспостинг статей из WordPress в PhpBB

Кросспостинг статей из WordPress в PhpBB

Я - постоянный читатель форумов Oszone (правда, не очень регулярный, да ну не суть). Есть одна фича, которую реализовали создатели ресурса - дублирование новостей сайта на форуме в специальном разделе. Это реально удобно в первую очередь для посетителей форума: увидел новые посты, понравилось что - пошел и прочитал. Короче, я решил реализовать подобное для Winreview.

На нашем сайте [теперь] используется WordPress и система форумов PhpBB, девственно чистая в плане модов. Имеющиеся готовые плагины трансляции WordPress в PhpBB меня не устроили: почти все у меня тупо не заработали, а последний, якобы гарантировано работающий, поверг меня в уныние тем, что предполагал модификацию движка PhpBB (и потенциальные грабли с его будущим обновлением, ну уж нет). Задача кросспостинга статей из WordPress в PhpBB на самом деле не настолько сложная, чтобы не поддаться соблазну сваять собственный велосипед с квадратными колёсами плагин для WordPress. Я не устоял и через час он был готов. Хотите узнать, что у меня получилось? Читайте продолжение статьи.

Не буду лукавить, в гостях у базы данных PhpBB я не в первый раз. Были другие задачи, связанные с добавлением данных в форум. Я поделюсь с вами алгоритмом, который я давно вывел для себя и который необходим и достаточен для размещения нового поста программно.

Исходные данные для программного постинга в PhpBB

Мне понадобилась следующая информация.

  • Параметры подключения к базе данных PhpBB.
  • Пользователь, который будет якобы постить новости. Необходимо получить его индентификатор, имя, айпи, и цвет ника.
  • Идентификатор форума. Это номер форума, в который будут публиковаться новости с движка WordPress. Каждую статью я буду размещать в отдельную тему, как на Oszone.

Запись данных в таблицы PhpBB

При "прямой" записи в таблицы форума PhpBB очень важно соблюдать заполнение тех полей, значения которых необходимы для корректной работы форума. Это поля для отображения данных, а также различная статистика, вроде счётчиков сообщений/постов/тем. Рассмотрим основные таблицы, которые необходимо обновить при постинге сообщения и темы.

Таблица phpbb_topics

Здесь и далее по тексту используется префикс таблиц форума по умолчанию.

Начать надо с таблицы phpbb_topics, она содержит названия тем форума. Поля, которые по моему мнению следует заполнить:

forum_id — идентификатор форума, в котором появится новая тема.

topic_approved — ожидает ли тема одобрения модератора. Сюда надо записать 1 — тема одобрена.

topic_title — название темы.

topic_poster — идентификатор пользователя, создавшего тему (user_id).

topic_time — дата создания форума, сюда пишется значение функции time().

topic_views — количество просмотров темы. Можно просто единицу записать.

topic_replies — количество постов в теме.

topic_last_post_id — идентификатор последнего поста из таблицы phpbb_posts, относящийся к этой теме.

topic_last_poster_id — автор последнего поста (user_id из phpbb_users).

topic_last_poster_name — имя(ник) автора последнего поста (user_name из phpbb_users).

topic_last_poster_colour - цвет ника автора первого поста (user_colour оттуда же).

topic_last_post_time — время размещения последнего поста.

topic_first_post_id — идентификатор первого поста

topic_first_poster_name — ник автора первого поста.

topic_first_poster_colour — цвет ника автора первого поста.

topic_last_view_time — время последнего просмотра темы.

 

Таблица phpbb_posts

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

topic_id — идентификатор темы из phpbb_topics

forum_id — идентификатор форума, которому принадлежит тема, в которую мы постим. Здесь и не только здесь движок использует избыточность данных в целях снижения нагрузки на сервер БД.

poster_id - ник автора сообщения (user_id из phpbb_users).

poster_ip — айпи адрес, с которого было оставлено сообщение.

post_time — время сообщения.

post_approved — одобрен ли пост. Пишем 1 — одобрен.

post_text — непосредственно текст сообщения.

post_subject — тема сообщения. В штатном режиме сюда пишется «Re: название темы».

 

Если post_text предполагает наличие bb code, придется заполнить ещё два поля:

bbcode_uid — внутренний уникальный идентификатор доски phpbb

bbcode_bitfield — шифрованная битовая маска, определяющая, какие bb-коды можно обрабатывать при выдаче контента поста в HTML виде. Вообще, этот вопрос тянет на отдельную статью. Если кому-то будет интересно, я поделюсь своими наработками в этом направлении, а сейчас я скажу одно — постить bb code я не собираюсь: можно получить HTML разметку WordPress, и записать её в PHPBB. Она будет корректно отображаться в форуме, но пост при этом не редактируется (редактируется, но вся разметка к чертям слетает). В контексте кросспостинга меня это нисколько не волнует, и конвертер «HTML->BB код» я писать не стал.

 

Таблица phpbb_forums

После того, как создана тема и помещен пост, требуется рекурсивно пройтись по записям в таблице phpbb_forums. Здесь типичная иерархия «предок-потомки», где для каждого предка обновляются поля со статистикой:

forum_posts — количество одобренных модератором тем в форуме.

forum_posts_real — количество тем, включая ожидающие одобрения

forum_posts — количество постов в темах форума.

Эти поля в phpbb обновляются только для форума последнего уровня, т. е. который содержит темы, а не только вложенные подфорумы.

 

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

 

Таблица phpbb_users

В таблице phpbb_users следует для пользователя, от имени которого выполняется кросспостинг, обновить:

user_posts — счётчик количества сообщений пользователя.

user_lastpost_time — время последнего сообщения.

Ну и user_lastvisit - время последнего посещения, из соображений эстетики.

Таблица phpbb_topics_posted

Это самая простая часть задачи, в эту таблицу нужно занести topic_id, user_id и в поле topic_posted единицу.

Реализация со стороны WordPress

Я написал простейший плагин, вешающий на событие публикации поста (publish_post) функцию, выполняющее всё вышеописанное+получение данных по конкретной записи WordPress.

Из WordPress меня интересует ссылка на полный пост (get_permalink()), заголовок поста ($post->post_title), и так называемый анонс, всё, что до тега <!--more-->. Я получил его так:

$phpbb_post_text_ar = explode('<!--more-->', $post->post_content);

$phpbb_post_text = $phpbb_post_text_ar[0];

Здесь вообще нет ничего сложного, WordPress отлично документирован.

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

<?php

/*

Plugin Name: wp2phpbb

Plugin URI: http://winreview.ru

Description: Crossposting to phpbb forum.

Version: 1.0

Author: Happy Bulldozer

Author URI: http://winreview.ru

License: GPL2

*/

require('db.php');

require('config.php');

 

function wp2phpbb($post_ID)

{

global $dbhost,$dbuser,$dbpasswd,$dbname;

global $phpbb_user_id,$phpbb_user_name,$phpbb_user_ip,$phpbb_user_colour;

global $phpbb_forum_id;

 

$time = time();

$post = get_post($post_ID);

$phpbb_meta = get_post_meta($post_ID, 'phpbb', true);

if ($phpbb_meta!=1)

{

$phpbb_topic_title = $post->post_title;

$link = get_permalink($post_ID);

$phpbb_post_text_ar= explode('<!--more-->', $post->post_content);

$phpbb_post_text = '<span style="color: #0000FF"><span style="font-size: 150%; line-height: 116%;"><span style="font-weight: bold">'.$phpbb_topic_title.'</span></span></span><br />'.$phpbb_post_text_ar[0].'&nbsp;&nbsp;<a href="'.$link.'">Читать полностью...</a>';

$phpbb_success=false;

 

$phpbb=new db;

if (!$phpbb->db_Connect($dbhost , $dbuser, $dbpasswd , $dbname))

{

die('forum connection failed');

}

 

$query = 'insert into phpbb_topics

(forum_id,topic_approved,topic_title,topic_poster,topic_time,topic_views)

values

('.$phpbb_forum_id.',1,\''.$phpbb_topic_title.'\','.$phpbb_user_id.','.$time.', 0)';

$phpbb->db_Query($query,true);

$phpbb_topic_id = $phpbb->LAST_ID;

if ($phpbb_topic_id>0)

{

$query = 'insert into phpbb_posts

(topic_id,forum_id,poster_id,poster_ip,post_time,post_approved,

post_username,post_text,post_subject,bbcode_uid,bbcode_bitfield)

values ('.$phpbb_topic_id.','.$phpbb_forum_id.','.$phpbb_user_id.',\''.$phpbb_user_ip.'\','.$time.',1,

\'\',\''.$phpbb_post_text.'\',\''.$phpbb_topic_title.'\',\'\',\'\')';

$phpbb->db_Query($query,true);

$phpbb_post_id = $phpbb->LAST_ID;

if ($phpbb_post_id>0)

{

//recount num of replies and statistics

$query = 'update phpbb_topics tp,

(select topic_id,count(post_id)-1 as cnt from phpbb_posts where topic_id = '.$phpbb_topic_id.' group by topic_id) p

set topic_replies=p.cnt, topic_replies_real=p.cnt,

topic_last_post_id = '.$phpbb_post_id.',

topic_last_poster_id = '.$phpbb_user_id.',

topic_first_post_id = '.$phpbb_post_id.',

topic_first_poster_name = \''.$phpbb_user_name.'\',

topic_first_poster_colour = \''.$phpbb_user_colour.'\',

topic_last_poster_name = \''.$phpbb_user_name.'\',

topic_last_poster_colour=\''.$phpbb_user_colour.'\',

topic_last_post_time = '.$time.',

topic_last_view_time = '.$time.',

topic_views = 1

where tp.topic_id=p.topic_id and tp.topic_id = '.$phpbb_topic_id;

$phpbb->db_Query($query);

 

//recount forums messages & statistics

UpdateForumStats($phpbb, $phpbb_forum_id,$phpbb_post_id,$phpbb_user_id,$phpbb_user_name,$time,$phpbb_user_colour);

 

//user - post count & last visit

$query = 'update phpbb_users pu,

(select poster_id,count(post_id) cnt from phpbb_posts where poster_id = '.$phpbb_user_id.' group by poster_id) pc

set pu.user_posts=pc.cnt,

user_lastvisit = '.$time.',

user_lastpost_time = '.$time.'

where pu.user_id=pc.poster_id and pu.user_id = '.$phpbb_user_id;

$phpbb->db_Query($query);

 

//pointless table

$query = 'select count(topic_posted) cnt from phpbb_topics_posted where topic_id='.$phpbb_topic_id.' and user_id='.$phpbb_user_id;

$phpbb->db_Query($query);

$phpbb_topics_posted_row = $phpbb->db_Fetch();

$phpbb_topics_posted = $phpbb_topics_posted_row['cnt'];

if ($phpbb_topics_posted==0)

{

$query = 'insert into phpbb_topics_posted (topic_id,user_id,topic_posted)

values ('.$phpbb_topic_id.','.$phpbb_user_id.',1)';

$phpbb->db_Query($query);

}

$phpbb_success=true;

}

}

 

//add post_meta

 

update_post_meta($post_ID, 'phpbb',$phpbb_success ? '1' : '0');

}//post meta check

 

return $post_ID;

}

 

function UpdateForumStats($osql, $pforum_id,$pforum_last_post_id,$pforum_last_poster_id,$pforum_last_poster_name,$pforum_last_post_time,$pposter_colour,$current_level=true)

{

if($pforum_id>0)

{

 

$query='select parent_id,forum_posts,forum_topics,forum_topics_real from phpbb_forums where forum_id = '.$pforum_id;

$osql->db_Query($query);

$orow = $osql->db_Fetch();

$parent_id = intval($orow['parent_id']);

$forum_posts = intval($orow['forum_posts'])+1;

$forum_topics = intval($orow['forum_topics'])+1;

$forum_topics_real = intval($orow['forum_topics_real'])+1;

 

$query='update phpbb_forums set '.

($current_level ? 'forum_posts='.$forum_posts.',' : '').

($current_level ? 'forum_topics_real='.$forum_topics_real.',' : '').

($current_level ? 'forum_topics='.$forum_topics.',' : '').'

forum_last_post_id='.$pforum_last_post_id.',

forum_last_poster_id='.$pforum_last_poster_id.',

forum_last_poster_name=\''.$pforum_last_poster_name.'\',

forum_last_post_time='.$pforum_last_post_time.' ,

forum_last_poster_colour=\''.$pposter_colour.'\'

where forum_id = '.$pforum_id;

$osql->db_Query($query);

//strange, but phpbb uses 'forum_posts' update only for current level

UpdateForumStats($osql, $parent_id,$pforum_last_post_id,$pforum_last_poster_id,$pforum_last_poster_name,$pforum_last_post_time,$pposter_colour,false);

}

 

}

add_action('publish_post', 'wp2phpbb');

В файле db.php находится простейший класс для работы с сервером MySQL, на деле представляющий собой пародию на более мощный класс CMS e107. Для этой задачи его должно хватить.

В файле config.php задаются параметры подключения к базе данных форума phpbb и все параметры пользователя, от имени которого выполняется кросспостинг.(так быстрее). Ну и само собой, ИД форума, в который будут размещаться новости.

Вы можете скачать всё, что у меня получилось: скачать плагин.

Демонстрация работы плагина.

Конечно, называть это полноценным или качественным решением нельзя, это по сути костыль, написанный на коленке. Я вовсе не претендую на оригинальность и не пытаюсь самоутвердиться при помощи демонстрации кода, который и написан то не самым лучшим образом. Просто я надеюсь, что, увидев эту публикацию, кто-то более талантливый сядет и напишет достойный плагин, полнофункциональный в плане кросспостинга, без миллиарда правок PhpBB, без тонны ненужных функций, плагин, который принесет пользу пользователям решений WordPress + PhpBB, коих немало. Если вы один из таких разработчиков — я буду рад обсудить ваши идеи и мнение в комментариях, и попробую быть полезен настолько, насколько смогу.

Winreview.ru можно найти в Вконтакте, Facebook и Twitter. Присоединяйтесь!

Комментарии

  1. ilgiz2690

    А где котенок?

  2. Сергей Ткаченко

    Чёрт, и правда забыл )

  3. Angel of Despair

    Сделай еще виджет последних постов с форума на главную. Ну, не в смысле себе, а чтобы было )

  4. Сергей Ткаченко

    А вот такие виджеты мне где-то попадались в репозитории плагинов WordPress. Наверняка хотя бы один из них работает (уж выборку-то просто написать, я щитаю).

  5. Zloy

    ilgiz2690

    А где котенок?

    Я вот тут подумал, кого могут привлечь котята? Только детей. Надо бы девушек голых постить или компы разобранные (на любителя).

  6. Сергей Ткаченко

    @Zloy
    Неправда, котята всем нравятся

  7. Дмитрий

    Zloy

    Я вот тут подумал, кого могут привлечь котята? Только детей. Надо бы девушек голых постить или компы разобранные (на любителя).

    Девки жгут, поддерживаю на 100%)))) Админ, просим исправить))

  8. ЁжЫГ

    чтоб никому не было обидно

    Голые девки с котятами на руках и... (или) прочих частях тела в интерьере разобранных компов D

  9. AZ

    Друг, огромное тебе спасибо! С этой долбаной интеграцией чуть с ума не сошел уже. Сам не программист, но твое решение адаптировать тыковки хватит )

  10. Сергей Ткаченко

    @AZ
    Всегда пожалуйста. Я сам, откровенно говоря, не программист. Вот подобные костыли подчас являются для меня потолком.

    Рад, что пригодилось и оказалось полезным.

  11. AZ

    Потестил плагин - работает отлично.

    Ссылки на форуме ставит правильно, с учетом транслитерации URL

    Не хватает только одной мульки - в блоге на вордпрессе ставить ссылку после всего текста "Обсудить на форуме" )

    Если вдруг решишь дальше развивать плагин, было бы здорово добавить.

    Еще раз спасибо за полезную вещь!

  12. Сергей Ткаченко

    @AZ
    Всегда. Ссылку можно прикрутить, если доработать плагин. Соответствие №записи Wordpress->ИД темы на форуме уже ведется в метаданных записи Wordpress

  13. R.S.

    Приветствую!

    Наверное я совсем чайник, но у меня не получается кросспостинг с помощью этого плагина.

    Если я правильно поняла, то нужно править только файл config.php

    $dbhost = 'your_database_server'; - откуда брать данные? Или нужно указать 'localhost'?

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

    Как узнать в чем причина того, что плагин не работает у меня?

    Заранее спасибо!

  14. Сергей Ткаченко

    $dbhost = ‘your_database_server’; - это сервер, на котором крутится база phpbb3

    Вроде, ничего больше не надо.

    Если надо, можем пообщаться в аське/скайпе/в какой-нибдуть ещё херне, я попробую помочь.

    hb860live.ru - моё мыло, можете сбросить контактную инфу свою.

  15. R.S.

    @Сергей Ткаченко

    Я Вам отправила письмо. Пока у меня ничего не выходит - все настройки взяла из файла config.php форума. Может быть дело в префиксах?

  16. Виктор

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

  17. Сергей Ткаченко

    @Виктор
    Он публикует всё, что до

    Можно изменить код плагина и публиковать всё, что возвращает the_excerpt

  18. Артем Шматок

    Не могу разобраться, какая функция отвечает за создание значения bbcode_bitfield ?

  19. Сергей Ткаченко

    @Артем Шматок
    Артем, не забивайте голову.

    Вот вам расшифровка

    The bitfield is a base64 encoded binary.

    Since the bitfield currently holds 13 bits, each switching on/off 1 BBCode tag, 2 BYTEs are used (aka 1 WORD)

    1 Quote

    2 B

    3 I

    4 Url

    5 Img

    6 Size (Font)

    7 Color (Font)

    8 U

    9 Code

    10 List

    11 Email

    12 Flash

    13 Attachment

    14 Filling, 0

    15 Filling, 0

    16 Filling, 0

    lNg= is Base64 and decodes to 94 D8 (Hex).

    94 D8 = 38104 = 1001010011011000 = Quote, Url, Size, Code, List, Flash, Attachment.

    kNg= is Base64 and decodes to 90 D8 (Hex).

    90 DB = 37080 = 1001000011011000 = Quote, Url, Code, List, Flash, Attachment.

    Значение, которое вам позволит использовать ВСЕ кода, вот такое $bbcode_bitfield='////';

Написать комментарий