netconstructorcom
  • 0
Мастер

Организация кода в файле functions.php темы WordPress?

  • 0

Чем больше настроек я делаю в WordPress, тем больше я начинаю думать о том, должен ли я организовать этот файл или разделить его.

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

Может ли разделение их на отдельные файлы или их группировка ускорить веб-сайт WordPress, или WordPress/PHP автоматически пропускает функции с префиксом кода is_admin?

Как лучше всего работать с большим файлом функций (у меня 1370 строк).

Share
  1. Если вы дошли до того, что код в вашей теме functions.php начинает вас перегружать, я бы определенно сказал, что вы готовы рассмотреть вопрос о разделении его на несколько файлов. Я склонен делать это почти второй натурой в этот момент.

    Используйте включить файлы в файл вашей functions.php темы

    Я создаю подкаталог под названием «includes» в каталоге моей темы и сегментирую свой код на включаемые файлы, организованные в соответствии с тем, что имеет смысл для меня в то время (это означает, что я постоянно реорганизую и перемещаю код по мере развития сайта). Я также редко поместите любой реальный код в functions.php ; все идет во включаемых файлах; просто мое предпочтение.

    Просто чтобы дать вам пример, вот моя тестовая установка, которую я использую для проверки своих ответов на вопросы здесь, в WordPress Answers. Каждый раз, когда я отвечаю на вопрос, я храню код на случай, если он мне снова понадобится. Это не совсем то, что вы будете делать для работающего сайта, но оно показывает механизм разделения кода:

    <?php 
    /*
     * functions.php
     * 
     */
    require_once( __DIR__ . '/includes/null-meta-compare.php');
    require_once( __DIR__ . '/includes/older-examples.php');
    require_once( __DIR__ . '/includes/wp-admin-menu-classes.php');
    require_once( __DIR__ . '/includes/admin-menu-function-examples.php');
    
    // WA: Adding a Taxonomy Filter to Admin List for a Custom Post Type?
    // http://wordpress.stackexchange.com/questions/578/
    require_once( __DIR__ . '/includes/cpt-filtering-in-admin.php'); 
    require_once( __DIR__ . '/includes/category-fields.php');
    require_once( __DIR__ . '/includes/post-list-shortcode.php');
    require_once( __DIR__ . '/includes/car-type-urls.php');
    require_once( __DIR__ . '/includes/buffer-all.php');
    require_once( __DIR__ . '/includes/get-page-selector.php');
    
    // http://wordpress.stackexchange.com/questions/907/
    require_once( __DIR__ . '/includes/top-5-posts-per-category.php'); 
    
    // http://wordpress.stackexchange.com/questions/951/
    require_once( __DIR__ . '/includes/alternate-category-metabox.php');  
    
    // http://lists.automattic.com/pipermail/wp-hackers/2010-August/034384.html
    require_once( __DIR__ . '/includes/remove-status.php');  
    
    // http://wordpress.stackexchange.com/questions/1027/removing-the-your-backup-folder-might-be-visible-to-the-public-message-generate
    require_once( __DIR__ . '/includes/301-redirects.php');  
    

    Или Создание плагинов

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

    Однако НЕТ значительного прироста производительности от организации кода PHP

    С другой стороны, структурирование ваших PHP-файлов на 99% связано с созданием порядка и удобством сопровождения и на 1% с производительностью, если это так (организация .js и .css файлы, вызываемые браузером через HTTP, — это совершенно другой случай и имеет огромные последствия для производительности). Но как вы организуете ваш PHP-код на сервере практически не имеет значения с точки зрения производительности.

    А организация кода — это личное предпочтение

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

    • 0
  2. Поздний ответ

    Как правильно включить файлы:

    function wpse1403_bootstrap()
    {
        // Here we load from our includes directory
        // This considers parent and child themes as well    
        locate_template( array( 'inc/foo.class.php' ), true, true );
    }
    add_action( 'after_setup_theme', 'wpse1403_bootstrap' );
    

    То же самое работает и в плагинах.

    Как получить правильный путь или URi

    Также взгляните на функции API файловой системы, такие как:

    • home_url()
    • plugin_dir_url()
    • plugin_dir_path()
    • admin_url()
    • get_template_directory()
    • get_template_directory_uri()
    • get_stylesheet_directory()
    • get_stylesheet_directory_uri()
    • и т.п.

    Как уменьшить количествоinclude/require

    Если вам нужно получить все файлы из каталога, используйте

    foreach ( glob( 'path/to/folder/*.php' ) as $file )
        include $file;
    

    Имейте в виду, что это игнорирует сбои (возможно, полезно для производственного использования)/не загружаемые файлы.

    Чтобы изменить это поведение, вы можете использовать другую конфигурацию во время разработки:

    $files = ( defined( 'WP_DEBUG' ) AND WP_DEBUG )
        ? glob( 'path/to/folder/*.php', GLOB_ERR )
        : glob( 'path/to/folder/*.php' )
    
    foreach ( $files as $file )
        include $file;
    

    Изменить: подход ООП/SPL

    Поскольку я только что вернулся и увидел, что этот ответ получает все больше и больше голосов, я подумал, что могу показать, как я это делаю сейчас — в мире PHP 5.3+. В следующем примере загружаются все файлы из подпапки тем с именем src/ . Здесь у меня есть библиотеки, которые обрабатывают определенные задачи, такие как меню, изображения и т. д. Вам даже не нужно заботиться об имени, поскольку загружается каждый отдельный файл. Если в этом каталоге есть другие подпапки, они игнорируются.

    \FilesystemIterator Является преемником PHP 5.3+ по сравнению с \DirectoryIterator . Оба являются частью PHP SPL. В то время как PHP 5.2 позволял отключить встроенное расширение SPL (менее 1% всех установок сделали это), SPL теперь является частью ядра PHP.

    <?php
    
    namespace Theme;
    
    $files = new \FilesystemIterator( __DIR__.'/src', \FilesystemIterator::SKIP_DOTS );
    foreach ( $files as $file )
    {
        /** @noinspection PhpIncludeInspection */
        ! $files->isDir() and include $files->getRealPath();
    }
    

    Ранее, когда я все еще поддерживал PHP 5.2.x, я использовал следующее решение: A \FilterIterator в src/Filters каталоге только для извлечения файлов (а не точечных указателей папок) и \DirectoryIterator для выполнения цикла и загрузки.

    namespace Theme;
    
    use Theme\Filters\IncludesFilter;
    
    $files = new IncludesFilter( new \DirectoryIterator( __DIR__.'/src' ) );
    foreach ( $files as $file )
    {
        include_once $files->current()->getRealPath();
    }
    

    Это \FilterIterator было так просто:

    <?php
    
    namespace Theme\Filters;
    
    class IncludesFilter extends \FilterIterator
    {
        public function accept()
        {
            return
                ! $this->current()->isDot()
                and $this->current()->isFile()
                and $this->current()->isReadable();
        }
    }
    

    Помимо того, что PHP 5.2 к настоящему времени мертв/EOL (и 5.3 тоже), есть тот факт, что в игре больше кода и еще один файл, поэтому нет причин использовать более позднюю версию и поддерживать PHP 5.2.x.

    Подвела

    РЕДАКТИРОВАТЬ Очевидно правильный способ — использовать namespace код d, подготовленный для автозагрузки PSR-4, помещая все в соответствующий каталог, который уже определен через пространство имен. Затем просто используйте Composer и a composer.json для управления вашими зависимостями и позвольте ему автоматически построить ваш автозагрузчик PHP (который автоматически импортирует файл, просто вызывая use \<namespace>\ClassName ). Это стандарт де-факто в мире PHP, самый простой способ и даже более автоматизированный и упрощенный WP Starter.

    • 0
  3. Мне нравится использовать функцию для файлов внутри папки. Такой подход упрощает добавление новых функций при добавлении новых файлов. Но я всегда пишу в классе или с пространствами имен — дайте ему больше контроля над пространством имен функций, методов и т. д.

    Ниже небольшой пример; но также использование с соглашением о классе *.php

    public function __construct() {
    
        $this->load_classes();
    }
    
    /**
     * Returns array of features, also
     * Scans the plugins subfolder "/classes"
     *
     * @since   0.1
     * @return  void
     */
    protected function load_classes() {
    
        // load all files with the pattern class-*.php from the directory classes
        foreach( glob( dirname( __FILE__ ) . '/classes/class-*.php' ) as $class )
            require_once $class;
    
    }
    

    В Темах я часто использую другой сценарий. Я определяю функцию внешнего файла в идентификаторе поддержки, см. пример. Это полезно, если я легко деактивирую функцию внешнего файла. Я использую основную функцию WP, require_if_theme_supports() и он загружается только в том случае, если идентификатор поддержки был активен. В следующем примере я определил этот поддерживаемый идентификатор в строке перед загрузкой файла.

        /**
         * Add support for Theme Customizer
         * 
         * @since  09/06/2012
         */
        add_theme_support( 'documentation_customizer', array( 'all' ) );
        // Include the theme customizer for options of theme options, if theme supported
        require_if_theme_supports( 
            'documentation_customizer',
            get_template_directory() . '/inc/theme-customize.php'
        );
    

    Вы можете увидеть больше этого в репозитории этой темы.

    • 0
  4. с точки зрения его разделения, в моем шаблоне я использую пользовательскую функцию для поиска папки с именем functions в каталоге темы, если ее нет, она создает ее. Затем он создает массив всех файлов.php, которые он находит в этой папке (если они есть), и запускает include(); на каждом из них.

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

    <?php
    /* 
    FUNCTIONS for automatically including php documents from the functions folder.
    */
    //if running on php4, make a scandir functions
    if (!function_exists('scandir')) {
      function scandir($directory, $sorting_order = 0) {
        $dh = opendir($directory);
        while (false !== ($filename = readdir($dh))) {
          $files[] = $filename;
        }
        if ($sorting_order == 0) {
          sort($files);
        } else {
          rsort($files);
        }
        return ($files);
      }
    }
    /*
    * this function returns the path to the funtions folder.
    * If the folder does not exist, it creates it.
    */
    function get_function_directory_extension($template_url = FALSE) {
      //get template url if not passed
      if (!$template_url)$template_url = get_bloginfo('template_directory');
    
    
      //replace slashes with dashes for explode
      $template_url_no_slash = str_replace('/', '.', $template_url);
    
      //create array from URL
      $template_url_array = explode('.', $template_url_no_slash);
    
      //--splice array
    
      //Calculate offset(we only need the last three levels)
      //We need to do this to get the proper directory, not the one passed by the server, as scandir doesn't work when aliases get involved.
      $offset = count($template_url_array) - 3;
    
      //splice array, only keeping back to the root WP install folder (where wp-config.php lives, where the front end runs from)
      $template_url_array = array_splice($template_url_array, $offset, 3);
      //put back togther as string
      $template_url_return_string = implode('/', $template_url_array);
      fb::log($template_url_return_string, 'Template'); //firephp
    
      //creates current working directory with template extention and functions directory    
      //if admin, change out of admin folder before storing working dir, then change back again.
      if (is_admin()) {
        $admin_directory = getcwd();
        chdir("..");
        $current_working_directory = getcwd();
        chdir($admin_directory);
      } else {
        $current_working_directory = getcwd();
      }
      fb::log($current_working_directory, 'Directory'); //firephp
    
      //alternate method is chdir method doesn't work on your server (some windows servers might not like it)
      //if (is_admin()) $current_working_directory = str_replace('/wp-admin','',$current_working_directory);
    
      $function_folder = $current_working_directory . '/' . $template_url_return_string . '/functions';
    
    
      if (!is_dir($function_folder)) mkdir($function_folder); //make folder, if it doesn't already exist (lazy, but useful....ish)
      //return path
      return $function_folder;
    
    }
    
    //removed array elements that do not have extension .php
    function only_php_files($scan_dir_list = false) {
      if (!$scan_dir_list || !is_array($scan_dir_list)) return false; //if element not given, or not array, return out of function.
      foreach ($scan_dir_list as $key => $value) {
        if (!strpos($value, '.php')) {
    
          unset($scan_dir_list[$key]);
        }
      }
      return $scan_dir_list;
    }
    //runs the functions to create function folder, select it,
    //scan it, filter only PHP docs then include them in functions
    
    add_action('wp_head', fetch_php_docs_from_functions_folder(), 1);
    function fetch_php_docs_from_functions_folder() {
    
      //get function directory
      $functions_dir = get_function_directory_extension();
      //scan directory, and strip non-php docs
      $all_php_docs = only_php_files(scandir($functions_dir));
    
      //include php docs
      if (is_array($all_php_docs)) {
        foreach ($all_php_docs as $include) {
          include($functions_dir . '/' . $include);
        }
      }
    
    }
    
    • 0
  5. Я управляю сайтом с примерно 50 уникальными пользовательскими типами страниц на нескольких разных языках через сетевую установку. Наряду с ТОННОЙ плагинов.

    В какой-то момент мы были вынуждены разделить все это. Файл функций с 20-30 тысячами строк кода — это совсем не смешно.

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

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

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

    Например, наша страница участника:

    страница-member.php. Отвечает за инициализацию страницы. Вызов правильных функций ajax или подобных. Может быть эквивалентно части контроллера в стиле MCV.

    функции-member.php. Содержит все функции, связанные с этой страницей. Это также включено в несколько других страниц, которым нужны функции для наших членов.

    содержимое-member.php. Подготавливает данные для HTML Может быть эквивалентно модели в MCV.

    layout-member.php. HTML часть.

    После внесения этих изменений время разработки легко сократилось на 50%, и теперь у владельца продукта возникают проблемы с постановкой новых задач. 🙂

    • 0
  6. Из файла functions.php дочерних тем:

        require_once( get_stylesheet_directory() . '/inc/custom.php' );
    
    • 0
  7. В functions.php более элегантным способом вызова требуемого файла будет:

    require_once locate_template(‘/inc/functions/shortcodes.php’);

    • 0
  8. Я объединил ответы @kaiser и @mikeschinkel.

    У меня есть все мои настройки моей темы в /includes папке, и в этой папке все разбито на подпапки.

    Я хочу, чтобы /includes/admin его подсодержимое было включено только тогда, когдаtrue === is_admin()

    Если папка исключена iterator_check_traversal_callback при возврате, false ее подкаталоги не будут повторяться (или передаваться в iterator_check_traversal_callback )

    /**
     *  Require all customizations under /includes
     */
    $includes_import_root = 
        new \RecursiveDirectoryIterator( __DIR__ . '/includes', \FilesystemIterator::SKIP_DOTS );
    
    function iterator_check_traversal_callback( $current, $key, $iterator ) {
        $file_name = $current->getFilename();
    
        // Only include *.php files
        if ( ! $current->isDir() ) {
            return preg_match( '/^.+\.php$/i', $file_name );
        }
    
        // Don't include the /includes/admin folder when on the public site
        return 'admin' === $file_name
            ? is_admin()
            : true;
    }
    
    $iterator_filter = new \RecursiveCallbackFilterIterator(
        $includes_import_root, 'iterator_check_traversal_callback'
    );
    
    foreach ( new \RecursiveIteratorIterator( $iterator_filter ) as $file ) {
        include $file->getRealPath();
    }
    
    • 0

Оставить ответ

You must login to add an answer.