четверг, 9 апреля 2015 г.

Как мы делаем бюджетные сайты / Хабрахабр

Как мы делаем бюджетные сайты



Доброго времени суток, уважаемый читатель. Планировал в качестве следующей статьи написать более подробно про то, как собираются типовые проекты на WP. Бюджеты у нас в Хабаровске довольно скромные, кушать хочется всем, в том числе и нам, поэтому есть множество моментов, которые необходимо учесть при разработке, чтобы сохранить должный уровень качества для наших клиентов, заработав на кусок хлеба с маслом себе. И предусмотреть такой нюанс, как обучение новых сотрудников.

Но комментарий пользователя m00t задел довольно чувствительную для меня струнку. Конфликт интересов бизнеса и интернет-агентств. Множество "мертвых" сайтов, живущих ровно до первого продления доменного имени. Такая ситуация заставляет меня грустить.

Поэтому в качестве вводной части выступают мои размышления о том, почему не всегда необходимо делать сайт на %framework_name%. Возможно мысли очевидные, возможно нет, но так тому и быть, без них пост будет не совсем полным. И да — то что подходит для нашего дальневосточного рынка, может не подходить для вашего. Приступим.

Для тех, кому интересно только то, как мы собираем проекты, без мыслей о том, зачем вообще нужно делать сайт за 10 000 рублей и философского сумбура — GOTO 10.

Вводная часть.


Некоторые утверждения немного спорны и эмоциональны, даже с моей точки зрения, но я стремлюсь к диалогу и был бы очень рад услышать мнения, которые не совпадают с моим или дополняют его. В споре рождается истина.

Доверие.

Здесь довольно уместна аллегория. Допустим мне необходимо заменить в ванной сантехнику. Если я не буду доверять мастеру, который занимается этим, постоянно критиковать, пытаться давать ему "ценные указания", "лезть под руку" — практически всегда это ни к чему хорошему не приведет (конечно, если вы сами не обладаете глубокими познаниями в этом деле, что, будем честны, не так часто встречается). Конфликт лишь создаст негатив, что крайне излишне. Да, бывают не очень хорошие исполнители, но выбор сантехника — не тема этой заметки.

Итак, первая мысль. На моей практике наиболее успешные проекты это те, где клиент понимает что ему необходимо, без указаний как это сделать. Черт возьми, подозреваю, что мастер лучше знает, как сделать разводку сантехники, опыта немного больше у него в этом. И главная задача студии — как можно лучше понять цели клиента, выбрав для их достижения максимально оптимальный инструмент. Что и подводит нас ко второй мысли.

"Продавать или помогать?"

Менеджер, при должном опыте, всегда может "продать" клиенту ajax-калькулятор на сайт парикмахерской c одним сотрудником, который и стрижет и директор. Может продать дизайн с иллюстрациями, по десять тысяч каждая, для сайта эвакуаторов с одной машиной. Сказав магические слова "юзабилити, конверсия, продакшн", навязать клиенту трехстраничник на Zend, с возможностью расширения до пульта управления космолетом, причем потенциальная аудитория — два человека в месяц. Всегда есть выбор, каждый решает сам по какому пути пойти.

Мысль тривиальна как 10 копеек — у клиента есть деньги, у меня есть деньги. Ресейл и все такое. Даже есть заготовленная фраза — "вам пока нет необходимости в проекте за %too_big_number% тысяч рублей, сделайте типовой, через год вернетесь, когда у вас будут ресурсы, сделаем крутой сайт".

Проекты делаются же не для показа исходников другим программистам, а для клиентов, с денег которых, в студиях, платится зарплата. Но тут важен баланс. Это не значит, что необходимо писать проект в одном файле, относиться «сделал и забыл». Если сделать хорошо — клиент вернется, а их в поле зрения студии конечное число, в любом случае. Да и о поддержке необходимо думать дальнейшей, ведь сэкономленный рубль — заработанный рубль. И тратить время программиста на смену телефона или добавление новости — не думаю, что это хорошо.

Простейший кейс, к примеру. Есть человек, владеющий фирмой, которая помогает зимой застрявшим автомобилистам. Бюджет ограничен. Что мы видим и что мы можем предложить? Аудитория не требовательна, конкуренция сравнительно низкая в нашем регионе, да и дело ли до моушена и дизайна, когда ты опаздываешь на работу, застряв на дороге. Запрос в поисковике -> номер телефона -> звонок. Делаем самый простейший сайт, подаем рекламу + сео, готово. Он получает клиентов, мы получаем его довольного, который расскажет о нас своим знакомым, и, вероятней всего, закажет в будущем разработку более высокого уровня, имея средства. И этот сайт не бесплатно делали.

По поводу того, как попытаться формализовать выбор того, что будет делаться. Смотрим в среднем на сколько процентов отличается конверсия бюджетных и «крутых» проектов, пробуем приблизительно высчитать разницу в чистой прибыли. Затем считаем срок, в какой окупится индивидуальная разработка, если для клиента подходит — работаем. Нет — человек выбирает шаблон, мы приступаем к сборке сайта. О чем и есть нижеследующее.

Сборка сайта на WP.


Данная методология (громкое слово, но стилистически оно уместно) предназначена больше для «типовых» проектов, но ничего не мешает нарисовать хороший дизайн, позаботиться о написании текстов, подобрать графику, сделать красивый «моушен» (любимое слово дизайнера, когда я начинаю верстать любопытные вещи), что выведет сайт на другой уровень. Это же просто админ-панель, она нужна больше для клиента, нежели чем для посетителя.

Требования для обучающего материала, которые были формализованы и исполнены:
  • Простой процесс сборки. Новый человек должен быстро вливаться в работу. Причем его знания могут быть крайне далеки от программирования, главное наличие логики, усидчивости, находчивости. Забавная метрика, под названием «Bus factor», пусть будет наиболее высокой.
  • Удобная и понятная для клиента админ-панель. Вся текстовая и графическая информация должна легко изменяться без знания аббревиатур HTML/CSS/PHP. Будет снижать количество просьб по смене телефона, контактов, добавления новости etc. до минимальных отметок.
  • Оптимальная скорость разработки. Один-два дня на вдумчивую сборку проекта, при условии готовой верстки. Можно и быстрее, но лучше тратить немного больше времени, но мелочи шлифовать.

Отступление небольшое. Кейс надуманный, но суть даст понять. Пытаюсь писать как можно лаконичней, поэтому, если будет желание ввести это где-то еще, необходимо иметь опытного человека, который сможет прояснить моменты, которые мне кажутся очевидными, но, может такое быть, что только для меня. И буду благодарен, если есть дополнения, т.к. хоть и зарекомендовал себя данный способ, всегда есть что-то лучше.

Дебют.

Поступает информация. Необходимо сделать сайт, который будет представлять информацию об услугах и товарах компании, без корзины/остатков и прочих штук интернет-магазина. Эта компания — наши соседи через здание. Маленький сервисный центр по ремонту телефонов, который еще и запчасти иногда продает.

Путем переговоров на свет рождается исписанный лист, который в данном случае и является неким «Техническим заданием» (что по нашей практике и есть достаточно). Затем в таск-менеджере появляется следующая задача:
Тип разработки: типовая.
Позиция по прайсу: каталог.
Структура меню:
— Главная
— О компании
— Ремонт
— Каталог запчастей
— Новости
— Контакты
Домен: simple.ru

Набор функционала тривиальный, когда нет дополнительных требований — этого обычно и достаточно для понимания того, что будет на сайте.

За данность возьмем следующее: у разработчика установлен LAMP-сервер, phpmyadmin, git, имеется репозиторий, к примеру на bitbucket, со штуками из предыдущего поста. Все команды даны относительно Ubuntu.

Ставим LAMP, если вдруг не стоит:

sudo apt-get install tasksel  sudo tasksel   sudo a2enmod rewrite  sudo apt-get install phpmyadmin  sudo apt-get install git  

Создаем VirtualHost, прописываем в hosts, включаем сайт:

mkdir /var/www/simple.ru  sudo nano /etc/apache2/sites-available/simple-ru.conf    sudo a2ensite simple-ru.conf  sudo service apache2 reload  sudo nano /etc/hosts   

Переходим в директорию проекта, тянем с git'а файлы, создаем бд и импортим дамп, который лежит в репозитории:

cd /var/www/simple.ru  git clone git@bitbucket.org:%username%/kosher_wordpress.git  mysql -uroot -p      mysql> CREATE DATABASE `simple-ru` CHARACTER SET utf8 COLLATE utf8_general_ci;  mysql -u username -p simple-ru < dump.sql  

Обязательно не забыть сделать sql запросы, чтобы wp понял то, на каком он домене находится.

Прописываем в wp-config.php параметры соединения с бд:

define('DB_NAME', 'simple-ru');  define('DB_USER', 'root');  define('DB_PASSWORD', 'pass');  define('DB_HOST', 'localhost');  

Переходим в браузере по адресу simple.ru и видим развернутый Wordpress с нашими любимыми плагинами и прочими нужными штуками. И сейчас, когда я пишу эту статью, стало ясно, что все вышесказанное можно запихнуть в один sh скрипт/оформить в гуях, т.к. первые 20 раз весело в консоли писать — потом нет. Но все же.

Миттельшпиль.

В качестве шаблона, который «выбрал» клиент, я буду использовать этот — FORNAX. Он очень наглядно покажет проблемы, которые возникают, пути их решения.

Упор делается, по большей части, на максимальную простоту для новичка, поэтому это не догма. Баланс, если брать опыт сборки большого количества проектов подобного типа и обучения ребят, за последний год, соблюден. Улучшения необходимые приходят с опытом, но как база — подходит. Поехали.

1. Переименовываем папку snippets в simple-ru и кидаем внутрь верстку, папка assets.



В файле themes/simple-ru/style.css пишем следующее:

  

Содержимое themes/simple-ru/assets/index.html копируем в themes/simple-ru/index.php и активируем тему в админ-панели WP (Внешний вид -> Темы -> Активировать). Если мы в данный момент посмотрим на сайт — стили/скрипты/изображения не подключились. Решим эту проблему функционалом редактора/IDE (я использую PhpStorm, CTRL+R) Найти и заменить. Вот три сниппета, которые справедливы в контексте этого шаблона, выполняются последовательно:

Найти: href="css/  Заменить: href="<?php bloginfo('template_url');?>/assets/css/    Найти: src="js/  Заменить: src="<?php bloginfo('template_url');?>/assets/js/    Найти: src="img/  Заменить: src="<?php bloginfo('template_url');?>/assets/img/  

В моем случае еще необходимо прописать пути к фавиконкам, что я и делаю.

2. Начинаем резать верстку по файлам

Для начала, исходя из структуры сайта, представляем сколько разных по типу страниц у нас будет. А именно:

  • Главная страница
  • Статические страницы (О компании, ремонт)
  • Страница контактов
  • Страница списка товаров
  • Страница списка новостей, страница отдельной новости (1 шаблон для них)

И, конечно, верхнюю часть и нижнюю часть страницы вынесем тоже в отдельные шаблоны. Создаем недостающие файлы:

  • front-page.php (Главная страница)
  • page.php (Статические страницы)
  • tpl-contacts.php (Страница контактов)
  • tpl-products.php (Страница продукции)

В админ-панели не забываем выставить Настройки->Чтение->На главной отображать->Указываем статическую страницу новостей и главную.

И разбрасываем верстку по файлам. Здесь необходимо применить чуть смекалки, но обычно ничего сложного нет. В файлы themes/simple-ru/header.php и themes/simple-ru/footer.php копируем верхний блок с меню, нижний с подвалом. Остальные страницы из themes/simple-ru/assets/*.html вырезаем соответственно в свои themes/simple-ru/*.php.

Добавляем get_header() наверх и get_footer() вниз каждого шаблона, для подключения шапки и футера. Сниппет «Найти и Заменить» исполняем аналогично, обычно нужна только часть, связанная с изображениями. В файлах tpl-contacts.php,tpl-products.php перед всем кодом должно быть следующее:

<?php    ?>  

Для чего? Потом в страницах будем выбирать их как шаблоны. Подробности.

Чтобы было наглядней, вот листинги текущего состояния, CTRL+C CTRL+V:

themes/simple-ru/header.php

themes/simple-ru/footer.php

themes/simple-ru/front-page.php

themes/simple-ru/index.php

themes/simple-ru/page.php

themes/simple-ru/tpl-contacts.php

themes/simple-ru/tpl-products.php

3. Наполняем смыслом «обвязку»

Теперь вся работа сводится к замену верстки на WP функции. Работа муторная, но что делать, мы же профессионалы.

Начнем с обвязки (header, footer). Необходимо следующее:

  1. Шрифт Source Sans Pro не имеет русских символов, поправить.
  2. Тайтлы, сео теги, контекстный админ-бар сверху. Пропишем wp_head() и wp_footer().
  3. Меню должно управляться с админ-панели.
  4. Оставить заголовок страницы только на внутренних.
  5. Редактируемый логотип
  6. Социальные сети внизу
  7. Копирайты

В шаблоне header.php прописываем тайтлы и заменяем шрифт (подбираем аналог, я взял для примера Open Sans).

<title>ShapeBootstrap Clean Template</title>  <meta name="viewport" content="width=device-width, initial-scale=1.0">  <meta name="description" content="">  <meta name="author" content="">  

<title></title>  <meta name="viewport" content="width=device-width, initial-scale=1.0">  <?php wp_head();?>  

<link href='http://fonts.googleapis.com/css?family=Source+Sans+Pro:200,300,400,600' rel='stylesheet' type='text/css'>  

<link href='http://fonts.googleapis.com/css?family=Open+Sans:200,300,400,600&subset=latin,cyrillic' rel='stylesheet' type='text/css'>  <!-- В файле assets/css/style.css заменяем вхождения Soure Sans Pro на Open Sans, CTRL+R -->  

И перед body в файле footer.php вставляем <?php wp_footer();?>.

С пунктом три немного интересней. Для вывода WP использует функцию wp_nav_menu($args). Наша цель состоит в том, чтобы сделать генерируемый этой функцией HTML аналогичным шаблону.

Как мы видим, исходя из верстки, класс дочерних меню — dropdown-menu. Да и для родителя не все хорошо:

class="dropdown-toggle" data-toggle="dropdown">About <b class="caret"></b>


Но ничего страшного, достаточно наследовать стандартный класс Walker_Nav_Menu, немного модифицировать, поместить его в functions.php и назначить его нашей функции, которая выводит меню. Ну и плюс, чтобы активный пункт меню подсвечивался.


В итоге у нас получилось меню, которое соответствует шаблону:



Walker писать это уже выходит за рамки направления, которое я взял, когда писал эту заметку, но обычно можно решить этот вопрос альтернативно, потратив некоторое время на модификацию верстки.

Для того, чтобы убрать заголовок с главной и показывать только на внутренних, существуют функции условий. Нам понадобится is_home(). Просто оборачиваем блок в условие, заодно выводим заголовок в него:

<?php  ?>  <?php if(!is_home()):?>      <!--PAGE TITLE-->      <div class="row">          <div class="span12">              <div class="page-header">                  <h1>                      <?php wp_title('');?>                  </h1>              </div>          </div>      </div>      <!-- /. PAGE TITLE-->  <?php endif;?>  

Идем дальше. Все остальные пункты нашей обвязки попадают под понятие «глобальные настройки сайта». Для этого я использую данный инструмент (благодарю автора).


В итоге получается довольно симпатичная форма настроек для темы:



Заменяем в верстке плейсхолдеры на <?php echo sa_option($id);?>, добавляем полей для социальных сетей и готово.

3. Переходим на внутренние страницы.

Для начала создадим все нужные нам страницы в админ-панели и назначим для страницы «Контакты» и страницы «Продукция» кастомные шаблоны. И в меню добавим заодно.



Теперь у нас можно переходить по меню, будут видны наши красивые странички. Но контент-менеджер, который будет наполнять это все дело, открутит голову мне, если я оставлю в таком виде. Продолжаем работать.

Шаблон статических страниц, page.php

Используем main loop, все стандартно. Листинг конечного шаблона:

<?php get_header();?>  <div class="row">      <div class="span12">          <?php if (have_posts()) : ?>              <?php while (have_posts()) : the_post(); ?>                  <?php the_content(); ?>              <?php endwhile; ?>          <?php else: ?>              <p><?php _e('Sorry, no posts matched your criteria.'); ?></p>          <?php endif; ?>      </div>  </div>  <div class="hr-divider"></div>  <?php get_footer();?>	  

Шаблон каталога, tpl-products.php

Создадим, используя плагин Magic Fields, новый тип постов. Дополнительных полей у этого типа нет, выбираем галочками дефолтные title, thumbnail и excerpt. С помощью WP_Query заменим плейсхолдеры в шаблоне tpl-products.php на цикл из бд.

Если поля есть — просто получать их функцией get();

Листинг конечного шаблона:

<?php    ?>  <?php get_header(); ?>  <div class="span12">      <?php      $args = array(          'post_type' => 'products',          'posts_per_page' => '-1'      );        $the_query = new WP_Query($args);      ?>        <?php if ($the_query->have_posts()) : ?>          <ul class="thumbnails">          <?php while ($the_query->have_posts()) : $the_query->the_post(); ?>                <?php              $url = wp_get_attachment_url(get_post_thumbnail_id($the_query->post->ID));              $image = vt_resize(null, $url, 600, 300, true);              if (!$image['url']) $image['url'] = 'http://placehold.it/600x300&text=NO IMAGE';              ?>                <li class="span4">                  <div class="thumbnail">                      <img alt="<?php echo the_title(); ?>" src="<?php echo $image['url']; ?>">                      <div class="caption">                          <strong><?php echo the_title(); ?></strong>                          <p><?php the_excerpt();?></p>                      </div>                  </div>              </li>            <?php endwhile; ?>          <?php wp_reset_postdata(); ?>          </ul>      <?php else: ?>          <p><?php _e('Sorry, no posts matched your criteria.'); ?></p>      <?php endif; ?>  </div>  <?php get_footer(); ?>  

Шаблон новостей, index.php

Дробить на сайдбары с виджетами не будем, ибо обычно нет в этом необходимости. Поэтому поступаем аналогично. Main loop и плейсхолдеры. Ну и несколько функций необходимо знать, для вывода тегов, паджинации, списка категорий. Код лаконичней объяснит:

  <?php get_header(); ?>    <div class="row">      <div class="span9">          <?php if (have_posts()) : ?>              <?php while (have_posts()) : the_post(); ?>                    <?php                  $url = wp_get_attachment_url(get_post_thumbnail_id($post->ID));                  $image = vt_resize(null, $url, 870, 400, true);                  if (!$image['url']) $image['url'] = 'http://placehold.it/870x400&text=NO IMAGE';                  ?>                  <div class="blog-post">                      <h2><?php the_title();?></h2>                        <div class="postmetadata">                          <ul>                              <li>                                  <i class="icon-calendar"></i><?php the_date();?>                              </li>                                <li>                                  <i class="icon-tags"></i> <?php echo  get_the_tag_list();?>                              </li>                          </ul>                      </div>                        <img src="<?php echo $image['url'];?>">                      <p><?php the_content('');?></p>                      <?php if(!is_singular()):?>                          <a class="btn btn-primary" href="<?php the_permalink();?>">Читать далее</a>                      <?php else:?>                          <a class="btn btn-primary" href="/novosti">Все новости</a>                      <?php endif;?>                  </div>              <?php endwhile; ?>              <div class="pagination">                  <?php global $wp_query; wp_corenavi($wp_query);?>              </div>          <?php else: ?>              <p><?php _e('Sorry, no posts matched your criteria.'); ?></p>          <?php endif; ?>      </div>        <div class="span3">          <div class="side-bar">              <h3>Рубрики</h3>              <?php echo get_the_category_list(); ?>          </div>            <div class="side-bar">              <h3>Метки</h3>                <?php echo  get_the_tag_list();?>          </div>      </div>  </div>  <?php get_footer(); ?>  


Шаблон главной, шаблон страницы контактов (front-page.php, tpl-contacts.php).

Есть множество путей, самый простой — WP_Query бросить на слайдер, создав кастомный тип в админке, остальные элементы через глобальные настройки сайта. Единственный нюанс на странице контактов. Какой сайт без формы обратной связи? Я использую плагин Contact Form 7, интеграция верстки довольно простая. Все аналогично предыдущим пунктам, приводим генерируемый код в вид шаблона.

Делай раз-два-три.

  1. Скопировать верстку в редактор формы
  2. Заменить <input class="input-xxlarge" type="text" placeholder="Name" /> на [text* name class:input-xxlarge akismet:author placeholder "Имя"]
  3. Настроить шаблон письма

Теперь у нас сайт, через который пользователи могут писать. Эту форму можно встроить в всплывающее окно, встроить на другие страницы etc. Сниппет для шаблонов:

    <?php echo do_shortcode('[contact-form-7 id="4" title="Форма обратной связи"]');?>  


Эндшпиль.

Деплоим сайт на сервер, наполняем контентом, высылаем клиенту доступы в админ-панель. Если необходимо — 20 минут консультаций по поводу администрирования и забываем вопросы про добавление страниц навсегда. Можно рассчитывать бюджет на seo/контекст.

А впереди еще целых 6 часов до конца рабочего дня.

Примечание. Да, данный сайт не является произведением искусства, но, есть один большой плюс. Этот сайт есть, и, на мой взгляд, он выглядит не совсем грустно. Дороже наша гипотетическая компания не смогла бы заказать по финансовым соображениям. И в следующий раз, когда у меня, моих знакомых, друзей, родственников, просто людей, сломается телефон, они смогут найти в интернете хоть что-то местное, а не сайты с кодом москвы в номере.

Результат.



Sent from my iPhone

Комментариев нет:

Отправить комментарий