• CSS
    • ПРОГРАММИРОВАНИЕ (CODING)
    • Emmet, ul, li, table, form
    • Style, hover, child
    • CSS Hat, font, background
    • Reset, margin, padding, float
    • Base64, relative, z-index
    • Google Fonts, PSD
    • Brackets, Bootstrap
    • Script, src, comments
    • jQuery, Slick Js, Tooltip
    • Bootstrap, Slick Nav, @media
    • Mobile Vew, Font Awesome
    • SASS, Bootstrap
    • Flexbox, Slider
  • Word Press
    • #1. Introduction to WordPress
    • #2. WordPress Files Configuration
    • #3. Kernel Review. Codex
    • #4. Standards of Encoding
    • #5. Develop a plugin, introduction
    • #6. Hooks, Filters, InterNation
    • #7. Adding Admin Menus, JS, CSS
    • #8. HTTP API, Shortcodes, Transients
    • #9. Options API, Settings API
    • #10. Database API, $wpdb object
    • #11. Ajax. Widget API. Dashboard API
    • #12. Post Type. Taxonomies. Metadata
    • #13. Theme Development. Basics
    • #14. Loop. Template. WP_Query
    • #15. File functions.php – I
    • #16. File functions.php – II
    • #17. Child Theme. Shortcode. TinyMCE
    • #18. Frameworks. Blank Theme
    • #19. Framework. Underscores. Unyson
    • #20: Framework Unyson. Options
    • #21. Extensions, Components, Manifest
    • #22. Unyson: Built-in Extensions
    • #23. Unyson: Helpers, Filters & Actions
    • #24. WC: Installation & Updating
    • #25. WC: Settings & Options
    • #26. WC: Product Setup
    • #27. WC: Sell Products, Order
    • #28. WC: Theming
    • #29. WC: Extending
    • #30. WC: Extending
  • PHP
    • Laravel, MVC, Composer
    • FW Yii2
  • JS
    • JS
    • React, Angular
  • Freelance
  • Projects
    • Useful Products
      • Free WordPress Themes (WP)
      • Free CSS templates (CSS, HTML)
      • Стартовая тема Word Press (WP)
    • Project
      • Practic Task
      • Real Democracy Game
      • Research Journal
      • Qubot
      • Cyber-street
      • Amatue

#21. Extensions, Components, Manifest

Rostyslav - 5 февраля, 2018 - One comment

    Extensions

    Directory Structure

    Load Locations

    Custom Load Locations

    Child Extensions

    Create Extension

    Cookbook

    Disable Child Extensions

    Validate Child Extensions

    Components

    Theme

    Backend

    Extensions

    Manifest

    Framework

    Расширения — это функциональные возможности, которые добавляют что-то новое к фреймворку или другому расширению. Они могут быть установлены на странице расширений, в комплекте с темой или загружаться из плагина (или любого каталога).

    • Directory Structure
    • Load Locations
    • Custom Load Locations
    • Child Extensions

    Directory Structure

    Каждое расширение имеет все необходимое в своей папке: settings, options, scripts, styles и т. д. Таким образом, расширения могут быть легко добавлены или удалены, не затрагивая другие файлы.Каталог расширений имеет следующую структуру:

    {extension-name}/
    ├─manifest.php  # Данные о расширении: версия, имя, зависимости и т. Д.
    ├─class-fw-extension-{extension-name}.php # class FW_Extension_{Extension_Name} extends FW_Extension { … }
    ├─config.php    # Extension specific configurations
    ├─static.php    # wp_enqueue_style() and wp_enqueue_script()
    ├─posts.php     # register_post_type() and register_taxonomy()
    ├─hooks.php     # add_filter() and add_action()
    ├─helpers.php   # Helper functions and classes
    ├─readme.md.php # Install instructions
    ├─options/
    │ ├─posts/      # Post types options
    │ │ ├─post.php
    │ │ ├─{post-type}.php
    │ │ └─…
    │ ├─taxonomies/ # Taxonomies terms options
    │ │ ├─category.php
    │ │ ├─post_tag.php
    │ │ ├─{taxonomy}.php
    │ │ └─…
    │ └-…
    ├─settings-options.php # Extension Settings page options
    ├─views/
    │ └─…
    ├─static/
    │ ├─js/
    │ ├─css/
    │ └─…
    ├─includes/ # All .php files are auto included (no need to require_once)
    │ ├─other.php
    │ └─…
    └───[extensions/] # Directory for sub extensions

    Давайте более подробно рассмотрим каждый каталог и файл и поймем, как это работает.

    • manifest.php — Единственный необходимый файл, все остальные файлы являются необязательными. Он содержит базовую информацию о расширении. Подробнее о extension manifest.
    • class-fw-extension-{extension-name}.php — Если расширение имеет некоторые дополнительные функции, оно может определить класс, который будет экземпляром расширения, возвращаемого функцией fw()->extensions->get(‘{extension-name}’). По умолчанию будет создан экземпляр класса по умолчанию, который является пустым классом, который просто расширяет класс FW_Extension. Этот файл нельзя перезаписать.
    • config.php — Массив конфигурации, доступ к которому осуществляется с помощью метода $ext->get_config (‘key’). Пользователи могут настроить его, создав тот же файл в {theme-name} / framework-customizations / extension / {extension-name} /config.php и перезаписать только некоторые ключи (внутренне делается array_merge ($extension_config, $ theme_customized_config)).
    • static.php — Вставлять скрипты и стили расширения. Он автоматически включается в действия wp_enqueue_scripts и admin_enqueue_scripts, поэтому вы можете помещать в него как скрипты, так и стили администратора и внешнего интерфейса, но вам придется использовать функцию is_admin (). Этот файл можно перезаписать из темы, создав {theme-name}/framework-customizations/extension/{extension-name}/static.php.
    • posts.php — Регистрируйте типы записей и таксономии для темы в этом файле. Он включается автоматически в действие init.
    • hooks.php — Файл, содержащий фильтры и действия. Этот файл автоматически включается как можно раньше, таким образом, ваше расширение не пропустит никаких действий или выполнения фильтра.
    • helpers.php — All extension’s helper functions and classes must be in this file.
    • readme.md.php — Инструкции по установке для пользователей, чтобы расширение работало.
    • options/ — Каталог, содержащий файлы option: типы post, таксономии или custom options. Фреймворк не будет автоматически выбирать их (например, параметры options), только расширение определяет, как использовать эти параметры. Вы можете получить к ним доступ с помощью методов $ext->get _ […] _ options(). Пользователи могут перезаписать в теме любой файл из каталога options / путем создания {theme-name}/framework-customizations/extension/{extension-name}/options/{file-name}.php.
    • settings-options.php — Options, используемые для страницы настроек расширения. Фреймворк выбирает их автоматически и сохраняет значения в базе данных. Используйте функцию fw_get_db_ext_settings_option(), чтобы получить значения параметров из базы данных. Этот файл не может быть перезаписан из темы, поэтому он не был помещен в options/ каталог.
    • views/ — Содержит шаблоны расширений. Внутри класса расширения вы можете визуализировать представление вида $ this->render_view(‘template-name’) ;. Представления (views) могут быть перезаписаны в теме путем создания {theme-name}/framework-customizations/extension/{extension-name}/views/{template-name}.php.
    • static/ — Содержит styles, scripts, изображения и другие статические файлы. Некоторые файлы могут быть перезаписаны в теме, некоторые нет, это зависит от того, как они помещены в очередь в расширении, используя $this->locate_URI() или $ this->get_declared_URI().
    • includes/ — Все .php-файлы в этом каталоге будут автоматически включены.

    Load Locations

    Расширения загружаются из следующих каталогов и в следующем порядке:

    1. framework/extensions/
    2. Пользовательские каталоги, заданные с помощью  fw_extensions_locations filter
    3. {parent-theme}/framework-customizations/extensions/
    4. {child-theme}/framework-customizations/extensions/

    Custom Load Locations

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

    /**

    * @internal

    */

    function _filter_plugin_awesome_extensions($locations) {

       $locations[ dirname(__FILE__) . ‘/extensions’ ]

       =

       plugin_dir_url( __FILE__ ) . ‘extensions’;

       return $locations;

    }

    add_filter(‘fw_extensions_locations’, ‘_filter_plugin_awesome_extensions’);

    Child Extensions

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

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

    1. Если расширение hello находится в framework, дочерние расширения могут быть размещены в: framework, родительской теме и дочерней теме.

    framework/

    └─extensions/

     └─hello/

       └─extensions/

         ├─hello-child/

         └─…

     

    ├─parent-theme/

    │ └─framework-customizations/

    │   └─extensions/

    │     └─hello/

    │       └─extensions/

    │         ├─hello-child/

    │         └─…

     

    └─child-theme/

     └─framework-customizations/

       └─extensions/

         └─hello/

           └─extensions/

             ├─hello-child/

             └─…

    Если расширение hello находится в родительской теме, дочерние расширения можно поместить в: родительскую тему и дочернюю тему.

    ├─parent-theme/

    │ └─framework-customizations/

    │   └─extensions/

    │     └─hello/

    │       └─extensions/

    │         ├─hello-child/

    │         └─…

     

    └─child-theme/

     └─framework-customizations/

       └─extensions/

         └─hello/

           └─extensions/

             ├─hello-child/

             └─…

    Если расширение hello находится в дочерней теме, дочерние расширения могут быть помещены только в дочернюю тему.

    └─child-theme/

     └─framework-customizations/

       └─extensions/

         └─hello/

           └─extensions/

             ├─hello-child/

             └─…

    Create Extension

    Чтобы создать расширение:

    1. Создайте каталог с именем расширения в любом каталоге extensions/ с файлом manifest.php. Внутренне, что создаст экземпляр класса FW_Extension_Default. Кроме того, вы можете поместить файл class-fw-extension- {extension-name}.php со следующим содержимым во вновь созданный каталог и начать создавать некоторые дополнительные функции:

    <?php if (!defined(‘FW’)) die(‘Forbidden’);

    class FW_Extension_{Extension_Name} extends FW_Extension

    {

       // …

    }

    Чтобы сделать расширение видимым на странице списка расширений (по умолчанию оно скрыто), установите для параметра display manifest значение true.

    Убедитесь, что вы понимаете, что означает параметр standalone manifest.

    Cookbook

    Cookbook представляет собой сборник конкретных рецептов, которые объясняют, как правильно решать наиболее повторяющиеся проблемы, с которыми сталкиваются разработчики в своей повседневной работе.

    Disable Child Extensions

    Дочерние расширения не будут активированы, если родительское расширение вернет false; Из _init().

    <?php if (!defined(‘FW’)) die(‘Forbidden’);

    class FW_Extension_Example extends FW_Extension

    {

       /**

        * @internal

        */

       protected function _init()

       {

           // …

           if ($this->something_is_wrong()) {

               return false; // Предотвращение активации дочерних расширений

           }

       }

    }

    Validate Child Extensions

    Родительское расширение имеет возможность проверять каждое дочернее расширение, если оно действительно или нет. Если дочерний добавочный номер недействителен, он не будет активирован. Чтобы сделать это, родительское расширение должно перезаписать метод

    _child_extension_is_valid().Метод должен возвращать true, если дочернее расширение является допустимым, и false, если нет.

    <?php if (!defined(‘FW’)) die(‘Forbidden’);

    class FW_Extension_Example extends FW_Extension

    {

       /**

        * {@inheritdoc}

        */

       public function _child_extension_is_valid($child_extension_instance)

       {

           // force child extensions  для расширения некоторого пользовательского класса вместо FW_Extension

           return is_subclass_of($child_extension_instance, ‘FW_Ext_Demo_Custom_Class’);

       }

       // …

    }

    Components

    Введение

    Unyson framework core состоит из трех компонентов:

     

    • Theme
    • Backend
    • Extensions

     

    Доступ к одному из компонентов ядра осуществляется следующим образом:

    fw()->{$component}->{$method}()

    fw() возвращает объект framework object, что является единственным способом доступа к основному ядру.

    Theme

    Компонент Theme обеспечивает связь между темой и фреймворком. Рабочий каталог — это framework-customizations/theme/ внутри дочерних и родительских тем.

    get_options($name) — Возвращает массив options из указанного файла option framework-customizations/theme/options/{$name}.php.

    $custom_options = fw()->theme->get_options(‘custom’);

    get_settings_options() — Возвращает массив options из framework-customizations/theme/options/settings.php.

    $settings_options = fw()->theme->get_settings_options();

    get_customizer_options() — Возвращает массив options из framework-customizations/theme/options/customizer.php.

    $customizer_options = fw()->theme->get_customizer_options();

    get_post_options($post_type)  — Возвращает массив options из

    framework-customizations/theme/options/posts/{$post_type}.php.

    $custom_post_options = fw()->theme->get_post_options(‘custom_post’);

    get_taxonomy_options($taxonomy) — Возвращает массив options из framework-customizations/theme/options/taxonomies/{$post_type}.php.

    $category_options = fw()->theme->get_taxonomy_options(‘category’);

    get_config($key = null) — Возвращает весь конфигурационный массив из framework-customizations/theme/config.php or only specified key.

    $backlisted_extensions = fw()->theme->get_config(‘extensions_blacklist’);

    locate_path($rel_path) — Поиск полного пути файла по заданному относительному пути. Будет искать в дочерней теме, а затем в родительской теме.

    echo fw()->theme->locate_path(‘/custom.php’);

    // prints ‘/…/wp-content/themes/scratch-theme/framework-customizations/theme/custom.php’

    Backend

    Функции администрирования:

    option_type($type) — Получить экземпляр зарегистрированного типа параметра.

    $option_type_text = fw()->backend->option_type(‘text’);

    echo $option_type_text->render(‘demo’, array( ‘value’ => ‘Demo Value’ ));

    render_option($id, $option, $data = array(), $design = ‘default’) — Вывести опцию html вместе с label, desc и help.

    ВНИМАНИЕ

    Не принимает options контейнера.

    // simple usage

    echo fw()->backend->render_option(‘demo’, array( ‘type’ => ‘text’ ));

    // advanced usage

    echo fw()->backend->render_option(

       ‘demo’,

       array(

           ‘type’  => ‘text’,

           ‘label’ => __(‘Demo Label’, ‘{domain}’),

           ‘desc’  => __(‘Demo Description’, ‘{domain}’),

           ‘html’  => __(‘Demo Help Tip’, ‘{domain}’),

           ‘value’ => ‘default value’,

       ),

       array(

           ‘id_prefix’   => ‘custom-id-prefix-‘,

           ‘name_prefix’ => ‘custom_name_prefix’,

           ‘value’       => ‘overwrite default value’

       ),

       ‘taxonomy’

    );

    render_options(&$options, &$values = array(), $options_data = array(), $design = ‘default’) — Генерировать html из любого массива опций.

    $options = array(

       ‘option-1’ => array( ‘type’ => ‘text’,     ‘value’ => ‘default value 1’ ),

       ‘option-2’ => array( ‘type’ => ‘textarea’, ‘value’ => ‘default value 2’ ),

    );

    // simple usage

    echo fw()->backend->render_options($options);

    $values = array(

       ‘option-1’ => ‘Some value’, // this overwrites default value

       // ‘option-2’ value is not specified, so it will have default value

    );

    // Расширенное использование

    echo fw()->backend->render_options(

       $options,

       $values,

       array(

           ‘id_prefix’   => ‘custom-id-prefix-‘,

           ‘name_prefix’ => ‘custom_name_prefix’,

           ‘value’       => ‘overwrite default value’

       ),

       ‘taxonomy’

    );

    render_box($id, $title, $content, $other = array()) — render WordPres metabox.

    // simple usage

    echo fw()->backend->render_box(‘some-html-id’, ‘Title’, ‘Some <strong>Content</strong>’);

    // advanced usage

    echo fw()->backend->render_box(

       ‘some-html-id’,

       ‘Title’,

       ‘Some <strong>Content</strong>’,

       array(

           ‘html_before_title’ => ‘&lt;’,

           ‘html_after_title’  => ‘&gt;’,

           ‘attr’ => array(

               ‘class’ => ‘custom-class’

           ), ) );

    enqueue_options_static($options) — enqueue options scripts и styles

    Extensions

    Расширения Extensions.

    • get($extension_name) — Получить экземпляр существующего активного расширения.

    echo fw()->extensions->get(‘extension_name’)->get_name();

    Также он может использоваться для проверки наличия расширения (активен).

    if (fw()->extensions->get(‘extension_name’)) {
       fw()->extensions->get(‘extension_name’)->some_method();
    }
    //Или для этого метода существует более короткий псевдоним
    if (fw_ext(‘extension_name’)) {
       fw_ext(‘extension_name’)->some_method();
    }

    Manifest

    Framework, Тема и каждое расширение имеет манифест. В манифесте содержится важная информация, например: название, версия, зависимости и т. д.

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

    Framework

    manifest фреймворка находится в файле framework/manifest.php и может быть доступен следующим образом:

    fw()->manifest->get(‘version’);

    Он поддерживает следующие параметры:

    <?php if (!defined(‘FW’)) die(‘Forbidden’);

    $manifest = array();

    $manifest[‘name’]         = __(‘Framework’, ‘fw’);

    $manifest[‘uri’]          = ‘http://themefuse.com/framework’;

    $manifest[‘description’]  = __(‘WordPress Framework’, ‘fw’);

    $manifest[‘version’]      = ‘1.0’;

    $manifest[‘author’]       = ‘ThemeFuse’;

    $manifest[‘author_uri’]   = ‘http://themefuse.com/’;

    $manifest[‘requirements’] = array(

       ‘wordpress’ => array(

           ‘min_version’ => ‘4.0’,

           /*’max_version’ => ‘4.99.9’*/

       ), );

    Theme

    Манифест темы расположен в файле framework-customizations/theme/manifest.php и может быть доступен следующим образом:

    fw()->theme->manifest->get(‘version’);

    Он поддерживает следующие параметры:

    <?php if (!defined(‘FW’)) die(‘Forbidden’);

    $manifest = array();

    /**

    * Уникальный идентификатор для идентификации вашей темы

     * Например, Это используется для хранения настроек темы в wp_option

    ‘fw_theme_settings_options:{theme_id}’

    */

    $manifest[‘id’] = get_option( ‘stylesheet’ );

    /**

    * Укажите расширения, которые вы настроили, которые будут хорошо выглядеть и хорошо работать с вашей темой.

     * После активации плагина, пользователь будет перенаправлен на страницу для установки этих расширений.

    */

    $manifest[‘supported_extensions’] = array(

       // ‘extension_name’ => array(),

       ‘page-builder’ => array(),

       ‘breadcrumbs’ => array(),

       ‘slider’ => array(),

       // …

       /**

        * Эти расширения отображаются на странице Unyson Extensions только в том

    *  случае, если они указаны здесь.

    *Потому что у них нет смысла быть доступным для темы, которая не настроена на их *поддержку.

        */

       ‘styling’ => array(),

       ‘megamenu’ => array(),

    );

    $manifest[‘requirements’] = array(

       ‘wordpress’ => array(

           ‘min_version’ => ‘4.0’,

           /*’max_version’ => ‘4.99.9’*/

       ),

       ‘framework’ => array(

           /*’min_version’ => ‘1.0.0’,

           ‘max_version’ => ‘1.99.9’*/

       ),

       ‘extensions’ => array(

           /*’extension_name’ => array(),*/

           /*’extension_name’ => array(

               ‘min_version’ => ‘1.0.0’,

               ‘max_version’ => ‘2.99.9’

           ),*/

       ) );

    // Эти ключи автоматически выбираются из темы styles.css

    //$manifest[‘name’] = __(‘Theme Title’, ‘{domain}’);

    //$manifest[‘description’] = __(‘Another awesome wordpress theme’, ‘{domain}’);

    //$manifest[‘uri’] = ‘http://themefuse.com/wp-themes-shop/theme-name’;

    //$manifest[‘version’] = ‘1.0’;

    //$manifest[‘author’] = ‘ThemeFuse’;

    //$manifest[‘author_uri’] = ‘http://themefuse.com/’;

    Extension

    Манифест расширения находится в {extension-name}/manifest.php и может быть доступен следующим образом:

    fw()->extensions->get(‘extension-name’)->manifest->get(‘version’);

    Он поддерживает следующие параметры:

    <?php if (!defined(‘FW’)) die(‘Forbidden’);

    $manifest = array();

    $manifest[‘name’]         = __(‘Extension Title’, ‘{domain}’);

    $manifest[‘uri’]          = ‘http://extension-homepage.com/’;

    $manifest[‘description’]  = __(‘Another awesome framework extension’, ‘{domain}’);

    $manifest[‘version’]      = ‘1.0’;

    $manifest[‘author’]       = ‘ThemeFuse’;

    $manifest[‘author_uri’]   = ‘http://themefuse.com/’;

    $manifest[‘requirements’] = array(

       ‘wordpress’ => array(

           ‘min_version’ => ‘4.0’,

           /*’max_version’ => ‘4.99.9’*/

       ),

       ‘framework’ => array(

           /*’min_version’ => ‘1.0.0’,

           ‘max_version’ => ‘1.99.9’*/

       ),

       ‘extensions’ => array(

           /*’extension_name’ => array(),*/

           /*’extension_name’ => array(

               ‘min_version’ => ‘1.0.0’,

               ‘max_version’ => ‘2.99.9’

           ),*/

       ) );

    /**

    * @type bool Display on the Extensions page or it’s a hidden extension

    */

    $manifest[‘display’] = false;

    /**

    * @type bool If extension can exist alone

    * false — Для него нет смысла существовать в одиночку, он существует только тогда, когда этого требует какое-то другое расширение.

    * true  — Может существовать один, не беспокоясь о других расширениях.

    */

    $manifest[‘standalone’] = false;

    /**

    * @type string Thumbnail used on the Extensions page

    * All framework extensions has thumbnails set in the available extensions list

    * but if your extension is not in that list and id located in the theme, you can set the thumbnail via this parameter

    */

    $manifest[‘thumbnail’] = null;

     

    Categories : Word Press, www

    • « Previous Post
    • Next Post »

    Discussions

    1. admin 5 февраля, 2018

      — написал расширение Homework Extension Name и активировал его
      — расширил расширение Homework Sub Extension Name

    • Word Press
      • #1. Introduction to WordPress
      • #2. WordPress Files Configuration
      • #3. Kernel Review. Codex
      • #4. Standards of Encoding
      • #5. Develop a plugin, introduction
      • #6. Hooks, Filters, InterNation
      • #7. Adding Admin Menus, JS, CSS
      • #8. HTTP API, Shortcodes, Transients
      • #9. Options API, Settings API
      • #10. Database API, $wpdb object
      • #11. Ajax. Widget API. Dashboard API
      • #12. Post Type. Taxonomies. Metadata
      • #13. Theme Development. Basics
      • #14. Loop. Template. WP_Query
      • Lecture #15. functions.php – I
      • Lecture #16. functions.php – II
      • #17. Child Theme. Shortcode. TinyMCE
      • #18. Frameworks. Blank Theme
      • #19. Framework. Underscores. Unyson
      • #20: Framework Unyson. Options
      • #21. Extensions, Components, Manifest
      • #22. Unyson: Built-in Extensions
      • #23. Unyson: Helpers, Filters & Actions
      • #24. WC: Installation & Updating
      • #25. WC: Settings & Options
      • #26. WC: Product Setup
      • #27. WC: Sell Products, Order
      • #28. WC: Theming
      • #29. WC: Extending
      • #30. WC: Extending
    • CSS
      • ПРОГРАММИРОВАНИЕ (CODING)
      • Emmet, ul, li, table, form
      • Style, hover, child
      • CSS Hat, font, background
      • Reset, margin, padding, float
      • Base64, relative, z-index
      • Google Fonts, PSD
      • Brackets, Bootstrap
      • Script, src, comments
      • jQuery, Slick Js, Tooltip
      • Bootstrap, Slick Nav, @media
      • Mobile Vew, Font Awesome
      • Flexbox, Slider
      • SASS, Bootstrap
    • Cron
    • Framework Yii2
    • React, Angular
    • JavaScript
    • Freelance

    Generic selectors
    Exact matches only
    Search in title
    Search in content
    Search in posts
    Search in pages
    Filter by Categories
    CSS
    JavaScript
    Word Press
    www

    2019 Rostyslav N Design © Уроки программирования