В общем стоит задача создать личный кабинет с не стандартной схемой вывода элементов:
Схема вывода:
Соберу тут все вопросы и собственно решения, если не возражает многоуважаемый модератор 🙂
В результате ожидается рабочий шаблон офиса.
****
Справочные материалы:
STEP 1
Создаем структуру адона-шаблона:
(folder) theme-mytemplate |- (folder) css | |- (file) style.css | |- (folder) js | |- (file) scripts.js | |- (folder) templates | |- (file) office.php | |- (file) info.txt |- (file) index.php |- (file) screenshot.jpg
Формируем инфо-блок в файле info.txt:
Name: mytemplate; Version: 0.1; Support Core: 15.0.0; Template: My Template; Description: Private cabinet; Author: My name; Author URI: http://www.mysite.com/;
Язвить я и не собирался, Отшельник. Тема все таки специфическая и возможно никакого отношения к данной рубрики форума иметь не будет. А значит - нарушение правил, за которыми вы следите. Отсюда и образное выражение "если не возражает модератор".
А вопросы будут ходу сборки шаблона.
***
STEP 2
Формируем HTML структуру office.php:
<?php /** * @package WordPress * @subpackage MyTheme * @since MyTheme 1.0. */ ?> <!-- Template office.php: BEGIN --> <aside id="sidebar-left" class="private"> <!-- Sidebar Switch: BEGIN --> <div id="tab-menu" class="left-sidebar"> <ul class="nav nav-tabs" role="tablist"> <li class="transition"> <a href="#catalog" aria-controls="catalog" role="tab" data-toggle="tab" class="transition" aria-expanded="false">Show Button First SB</a> </li> <li class="transition active"> <a href="#dialogue" aria-controls="dialogue" role="tab" data-toggle="tab" class="transition" aria-expanded="true">Show Button Second SB</a> </li> </ul> </div> <!-- Sidebar Switch: END --> <div class="left-sidebar tab-content"> <div role="tabpanel" class="tab-pane fade in active transition" id="catalog"> <div id="lk-menu" class="rcl-menu"> // Left Sidebar first </div> </div> <div role="tabpanel" class="tab-pane fade transition" id="dialogue"> // Left Sidebar second </div> </div> </aside> <div class="content"> <!-- Tab-block private cabinet: BEGIN --> <div id="rcl-tabs"> <div id="lk-content" class="rcl-content"> // Content private cabinet </div> </div> <!-- Tab-block private cabinet: END --> </div> <div class="clearfix"></div> <!-- Template office.php: END -->
P.S. Разметка дана с учетом того, что на ранее на сайте был подключен Framework Bootstrap - для корректной смены сайдбаров при клике на активирующие кнопки.
STEP 3
Выводим контент сайдбара.
SB First - меню управления табами:
Заменяем в предыдущем коде:
// Left Sidebar first
на:
<?php do_action( 'rcl_area_menu' ); ?>
SB Second - список контактов.
Вот тут появляется первый вопрос.
У нас есть возможность вызвать список шорткодом
echo do_shortcode( ' [ rcl-tab tab_id="chat" ] ' );
но этот код вызывает список в "обертке" ID которой будут конфликтовать с аналогичным содержимым таба Чат. Значит такое решение не подходит.
Можно ли вернуть иным способом список контактов шатными средствами плагина?
Сенкс Андрей.
Функция нам возвращает HTML строку с кодом всех контактов.
А если таковых нет, то строку "Пока контактов нет. Начните переписку на странице другого пользователя".
Отсюда сразу вопрос, а если необходимо заменить на свой текст? Не репласить же ее интерпретатором...
Сорри, конечно за такой примитив, но я не смог найти эту функцию в коде плагина, что б посмотреть параметры вызова 🙁
STEP 3 (продолжение: выводим список контактов во втором сайдбаре)
Итак, воспользовавшись советом многоуважаемого автора, начинаем переназначать функцию.
Открываем файл index.php (в нашей теме) и вставляем следующие функции:
<?php /** * [user_contact_list Contact list current user] * @return [string] [HTML code contact list] */ function user_contact_list() { global $user_LK; if( $user_LK ){ $contacts = new_rcl_get_user_contacts_list( $user_LK ); if( !$contacts ) { $contacts = '<span class="no-contacts">'; $contacts .= __( 'Список контактов пуст' ); $contacts .= '</span>'; } } else { $contacts = '<span> <i class="fa fa-exclamation-triangle" aria-hidden="true"></i>' . __( 'Для начала диалога требуется авторизация' ) . '</span>'; } return $contacts; }
Тут мы формируем кастомные выводы если пользователь не авторизован и если у него нет контактов.
В этот же файл вставляем и измененную функцию автора:
/** * [new_rcl_get_user_contacts_list Modification base function generate contact list current user] * @param [integer] $user_id [Current user ID] * @return [string] [HTML code contact list] */ function new_rcl_get_user_contacts_list( $user_id ) { global $wpdb; $amount = $wpdb->query( "SELECT COUNT(chat_messages.chat_id) FROM ".RCL_PREF."chat_messages AS chat_messages " . "INNER JOIN ".RCL_PREF."chat_users AS chat_users ON chat_messages.chat_id=chat_users.chat_id " . "WHERE chat_messages. private_key!='0' " . "AND (chat_messages.user_id='$user_id' OR chat_messages.private_key='$user_id') " . "AND chat_users.user_id='$user_id' " . "AND chat_users.user_status!='0' " . "GROUP BY chat_messages.chat_id " ); if( !$amount ) { return false; } $inpage = 20; $pagenavi = new Rcl_PageNavi( 'chat-contacts', $amount, array( 'in_page' => $inpage ) ); $messages = rcl_get_user_contacts( $user_id, array( $pagenavi->offset, $inpage ) ); foreach( $messages as $k => $message ) { $messages[$k]['user_id'] = ( $message['user_id'] == $user_id ) ? $message['private_key'] : $message['user_id']; } $content = '<div class="rcl-chat-contacts">'; foreach( $messages as $message ) { $class = (!$message['message_status'])? 'noread-message': ''; $content .= '<div class="contact-box" data-contact="'.$message['user_id'].'">'; $content .= '<a href="#" title="'.__('Delete contact','wp-recall').'" onclick="rcl_chat_remove_contact(this,'.$message['chat_id'].');return false;"><i class="fa fa-times" aria-hidden="true"></i></a>'; $content .= '<a class="chat-contact '.$class.'" href="'.rcl_format_url(get_author_posts_url($message['user_id']),'chat').'">'; $content .= '<div class="avatar-contact">' . get_avatar($message['user_id'],50) . '</div>'; $content .= '<div class="message-content">' . '<div class="message-meta">' . '<span class="author-name">'.get_the_author_meta('display_name',$message['user_id']).'</span>' . '<span class="time-message">'.rcl_human_time_diff($message['message_time']).' '.__('ago','wp-recall').'</span>' . '</div>' . '<div class="message-text">'.rcl_chat_excerpt($message['message_content']).'</div>' . '</div>'; $content .= '</a>'; $content .= '</div>'; } $content .= '</div>'; $content .= $pagenavi->pagenavi(); return $content; }
В функции был изменен только участок, возвращающий ответ, если контактов нет - возвращаем вместо строки булев тип:
if( !$amount ) { return false; }
Теперь возвращаемся в файл office.php и меняем:
// Left Sidebar second
на вызов нашей функции:
<?php echo user_contact_list(); ?>
RESULT STEP 1-3
В общем после проделанного и некоторой кастомизации имеем первый результат - двойной сайдбар:
P.S. Очередной вопрос - на скрине SIDEBAR SECOND в круглых скобках должно быть указано количество не прочитанных сообщений по данному контакту. За что зацепится, что-б получить такие данные?
STEP 4
Формируем вывод основного контента (табы).
В стандартной теме для этого есть зацепка do_action( 'rcl_area_tabs' ), на которую вешается класс Rcl_Tabs...
Очередной вопрос: получается для изменения параметров вывода нам придется переназначать класс?
Например, требуется убрать весь контент областей "top", "action", "counter" в таб "профиль". Переписываем класс или есть какие другие штатные методы? Там хуки/фильтры, например...
P.S. А так-же хотелось услышать ответ на вопрос из предыдущего поста. 🙂
Перечитав в очередной раз мануалы, нашел вроде бы решение кастомизации табов:
Начинаю экспериментировать. В файл index.php вставляю свою функцию:
function filter_function_profile( $data ) { if( $data['id'] != 'profile' ) { return $data; } $data['callback'] = 'handler_function_profile'; return $data ; } add_filter( 'tab_data_rcl', 'filter_function_profile' ); function handler_function_profile( $user_lk ) { // код базовой функции rcl_tab_profile_content() }
P.S. Результирующий код будет позже - после кастомизации.
P.P.S. Вопрос с 11 поста пока закрыт.
Rob Roy сказал(а)
P.S. Очередной вопрос - на скрине SIDEBAR SECOND в круглых скобках должно быть указано количество не прочитанных сообщений по данному контакту. За что зацепится, что-б получить такие данные?
функции подсчета сообщений по определенному контакту нет, придется писать самому
Андрей CS сказал(а)
функции подсчета сообщений по определенному контакту нет, придется писать самому
можете попробовать эту функцию
function rcl_chat_noread_contact_messages_amount($user_id,$contact_id){ global $wpdb; $amount = $wpdb->get_var( "SELECT COUNT(chat_messages.message_id) FROM ".RCL_PREF."chat_messages AS chat_messages " . "WHERE chat_messages.private_key='$user_id' " . "AND chat_messages.user_id='$contact_id' " . "AND chat_messages.message_status='0' " ); return $amount; }
Итак, проект ушел в тестинг - можна продолжить. 🙂
Андрей CS сказал(а)
возможно, будет удобнее сразу получить весь массив вкладок через фильтр rcl_tabs и обработать его нужным образом за раз.
Насколько я понимаю, то такой вариант приемлем в случае если требуется внести изминения в несколько или во все закладки.
Но в нашем случае требуется внести изменения только в таб профиля, поэтому воспользуемся все таки фильтром tab_data_rcl().
STEP 5.
Кастомизируем под себя функцию handler_function_profile(). Например добавляем аватар пользователя и функцию ее редактирования:
// Add avatar box $profile_block = '<div class="lk-avatar"> <div class="lk-label">' . __( 'Avatar:' ) . '</div> <div id="rcl-avatar"> <span class="avatar-image">' . get_avatar( $user_lk, 60 ) . '<span id="avatar-upload-progress"><span></span></span> </span>'; // Upload avatar $icons = rcl_avatar_icons(); if( !empty($icons) ) { $html = array(); foreach( $icons as $icon_id => $icon ) { $atts = array(); if( isset( $icon['atts'] ) ) { foreach( $icon['atts'] as $attr => $val ) { $val = ( is_array( $val ) ) ? implode( ' ', $val ) : $val; $atts[] = $attr . '="' . $val . '"'; } } $string = '<a ' . implode( ' ', $atts ) . '>'; if(isset($icon['icon'])) { $string .= __( 'Загрузить файл' ); } if(isset($icon['content'])) { $string .= $icon['content']; } $string .= '</a>'; $html[] = '<span class="rcl-avatar-icon icon-'.$icon_id.'">'.$string.'</span>'; } $profile_block .= '<span class="avatar-icons">' . implode( '', $html ) . '</span>'; } $profile_block .= '</div> </div>';
STEP 6. Кастомизация.
Итак, после создания требуемой структуры, осталось только кастомизировать его под наш дизайн.
Все в том-же index.php подключаем поддержку кастомных таблиц CSS и скриптов JavaScript:
/** * [theme_script_load Add custom JavaScript] * @return [No return] */ function theme_css_load(){ rcl_enqueue_style('theme-css',rcl_addon_url('css/style.css', __FILE__)); } if (!is_admin()): add_action( 'rcl_enqueue_scripts', 'theme_css_load' ); endif;
/** * [theme_script_load Add custom JavaScript] * @return [No return] */ function theme_script_load() { global $user_LK; if( $user_LK ){ rcl_enqueue_script( 'theme-scripts', rcl_addon_url( 'js/scripts.js', __FILE__ ), false, true ); } } add_action( 'rcl_enqueue_scripts', 'theme_script_load' );
P.S. Не забываем добавить соответствующие файлы в нашу тему: css/style.css и js/scripts.js
В итоге всех манипуляций должно получится что нибудь типа этого:
P.P.S. Готовый код не вижу куда прикрепить 🙁
Андрей CS сказал(а)
...фильтр tab_data_rcl больше не работает, он заменен фильтром rcl_tab.../
Грустно, но не смертельно. Переписать код под новый фильтр не составит труда любому, кто знаком с основами програмирования 🙂
P.S. Смысла в выкладывании кода тогда вообще не вижу 🙂
P.P.S. Уйду на пенсию - перепишу тему под последнюю версию плагина WP-Recall 😆
Андрей CS сказал(а)
а это реализация вообще чего? кому то на заказ?
Разрабатывалась в комплексе при разработке сайта на заказ. Из нее выкинуть кастомные нестандартные функции и дефолтные стили прицепить и в принципе можно ставить на чистый WP-Recall.
P.S. Смысла в выкладывании кода тогда вообще не вижу
есть смысл не тупо в выкладывании кода (грубо звучит, но не суть) - а в методологии. Т.е. в создании какого либо мануала с шагами, на котором будут понятны общие принципы. Где будут показаны важные моменты. Вот это ценного стоит. А фрагменты кода - да, сейчас они актуальны, а завтра нет. И это проблема всех АПИ. Обратная совместимость у которых поддерживается - но не вечно. Мир меняется стремительно и то что сегодня работало - завтра не будет. Это надо принимать как истину.