在分数之间传递PHP变量的最佳方式是什么?

时间:2015-04-14 作者:Wordpressor

标题中有一个变量。php,例如:

$page_extra_title = get_post_meta($this_page->ID, "_theme_extra_title", true);
一旦我这样做:

var_dump($page_extra_title);
我总是NULL 收割台外侧。php(var\\u dump仅在header.php中正常工作)。我一直在我需要的任何地方粘贴相同的变量(page.php、post.php、footer.php等),但这太疯狂了,几乎让一切都无法维护。

我想知道通过主题中的所有文件传递变量的最佳方式是什么?我猜是使用函数。php和“get\\u post\\u meta”可能不是最好的主意:)

5 个回复
最合适的回答,由SO网友:kaiser 整理而成

基本的分离数据结构要传递数据,通常使用模型(即“MVC”中的“M”)。让我们来看一个非常简单的数据接口接口仅用作构建块的“配方”:

namespace WeCodeMore\\Package\\Models;
interface ArgsInterface
{
    public function getID();
    public function getLabel();
}
以上是我们传递的信息:一个通用ID和一个“标签”。

通过组合原子块显示数据接下来,我们需要一些视图,在我们的模型和。。。我们的模板。

namespace WeCodeMore\\Package;
interface PackageViewInterface
{
    /**
     * @param Models\\ArgsInterface $args
     * @return int|void
     */
    public function render( Models\\ArgsInterface $args );
}
基本上界面说

“我们可以渲染一些东西,并且该任务必须有一个模型”

最后,我们需要实现上述内容并构建实际的视图。如您所见,构造函数告诉我们视图的必备内容是模板,我们可以渲染它。为了便于开发,我们甚至会检查模板文件是否确实存在,以便我们可以让其他开发人员(以及我们的开发人员)的生活更轻松,并注意到这一点。

在渲染函数的第二步中,我们使用闭包来构建实际的模板包装器,并bindTo() 将模型复制到模板。

namespace WeCodeMore\\Package;

use WeCodeMore\\Package\\Models\\ArgsInterface;

/** @noinspection PhpInconsistentReturnPointsInspection */
class PackageView implements PackageViewInterface
{
    /** @var string|\\WP_Error */
    private $template;
    /**
     * @param string $template
     */
    public function __construct( $template )
    {
        $this->template = ! file_exists( $template )
            ? new \\WP_Error( \'wcm-package\', \'A package view needs a template\' )
            : $template;
    }
    /**
     * @param Models\\ArgsInterface $args
     * @return int|void
     */
    public function render( Models\\ArgsInterface $args )
    {
        if ( is_wp_error( $this->template ) )
            return print $this->template->get_error_message();

        /** @var $callback \\Closure */
        $callback = function( $template )
        {
            extract( get_object_vars( $this ) );
            require $template;
        };
        call_user_func(
            $callback->bindTo( $args ),
            $this->template
        );
    }
}
分离视图和渲染这意味着我们可以使用如下非常简单的模板

<!--suppress HtmlFormInputWithoutLabel -->
<p><?= $label ?></p>
来呈现我们的内容。将这些部分放在一起,我们将得到以下几行内容(在控制器、中介器等中):

namespace WeCodeMore\\Package;

$view = new PackageView( plugin_dir_path( __FILE__ ).\'tmpl/label.tmpl.php\' );
$view->render( new Models\\Args );
我们得到了什么

这样我们可以

无需更改数据结构即可轻松交换模板具有易读的模板避免全局范围可以进行单元测试可以在不损害其他组件的情况下交换模型/数据get_header(), get_footer(), 等等,对吧?错误的只需在任何模板或模板部分调用您的类即可。渲染它,转换数据,做任何你想做的事情。如果你真的很好,你甚至可以添加自己的一组自定义过滤器,并让一些谈判人员来处理哪个控制器在哪个路由/条件模板加载上呈现的内容。

结论

您可以在WP中毫无问题地使用上述内容,并且仍然坚持使用基本API,重用代码和数据,而无需调用单个全局或弄乱和污染全局名称空间。

SO网友:gmazzap

这是一种替代方法@kaiser 答案是,我觉得很好(+1),但需要额外的工作才能与核心WP函数一起使用,而且它本身与模板层次结构的集成度很低。

我想分享的方法是基于一个类(这是我正在研究的一个精简版本),它负责模板的渲染数据。

它有一些(IMO)有趣的特性:

模板是标准的WordPress模板文件(single.php,page.php),它们有更多的功能,现有模板可以正常工作,因此您可以轻松地从现有主题中集成模板@kaiser 方法,在模板中使用$this 关键词:这使您可以避免在生产中出现未定义变量的通知Engine 类别

namespace GM\\Template;

class Engine
{
    private $data;
    private $template;
    private $debug = false;

  /**
   * Bootstrap rendering process. Should be called on \'template_redirect\'.
   */
  public static function init()
  {
      add_filter(\'template_include\', new static(), 99, 1);
  }

  /**
   * Constructor. Sets debug properties.
   */
  public function __construct()
  {
      $this->debug =
          (! defined(\'WP_DEBUG\') || WP_DEBUG)
          && (! defined(\'WP_DEBUG_DISPLAY\') || WP_DEBUG_DISPLAY);
  }

  /**
   * Render a template.
   * Data is set via filters (for main template) or passed to method for partials.
   * @param string $template template file path
   * @param array  $data     template data
   * @param bool   $partial  is the template a partial?
   * @return mixed|void
   */
  public function __invoke($template, array $data = array(), $partial = false)
  {
      if ($partial || $template) {
          $this->data = $partial
              ? $data
              : $this->provide(substr(basename($template), 0, -4));
          require $template;
          $partial or exit;
      }

      return $template;
  }

  /**
   * Render a partial.
   * Partial-specific data can be passed to method.
   * @param string $template template file path
   * @param array  $data     template data
   * @param bool   $isolated when true partial has no access on parent template context
   */
  public function partial($partial, array $data = array(), $isolated = false)
  {
      do_action("get_template_part_{$partial}", $partial, null);
      $file = locate_template("{$partial}.php");
      if ($file) {
          $class = __CLASS__;
          $template = new $class();
          $template_data =  $isolated ? $data : array_merge($this->data, $data);
          $template($file, $template_data, true);
      } elseif ($this->debug) {
          throw new \\RuntimeException("{$partial} is not a valid partial.");
      }
  }

  /**
   * Used in templates to access data.
   * @param string $name
   * @return string
   */
  public function __get($name)
  {
      if (array_key_exists($name, $this->data)) {
          return $this->data[$name];
      }
      if ($this->debug) {
          throw new \\RuntimeException("{$name} is undefined.");
      }

      return \'\';
  }

  /**
   * Provide data to templates using two filters hooks:
   * one generic and another query type specific.
   * @param string $type Template file name (without extension, e.g. "single")
   * @return array
   */
  private function provide($type)
  {
      $generic = apply_filters(\'gm_template_data\', array(), $type);
      $specific = apply_filters("gm_template_data_{$type}", array());

      return array_merge(
        is_array($generic) ? $generic : array(),
        is_array($specific) ? $specific : array()
     );
  }
}
(可用作Gist 此处。)

如何使用,只需调用Engine::init() 方法,可能打开\'template_redirect\' 钩这可以在主题中完成functions.php 或者从插件。

require_once \'/path/to/the/file/Engine.php\';
add_action(\'template_redirect\', array(\'GM\\Template\\Engine\', \'init\'), 99);
仅此而已。

现有模板将按Expected工作。但现在您可以访问自定义模板数据。

自定义模板数据要将自定义数据传递给模板,有两个筛选器:

  • \'gm_template_data\'
  • \'gm_template_data_{$type}\'{$type} 是没有文件扩展名的模板文件的基名称。

    E、 g.过滤器\'gm_template_data_single\' 可用于将数据传递给single.php 样板

    附加到这些挂钩的回调have to return an array, 其中键是变量名。

    例如,可以将元数据作为模板数据传递,如下所示:

    add_filter(\'gm_template_data\', function($data) {
        if (is_singular()) {
            $id = get_queried_object_id();
            $data[\'extra_title\'] = get_post_meta($id, "_theme_extra_title", true);
        }
    
        return $data;
    };
    
    然后,在模板内,您可以只使用:

    <?= $this->extra_title ?>
    
    当两个常量WP_DEBUGWP_DEBUG_DISPLAY 如果为true,则类将在调试模式下工作。这意味着,如果未定义变量,将引发异常。

    当类不处于调试模式(可能在生产环境中)时,访问未定义的变量将输出空字符串。

    数据模型组织数据的一种好的、可维护的方法是使用模型类。

    它们可以是非常简单的类,使用上述相同的过滤器返回数据。没有特定的界面可遵循,它们可以根据您的喜好进行组织。

    Belowe,这只是一个例子,但你可以自由地用自己的方式去做。

    class SeoModel
    {
      public function __invoke(array $data, $type = \'\')
      {
          switch ($type) {
              case \'front-page\':
              case \'home\':
                $data[\'seo_title\'] = \'Welcome to my site\';
                break;
              default:
                $data[\'seo_title\'] = wp_title(\' - \', false, \'right\');
                break;
          }
    
          return $data;
      }
    }
    
    add_filter(\'gm_template_data\', new SeoModel(), 10, 2);
    
    The__invoke() 方法(当类像回调一样使用时运行)返回要用于<title> 模板的标记。

    因为第二个论点通过了\'gm_template_data\' 是模板名称,该方法返回主页的自定义标题。

    有了上面的代码,就可以使用

     <title><?= $this->seo_title ?></title>
    
    <head> 页面的节。

    Partials具有如下功能get_header()get_template_part() 可用于将分部加载到主模板中。

    这些函数与所有其他WordPress函数一样,可以在使用Engine

    唯一的问题是,在使用核心WordPress函数加载的部分中,不可能使用使用$this.

    因此Engine 类有一个方法partial() 这允许加载分部(以完全与子主题兼容的方式),并且仍然能够在分部中使用自定义模板数据。

    用法非常简单。

    假设有一个名为partials/content.php 在主题(或子主题)文件夹中,可以使用以下方法将其包括在内:

    <?php $this->partial(\'partials/content\') ?>
    
    在该部分中,访问所有父主题数据的方式是相同的。

    与WordPress函数不同,Engine::partial() 方法允许将特定数据传递给partials,只需传递一个数据数组作为第二个参数。

    <?php $this->partial(\'partials/content\', array(\'greeting\' => \'Welcome!\')) ?>
    
    默认情况下,partials可以访问父主题中可用的数据和显式传递的数据。

    如果显式传递给partial的某个变量与父主题变量的名称相同,则显式传递的变量将获胜。

    但是,也可以在隔离模式下包含分部,即分部无法访问父主题数据。要做到这一点,只需通过true 作为第三个参数partial():

    <?php $this->partial(\'partials/content\', array(\'greeting\' => \'Welcome!\'), true) ?>
    
    结论即使很简单,Engine 课程相当完整,但肯定可以进一步改进。E、 g.无法检查是否定义了变量。

    由于它与WordPress功能和模板层次结构完全兼容,您可以将其与现有代码和第三方代码集成,而不会出现任何问题。

    然而,请注意,这只是部分测试,因此可能存在我尚未发现的问题。

    以下五点"What did we gain?" 在里面@kaiser answer:

    无需更改数据结构即可轻松交换模板具有易读的模板避免全局范围可以进行单元测试可以在不损害其他组件的情况下交换模型/数据也都对我的类有效。

SO网友:Mark Kaplun

答案很简单,不要在任何地方传递变量,因为使用全局变量会让人觉得很糟糕。

从您的示例来看,您似乎正在尝试进行早期优化,这是另一个缺点;)

使用wordpress API获取存储在DB中的数据,不要试图智取和优化其使用,因为API所做的不仅仅是检索值,它会激活过滤器和操作。通过删除API调用,您可以消除其他开发人员在不修改代码的情况下更改代码行为的能力。

SO网友:redelschaap

虽然凯撒的回答在技术上是正确的,但我怀疑这对你来说是最好的答案。

如果您正在创建自己的主题,那么我认为这确实是使用类(也可能是名称空间和接口,尽管对于WP主题来说这可能有点太多)设置某种框架的最佳方式。

另一方面,如果您只是扩展/调整现有主题,只需要传递一个或几个变量,我认为您应该坚持global. 因为header.php 包含在函数中,则您在该文件中声明的变量只能在该文件中使用。具有global 您可以在整个WP项目中访问它们:

在里面header.php:

global $page_extra_title;

$page_extra_title = get_post_meta($this_page->ID, "_theme_extra_title", true);
在中single.php (例如):

global $page_extra_title;

var_dump( $page_extra_title );

SO网友:pbd

一个简单的解决方案是编写一个函数来获取额外的标题。我使用静态变量将数据库调用保持为仅一个。把这个放在你的函数中。php。

function get_extra_title($post_id) {
    static $title = null;
    if ($title === null) {
        $title = get_post_meta($post_id, "_theme_extra_title", true)
    }
    return $title;
}
外部收割台。php,调用函数以获取值:

var_dump(get_extra_title($post->ID));

结束

相关推荐

需要通过Functions.Php注销脚本

嗯,我有点失望Wordpress注销脚本有多么困难。首先,我得到了所有句柄的列表,所以我查找了它,句柄是jquery migrate然后我将其添加到我的函数中。phpwp_dequeue_script(\'jquery-migrate\'); 还有这个wp_dequeue_script(\'jquery\'); 尽管脚本已正确注册,但它什么也不做。版本字符串出了什么问题,我想不出为什么它们仍然包含这些字符串,应该尽快在下一个WP版本中删除,它们只会在某些情况下阻止缓存正确缓存,这很烦人