tbruckmaier / corcel-acf
Corcel 的 Advanced Custom Field (ACF) 插件
Requires
- php: >=7.0.0|^8.0
- jgrossi/corcel: >=2.5
Requires (Dev)
- laravel/framework: >=7.0
- laravel/legacy-factories: ^1.3
- orchestra/testbench: >=3.4
- phpunit/phpunit: >=6.0
README
在 Laravel 中使用 WordPress 高级自定义字段 (ACF)
此 Corcel 插件允许您使用与 Laravel 框架相同的语法,使用 Eloquent 语法从 WordPress 后端获取由 ACF 插件创建的自定义字段。您可以使用 Eloquent 模型和集合来提高您的开发效率。
有关 Corcel 的工作原理的更多信息,请访问 存储库。
安装
安装 Corcel 的 ACF 插件非常简单
composer require tbruckmaier/corcel-acf
此插件需要 Corcel,但请放心,如果它缺失,它也会被安装。
功能
- 通过 Eloquent 关系加载 ACF 字段
- 只为帖子加载一次 acf 数据并保存 SQL 查询
- 支持 eager loading of acf 关系
- 支持深层封装的字段(例如,在灵活内容中的重复器中的图像)
- 为不同的 acf 字段返回合适的数据类型(请参阅下表)
- 未知字段返回一个具有访问原始 db 值的通用类
- 可以使用自定义类来处理现有和未知字段
- 可以访问 acf 字段配置和内部属性
- 完全支持选项页面
- 支持基于 PHP 和数据库的 ACF 配置
toArray()
和toJson()
在嵌套重复器/其他字段上递归工作(自 1.6 起支持)
基本用法
创建 acf 关系的最简单方法是包含的 trait
use \Corcel\Models\Post as BasePost; use Tbruckmaier\Corcelacf\AcfTrait; class Post extends BasePost { use AcfTrait; public static function boot() { self::addAcfRelations(['title', 'thumbnail']); parent::boot(); } }
这会动态创建关系 acf_title()
和 acf_thumbnail()
。现在可以访问 acf 字段
use Corcel\Models\Post; use Corcel\Models\Attachment; use Tbruckmaier\Corcelacf\Models\Text; use Tbruckmaier\Corcelacf\Models\Image; $post = Post::find(1); // post has a text field named "title" and a image field called "thumbnail" $post->acf_title; // an instance of Text::class $post->acf_title->value; // "Example title" $post->acf_thumbnail; // Image::class $post->acf_thumbnail->value; // an instance of Attachment::class representing the specified image
为了简化,AcfTrait
还包括 getAcfAttribute
,它返回辅助类 Acf
的实例(这替代了过时的 corcel acf 插件)。关系也可以这样访问
$post->acf->title; // (string) the parsed value, for instance "Example Page #1" $post->acf->title(); // an instance of the underlying Text::class $post->acf->title()->value; // the parsed value, $post->acf->title is a short version of this $post->acf->title()->internal_value; // the unparsed value, for text's this is the same as value $post->acf->title()->config; // the acf field config array defined in wordpress, sth like ['type' => 'text', 'instructions' => 'The site title', ...] $post->acf->thumbnail; // an instance of Attachment::class representing the specified image $post->acf->thumbnail(); // an instance of the underlying Image::class $post->acf->thumbnail()->value; // again the same Attachment::class $post->acf->thumbnail()->internal_value; // the unparsed value from the `postmeta` table, in this case the attachment id $post->acf->thumbnail()->config; // the thumbnail acf field config array (['type' => 'image', ...])
基于 PHP 的 ACF 配置
如果您的 ACF 配置通过 PHP 工作的话,您必须在 AcfTrait
中传递配置数组
// wordpress functions.php acf_add_local_field_group(array( 'key' => 'group_1', 'title' => 'My Group', 'fields' => array ( array ( 'key' => 'field_1', 'label' => 'Sub Title', 'name' => 'sub_title', 'type' => 'text', ) ), 'location' => array ( array ( array ( 'param' => 'post_type', 'operator' => '==', 'value' => 'post', ), ), ), ));
// laravel model use \Corcel\Models\Post as BasePost; use Tbruckmaier\Corcelacf\AcfTrait; class Post extends BasePost { use AcfTrait; public static function boot() { self::addAcfRelations([ 'field_1' => [ 'key' => 'field_1', 'label' => 'Sub Title', 'name' => 'sub_title', 'type' => 'text', ], ]); parent::boot(); } }
为了确定用于哪个字段的模型,使用 acf 字段的 type
变量。下面是完整列表。
功能
WordPress 将每个 acf 字段的配置存储在 wp_posts
表中,作为一个自定义帖子类型 acf-field
。其中 post_content
包含序列化的配置数组,该数组包含 acf 字段类型(type
)和您在创建 acf 字段时可以指定的所有其他内容。其中一些值对于解析很重要,而另一些则仅指定如何在 WordPress 中显示字段。
当在Wordpress中使用acf字段保存帖子时,这些值将作为帖子的元数据存储在表wp_postmeta
中。每个acf字段保存两个值:在wp_posts
中的对应acf字段名称和实际值。根据acf字段的类型和配置,保存的值可能不同(文本字段值以纯文本形式存储,关系字段(如图片)以附件ID存储,重复和灵活内容字段以一系列不同的字段存储)。
例如,上面的示例字段保存如下
| meta_key | meta_value |
|:-----------|:--------------------|
| _title | field_5bdae4fb72c4a |
| title | Example Page #1 |
| _thumbnail | field_5c3b6543480d6 |
| thumbnail | 5 |
使用corcel加载帖子时,无论是否定义了模型的boot()
方法中的静态属性$acfRelations
,元数据都会自动从数据库中检索。
Acf
基类使用这些数据并将它们传递给所有字段(以及可能的子字段),因此不需要额外的查询。只需关系字段(如Image
)需要另一个查询来找到正确的Attachment
类(尽管如果您只对附件的ID感兴趣,您可以通过$post->acf->thumbnail()->internal_value
访问它,并且不需要使用额外的查询)。
这仅添加了一个getAcfAttribute()
方法,它返回一个Tbruckmaier\Corcelacf\Acf
基类实例(这覆盖了corcel内部对过时的Corcel acf插件的默认支持:[https://github.com/corcel/acf/tree/](https://github.com/corcel/acf/tree/)。如果您想并行使用它,您可以自己定义一个不同名称的getAcfAttribute
方法)。
选项页面
ACF选项页面中的字段可以以相同的方式使用,尽管实例化选项页面稍微有些棘手。相关的字段配置存储在具有acf-field
的wp_posts
中,并且都是acf-field-group
(通过post_parent
)的子项。字段值存储在wp_options
中,具有特定的前缀(默认为options
)。
wp_options
| option_name | option_value |
|:---------------------------------------|:--------------------|
| _options_page-title | field_5bdae4fb72c4a |
| options_page-title | My page |
| _options_page-description | field_5891ef34058bf |
| options_page-title | My description |
| _additional-options-my-repeater | field_5c3b6543480d6 |
| additional-options-my-repeater | 2 |
| _additional-options-my-repeater_0_text | field_58737273acc78 |
| additional-options-my-repeater_0_text | Entry #1 |
| _additional-options-my-repeater_1_text | field_58737273acc78 |
| additional-options-my-repeater_1_text | Entry #2 |
首先,我们需要找到选项页的acf-field-group
。我们可以在Wordpress中编辑字段组时在URL中找到其ID:[https://wp-admin/post.php?post=1016&action=edit](https://wp-admin/post.php?post=1016&action=edit)。它也可以通过其slug或页面标题找到(见下文)
前缀通常在functions.php
中设置,默认为options
。
// functions.php: // no parameters result in the prefix "options" acf_add_options_page(); // another option page with a different prefix acf_add_options_page([ 'post_id' => 'additional-options', ]); // laravel: use Tbruckmaier\Corcelacf\OptionPage; // get the option page's field group by id, take it from the url for instance $optionPage = OptionPage::find(1016); // ... or find it by its title. This is not the title given to acf_add_options_page(), but the field group name. $optionPage1 = OptionPage::byTitle('Page option fields')->first(); // load the option data from the database $optionPage->loadOptions(); // alternatively with a custom prefix $optionPage1->loadOptions('additional-options'); // get a option $pageTitle = $optionPage->getOption('page-title'); // "My page" // or the underlying Field $pageTitle = $optionPage->getOptionField('page-title'); // Text::class // works with all fields: $myRepeater = $optionPage1->getOption('my-repeater'); // Collection $myRepeater->first()->text; // "Entry #1"
如果有人找到了更简单的选项页面解决方案,我愿意听取建议。也许可以通过传递前缀或相反的方式来获取字段组?
高级使用
自定义字段类
您可以使用自己的类为某些字段类型扩展自定义属性和方法。通过运行artisan vendor:publish --provider='Tbruckmaier\Corcelacf\ServiceProvider'
发布配置,并在config/corcel-acf.php
中填写类名。您可以覆盖现有的字段类型或定义新的类型。
// config/corcel-acf.php 'classMapping' => [ 'text' => CustomText::class, 'google_maps' => GoogleMapsField::class, ] // CustomText.php class CustomText extends \Tbruckmaier\Corcelacf\BaseField { public function getValueAttribute() { return htmlentities($this->internal_value); } public function getWordsAttribute() { return explode(' ', $this->internal_value); } } // Usage $post->acf->my_text_field(); // CustomText::class $post->acf->my_text_field; // "one & two" $post->acf->my_text_field()->words; // ["one", "&", "two"]
自定义类应扩展Tbruckmaier\Corcelacf\BaseField
。
定义acf关系
除了使用模型的boot()
方法动态创建关系之外,还可以手动定义它们。
use Corcel\Models\Post as BasePost; use Tbruckmaier\Corcelacf\AcfTrait; class Post extends BasePost { use AcfTrait; public function thumbnail() { return $this->hasAcf('thumbnail'); } } $post = Post::find(1); $post->thumbnail; // Image::class $post->thumbnail->value; // Attachment
每当返回Corcel模型(例如,对于图像的Corcel\Model\Attachment
类)时,都会考虑corcel类映射配置(见[https://github.com/corcel/corcel#-custom-post-type](https://github.com/corcel/corcel#-custom-post-type))。
预加载
如果您想预加载acf字段,可以使用标准的eloquent语法。如果关系是从$acfRelations
创建的,不要忘记传递前缀。
$posts = Post::all()->load('acf_thumbnail');
字段
以下字段类型受到支持(其他所有内容都返回一个Generic
字段)
链接
链接字段对配置的返回值做出反应,因此它返回一个包含title
、text
和url
的数组或只是一个字符串url
。
该字段具有一个 render()
方法,用于渲染HTML标签。render()
支持自定义链接文本和自定义属性:render('<img src="img.jpg" />', ['class' => 'class-1'])
返回 <a href="#" target="_blank" class="class-1" title="acf title"><img src="img.jpg" /></a>
当将字段作为字符串访问时(如 (string)$post->acf->link()
或在 blade 中 {!! $post->acf->link !!}
),会调用 render()
,因此返回一个HTML字符串。
重复器和灵活内容
重复器字段返回一个 Collection
,其中包含 RepeaterLayout
。灵活内容字段返回一个 FlexibleContentLayout
。这些模型类似于原始的 Acf
类:当以属性访问字段时,返回字段的解析值,否则返回与上表类似的字段。
use Corcel\Models\Post; use Tbruckmaier\Corcelacf\Models\Text; use Tbruckmaier\Corcelacf\Models\Repeater; use Tbruckmaier\Corcelacf\Models\FlexibleContent; use Tbruckmaier\Corcelacf\Support\RepeaterLayout; use Tbruckmaier\Corcelacf\Support\FlexibleContentLayout; $post = Post::find(1); $post->acf->main_repeater(); // Repeater $repeaterFields = $post->acf->main_repeater; // Collection of RepeaterLayout $repeaterFields->first()->title(); // Text::class $repeaterFields->first()->title; // parsed response "Main repeater title #1" $repeaterFields->get(1)->title(); // Text::class $repeaterFields->get(1)->title; // "Main repeater title #2" $post->acf->main_content(); // FlexibleContent $fcLayouts = $post->acf->main_content; // Collection of FlexibleContentLayout $fcLayouts->get(0)->getType(); // layout type of the first block, for example "text_with_image" $fcLayouts->get(0)->text(); // Text::class $fcLayouts->get(0)->text; // "Text of the first content block" $fcLayouts->get(0)->image(); // Image::class $fcLayouts->get(0)->image; // Attachment::class (linked image) $fcLayouts->get(1)->getType(); // layout type of the second block, for example "accordion" $fcLayouts->get(1)->accordion_title; // "Accordion #1" $fcLayouts->get(1)->accordion_items(); // Repeater::class $fcLayouts->get(1)->accordion_items; // Collection of RepeaterLayouts $fcLayouts->get(1)->accordion_items->first()->title; // "First accordion element" $fcLayouts->get(1)->accordion_items->first()->content; // "First accordion content..."
预加载关联关系
如果你有一个包含图像字段的重复器,预先加载图像的 Attachment
关系可能是明智的(否则每个附件都会触发一个自己的查询)。
use Tbruckmaier\Corcelacf\Models\Repeater; $post = Post::find(1); // fires 2 queries per iteration foreach ($post->acf->main_repeater as $layout) { $layout->foo_image->attachment; $layout->bar_image->attachment; } // preloads all attachment relations, fires 2 queries in total foreach ($post->acf->main_repeater()->load('foo_image.attachment', 'bar_image.attachment')->value as $layout) { $layout->foo_image->attachment; $layout->bar_image->attachment; }
分组字段
分组字段返回一个 GroupLayout
,其中包含所有分组字段。GroupLayout
类似于 FlexibleContentLayout
或 RepeaterLayout
:通过以属性访问其字段,返回解析值。当以方法访问时,返回类本身。
use Corcel\Models\Post; use Tbruckmaier\Corcelacf\Models\Group; use Tbruckmaier\Corcelacf\Models\Text; use Tbruckmaier\Corcelacf\Models\Repeater; use Tbruckmaier\Corcelacf\Support\GroupLayout; $post = Post::find(1); $post->acf->header_fields(); // Group $post->acf->header_fields; // GroupLayout $post->acf->header_fields->title; // "site title" $post->acf->header_fields->title(); // Text::class
运行测试
要运行phpunit测试,执行 phpunit
./vendor/bin/phpunit
不同php和laravel版本的测试定义在 .github/workflows/ci.yml
中。它们可以通过 act 在本地运行。
许可证
MIT License © Junior Grossi