Я - постоянный читатель форумов 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='////';