Пишем плагин для обратной связи — Метабокс Автора.

Пишем плагин для обратной связи — Метабокс Автора.

6770
8
ПОДЕЛИТЬСЯ

Плагин Метабокс Автора — настраиваемый вывод информации об авторе публикации с иконками социальных сетей из профиля, вывод последних публикаций автора, контактная форма для связи с автором статьи.

Так уж получилось, что в последнее время, мне пришлось работать с новостными и мульти-авторскими сайтами. И каждый раз, я наталкивался на одни и те же «хотелки», необходимо было на страницах публикаций, выводить информацию об авторе статьи с фотографией, а также выводить несколько последних написанных им статей. Плюс к этому частым требованием была возможность отправлять письма через контактную форму не администрации сайта, а именно автору публикации. Помимо этого, должна иметься возможность отключать или включать вывод вышеописанного содержимого самим автором, чтобы автор самостоятельно определял, хочет ли он видеть информацию о себе на сайте, хочет ли чтобы была возможность получать письма отправленные с сайта, и нужно ли ему, чтобы на странице с его публикацией был вывод последних написанных им статей, и хорошо бы чтобы имелась возможность размещать метабокс с помощью шоткода в любом месте статьи, например так:
[asdb-author-info]
Идею, как разрешить данную проблему, подал автор публикации Stay Connected with WordPress Authors но лично у меня, следуя этим рекомендациям собрать плагин не получилось. И хотя вот тут обнаружился перевод статьи, на самом то деле это ничуть не помогло, вопросы которые возникли после прочтения оригинала, так и остались вопросами и в переводе. Отсутствие в статье некоторых ключевых моментов, как то скрипты для валидации формы отправки сообщений и собственно передачу данных из формы на обработчик php, вынуждали искать другие решения, но все они были либо громоздкими, либо не выполняли все необходимые мне функции. Но идея есть, каркас плагина — есть, осталось только приложить к этому руки или голову. Давайте этим и займемся.
Что хотим получить в итоге?
screenshot

screenshot1

Создаем файл плагина — Метабокс автора

Создадим рабочую директорию плагина — 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');

Настройки плагина

screenshot2
Мы хотим в профиле пользователя, получить возможность разрешать или запрещать вывод определенных, функций нашего плагина.

//Выводим в профиле пользователя настройки плагина (чекбокс отмечен - Да, Снят - Нет)
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 );

В результате в профиле автора мы получим нужные нам поля:
screenshot4
Далее формируем функцию для вывода 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;
?>

Приветствуются любые улучшения функционала или кода.
Скачать готовый плагин

comments powered by HyperComments
ПОДЕЛИТЬСЯ
Предыдущая статьяСоздаем robots.txt для WordPress
Следующая статьяИсключить прилепленную(Sticky Posts) запись из цикла
Tkacheff.ru
WordPress — БлогоСтроение. Так и хочется срифмовать с настроением ;-). Строя сайты, часто приходится уходить "в поиск", и разгребать мегобайты "мусора" в поисках нужного ответа. Это попытка собрать рабочие решения, проверенные и опробованные мной лично. Прежде всего для себя. Но если кому то пригодится - я буду только рад! Пусть Ваше настроение всегда остается оптимистичным!
Александр Примак
2015-02-07 17:28:48
Гуру!
Александр Примак
2015-02-07 17:29:03
Гуру +++
Dastarhan Aktobe
2015-06-24 19:48:27
а где можно скачать готовый?
Andrey
2015-07-10 02:03:50
Тоже хочется готовый плагин))
Tkacheff.ru
Tkacheff.ru
2015-07-25 23:10:25
http://tkacheff.ru/wp-content/uploads/2014/01/asdb-author-info.zip
Britney Jean
2016-02-29 10:28:10
Спасибо за статью! Ребят, попробуйте сервис от pozvonim.com Простая установка на любую cms, хорошая поддержка. Не сочтите за рекламу, ссылка не реферальная, просто можно взять и попробовать на тестовый период. А потом уже решить подходит или нет. Цены как у всех, можно пакеты брать, а можно количество клиентов или минут. Лидогенерация очень высокая, а окупаемость быстрая. Может кому пригодится мой комментарий
Стас
2016-09-20 22:44:15
Не могу найти где же в консоли выводится форма обратной связи? или я не вывел шорткод, Добавьте в конце статьи как выглядит форма связи и как она отображается?(шорткод там куда вставить )
Tkacheff.ru
Tkacheff.ru
2016-10-06 00:37:25
Это не шорткод. Заходите в админке в редактирование пользователя, и включаете чекрыжик - выводить метабокс автора.