Плагин Метабокс Автора — настраиваемый вывод информации об авторе публикации с иконками социальных сетей из профиля, вывод последних публикаций автора, контактная форма для связи с автором статьи.
Так уж получилось, что в последнее время, мне пришлось работать с новостными и мульти-авторскими сайтами. И каждый раз, я наталкивался на одни и те же «хотелки», необходимо было на страницах публикаций, выводить информацию об авторе статьи с фотографией, а также выводить несколько последних написанных им статей. Плюс к этому частым требованием была возможность отправлять письма через контактную форму не администрации сайта, а именно автору публикации. Помимо этого, должна иметься возможность отключать или включать вывод вышеописанного содержимого самим автором, чтобы автор самостоятельно определял, хочет ли он видеть информацию о себе на сайте, хочет ли чтобы была возможность получать письма отправленные с сайта, и нужно ли ему, чтобы на странице с его публикацией был вывод последних написанных им статей, и хорошо бы чтобы имелась возможность размещать метабокс с помощью шоткода в любом месте статьи, например так:
[asdb-author-info]
Идею, как разрешить данную проблему, подал автор публикации Stay Connected with WordPress Authors но лично у меня, следуя этим рекомендациям собрать плагин не получилось. И хотя вот тут обнаружился перевод статьи, на самом то деле это ничуть не помогло, вопросы которые возникли после прочтения оригинала, так и остались вопросами и в переводе. Отсутствие в статье некоторых ключевых моментов, как то скрипты для валидации формы отправки сообщений и собственно передачу данных из формы на обработчик php, вынуждали искать другие решения, но все они были либо громоздкими, либо не выполняли все необходимые мне функции. Но идея есть, каркас плагина — есть, осталось только приложить к этому руки или голову. Давайте этим и займемся.
Что хотим получить в итоге?
Создаем файл плагина — Метабокс автора
Создадим рабочую директорию плагина — asdb-author-info, в ней создадим еще две директории inc
, где у нас будут храниться стили и скрипты и img
для хранения картинок. В корневой директории плагина создадим файл asdb-author-info.php — основной рабочий файл плагина. Чтобы WordPress понял, что это плагин, необходимо в начале файла разместить заголовок плагина.
Не забываем, что файл должен быть в кодировке UTF-8 без BOM
/* Plugin Name: Метабокс Автора Plugin URI: http://tkacheff.ru/697/plugins-author-metabox/ Description: Настраиваемый Метабокс Автора публикации. Содержит 3 бокса: Бокс - информация об Авторе с иконками социальных сетей, Бокс - последние посты Атора, и Бокс - контактная форма для связи с Автором. Version: 1.0.1 Author: Михаил Ткачев Author URI: http://tkacheff.ru */ /* Copyright 2014 */
Служебная часть плагина. Получаем папку в которую установлен плагин, загружаем стили, загружаем jQuery и скрипт плагина.
//получаем папку установки плагина $asdb_dir = preg_replace("/^.*[\/\\\]/", "", dirname(__FILE__)); define("ASDB_DIR", "/wp-content/plugins/" . $asdb_dir); class ASDBAuthorInfo { // формируем токен для проверки отправки email из формы function token() { $admin_email = get_option("admin_email"); return md5("asdb-" . $admin_email . date("WY")); } } $asdb = new ASDBAuthorInfo(); //Загрузка необходимых для работы плагина скриптов и стилей function asdb_scripts() { wp_enqueue_script('jquery'); wp_enqueue_script('asdb_functions', plugins_url('/inc/functions.js', __FILE__), 'jquery'); wp_enqueue_style('asdb_style', plugins_url('/inc/asdb.css', __FILE__)); } add_action('wp_enqueue_scripts', 'asdb_scripts');
Настройки плагина
Мы хотим в профиле пользователя, получить возможность разрешать или запрещать вывод определенных, функций нашего плагина.
//Выводим в профиле пользователя настройки плагина (чекбокс отмечен - Да, Снят - Нет) add_action('show_user_profile', 'asdb_preferences'); add_action('edit_user_profile', 'asdb_preferences'); function asdb_preferences($user) { $asdb_email_status = (esc_attr(get_the_author_meta('asdb_email_status', $user->ID)) != 'allow') ? '' : 'checked'; $asdb_metabox_status = (esc_attr(get_the_author_meta('asdb_metabox_status', $user->ID)) != 'allow') ? '' : 'checked'; $asdb_related_status = (esc_attr(get_the_author_meta('asdb_related_status', $user->ID)) != 'allow') ? '' : 'checked'; echo <<<END <h3>Настройка плагина Метабокс Автора</h3> <table class="form-table"> <tr> <th><label>Выводить метабокс Автора?</label></th> <td><input type="checkbox" name="asdb_metabox_status" id="asdb_metabox_status" value="allow" $asdb_metabox_status /><br /></td> </tr><tr> <th><label>Принимать почту с сайта?</label></th> <td><input type="checkbox" name="asdb_email_status" id="asdb_email_status" value="allow" $asdb_email_status /><br /></td> </tr><tr> <th><label>Выводить последние сообщения?</label></th> <td><input type="checkbox" name="asdb_related_status" id="asdb_related_status" value="allow" $asdb_related_status /><br /></td> </tr> </table>\n END; } //сохраняем введенные значения add_action('personal_options_update', 'asdb_save_preferences'); add_action('edit_user_profile_update', 'asdb_save_preferences'); function asdb_save_preferences($user_id) { if (!current_user_can('edit_user', $user_id)) return FALSE; update_usermeta($user_id, 'asdb_metabox_status', $_POST['asdb_metabox_status']); update_usermeta($user_id, 'asdb_email_status', $_POST['asdb_email_status']); update_usermeta($user_id, 'asdb_related_status', $_POST['asdb_related_status']); }
Функция вывода метабокса информации об авторе
Добавляем нужные поля в профиль пользователя… И убираем ненужные. Добавляем в профиль пользователя нужные социальные сети, и «под шумок» избавляемся от неиспользуемых. По аналогии, можно удалить или добавить нужную Вам социальную сеть.
// добавляем и удаляем социальные сети function asdb_social_contactmethod( $contactmethods ) { // Удаляем Yahoo YIM if ( isset( $contactmethods['yim'] ) ) unset( $contactmethods['yim'] ); // Удаляем AIM if ( isset( $contactmethods['aim'] ) ) unset( $contactmethods['aim'] ); // Удаляем Jabber if ( isset( $contactmethods['jabber'] ) ) unset( $contactmethods['jabber'] ); // Добавляем VKontakte if ( !isset( $contactmethods['vkontakte'] ) ) $contactmethods['vkontakte'] = 'ВКонтакте'; // Добавляем Twitter if ( !isset( $contactmethods['twitter'] ) ) $contactmethods['twitter'] = 'Twitter'; // Добавляем Google Plus if ( !isset( $contactmethods['googleplus'] ) ) $contactmethods['googleplus'] = 'Google Plus'; // Добавляем Facebook if ( !isset( $contactmethods['facebook'] ) ) $contactmethods['facebook'] = 'Facebook'; // Добавляем LiveJournal if ( !isset( $contactmethods['livejournal'] ) ) $contactmethods['livejournal'] = 'LiveJournal'; return $contactmethods; } add_filter( 'user_contactmethods', 'asdb_social_contactmethod', 10, 1 );
В результате в профиле автора мы получим нужные нам поля:
Далее формируем функцию для вывода html кода краткой информации об авторе, с его социальными сетями.
//формируем бокс Инфо об Авотре с социальными иконками function asdb_get_author_information() { $asdb_metabox_status = get_the_author_meta('asdb_metabox_status', $authordata->ID); $asdb_html = ''; if ($asdb_metabox_status == 'allow') { $vkontakte = get_the_author_meta( 'vkontakte'); $twitter = get_the_author_meta( 'twitter'); $facebook = get_the_author_meta( 'facebook'); $livejournal = get_the_author_meta( 'livejournal'); $googleplus = get_the_author_meta( 'googleplus'); if (isset($vkontakte)) $imageHtml .= ' <a class="b-share__handle" href="'.$vkontakte.'" rel="author" target="_blank"><span class="b-share-icon b-share-icon_vkontakte"></span></a>'; if (isset($twitter)) $imageHtml .= ' <a class="b-share__handle" href="'.$twitter.'" rel="author" target="_blank"><span class="b-share-icon b-share-icon_twitter"></span></a>'; if (isset($facebook)) $imageHtml .= ' <a class="b-share__handle" href="'.$facebook.'" rel="author" target="_blank"><span class="b-share-icon b-share-icon_facebook"></span></a>'; if (isset($googleplus)) $imageHtml .= ' <a class="b-share__handle" href="'.$googleplus.'" rel="author" target="_blank"><span class="b-share-icon b-share-icon_gplus"></span></a>'; if (isset($livejournal)) $imageHtml .= ' <a class="b-share__handle" href="'.$livejournal.'" rel="author" target="_blank"><span class="b-share-icon b-share-icon_lj"></span></a>'; $imageHtml .= ' '; $asdb_post_author = get_the_author_meta('user_email'); $asdb_html = "<div id='asdb-author-box' class='author-bio'> <div id='author-avatar' class='bio-avatar'>" . get_avatar(get_the_author_email(), '128') . "</div> <div id='author-name' class='bio-name'>" . get_the_author_meta('first_name') . " " . get_the_author_meta('last_name') . "<div id='author-social' class='bio-social'><span class='b-share'>" . $imageHtml . "</span></div></div> <div id='author-desc' class='bio-desc'>" . get_the_author_meta('description') . "</div> <div class='clear'></div> </div>"; } return $asdb_html; }
Функция вывода последних постов (статей) автора
// Формируем бокс с последними постами Автора (4шт) function asdb_get_author_posts() { global $authordata, $post; $asdb_related_status = get_the_author_meta('asdb_related_status', $authordata->ID); $asdb_html = ""; if ($asdb_related_status == 'allow') { $asdb_author_posts = get_posts(array('author' => $authordata->ID, 'post__not_in' => array($post->ID), 'posts_per_page' => 4)); foreach ($asdb_author_posts as $key => $asdb_author_post) { $title_post_url = get_permalink($asdb_author_post->ID); if (has_post_thumbnail($asdb_author_post->ID)) { $asdb_html .= "<li class='asdb-related post-hover'><div class='post-thumbnail'>" . get_the_post_thumbnail($asdb_author_post->ID, array(100, 100)) . "</div><div id='asdb-related-inner'><h4 class='asdb-post-title post-title'><a title='$asdb_author_post->post_title' href='" . $title_post_url . "'>$asdb_author_post->post_title</a></h4></div></li>"; } else { $url = plugins_url(); $asdb_html .= "<li class='asdb-related post-hover'><div class='post-thumbnail'><img width='100' height='100' src='" . $url . "/asdb-author-info/img/thumb-medium.png' /> </div><div id='asdb-related-inner'><h4 class='asdb-post-title post-title'><a title='$asdb_author_post->post_title' href='" . $title_post_url . "'>$asdb_author_post->post_title</a></h4></div></li>"; } } if($asdb_html != ''){ $asdb_html = "<div id='asdb-post-head'>Последние публикации Автора</div><div id='asdb-post-list'><ul class='asdb-related-post group'>".$asdb_html."</ul></div>"; } } return $asdb_html; }
Создаем контактную форму для связи с автором
//Вывод бокса отправки почты Автору публикации function asdb_send_email_box() { global $authordata; $token = ASDBAuthorInfo::token(); $asdb_email_status = get_the_author_meta('asdb_email_status', $authordata->ID); $asdb_html = ''; if ($asdb_email_status == 'allow') { $asdb_html = ' <div class="asdb-post-head"><a href="javascript:void(0)" onclick="toggleEmail();">Связаться с Автором</a></div> <div id="asdbemailpanel" style="display: none;"> <form method="POST" id="asdbForm" class="asdbform" action="javascript:void(null);" > <table class="asdb-author-emails"> <tr> <th><label>Имя:</label></th> <td><div class="name amess"><input type="text" name="name" id="name" class="text" /></div></td> </tr> <tr> <th><label>EMail:</label></th> <td><div class="amess"><input type="text" name="email" id="email" class="text" /></div></td> </tr> <tr> <th><label>Тема:</label></th> <td><div class="amess"><input type="text" name="subject" id="subject" class="text" /></div></td> </tr> <tr> <th><label>Сообщение:</label></th> <td><div class="amess"><textarea name="message" id="message" class="text textarea"></textarea></div></td> </tr> <tr> <th><label></label></th> <td><input type="hidden" name="author_id" id="author_id" value="'.$authordata->ID.'" /> <input type="hidden" name="source" id="source" value="' . ASDB_DIR . '/asdb-data.php" /> <input type="hidden" name="token" id="token" value="'. $token . '" /> <input type="hidden" name="submitted" id="submitted" value="send" /> <input type="submit" name="submit" value="Отправить" id="send" /><!--<div class="loading"></div>--> </td> </tr> </table> </form></div> <div class="asdb-author-msg">Ваше сообщение успешно отправлено!</div> '; } return $asdb_html; }
Завершаем работу над плагином — Матабокс Автора
// формируем вывод полного метабокса на страницах записей (is_single) function asdb_generate_author_box($content) { if (is_single ()) { $asdb_author_info = asdb_get_author_information(); $asdb_author_posts = asdb_get_author_posts(); $asdb_email_box = asdb_send_email_box(); $asdb_html = "<div id='asdb-author-panel'>" . $asdb_author_info . $asdb_author_posts . $asdb_email_box ."</div>"; return $content . $asdb_html; } else { return $content; } } add_filter('the_content', 'asdb_generate_author_box'); add_shortcode('asdb-author-info', 'asdb_generate_author_box'); add_shortcode('asdb-author-info-bio', 'asdb_get_author_info'); add_shortcode('asdb-author-info-related', 'asdb_get_author_posts'); add_shortcode('asdb-author-info-contact', 'asdb_send_email_box');
Каркас плагина готов. Необходимо оформить внешний вид выводимых метабоксов, для этого создадим в папке inc
нашего плагина файл asdb.css. Далее, необходимо в этой же папке создать скрипт function.js с таким содержимым:
function toggleEmail() { if (document.all.asdbemailpanel.style.display=="none") (document.all.asdbemailpanel.style.display="block"); else (document.all.asdbemailpanel.style.display="none"); } (function($){ $(function(){ //Нажата кнопка submit $("#asdbemailpanel").submit(function() { //Получаем данные из введенных полей var name = $('input[name=name]'); var email = $('input[name=email]'); var subject = $('input[name=subject]'); var token = $('input[name=token]'); var source = $('input[name=source]'); var author_id = $('input[name=author_id]'); var submitted = $('input[name=submitted]'); var message = $('textarea[name=message]'); //Проверяем пустые значения //Если значение пустое подсвечиваем текстовое поле классом hightlight if (name.val()=='') { name.addClass('hightlight'); return false; } else name.removeClass('hightlight'); if (email.val()=='') { email.addClass('hightlight'); return false; } else email.removeClass('hightlight'); if (message.val()=='') { message.addClass('hightlight'); return false; } else message.removeClass('hightlight'); // Объединяем данные var data = 'name=' + name.val() + '&email=' + email.val() + '&subject=' + subject.val() + '&token=' + token.val() + '&source=' + source.val() + '&author_id=' + author_id.val() + '&submitted=' + submitted.val() + '&message=' + encodeURIComponent(message.val()); // AJAX $.ajax({ //путь до обработчика php. Валидация и отправка EMail url: "/wp-content/plugins/asdb-author-info/asdb-data.php", type: "POST", //данные data: data, cache: false, success: function (html) { //Если php вернул 1/true - все Ок if (html==1) { // очистка формы $('.text').val(''); // блокируем поля формы до обновления. $('.text').attr('disabled','true'); //Скрываем форму $('#asdbemailpanel').fadeOut('slow'); //Показываем сообщение что все ОК $('.asdb-author-msg').fadeIn('slow'); //Если php вернуло 0/false - сообщение не отправлено } else alert('Ваше сообщение не отправлено, попробуйте позже'); } }); return false; }); }); })(jQuery)
ну и последний штрих, обработчик php который будет производить валидацию контактной формы, и отправку почтового сообщения автору публикации.
файл должен лежать в корневой директории плагина, и называться — asdb-data.php
<?php require_once("../../../wp-config.php"); $asdb_dir = preg_replace("/^.*[\/\\\]/", "", dirname(__FILE__)); if (!defined("ASDB_DIR")) { define("ASDB_DIR", "/wp-content/plugins/" . $asdb_dir);} // Получаем данные из формы $action = isset($_POST["submitted"]) ? $_POST["submitted"] : ""; if ($action == "send") { // Если получен сигнал send $name = isset($_POST["name"]) ? $_POST["name"] : ""; $email = isset($_POST["email"]) ? $_POST["email"] : ""; $subject = isset($_POST["subject"]) ? $_POST["subject"] : ""; $message = isset($_POST["message"]) ? $_POST["message"] : ""; $token = isset($_POST["token"]) ? $_POST["token"] : ""; $author_id = isset($_POST["author_id"]) ? $_POST["author_id"] : ""; $mailTo = get_the_author_meta('user_email', $author_id); // Сравниваем токены, если совпадают, формируем сообщение если нет - выход if ($token == ASDBAuthorInfo::token()) { sendEmail($name, $email, $subject, $message, $mailTo); _e("1"); } else { _e("0"); } } // функция отправки почты function sendEmail($name, $email, $subject, $message, $mailTo) { $to = $mailTo; // фильтруем Имя отправителя и Тему сообщения $name = filter($name); $subject = empty($subject) ? get_option("asdb_subject") : filter($subject); // Удаляем экранирование символов $message = stripslashes($message); // Фильтруем и проверяем Email $email = filter($email); if (!validateEmail($email)) { $subject .= " - invalid email"; $message .= "\n\nBad email: $email"; $email = $to; } // формируем сообщение $body = "From: $name\n"; $body .= "Message: $message\n"; $body = wordwrap($body); // По умолчанию 75 символов // Формируем заголовок письма $headers = "From: $email\n"; $headers .= "X-Mailer: PHP/ASDBAuthorInfo\n"; // Конвертируем строку в кодированное слово для поля шапки UTF-8 if (function_exists('mb_encode_mimeheader')) { $subject = mb_encode_mimeheader($subject, "UTF-8", "B", "\n"); } else { } $headers .= "MIME-Version: 1.0\n"; $headers .= "Content-type: text/plain; charset=utf-8\n"; $headers .= "Content-Transfer-Encoding: quoted-printable\n"; // Отправляем сформированное письмо if(mail($to, $subject, $body, $headers)){ echo 'Сообщение отправлено'; }else{ echo "Ошибка отправки сообщения"; } exit; } // Удаляем небезопасные значения function filter($value) { $pattern = array("/\n/", "/\r/", "/content-type:/i", "/to:/i", "/from:/i"); $value = preg_replace($pattern, "", $value); return $value; } // Валидация email адреса function validateEmail($email) { $at = strrpos($email, "@"); // Проверяем, чтобы символ @ не был первым или последним if ($at && ($at < 1 || ($at + 1) == strlen($email))) return false; // Make sure there aren't multiple periods together if (preg_match("/(\.{2,})/", $email)) return false; // Разделяем локальный и внешний домены $local = substr($email, 0, $at); $domain = substr($email, $at + 1); // проверяем количество символов в домене $locLen = strlen($local); $domLen = strlen($domain); if ($locLen < 1 || $locLen > 64 || $domLen < 4 || $domLen > 255) return false; // Фильтруем точку в начале и конце if (preg_match("/(^\.|\.$)/", $local) || preg_match("/(^\.|\.$)/", $domain)) return false; // Адрес в ковычках? Разрешаем if (!preg_match('/^"(.+)"$/', $local)) { if (!preg_match('/^[-a-zA-Z0-9!#$%*\/?|^{}`~&\'+=_\.]*$/', $local)) return false; } // Проверяем допустимые символы и наличие хотя бы одной точки разделителя if (!preg_match('/^[-a-zA-Z0-9\.]*$/', $domain) || !strpos($domain, ".")) return false; return true; } exit; ?>
Приветствуются любые улучшения функционала или кода.
Скачать готовый плагин