ncaroyannis/corcel

使用 Laravel 后端或任何 PHP 框架配合 WordPress


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 数组中定义的一些别名,例如 titlepost_titlecontentpost_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以使用更忠实于WordPress简码正则表达式的WordpressParser。为此,如果您使用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

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

贡献

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

在您提交Pull Request (PR) 之前,请考虑以下准则:

  • 在Github上Fork https://github.com/corcel/corcel

  • 克隆您的Forked仓库(不是Corcel的)到本地,并基于您要修复的版本(例如2.12.22.32.42.5)创建自己的分支:git checkout -b my-fix-branch 2.5

  • 进行所有代码更改。请记住,在这里为任何添加的功能或任何尚未测试的错误修复至少编写一个测试用例。我们的目标是使100%的代码通过测试,所以请帮助我们编写更好的代码;-) 如果您没有测试经验,这是一个学习的好机会。只需查看我们的测试用例,您就会看到它们是多么简单。

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

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

  • 在GitHub上再次操作,从您的自定义my-fix-branch分支(从您的Forked仓库)创建一个Pull Request (PR) 到相关分支(例如,corcel:2.5,而不是corcel:master,请);

  • 等待批准:-)

许可证

MIT License © Junior Grossi