jgrossi/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将要使用的数据库连接

假设您在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_title,而 content 对应于 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特质的类(如Post)中调用setShortcodeParser()方法。

$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' => 'http://localhost/wp-content/uploads/filename-300x300.jpg',
     * ]
     */
    print_r($post->thumbnail->size(Corcel\Model\Meta\ThumbnailMeta::SIZE_THUMBNAIL));

    // http://localhost/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。

在您提交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;

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

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

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

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

  • 等待批准 :-)

许可证

MIT License © Junior Grossi