Я - постоянный читатель форумов Oszone (правда, не очень регулярный, да ну не суть). Есть одна фича, которую реализовали создатели ресурса - дублирование новостей сайта на форуме в специальном разделе. Это реально удобно в первую очередь для посетителей форума: увидел новые посты, понравилось что - пошел и прочитал. Короче, я решил реализовать подобное для Winreview.
На нашем сайте [теперь] используется WordPress и система форумов PhpBB, девственно чистая в плане модов. Имеющиеся готовые плагины трансляции WordPress в PhpBB меня не устроили: почти все у меня тупо не заработали, а последний, якобы гарантировано работающий, поверг меня в уныние тем, что предполагал модификацию движка PhpBB (и потенциальные грабли с его будущим обновлением, ну уж нет). Задача кросспостинга статей из WordPress в PhpBB на самом деле не настолько сложная, чтобы не поддаться соблазну сваять собственный велосипед с квадратными колёсами плагин для WordPress. Я не устоял и через час он был готов. Хотите узнать, что у меня получилось? Читайте продолжение статьи.
Исходные данные для программного постинга в 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-->. Я получил его так:
[code]$phpbb_post_text_ar = explode('<!--more-->', $post->post_content);
$phpbb_post_text = $phpbb_post_text_ar[0];[/code]
Здесь вообще нет ничего сложного, WordPress отлично документирован.
Плагин, который у меня получился, выглядит так:
[code]<?php
/*
Plugin Name: wp2phpbb
Plugin URI: https://winreviewer.com
Description: Crossposting to phpbb forum.
Version: 1.0
Author: Happy Bulldozer
Author URI: https://winreviewer.com
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].' <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');[/code]
В файле db.php находится простейший класс для работы с сервером MySQL, на деле представляющий собой пародию на более мощный класс CMS e107. Для этой задачи его должно хватить.
В файле config.php задаются параметры подключения к базе данных форума phpbb и все параметры пользователя, от имени которого выполняется кросспостинг.(так быстрее). Ну и само собой, ИД форума, в который будут размещаться новости.
Вы можете скачать всё, что у меня получилось: скачать плагин.
Конечно, называть это полноценным или качественным решением нельзя, это по сути костыль, написанный на коленке. Я вовсе не претендую на оригинальность и не пытаюсь самоутвердиться при помощи демонстрации кода, который и написан то не самым лучшим образом. Просто я надеюсь, что, увидев эту публикацию, кто-то более талантливый сядет и напишет достойный плагин, полнофункциональный в плане кросспостинга, без миллиарда правок PhpBB, без тонны ненужных функций, плагин, который принесет пользу пользователям решений WordPress + PhpBB, коих немало. Если вы один из таких разработчиков — я буду рад обсудить ваши идеи и мнение в комментариях, и попробую быть полезен настолько, насколько смогу.
💡Узнавайте о новых статьях быстрее. Подпишитесь на наши каналы в Telegram и Twitter.
А где котенок?
Чёрт, и правда забыл 🙂
Сделай еще виджет последних постов с форума на главную. Ну, не в смысле себе, а чтобы было 🙂
А вот такие виджеты мне где-то попадались в репозитории плагинов WordPress. Наверняка хотя бы один из них работает (уж выборку-то просто написать, я щитаю).
Я вот тут подумал, кого могут привлечь котята? Только детей. Надо бы девушек голых постить или компы разобранные (на любителя).
Неправда, котята всем нравятся
Девки жгут, поддерживаю на 100%)))) Админ, просим исправить))
чтоб никому не было обидно:
Голые девки с котятами на руках и… (или) прочих частях тела в интерьере разобранных компов 😀
Друг, огромное тебе спасибо! С этой долбаной интеграцией чуть с ума не сошел уже. Сам не программист, но твое решение адаптировать тыковки хватит 🙂
Всегда пожалуйста. Я сам, откровенно говоря, не программист. Вот подобные костыли подчас являются для меня потолком.
Рад, что пригодилось и оказалось полезным.
Потестил плагин — работает отлично.
Ссылки на форуме ставит правильно, с учетом транслитерации URL
Не хватает только одной мульки — в блоге на вордпрессе ставить ссылку после всего текста «Обсудить на форуме» 🙂
Если вдруг решишь дальше развивать плагин, было бы здорово добавить.
Еще раз спасибо за полезную вещь!
Всегда. Ссылку можно прикрутить, если доработать плагин. Соответствие №записи WordPress->ИД темы на форуме уже ведется в метаданных записи WordPress
Приветствую!
Наверное я совсем чайник, но у меня не получается кросспостинг с помощью этого плагина.
Если я правильно поняла, то нужно править только файл config.php
$dbhost = ‘your_database_server’; — откуда брать данные? Или нужно указать ‘localhost’?
C остальным все более-менее понятно. Нужно ли еще куда-то вносить изменения, чистить кэши или какие-то дополнительные действия?
Как узнать в чем причина того, что плагин не работает у меня?
Заранее спасибо!
$dbhost = ‘your_database_server’; — это сервер, на котором крутится база phpbb3
Вроде, ничего больше не надо.
Если надо, можем пообщаться в аське/скайпе/в какой-нибдуть ещё херне, я попробую помочь.
hb860[собако]live.ru — моё мыло, можете сбросить контактную инфу свою.
@Сергей Ткаченко
Я Вам отправила письмо. Пока у меня ничего не выходит — все настройки взяла из файла config.php форума. Может быть дело в префиксах?
Просто и со вкусом спасибо, вот только жаль что посты полностью публикует, не плохо было бы только анонсы, и возможность картинки при не обходимости убрать, хотя это при помощи php просто.
Он публикует всё, что до
Можно изменить код плагина и публиковать всё, что возвращает the_excerpt
Не могу разобраться, какая функция отвечает за создание значения bbcode_bitfield ?
Артем, не забивайте голову.
Вот вам расшифровка:
Значение, которое вам позволит использовать ВСЕ кода, вот такое:
$bbcode_bitfield='////';