Как написать плагин для WordPress. Руководство по кастомным типам записей WordPress Создание дополнительных полей для пользовательских типов записей

WordPress подразумевает кастомизацию/настройку. Он был создан таким образом, чтобы можно было настроить абсолютно каждый раздел. В этом уроке мы рассмотрим пользовательские типы записей , одну из наиболее значительных и замечательных возможностей WordPress, с помощью которой WordPress смог достичь новых высот.

Что такое пользовательские типы записей?

Предположим, вы хотите чтобы в вашем блоге был отдельный раздел для кинообзоров. Используя пользовательские типы записей вы сможете создать новый тип, к примеру, Записи и Страницы, который будет содержать другой вид данных. У него будет свое меню администратора, специальные страницы для редактирования, свои таксономии и многие другие инструменты, которые нужны для полноценной работы с публикациями.

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

Зачем использовать пользовательские типы записей?

Пользовательские типы записей помогают хранить разные типы записей в разных местах. Это помогает отделить обычные посты от других. Вот и все.

Создаем плагин для пользовательского типа записи

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

Шаг 1 . Создайте папку для WordPress плагина

Откройте папку с WordPress плагинами и создайте новую папку Movie-Reviews .

Шаг 2 : Создайте PHP файл

В созданной папке создайте PHP файл Movie-Reviews.php

Шаг 3 : Добавьте шапку

Откройте созданный файл и вставьте код для шапки сверху.

Перед тегом закрытия PHP команды введите следующую строку кода create_movie_review . При инициализации она будет запускать соответствующую пользовательскую функцию каждый раз при генерации страницы.

Add_action("init", "create_movie_review");

Шаг 5 : Выполнение функции

Код для выполнения функции create_movie_review .

Function create_movie_review() { register_post_type("movie_reviews", array("labels" => array("name" => "Movie Reviews", "singular_name" => "Movie Review", "add_new" => "Add New", "add_new_item" => "Add New Movie Review", "edit" => "Edit", "edit_item" => "Edit Movie Review", "new_item" => "New Movie Review", "view" => "View", "view_item" => "View Movie Review", "search_items" => "Search Movie Reviews", "not_found" => "No Movie Reviews found", "not_found_in_trash" => "No Movie Reviews found in Trash", "parent" => "Parent Movie Review"), "public" => true, "menu_position" => 15, "supports" => array("title", "editor", "comments", "thumbnail", "custom-fields"), "taxonomies" => array(""), "menu_icon" => plugins_url("images/image.png", __FILE__), "has_archive" => true)); }

Функция register_post_type сделает бОльшую часть работы в нашем случае. Сразу как она вызовется, она подготовит необходимую для нового пользовательского поста конфигурацию WordPress, включая дополнительные разделы для администратора. В функцию передается два типа аргументов: уникальное имя (name) пользовательского типа поста и массив с его свойствами. Это другой массив с другими метками, которые указывают какие текстовые строки будут показываться в разных частях пользовательского типа записи, например: " name " выводит название пользовательского типа записи на панели управления, " edit " и " view " выводят кнопки Edit и View . Думаю, все остальные аргументы говорят сами за себя.

Так, в следующих аргументах:

  • "public" => true задает видимость пользовательского типа записи как на панели управления администратора, так и в клиентской части.
  • "menu_position" => 15 задает, где в меню, будет находиться пользовательский тип записи.
  • "supports" => array("title", "editor", "comments", "thumbnail", "custom-fields") задает те атрибуты пользовательского типа записи, которые будут отображаться.
  • "taxonomies" => array("") создает пользовательские таксономии. В данном случае они не определены.
  • "menu_icon" => plugins_url("images/image.png", __FILE__) показывает иконку в меню администратора.
  • "has_archive" => true разрешает архивирование пользовательских типов записей.

Вы можете узнать больше о других аргументах, используемых в пользовательских типах записей на странице WordPress Codex register_post_type .

Шаг 6 : Иконка для пользовательского типа записей

Сохраните иконку размером 16x16 пикселей в вашей папке с плагином. Это нужно для того, чтобы на панели управления у пользовательского типа записи была иконка.

Шаг 7 : Активируйте плагин

Активируйте плагин, и вуаля, у вас есть пользовательский тип записи с возможностью редактировать текст, настройками для публикации, изображений, комментариев, а также редактор пользовательских полей.

Шаг 8 : Добавляем новую запись

Выберите Добавить новую , чтобы открыть панель редактирования пользовательского типа записи. Добавьте название фильма, текст обзора, а также выберите миниатюру изображения.

Шаг 9 : Публикуем

Опубликуйте запись и нажмите View Movie Review , чтобы увидеть созданный кинообзор.

Создание дополнительных полей для пользовательских типов записей

Механизм дополнительных полей (метабоксов) использует встроенную в WordPress систему дополнительных полей. Это помогает добавлять поля, предназначенные исключительно для пользовательских типов записей, не используя в редакторе пользовательских полей по умолчанию.

Шаг 1 : Регистрируем пользовательскую функцию

Откройте файл Movie-Reviews.php и добавьте следующий код перед тегом закрытия. Этот код регистрирует функцию, которая будет вызываться при посещении панели администратора WordPress.

Add_action("admin_init", "my_admin");

Шаг 2 : Выполняем пользовательскую функцию

Добавьте выполнение функции my_admin , которая регистрирует дополнительные поля и связывает их с пользовательским типом записи movie_reviews .

Function my_admin() { add_meta_box("movie_review_meta_box", "Movie Review Details", "display_movie_review_meta_box", "movie_reviews", "normal", "high"); }

В данном случае функция add_meta_box используется для добавления дополнительных полей к пользовательскому типу записей. Об атрибутах:

  • movie_review_meta_box необходимый атрибут для HTML id
  • Movie Review Details текст, которые будет виден в заголовке дополнительного поля
  • display_movie_review_meta_box функция обратного вызова которая отображает содержимое дополнительных полей
  • movie_review имя пользовательского типа записи, где будут отображаться дополнительные поля
  • normal определяет где на странице будет показан блок редактирования
  • high определяет приоритет отображаемых полей

Шаг 3: Выполняем функцию display_movie_review_meta_box

ID, "movie_director", true)); $movie_rating = intval(get_post_meta($movie_review->ID, "movie_rating", true)); ?>
Movie Director
Movie Rating

Этот код выводит содержимое дополнительных полей. Здесь используется объектная переменная, которая содержит информацию о каждом из показанных на панели редактирования кинообзоров. Используя этот объект мы получили ID записи и использовали его, чтобы сделать запрос в базу данных для получения имени режиссера и рейтинга, что в свою очередь выведется в полях на экране. При добавлении новой записи, функция get_post_meta возвратит пустую строку, и в итоге дополнительные поля будут пустыми.

Шаг 4 : Регистрируем функцию сохранения записи

add_action("save_post", "add_movie_review_fields", 10, 2);

Эта функция вызывается при сохранении записи в базе данных.

Шаг 5 : Выполняем функцию add_movie_review_fields

function add_movie_review_fields($movie_review_id, $movie_review) { // Check post type for movie reviews if ($movie_review->post_type == "movie_reviews") { // Store data in post meta table if present in post data if (isset($_POST["movie_review_director_name"]) && $_POST["movie_review_director_name"] != "") { update_post_meta($movie_review_id, "movie_director", $_POST["movie_review_director_name"]); } if (isset($_POST["movie_review_rating"]) && $_POST["movie_review_rating"] != "") { update_post_meta($movie_review_id, "movie_rating", $_POST["movie_review_rating"]); } } }

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

Шаг 6 : Отключаем стандартные пользовательские поля

Создавая пользовательский тип записи, мы задали функцию create_movie_review . Удалите элемент custom-fields из массива supports , поскольку он нам больше не понадобиться. Теперь, если вы сохраните файл и откроете панель редактирования Movie Reviews , вы увидите два поля в дополнительных полях: Movie Author и Movie Rating . Вы можете добавить другие элементы тем же способом.

Создание шаблона для пользовательского типа записи

Правильным будет для каждого типа пользовательских записей использовать свои шаблоны для отображения данных. В нашем случае мы создадим шаблон, которые выводит все кинообзоры, которые были добавлены с использованием пользовательского типа записи Movie Review .

Шаг 1 : Регистрируем функцию запуска шаблона

Откройте файл Movie-Reviews.php и перед тегом закрытия добавьте следующий код. Этот код регистрирует функцию, которая будет вызываться при посещении панели администратора WordPress.

Add_filter("template_include", "include_template_function", 1);

Шаг 2 : Выполняем функцию

function include_template_function($template_path) { if (get_post_type() == "movie_reviews") { if (is_single()) { // checks if the file exists in the theme first, // otherwise serve the file from the plugin if ($theme_file = locate_template(array ("single-movie_reviews.php"))) { $template_path = $theme_file; } else { $template_path = plugin_dir_path(__FILE__) . "/single-movie_reviews.php"; } } } return $template_path; }

Здесь проверяется, есть ли в текущей папке темы шаблон типа single-(post-type-name).php . Если его там нет, то проверяется наличие шаблона в папке с плагином, куда мы и поместим наш шаблон, как часть плагина. Событийный обработчик (хук) template_include используется, чтобы изменить обычное выполнение программы и принудительно запустить специальный шаблон.

Шаг 3 : Создаем файл шаблона Single Page

Сохранив ранее открытый файл с плагином, создайте другой файл с именем single-movie_reviews.php и вставьте в него следующий код.

"movie_reviews",); $loop = new WP_Query($mypost); ?> have_posts()) : $loop->the_post();?>
>
Title:
Director:
Rating: "; } else { echo ""; } } ?>

В данном случае мы создали базовый шаблон страницы с использованием цикла. Функция query_posts получает элементы пользовательского типа записей и отображает их используя цикличность. Это конечно совсем простой цикл, вы можете менять его, как вам необходимо. Вы также можете использовать необходимые CSS стили, чтобы поменять внешнее оформление.

Внимание : необходимо создать новую страницу из панели управления используя созданный шаблон.

Шаг 4: Изображения

Сохраните два изображения с иконками для звездочек размером 32x32 пикселя в вашу папку с плагином. Назовите их соответственно icon.png и grey.png . Вот и все, теперь кинообзоры показываются на отдельной странице и отсортированы по дате.

A full stack framework that is faster than most if not all micro frameworks. This framework is not for beginners. It gives you the tools, but it"s up to the developer to implement them. If you have a genuine understanding of PHP, and performance is of concern, look no further. The documentation is thorough, but not beginner oriented, and the community is somewhat sparse, but I can"t stress performance enough. This framework puts my PHP applications on a performance level with JAVA applications.

Phlacon is from my point of view not just fastest framework on the market, but also it offers various features and nice components. Also very good to use as MicroFramework for restfull API"s or full MVC framework. Comes with C ORM, and twig template engine. Also what I really appreciate is how the framework is dynamic, you use only what you want, you can simply replace classes and libraries for custom ones or affect flow with events.

Very good job, only one problem is the community but I believe it will grow very fast:)

Phalcon is undoubtedly one of the most fast frameworks out there, and that"s its strong point. On the other hand, the documentation is a bit disorganized, Web tools (code generator) has major issues in Windows, and it is still lacking a bit more of a community to help new developers. But once again, performance, WOW.

Ответ

На основе https://toster.ru/q/276441 Понятное дело, многое зависит от проекта, поэтому данный пост стоит адаптировать под ваш случай.

* Безопасность:
- Каждый аргумент метода простого типа должен проверяться на тип в случае его проксирования и на граничные значения в случае обработки. Чуть что не так - бросается исключение. Если метод с несколькими аргументами на 80% состоит из поверки из аргументов - это вполне нормально))
- Никаких trigger_error, только исключения.
- Исключения ДОЛЖНЫ быть человеко-понятны, всякие "Something went wrong" можно отдавать пользователю, но в лог должно попасть исключение со стектрейсом и человеко-понятным описанием, что же там пошло не так.
- Каждый аргумент (объект) метода должен быть с тайпхинтингом на этот его класс, или интерфейс.
- За eval как правило жесткий выговор
- @ допускается только в безвыходных ситуациях, например проверка json_last_error.
- Перед работой с БД - обязательная проверка данных.
- Никаких == и!=. Со swtich - единственное исключение, по ситуации.
- Если метод возвращает не только bool, а еще что-то - жесткая проверка с ===, или!== обязательна.
- Никаких условий с присваиваниями внутри. while($row = ...) - тоже недопустимо.
- Магические геттеры/сеттеры разрешаются только в безвыходных ситуациях, в остальном - запрещены.
- Конкатенации в sql - только в безвыходных ситуациях.
- Параметры в sql - ТОЛЬКО через плейсхолдеры.
- Никаких глобальных переменных.
- Даты в виде строки разрешаются только в шаблонах и в БД, в пхп коде сразу преобразуется в \DateTimeImmutable (в безвыходных ситуациях разрешено \DateTime)
- Конечно зависит от проекта, но как правило должно быть всего две точки входа: index.php для web и console(или как-то по другому назваться) - для консоли.

* Кодстайл PSR-2 + PSR-5 как минимум, + еще куча более жестких требований (для начала все то что в PSR помечено как SHOULD - становится MUST)
- В PhpStorm ни одна строчка не должна подсвечиваться (исключением является typo ошибки, например словарик не знает какой-то из аббревиатур, принятых в вашем проекте). При этом разрешается использовать /** @noinspection *** */ для безвыходных ситуаций.
- Если кто-то говорит, что пишет в другом редакторе и у него не подсвечивается, все равно отправляется на доработку.

* Организация кода:
- Никаких глобальных функций.
- Классы без неймспейса разрешаются только в исключительно безвыходных ситуациях.

* Тестируемость (в смысле простота тестирования) кода должна быть высокая.
- Покрытие кода обязательно для всех возможных кейсов использования каждого публичного метода с моками зависимостей.

* Принципы MVC:
- Никаких обработок пользовательского ввода в моделях, от слова совсем.
- Никаких запросов в БД из шаблонов.
- Никаких верстки/js/css/sql-ин в контроллерах.
- В моделях НИКАКОЙ МАГИИ, только приватные свойства + геттеры с сеттерами.
- В моделях разрешено использовать метод save(при наличии такого разумеется) только в исключительных ситуациях. Во всех остальных - либо insert, либо update.

* Принципы SOLID:
- Никаких универсальных объектов, умеющих все.
- Если метод для внутреннего пользования - private, никаких public.
- Статические методы разрешаются только в случае безвыходности.

* Принцип DRY разрешено нарушать в случаях:
- Явного разделения обязанностей
- В тестах (каждый тест должен быть независимым, на сколько это возможно)

* Работа с БД:
- Запрос в цикле должен быть РЕАЛЬНО обоснован.
- За ORDER BY RAND() жесткий выговор
- Поиск не по ключам (конечно если таблица НЕ на 5 строк) запрещен.
- Поиск без LIMIT (опять же если таблица НЕ на 5 строк) запрещен.
- SELECT * - запрещен.
- Денормализация БД должна быть обоснована.
- MyISAM не используется (так уж)))
- Множественные операции обязательно в транзакции, с откатом если что-то пошло не так.
- БД не должна содержать бизнес логики, только данные в целостном виде.
- Не должно быть нецелесообразного дерганья БД там, где без этого можно обойтись.

* Кэш должен очищаться по двум условиям (не по одному из, а именно по двум):
- Время.
- Протухание по бизнес логике.
Разрешается по только времени в безвыходных ситуациях, но тогда время - короткий период.
- При расчете ключей кэша должна использоваться переменная из конфигурации приложения (на случай обновлений кэш сбрасывается кодом, а не флашем кэш-сервера). В случае использования множества серверов - это очень удобный и гибкий инструмент при диплое.

* О людях:
- "Я привык писать так и буду дальше" - не вопрос, ревью пройдешь только когда поменяешь свое мнение.
- "Я пишу в vim-е и мне так удобно" - здорово, код консолью я тоже в нем пишу)) но есть требования к коду, если в них не сможешь - не пройдешь ревью.
- "Я скопировал этот страшный метод и поменял 2 строчки" - это конечно замечательно, но по блейму автор всего этого метода ты, так что давай без ерунды, хорошо?
- "Оно же работает!" - вот эта фраза переводится примерно так: "да, я понимаю, что пишу полную ерунду, но не могу писать нормально потому, что не могу", я правильно тебя понял?))
- "У меня все работает!" - рад за тебя, а как на счет продакшна?
- "Там все просто" - не используй слово "просто", от слова "совсем". Вот тебе кусок кода (первого попавшегося со сложной бизнес логикой), где там ошибка (не важно есть она, или нет)? Ты смотришь его уже 2 минуты, в чем проблема, там же все "просто"))

* Всякое:
ActiveRecord (это я вам как в прошлом фанат Yii говорю) - полный отстой, примите за исходную. По факту у вас бесконтрольно по проекту гуляют модельки с подключением к БД. Не раз натыкался на то, что в тех же шаблонах вызывают save, или update (за такое надо сжигать).

Основное:
1. Наличие критических ошибок и устаревших функций.
2. Использование паттернов, элегантность решений.
3. Читабельность кода, наличие коментариев, наличие доков.
4. Соблюдение парадигм и соглашений (например, нарушение MVC).

Второстепенно\непринципиально:
1. Быстродействие кода (за исключением хайлоад)
2. Потребление памяти (за исключением бигдаты)
3. Эфективность SQL запросов (за исключением совсем уж несуразных)
4. Избегание в данных момент неважных, но потенциально узких мест (например замедление работы файловой системы при большом количестве картинок в папке аплоада)
5. Новизна примененых технологий.
6. Оправданое\Неоправднанное\Избыточное Велосипедирование.

  1. Код не содержит явных и потенциальных ошибок.
  2. Код работает так, как это описано в документации, техническом задании или сопроводительных комментариях.
  3. Стиль кодирования соответствует принятым правилам кодирования
  4. Код имеет сопроводительные комментарии в соответствии с phpDoc
  5. Вложенность блоков не превышает 4-го уровня.
  6. Код не генерирует сообщения уровня Strict, Warning, Notice, Deprecated. Если этого невозможно избежать, то непосредственно перед строкой, которая это генерирует необходимо принудительно отключить error_reporting, а непосредственно после строки включить error_reporting в исходное значение (которое было до этого). Такой код должен быть задокументирован специальным образом.
  7. Закомментированный кусок кода должен быть удален.
  8. В PHP коде (за исключением phpTemplate) запрещены вставки HTML, JavaScript. Все вставки должны производиться через специальные шаблоны.
  9. Классы, функции, переменные и константы должны логически именоваться человекопонятным способом на английском языке в соответствии со стандартами кодирования. Не допускается именование транслитом на русском, либо на иных языках
  10. Область видимости переменных и методов классов всегда должна быть определена (private, protected, public).
  11. Размер одного метода не должен превышать 40-50 строк.
  12. Переменная, используемая в цикле, либо в условном блоке должна быть инициализирована заранее.
  13. Переменная в любой момент времени должна содержать только один тип. Пустая переменная должна содержать null. (не допускается $var = false; $var = "test"; . Допускается $var = null; $var = "test";).
  14. При передаче объектов классов в методы должен использоваться контроль типов.

First, from a code organization standpoint, it’d be better to put all of the review logic into one or more includable files and then include it on product pages:

Include("includes/reviews.php");

This way, the product pages can remain unadulterated and the same review code can easily be used, or modified, as needed. The reviews.php script would do several things:

  • Show the review form
  • Handle the review form
  • List the existing reviews
  • Handle secondary actions, such as flagging reviews or comments as inappropriate, indicating that reviews were helpful, adding comments to reviews, indicating that comments where helpful, and so forth

Hopefully you’ve done plenty of web development already, so you know that a form for adding reviews would just be like so:

Review This Product

5 4 3 2 1

Clearly you’d want to use some CSS to make it pretty, but that’s the basic idea. The main catch is that the product ID and product type (or whatever the database must have in order to associate a review with an item) must be stored in hidden inputs. You’d have the PHP script that displays the product write these values to the inputs.

If login is required, you might add (PHP) code that only shows the form to logged-in users, or prints a comment saying the user must log in to review the product. Similarly, if you have a system in place for guaranteeing a person only ever reviews a product once, you’d have PHP check for that scenario before showing this form.

The form submission could go to a new page, but then the user would need to click the Back button to return to the product page, which isn’t ideal. I would instead submit the form back to the product page. For example, on any dynamic website, the same PHP script is used to display all the content of a specific type. In my Effortless E-Commerce with PHP and MySQL book, the first example site uses the page.php script to show any page of content. The action attribute of the form would point to the same page.php . You can accomplish this by just leaving the attribute empty, or by using PHP to dynamically set the value.

If the PHP page that lists the products requires that a value identifying the product be passed in the URL, then the form would need to store that value in a hidden input as well. (That may already be the case, with the product_id input, depending upon how the site is set up.) Secondarily, the product script would also need to be updated to allow for the product value to be received via POST .

For the reviews.php script to know when to handle a form submission, it can check how the script was accessed:

If ($_SERVER["REQUEST_METHOD"] == "POST") { // Handle the form.

When the review form is submitted, the form data should be validated. You should also apply strip_tags() to the data to prevent Cross-Site Scripting (XSS) attacks or other bad behavior. And non-numeric values would be run through an escaping function, such as mysqli_real_escape_string() . Or you could just use prepared statements or stored procedures for better security and performance.

If you add an anchor to the form’s action attribute— action="page.php#reviews "—the user will be taken to the reviews section of the page upon the submission, which is a nice touch.

If the reviews.php script is also handling some of the other actions—inappropriate reviews or comments, helpful indicators, etc.—the script would need to watch for those submissions, too. I would use hidden inputs named “task” to indicate which action is being taken.

In a separate article, I demonstrate how to use Ajax for a simple rating system. Similar Ajax code could be used for the review system, too.

Шаблоны файлов WooCommerce содержат разметку и структуру шаблона интерфейса (и HTML сообщения электронной почты) вашего магазина. Если Вы откроете эти файлы, то Вы заметите, что все они содержат много хуков (hooks), которые позволят Вам добавлять / перемещать контент без необходимости редактирования самих файлов шаблона. Такой подход защищает от любых проблем с обновлениями, так как файлы шаблона могут оставаться полностью нетронутыми.

Кроме того, вы можете редактировать эти файлы безопасным способом с помощью подмены. Просто скопируйте их в Ваш шаблон в папку с именем /woocommerce , сохраняя ту же иерархическую структуру вложенных файлов и папок. Скопированные файлы шаблонов переопределят файлы шаблонов WooCommerce, используемые по умолчанию. Не редактируйте файлы шаблонов в ядре самого плагина, так как они будут перезаписаны в процессе обновления и все внесенные в них изменения будут потеряны, поскольку обновленные файлы шаблонов затрут старые файлы шаблонов.

Если Вы хотите внести изменения в один из шаблонов , то нет необходимости копировать все файл шаблонов, расположенные в папке templates, а достаточно скопировать только файл шаблона, в который Вы хотите внести изменения . Для этого с директории в вашей темой создайте папку woocommerce и перенесите в нее шаблон, соблюдая вложенность папок.

Пример: для внесения изменений в шаблон корзины, скопируйте woocommerce/templates/cart/cart.php в . После этого Вы можете вносить любые изменения в файл шаблона cart.php , расположенный в папке с вашей темой (т.е. в файл cart.php, расположенный по адресу ваша_тема/woocommerce/cart/cart.php ), и внесенные вами изменения сохранятся даже после обновления WooCommerce.


В директории /woocommerce/templates/ можно найти следующие файлы шаблонов

Спойлер: Список файлов

(данный список файлов шаблонов актуален для версии WooCommerce 2.0+):

· archive-product.php

· cart/


· cart-empty.php

· cross-sells.php

· mini-cart.php

· shipping-calculator.php

· shipping-methods.php

· totals.php​


· checkout/


· cart-errors.php

· form-billing.php

· form-checkout.php

· form-coupon.php

· form-login.php

· form-pay.php

· form-shipping.php

· review-order.php

· thankyou.php

· content-product_cat.php

· content-product.php

· content-single-product.php​


· emails/


· admin-new-order.php

· customer-completed-order.php

· customer-invoice.php

· customer-new_account.php

· customer-note.php

· customer-processing-order.php

· customer-reset-password.php

· email-addresses.php

· email-footer.php

· email-header.php

· email-order-items.php​


· loop/


· add-to-cart.php

· loop-end.php

· loop-start.php

· no-products-found.php

· pagination.php

· result-count.php

· sale-flash.php​


· myaccount/


· form-change-password.php

· form-edit-address.php

· form-login.php

· form-lost-password.php

· my-account.php

· my-address.php

· my-downloads.php

· my-orders.php​


· order/


· form-tracking.php

· order-details.php

· tracking.php​


· shop/


· breadcrumb.php

· form-login.php

· messages.php

· wrapper-end.php

Понравилось? Лайкни нас на Facebook