fabianmuema/corcel

使用 WordPress 后端(管理面板)与 Laravel 或任何 PHP 框架升级,适用于 Laravel 9 和 10

1.0.2 2023-04-02 08:58 UTC

This package is auto-updated.

Last update: 2024-10-01 00:15:00 UTC


README

一组模型类,允许您直接从 WordPress 数据库获取数据。

Actions Status Packagist Packagist Test Coverage Maintainability

Corcel 是基于 Eloquent ORM(来自 Laravel 框架)构建的 PHP 类集合,提供流畅的接口以直接连接和获取 WordPress 数据库中的数据。

您可以将 WordPress 用作后端(管理面板)或 CMS,用于插入帖子、自定义类型等,并将任何其他 PHP 应用程序用于查询这些数据(作为模型层)。与 Laravel 一起使用 Corcel 更容易,但您可以使用任何使用 Composer 的 PHP 项目。

买我一杯咖啡 | 关注 Corcel 在 Twitter

目录

安装 Corcel

版本兼容性

安装 Corcel

您需要使用 Composer 将 Corcel 安装到您的项目中

composer require jgrossi/corcel

配置(Laravel)

Laravel 5.5 及更高版本

Corcel 将使用 Laravel 的 自动发现 注册自身。

Laravel 5.4 及更早版本

您需要在您的 config/app.php 中包含 CorcelServiceProvider

'providers' => [
    /*
     * Package Service Providers...
     */
    Corcel\Laravel\CorcelServiceProvider::class,
]

发布配置文件

现在配置我们的配置文件,以确保您的数据库设置正确,并允许您以非常简单的方式注册自定义帖子类型和简码

在终端中运行以下 Artisan 命令

php artisan vendor:publish --provider="Corcel\Laravel\CorcelServiceProvider"

现在您有一个 config/corcel.php 配置文件,其中您可以设置数据库连接(与 WordPress 表相关)以及更多。

数据库设置

Laravel 设置

只需在 config/corcel.php 中设置 Corcel 使用的数据库 connection

假设您在 config/database.php 文件中具有以下数据库连接

// File: /config/database.php

'connections' => [

    'mysql' => [ // for Laravel database
        'driver'    => 'mysql',
        'host'      => 'localhost',
        'database'  => 'mydatabase',
        'username'  => 'admin'
        'password'  => 'secret',
        'charset'   => 'utf8',
        'collation' => 'utf8_unicode_ci',
        'prefix'    => '',
        'strict'    => false,
        'engine'    => null,
    ],

    'wordpress' => [ // for WordPress database (used by Corcel)
        'driver'    => 'mysql',
        'host'      => 'localhost',
        'database'  => 'mydatabase',
        'username'  => 'admin',
        'password'  => 'secret',
        'charset'   => 'utf8',
        'collation' => 'utf8_unicode_ci',
        'prefix'    => 'wp_',
        'strict'    => false,
        'engine'    => null,
    ],
],

在这种情况下,您应该想为 Corcel 使用 wordpress 连接,因此只需将其设置为 Corcel 配置文件 config/corcel.php 中的值。

'connection' => 'wordpress',

其他 PHP 框架(非 Laravel)设置

在此,您必须配置数据库以满足 Corcel 的要求。首先,如果您尚未加载,应包含 Composer 的 autoload 文件

require __DIR__ . '/vendor/autoload.php';

现在您必须设置您的 WordPress 数据库参数

$params = [
    'database'  => 'database_name',
    'username'  => 'username',
    'password'  => 'pa$$word',
    'prefix'    => 'wp_' // default prefix is 'wp_', you can change to your own prefix
];
Corcel\Database::connect($params);

您可以指定所有 Eloquent 参数,但其中一些是默认的(但您可以覆盖它们)。

'driver'    => 'mysql',
'host'      => 'localhost',
'charset'   => 'utf8',
'collation' => 'utf8_unicode_ci',
'prefix'    => 'wp_', // Specify the prefix for WordPress tables, default prefix is 'wp_'

使用方法

帖子

每次您看到 Post::method(),如果您正在使用自己的 Post 类(在此类中您设置了连接名称),例如 App\Post,则应使用 App\Post::method() 而不是 Post::method()。所有示例都假设您已经了解这种区别。

在示例中,每次您看到 Post::method(),请假设为 Corcel\Model\Post::method()

// All published posts
$posts = Post::published()->get();
$posts = Post::status('publish')->get();

// A specific post
$post = Post::find(31);
echo $post->post_title;

创建自己的模型类

可选地,您可以为 Post 模型(或页面,或其他任何)创建自己的模型,该模型扩展 Corcel\Post。然后设置您正在使用的连接名称(如果您想覆盖 Corcel 的默认连接名称),在这种情况下为 foo-bar

扩展 Corcel\Model\Post 类可以增加您项目的灵活性,一旦您可以为从 WordPress 数据库中需要使用的功能添加自定义方法和逻辑。

<?php // File: app/Post.php

namespace App;

use Corcel\Model\Post as Corcel;

class Post extends Corcel
{
    protected $connection = 'foo-bar';

    public function customMethod() {
        //
    }
}

因此,现在您可以使用自己的类获取 WP 数据库数据

$posts = App\Post::all(); // using the 'foo-bar' connection

请记住,您不必扩展我们的 Post 类,您可以使用 Corcel\Model\Post 和所有其他模型,而不会出现任何问题。

元数据(自定义字段)

注意:在 Corcel v1 中,您可以使用 Post::save() 方法保存元数据。现在不允许这样做。使用 saveMeta()createMeta()(见下文)方法保存帖子元数据。

您也可以从帖子中检索元数据。

// Get a custom meta value (like 'link' or whatever) from a post (any type)
$post = Post::find(31);
echo $post->meta->link; // OR
echo $post->fields->link;
echo $post->link; // OR

要创建或更新用户表单的元数据,只需使用 saveMeta()saveField() 方法。它们返回 bool,类似于 Eloquent 的 save() 方法。

$post = Post::find(1);
$post->saveMeta('username', 'jgrossi');

您也可以同时保存多个元数据。

$post = Post::find(1);
$post->saveMeta([
    'username' => 'jgrossi',
    'url' => 'http://jgrossi.com',
]);

您还有 createMeta()createField() 方法,它们的工作方式类似于 saveX() 方法,但它们仅用于创建,并返回创建的 PostMeta 实例,而不是 bool

$post = Post::find(1);
$postMeta = $post->createMeta('foo', 'bar'); // instance of PostMeta class
$trueOrFalse = $post->saveMeta('foo', 'baz'); // boolean

通过自定义字段(元数据)查询帖子

有多种方法可以通过在 Post(或其他使用 HasMetaFields 特性的模型)类上使用作用域来通过自定义字段(元数据)查询帖子。

要检查元键是否存在,请使用 hasMeta() 作用域。

// Finds a published post with a meta flag.
$post = Post::published()->hasMeta('featured_article')->first();

如果您想精确匹配元字段,可以使用带有值的 hasMeta() 作用域。

// Find a published post which matches both meta_key and meta_value.
$post = Post::published()->hasMeta('username', 'jgrossi')->first();

如果您需要匹配多个元字段,也可以使用带有数组参数的 hasMeta() 作用域。

$post = Post::hasMeta(['username' => 'jgrossi'])->first();
$post = Post::hasMeta(['username' => 'jgrossi', 'url' => 'jgrossi.com'])->first();
// Or just passing the keys
$post = Post::hasMeta(['username', 'url'])->first();

如果您需要匹配不区分大小写的字符串或使用通配符匹配,可以使用带有值的 hasMetaLike() 作用域。这使用 SQL 的 LIKE 操作符,因此请使用 '%' 作为通配符操作符。

// Will match: 'J Grossi', 'J GROSSI', and 'j grossi'.
$post = Post::published()->hasMetaLike('author', 'J GROSSI')->first();

// Using % as a wildcard will match: 'J Grossi', 'J GROSSI', 'j grossi', 'Junior Grossi' etc.
$post = Post::published()->hasMetaLike('author', 'J%GROSSI')->first();

字段别名

Post 类支持“别名”,因此如果您检查 Post 类,您应该注意静态 $aliases 数组中定义的一些别名,例如 title 对应 post_titlecontent 对应 post_content

$post = Post::find(1);
$post->title === $post->post_title; // true

如果您正在扩展 Post 类以创建自己的类,您也可以使用 $aliases。只需在您的类中添加新别名到该静态属性,它将自动继承父 Post 类的所有别名。

class A extends \Corcel\Post
{
    protected static $aliases = [
        'foo' => 'post_foo',
    ];
}

$a = A::find(1);
echo $a->foo;
echo $a->title; // from Post class

自定义作用域

要排序帖子,您可以使用 newest()oldest() 作用域,适用于 PostUser 类。

$newest = Post::newest()->first();
$oldest = Post::oldest()->first();

分页

要排序帖子,只需使用 Eloquent 的 paginate() 方法。

$posts = Post::published()->paginate(5);
foreach ($posts as $post) {
    // ...
}

要显示分页链接,只需调用 links() 方法。

{{ $posts->links() }}

高级自定义字段(ACF)

如果您想检索由 高级自定义字段(ACF) 插件创建的自定义字段,您必须安装 corcel/acf 插件 - 点击此处获取更多信息 - 并像这样调用自定义字段

$post = Post::find(123);
echo $post->acf->some_radio_field;
$repeaterFields = $post->acf->my_repeater_name;

为了防止不必要的SQL查询,只需设置你请求的字段类型。通常需要两个SQL查询来获取字段类型,因此如果你想要指定它,你可以跳过那些额外的查询。

$post = Post::find(123);
echo $post->acf->text('text_field_name');
echo $post->acf->boolean('boolean_field_name');

自定义帖子类型

你还可以处理自定义帖子类型。你可以使用type(string)方法或创建自己的类。

// using type() method
$videos = Post::type('video')->status('publish')->get();

// using your own class
class Video extends Corcel\Post
{
    protected $postType = 'video';
}
$videos = Video::status('publish')->get();

使用type()方法将使Corcel返回所有对象为Corcel\Post。使用你自己的自定义类,你可以有自定义类、包括自定义方法和属性的优势,例如返回所有对象为Video

自定义帖子类型和元数据

// Get 3 posts with custom post type (store) and show its address
$stores = Post::type('store')->status('publish')->take(3)->get();
foreach ($stores as $store) {
    $storeAddress = $store->address; // option 1
    $storeAddress = $store->meta->address; // option 2
    $storeAddress = $store->fields->address; // option 3
}

配置返回实例

每次你调用类似Post::type('video')->first()Video::first()的东西时,你都会收到一个Corcel\Model\Post实例。

如果你选择为你自定义的帖子类型创建一个新的类,你可以让这个类为该帖子类型的所有实例返回。

注册帖子类型(简单方法)

而不是为所有想要注册的自定义帖子类型调用Post::registerPostType()方法,只需使用Corcel的配置文件并映射所有自定义帖子及其类。它们将自动为你注册。

'post_types' => [
    'video' => App\Video::class,
    'foo' => App\Foo::class,
]

所以每次你查询自定义帖子类型时,都会返回映射的实例。

这在当你打算获取不同类型的帖子集合(例如在获取在菜单中定义的帖子时)特别有用。

注册帖子类型(困难方法)

//all objects in the $videos Collection will be instances of Post
$videos = Post::type('video')->status('publish')->get();

// register the video custom post type and its particular class
Post::registerPostType('video', '\App\Video')


//now all objects in the $videos Collection will be instances of Video
$videos = Post::type('video')->status('publish')->get();

你还可以为内置类,如页面或帖子,做这件事。只需将页面或帖子类与相关的帖子类型字符串注册,然后返回该对象而不是默认对象。

短代码

从配置(Laravel)

你可以在config/corcel.php文件中,在'shortcodes'键下映射你想要的全部短代码。在这种情况下,你应该创建一个自己的类,该类实现了Corcel\Shortcode接口,该接口需要有一个render()方法。

'shortcodes' => [
    'foo' => App\Shortcodes\FooShortcode::class,
    'bar' => App\Shortcodes\BarShortcode::class,
],

这是一个短代码类的示例

class FakeShortcode implements \Corcel\Shortcode
{
    /**
     * @param ShortcodeInterface $shortcode
     * @return string
     */
    public function render(ShortcodeInterface $shortcode)
    {
        return sprintf(
            'html-for-shortcode-%s-%s',
            $shortcode->getName(),
            $shortcode->getParameter('one')
        );
    }
}

在运行时

你可以通过在Post模型上调用addShortcode方法来添加短代码

// [gallery id="1"]
Post::addShortcode('gallery', function ($shortcode) {
    return $shortcode->getName() . '.' . $shortcode->getParameter('id');
});
$post = Post::find(1);
echo $post->content;

Laravel 5.5使用包自动发现,因此不需要手动添加ServiceProvider。

如果你使用Laravel,我们建议在App\Providers\AppServiceProvider中添加你的短代码处理程序,在boot方法中。

短代码解析

短代码使用thunderer/shortcode库解析。

提供了几个不同的解析器。RegularParser是最技术正确的,并且是默认提供的。这适用于大多数情况。然而,如果你在短代码解析中遇到一些不规则性,你可能需要配置Corcel使用WordpressParser,它更忠实于WordPress的短代码正则表达式。要做到这一点,如果你使用Laravel,编辑config/corcel.php文件,并取消注释你喜欢的解析器。或者,你可以替换为你自己的解析器。

'shortcode_parser' => Thunder\Shortcode\Parser\RegularParser::class,
// 'shortcode_parser' => Thunder\Shortcode\Parser\WordpressParser::class,

如果你不使用Laravel,你可以在运行时这样做,通过从任何使用Shortcodes特质的类中调用setShortcodeParser()方法,例如Post

$post->setShortcodeParser(new WordpressParser());
echo $post->content; // content parsed with "WordpressParser" class

有关短代码包的更多信息,请点击这里

分类法

你可以获取特定帖子的分类法,如下所示

$post = Post::find(1);
$taxonomy = $post->taxonomies()->first();
echo $taxonomy->taxonomy;

或者你可以通过其分类法搜索帖子

$post = Post::taxonomy('category', 'php')->first();

帖子格式

您还可以获取文章格式,例如WordPress函数get_post_format()

echo $post->getFormat(); // should return something like 'video', etc

页面

页面类似于自定义文章类型。您可以使用Post::type('page')Corcel\Model\Page类。

use Corcel\Model\Page;

// Find a page by slug
$page = Page::slug('about')->first(); // OR
$page = Post::type('page')->slug('about')->first();
echo $page->post_title;

分类和分类法

获取一个分类或分类法或从特定分类加载文章。有多种方法可以实现。

// all categories
$cat = Taxonomy::category()->slug('uncategorized')->posts->first();
echo "<pre>"; print_r($cat->name); echo "</pre>";

// only all categories and posts connected with it
$cat = Taxonomy::where('taxonomy', 'category')->with('posts')->get();
$cat->each(function($category) {
    echo $category->name;
});

// clean and simple all posts from a category
$cat = Category::slug('uncategorized')->posts->first();
$cat->posts->each(function($post) {
    echo $post->post_title;
});

附件和修订版

PostPage获取附件和/或修订版。

$page = Page::slug('about')->with('attachment')->first();
// get feature image from page or post
print_r($page->attachment);

$post = Post::slug('test')->with('revision')->first();
// get all revisions from a post or page
print_r($post->revision);

缩略图

获取PostPage的缩略图。

$post = Post::find(1);

// Retrieve an instance of Corcel\Model\Meta\ThumbnailMeta.
print_r($post->thumbnail);

// For convenience you may also echo the thumbnail instance to get the URL of the original image.
echo $post->thumbnail;

要检索特定的缩略图大小,您可以在缩略图对象上调用->size()方法并传入一个缩略图大小字符串参数(例如thumbnailmedium)。如果缩略图已被生成,此方法返回一个图像元数据数组,否则将返回原始图像URL作为回退。

if ($post->thumbnail !== null) {
    /**
     * [
     *     'file' => 'filename-300x300.jpg',
     *     'width' => 300,
     *     'height' => 300,
     *     'mime-type' => 'image/jpeg',
     *     'url' => 'https:///wp-content/uploads/filename-300x300.jpg',
     * ]
     */
    print_r($post->thumbnail->size(Corcel\Model\Meta\ThumbnailMeta::SIZE_THUMBNAIL));

    // https:///wp-content/uploads/filename.jpg
    print_r($post->thumbnail->size('invalid_size'));
}

选项

在Corcel的先前版本中,此类称为Options而不是Option(单数)。因此,请注意从v2.0.0版本开始始终以单数形式使用此类。

在Corcel 2+中删除了Option::getAll()方法,改用Option::asArray($keys [])

您可以使用Option类从wp_options表获取数据。

$siteUrl = Option::get('siteurl');

您还可以添加新选项

Option::add('foo', 'bar'); // stored as string
Option::add('baz', ['one' => 'two']); // this will be serialized and saved

您可以以简单的数组形式获取所有选项

$options = Option::asArray();
echo $options['siteurl'];

或者,您可以指定您想要获取的键

$options = Option::asArray(['siteurl', 'home', 'blogname']);
echo $options['home'];

菜单

要按其别名获取菜单,请使用以下语法。菜单项将加载到items变量中(它是一个Corcel\Model\MenuItem对象集合)。

目前支持以下菜单项:页面、文章、自定义链接和分类。

一旦您拥有MenuItem类的实例,如果您想使用原始实例(例如原始页面或术语,例如),只需调用MenuItem::instance()方法。MenuItem对象只是一个具有post_type等于nav_menu_item的帖子。

$menu = Menu::slug('primary')->first();

foreach ($menu->items as $item) {
    echo $item->instance()->title; // if it's a Post
    echo $item->instance()->name; // if it's a Term
    echo $item->instance()->link_text; // if it's a custom link
}

instance()方法将返回匹配的对象

  • Post实例用于post菜单项;
  • Page实例用于page菜单项;
  • CustomLink实例用于custom菜单项;
  • Term实例用于category菜单项。

多级菜单

要处理多级菜单,循环所有菜单项,例如,将它们放在正确的级别上。

您可以使用MenuItem::parent()方法检索该菜单项的父实例。

$items = Menu::slug('foo')->first()->items;
$parent = $items->first()->parent(); // Post, Page, CustomLink or Term (category)

要按其父项对菜单项进行分组,您可以在$menu->items集合中使用->groupBy()方法,按其$item->parent()->ID对菜单项进行分组。

有关groupBy()方法的更多信息,请参阅Laravel文档

用户

您可以使用与处理文章相同的方式操纵用户

// All users
$users = User::get();

// A specific user
$user = User::find(1);
echo $user->user_login;

身份验证

使用Laravel

如果您正在使用Laravel 5.4或更早版本,请确保您已注册了CorcelServiceProvider提供程序

然后,在config/auth.php中定义用户提供程序,以便Laravel可以使用WordPress用户进行登录。

'providers' => [
    'users' => [
        'driver' => 'corcel',
        'model'  => Corcel\Model\User::class,
    ],
],

现在您可以使用 Auth 外观类来验证用户

Auth::validate([
    'email' => 'admin@example.com', // or using 'username' too
    'password' => 'secret',
]);

为了使 Laravel 的密码重置功能与 Corcel 一起工作,我们必须覆盖数据库中密码的存储方式。为此,您必须将 Auth/PasswordController.php

use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\ResetsPasswords;

class PasswordController extends Controller
{
    use ResetsPasswords;

修改为

use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\ResetsPasswords;
use Corcel\Laravel\Auth\ResetsPasswords as CorcelResetsPasswords;

class PasswordController extends Controller
{
    use ResetsPasswords, CorcelResetsPasswords {
        CorcelResetsPasswords::resetPassword insteadof ResetsPasswords;
    }

不使用 Laravel

您可以使用 AuthUserProvider 类手动验证用户

$userProvider = new Corcel\Laravel\Auth\AuthUserProvider;
$user = $userProvider->retrieveByCredentials(['username' => 'admin']);
if(!is_null($user) && $userProvider->validateCredentials($user, ['password' => 'admin'])) {
    // successfully login
}

请记住,您可以使用 usernameemail 作为用户的凭证。

运行测试

要运行 phpunit 测试,请执行以下命令

./vendor/bin/phpunit

如果您已安装全局 phpunit 命令,只需键入

phpunit

所有测试都使用 Sqlite 和 :memory 数据库编写,因此它们在您的内存中运行。所有测试都使用 factoriesmigrations。请查看 tests/database/factoriestests/database/migrations 目录以获取更多信息。

贡献

欢迎所有贡献来帮助改进 Corcel。

在您提交拉取请求 (PR) 之前,请考虑以下准则

  • 在 Github 上 https://github.com/corcel/corcel 进行分支

  • 在本地克隆您的分支(不是 Corcel 的)并创建一个基于您想要修复的版本(例如 2.12.22.32.42.5)的分支: git checkout -b my-fix-branch 2.5

  • 进行所有代码更改。请记住,在此处为任何新增功能或任何未测试的 bugfix 至少编写一个测试用例。我们的目标是让 100% 的代码都经过测试,所以请帮助我们编写更好的代码 ;-). 如果您没有测试经验,这是一个学习的好机会。只需查看我们的测试用例,您就会看到它们是多么简单。

  • 在本地运行单元测试以确保您的更改没有破坏任何其他代码片段

  • 将您的新分支推送到您分支的仓库,通常 git push origin HEAD 应该可以工作

  • 在 GitHub 上,从您的自定义 my-fix-branch 分支(从您的分支仓库)向相关分支(例如 corcel:2.5,而不是 corcel:master)创建一个拉取请求(PR)

  • 等待审批 :-)

许可证

MIT 许可证 © Junior Grossi