Делаем из записей WordPress быструю CMS
Вторник, 18 декабря 2007 г.
Просмотров: 1723
Подписаться на комментарии по RSS
Совершенно не уверен, что данный пост имеет какое-то практическое значение. Поэтому будем думать, что это нужно для ознакомительных целей. Так сказать, введение в CMS.
Итак задача - нужно взять все записи из WordPress и сделать «движок», работающий с этими записями. Наличие минимальной навигации обязательно.
Первая часть задачи решается довольно просто. Алгоритм такой:
- Нужно подключиться к базе данных WordPress.
- Выполнить запрос и сохранить каждую запись в отдельный файл.
Для начала сделаем на сервере отдельный каталог, например «text». В нем будет подкаталог «txt» (установите на него права 777), где будут храниться наши тексты.
Для получения данных из базы создадим в «text» файл update.php:
<?php
require_once('../wp-config.php');
function fr($fn, $msg = '') {
$fp = fopen( dirname( __FILE__ ) . '/txt/' . $fn . '.txt', "w");
fwrite($fp, $msg);
fclose($fp);
}
function go() {
global $wpdb;
$request = "SELECT ID, post_title, post_date, post_content
FROM $wpdb->posts
WHERE post_status = 'publish'
ORDER BY ID";
$posts_new = $wpdb->get_results($request);
if ( $posts_new ) {
$arr_all = array();
foreach ($posts_new as $p) {
$m = $p->post_title;
$m .= "\n";
$m .= $p->post_date;
$m .= "\n";
$m .= wpautop($p->post_content);
fr($p->ID, $m);
$arr_all[$p->ID] = $p->post_title;
}
fr('all', serialize($arr_all) );
}
echo '... update';
}
go();
?>
Теперь разбираем код.
Функция fr() принимает имя файла (точнее его ID) и текст, которые в него записывает. Путь берется относительно каталога скрипта. Расширение файла всегда «.txt».
Функция go() собственно и выполняет всю нужную нам работу. Также обратите внимание, что в начале скрипта мы подключили wp-config.php. Сделано это по той причине, чтобы не загромождать код собственными функциями работы с БД.
Теперь нам доступен класс для работы с БД, и мы пишем простенький запрос и получаем в массиве все записи.
Сразу определимся как будут храниться записи в файлах. Очевидно, что нам нужны:
- Заголовок
- Дата
- Текст
- ID (номер) записи
Теперь в файл записываем: в первой строчке заголовок, второй - дата, остальные - текст.
Текст мы пропускаем через вордпрессовскую функцию wpautop(), которая расставляет все html-тэги перед публикацией.
Номер записи у нас будет равен имени файла + «.txt».
Попутно мы делаем еще один файл «all.txt», в котором сохраним массив всех записей вида «[ID] => [Заголовок]». Но сам массив $arr_all мы серилизуем, то есть преобразуем с строку. В самом «движке» мы сделаем обратную операцию и получим полностью готовый к использованию массив данных.
Скрипт получился достаточно простой и если запустить его, то в «txt» появятся файлы с записями.
Следующий скрипт (index.php) немного сложнее, но разобраться с ним думаю тоже не составит труда. Вначале некоторые основные принципы.
- Страницы мы будем вызывать в виде сайт/text/?12 - это значит, что нужно отобразить запись №12.
- Если номер записи не указан, то отобразим список всех записей. Можно ввести ограничение на количество.
- Если запись указана, то выводим её и делаем навигацию «Предыдущая - следующая записи».
- Для оформления будем использовать мастер-шаблон, где в нужных местах пропишем специальные-метки, которые и буду заменены на нужную информацию.
Данный скрипт будем рассматривать по частям.
$this_host = 'http://сайт/text/'; // путь к сайту $this_query = $HTTP_SERVER_VARS['QUERY_STRING']; $this_query = (int) trim($this_query); if ( $this_query < 1 ) go_index(); // нет запроса или ошибочный else go($this_query); // вроде нормальный запрос
Здесь мы получаем строку запроса и выполняем небольшую проверку, чтобы она была корректной. Если в будущем, вы решите как-то модернизировать скрипт, то именно в этой части можно определить нужные действия по входящему запросу. У нас же сейчас управление передается на две функции - go_index() - для отображение главной страницы, и go() - для отображение указанной записи.
Функция go_index() немного проще, начнем с неё:
function go_index() {
global $this_host;
$home = '<a href="' . $this_host . '">Главная</a>';
$template = file_get_contents('template.html');
$template = str_replace('%navigation%', navigation(), $template);
$template = str_replace('%home%', '', $template);
$template = str_replace('%home_top%', $home, $template);
$template = str_replace('%header%', 'Супер-пупер система', $template);
$template = str_replace('%date%', 'Ура!', $template);
$template = str_replace('%text%', 'Привет!', $template);
@header('Content-type: text/html; charset=utf-8');
echo $template;
}
Тут пример того, как работает парсинг шаблона. Принцип такой: есть файл template.html, который содержит полный html с вашим дизайном и всё-такое. Те места, которые требуются менять динамически, мы в самом шаблоне отмечаем в виде служебных меток. Теперь мы считываем весь шаблон, пердварительно подготавливаем изменяемые данные, например дата или заголовок, и выполняем простую замену. У меня используются метки в виде %метка%:
- %navigation% - блок навигации внизу
- %home% - ссылка на главную страницу
- %home_top% - ссылка на главную, только вверху
- %header% - заголовок
- %date% - дата
- %text% - текст заметки
Как видите функция довольно проста и легко настраивается под себя.
Описание функций навигации, парсинга чуть ниже.
Следующая функция go() принимает номер записи:
function go($t) {
global $this_host;
$template = file_get_contents('template.html');
$text = @file( dirname( __FILE__ ) . '/txt/' . $t . '.txt' );
$header = $text[0];
$date = $text[1];
$text[0] = '';
$text[1] = '';
$text = parse( trim( implode($text) ) );
$home = '<a href="' . $this_host . '">Главная</a>';
$template = str_replace('%navigation%', navigation_next_prev($t), $template);
$template = str_replace('%home%', '<li>' . $home . '</li>', $template);
$template = str_replace('%home_top%', $home, $template);
$template = str_replace('%header%', $header, $template);
$template = str_replace('%date%', $date, $template);
$template = str_replace('%text%', $text , $template);
@header('Content-type: text/html; charset=utf-8');
echo $template;
}
Она примерна такая же, как и предыдущая, только уже считывает файл с записью в отдельный массив. В данном случае удобней использовать именно массив, потому что у нас известно, что первый элемент будет заголовок, а второй - дата. После того, как мы заполнили соответствующие переменные, мы удаляем первые два элемента и преобразуем оставшийся массив в строку. Дальше уже знакомые операции с шаблоном.
Теперь о том, что такое функция parse(). Я её взял из своего плагина «Псевдокод», и выполняет он замены одних кодов на другие. Это может пригодится, если вы используете псевдокод, или нужно исправить некоректную работу wpautop().
У нас оставлось разобрать только две функции: navigation() и navigation_next_prev().
Я не буду приводить их код (оставим как домашнее задание), просто расскажу про алгоритм их работы.
- Прежде всего считывается файл all.txt. В нем, как вы помните у нас хранится массив с ID и заголовками записей.
- Мы выполняем unserialize, чтобы восставновить массив в переменную.
- Для navigation мы выполняем обратную сортировку массива, чтобы последние записи, оказались в начале. Дальше в цикле формируем ссылки и возвращаем полученную строку.
- Для navigation_next_prev алгоритм немного сложней. Нам нужно найти предыдущую и последующую запись. Проблема в том, что номер элемента в массиве может не совпадать с номером записи, поэтому предыдущую запись нельзя определить как $ID-1. Таким образом я решил вначале найти текущую запись путем перебора массива и установить курсор на следующую запись ($next). Для предыдущей же нужно сдвинуть курсор массива назад на три позиции. Тами образом получаем $prev. Может это и немного путано, но другого алгоритма я не придумал.
Вот собственно и всё.
Сам «движок» получился примерно 5Кб (), и состоит из пяти функций. Вы можете скачать мой вариант, только не забудьте указать свой хост в index.php.
Но это еще не всё. ;)
Что и как можно изменить. Можно дополнительно для каждой записи указывать рубрику. Можно пойти двумя путями. Первый - в момен обновления текстовых файлов добавить в SQL-запрос получающий название рубрик и добавить их, скажем в третью строчку.
Второй способ сложней - можно попробовать сформировать отдельный файл cat.txt, где хранить структуру записей и рубрик в виде массива. В этом случае, при отображении записи нужно будет обратиться к этому массиву и найти рубрики, отмеченные для этой записи.
Второй способ еще удобен в том, что на его основе можно организовать отображение рубрик в сайбаре и вообще любую навигацию по рубрикам.
Еще в «движке» можно изменить шаблон. Сейчас он парсится как текст, но можно выполнить его как php-файл, который подключается с помощью require. Естественно, вместо меток тогда нужно предусмотреть php-функции для вывода, как это делается в WordPress'е.

Комментариев: 16
Если честно, не понял зачем это нужно :neutral:
Максим, хотел спросить, есть ли способ победить вот это?
http://websuccess.ru/forum/index.php?showtopic=334
Попробуйте установить в .htaccess
php_value memory_limit 16M.HTACCESS такой:
# BEGIN WordPress
php_value memory_limit 16M
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
# END WordPress
На сайте выдает ошибку:
Internal Server Error
The server encountered an internal error or misconfiguration and was unable to complete your request.
Please contact the server administrator, webmaster@blog.codingclub.ru and inform them of the time the error occurred, and anything you might have done that may have caused the error.
More information about this error may be available in the server error log.
Additionally, a 500 Internal Server Error error was encountered while trying to use an ErrorDocument to handle the request.
Если сервер ругается на добавленную строчку, значит команда запрещена на сервере. Поробуйте уточнить у хостера этот вопрос. Обычно для WordPress 2.3 хватает 16М.
ответ админа такой:
да у нас ограничени выделенной памяти 10 мегабайт...
если увеличивать то будут тормаза на сервере, и тормаза в аккаунтах...
да и вообще может просто нехватать памяти
Тогда следует сменить хостинг на более приличный.
Макс, а скрытые (приватные) записи тоже будут это... парситься,т.е. складываться в ту папочку?
И вообще у меня к тебе вопрос - я где-то у тебя читал по поводу работы ВП, и там вроде было что-то типа того, что ВП при генерации страниц считывает всю базу, что есть его минусом, а потом уже использует то, что нужно... Я короче тут напутал, но думаю ты понял... Так вот вопрос - можно ли увидеть скрытые записи блога любым нехакерским путем, обращаясб каким-либо образом к БД или используя определенные УРЛы?
Ну чтобы получить вообще все записи, то нужно изменить условие запроса, то есть убрать «WHERE post_status = 'publish'».
Макс, небольшой баг - приватные страницы генерирует (с постами все ок)
И еще. Все работает - но файлов с текстами в папке я так и не увидел...
Понимаю, что сабж прикольный, но тоже пока не понимаю, где его применение может пригодиться.
З.Ы. памяти WP может нехватать, если статических страниц много (не знаю как самых последних версиях) он их грузит "полюбому все в память всегда".
Очень странный пост. С одной стороны правильное желание сделать что-то легче, чем wordpress... А с другой - зачем-то используете дамп базы в текстовых файлах и str_replace. Ваш мозг захватил ПоХаПэ!
Сделайте генерацию статичных HTML-страниц, без промежуточных костылей - это намного интереснее и полезнее.
Не совсем так. Тексты - это просто пример, грубая иммитация базы данных. Именно в таком виде они и хранятся. А готовые HTML это как раз плохо - нам нужен шаблон, который можно поменять в любой момент.
(Мечтательно) Эх, увидеть бы теперь реализацию редактора для этих файлов...
А так все получилось очень даже неплохо - шустро и понятно.
Спасибо.
Максим, может поможешь либо подскажешь где копать. Задача стоит обратная из массива содержимого, тайтлов, категорий надо собрать базу ВП. Сам с ВП плотно не знаком, поэтому и интересуюсь
Успешно получилось, просто.
Я не думал что все так просто.
Возникают вопросы, зачем нужны громоздкие CMS, как без ВП заполнить базу данных.
Автору - спасибо за простоту и ясность.