使用Laravel或任何PHP框架的WordPress后端 - Fork自jgrossi/corcel

6.0.x-dev 2022-10-11 13:28 UTC

This package is auto-updated.

Last update: 2024-09-11 17:31:45 UTC


README

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

Actions Status Packagist Packagist Test Coverage Maintainability

Corcel是一组基于Eloquent ORM(来自Laravel框架)构建的PHP类,提供了一个流畅的接口来连接并直接从WordPress数据库获取数据。

您可以将WordPress用作后端(管理面板)或CMS,用于插入文章、自定义类型等,同时在另一侧查询这些数据(作为模型层)。与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配置文件,其中您可以设置数据库连接以及更多内容。

数据库设置

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 数组中定义的一些别名,例如 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 使用 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' => '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
}

请记住,您可以使用用户名电子邮件作为用户的凭证。

运行测试

要运行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;

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

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

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

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

  • 等待批准 :-)

许可证

MIT License © Junior Grossi