Use WordPress backend with Laravel or any PHP application

Overview

Corcel PHP

A collection of Model classes that allows you to get data directly from a WordPress database.

Actions Status Packagist Packagist Test Coverage Maintainability

Corcel is a collection of PHP classes built on top of Eloquent ORM (from Laravel framework), that provides a fluent interface to connect and get data directly from a WordPress database.

You can use WordPress as the backend (administration panel) or CMS, for inserting posts, custom types, etc, and any other PHP app in the other side querying those data (as a Model layer). It's easier to use Corcel with Laravel, but you're free to use it with any PHP project that uses Composer.

Buy me a Coffee | Follow Corcel on Twitter

Table of Contents

Installing Corcel

Version Compatibility

Laravel Corcel
5.1.x ~2.1.0
5.2.x ~2.2.0
5.3.x ~2.3.0
5.4.x ~2.4.0
5.5.x ~2.5.0
5.6.x ~2.6.0
5.7.x ~2.7.0
5.8.x ~2.8.0
6.0.x ^3.0.0
7.0.x ^4.0.0
8.0.x ^5.0.0

Installing Corcel

You need to use Composer to install Corcel into your project:

composer require jgrossi/corcel

Configuring (Laravel)

Laravel 5.5 and newer

Corcel wil register itself using Laravel's Auto Discovery.

Laravel 5.4 and older

You'll have to include CorcelServiceProvider in your config/app.php:

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

Publishing the configuration file

Now configure our config file to make sure your database is set correctly and to allow you to register custom post types and shortcodes in a very easy way:

Run the following Artisan command in your terminal:

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

Now you have a config/corcel.php config file, where you can set the database connection with WordPress tables and much more.

Database Setup

Laravel Setup

Just set the database connection you want to be used by Corcel in config/corcel.php.

Let' suppose you have those following database connections in your config/database.php file:

// 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,
    ],
],

In this case you should want to use the wordpress connection for Corcel, so just set it into the Corcel config file config/corcel.php:

'connection' => 'wordpress',

Other PHP Framework (not Laravel) Setup

Here you have to configure the database to fit the Corcel requirements. First, you should include the Composer autoload file if not already loaded:

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

Now you must set your WordPress database params:

$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);

You can specify all Eloquent params, but some are default (but you can override them).

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

Usage

Posts

Every time you see Post::method(), if you're using your own Post class (where you set the connection name), like App\Post you should use App\Post::method() and not Post::method(). All the examples are assuming you already know this difference.

In the examples, every time you see Post::method() assume 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;

Creating your own model classes

Optionally you can create your own Post model (or Page, or whatever) which extends Corcel\Post. Then set the connection name (if you want to override the Corcel's default one) you're using, in this case foo-bar:

Extending Corcel\Model\Post class can add flexibility to your project, once you can add custom methods and logic, according what you need to use from your WordPress database.

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

namespace App;

use Corcel\Model\Post as Corcel;

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

    public function customMethod() {
        //
    }
}

So, now you can fetch WP database data using your own class:

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

Just remember you don't have to extends our Post class, you can use Corcel\Model\Post and all others model without any problem.

Meta Data (Custom Fields)

NOTE: In Corcel v1 you could save meta data using the Post::save() method. That's not allowed anymore. Use saveMeta() or createMeta() (see below) methods to save post meta.

You can retrieve meta data from posts too.

// 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

To create or update meta data form a User just use the saveMeta() or saveField() methods. They return bool like the Eloquent save() method.

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

You can save many meta data at the same time too:

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

You also have the createMeta() and createField() methods, that work like the saveX() methods, but they are used only for creation and return the PostMeta created instance, instead of bool.

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

Querying Posts by Custom Fields (Meta)

There are multiples possibilities to query posts by their custom fields (meta) by using scopes on a Post (or another other model which uses the HasMetaFields trait) class:

To check if a meta key exists, use the hasMeta() scope:

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

If you want to precisely match a meta-field, you can use the hasMeta() scope with a value.

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

If you need to match multiple meta-fields, you can also use the hasMeta() scope passing an array as parameter:

$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();

If you need to match a case-insensitive string, or match with wildcards, you can use the hasMetaLike() scope with a value. This uses an SQL LIKE operator, so use '%' as a wildcard operator.

// 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();

Fields Aliases

The Post class has support to "aliases", so if you check the Post class you should note some aliases defined in the static $aliases array, like title for post_title and content for post_content.

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

If you're extending the Post class to create your own class you can use $aliases too. Just add new aliases to that static property inside your own class and it will automatically inherit all aliases from parent Post class:

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

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

Custom Scopes

To order posts you can use newest() and oldest() scopes, for both Post and User classes:

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

Pagination

To order posts just use Eloquent paginate() method:

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

To display the pagination links just call the links() method:

{{ $posts->links() }}

Advanced Custom Fields (ACF)

If you want to retrieve a custom field created by the Advanced Custom Fields (ACF) plugin, you have to install the corcel/acf plugin - click here for more information - and call the custom field like this:

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

To avoid unnecessary SQL queries just set the field type you're requesting. Usually two SQL queries are necessary to get the field type, so if you want to specify it you're skipping those extra queries:

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

Custom Post Type

You can work with custom post types too. You can use the type(string) method or create your own class.

// 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();

Using type() method will make Corcel to return all objects as Corcel\Post. Using your custom class you have the advantage to customize classes, including custom methods and properties, return all objects as Video, for example.

Custom post types and meta data:

// 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
}

Configuring the returning Instance

Every time you call something like Post::type('video)->first() or Video::first() you receive a Corcel\Model\Post instance.

If you choose to create a new class for your custom post type, you can have this class be returned for all instances of that post type.

Registering Post Types (the easy way)

Instead of call Post::registerPostType() method for all custom post type you want to register, just use the Corcel's config file and map all custom posts and it's classes. They will be registered automatically for you:

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

So every time you query a custom post type the mapped instance will be returned.

This is particular useful when you are intending to get a Collection of Posts of different types (e.g. when fetching the posts defined in a menu).

Registering Post Types (the hard way)

//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();

You can also do this for inbuilt classes, such as Page or Post. Simply register the Page or Post class with the associated post type string, and that object will be returned instead of the default one.

Shortcodes

From config (Laravel)

You can map all shortcodes you want inside the config/corcel.php file, under the 'shortcodes' key. In this case you should create your own class that implements the Corcel\Shortcode interface, that requires a render() method:

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

This is a sample shortcode 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')
        );
    }
}

In runtime

You can add shortcodes by calling the addShortcode method on the Post model :

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

Laravel 5.5 uses Package Auto-Discovery, so doesn't require you to manually add the ServiceProvider

If you are using Laravel, we suggest adding your shortcodes handlers in App\Providers\AppServiceProvider, in the boot method.

Shortcode Parsing

Shortcodes are parsed with the thunderer/shortcode library.

Several different parsers are provided. RegularParser is the most technically correct and is provided by default. This is suitable for most cases. However if you encounter some irregularities in your shortcode parsing, you may need to configure Corcel to use the WordpressParser, which more faithfully matches WordPress' shortcode regex. To do this, if you are using Laravel, edit the config/corcel.php file, and uncomment your preferred parser. Alternatively, you can replace this with a parser of your own.

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

If you are not using Laravel, you can to do this in runtime, calling the setShortcodeParser() method from any class which uses the Shortcodes trait, such as Post, for example.

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

For more information about the shortcode package, click here.

Taxonomies

You can get taxonomies for a specific post like:

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

Or you can search for posts using its taxonomies:

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

Post Format

You can also get the post format, like the WordPress function get_post_format():

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

Pages

Pages are like custom post types. You can use Post::type('page') or the Corcel\Model\Page class.

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;

Categories and Taxonomies

Get a category or taxonomy or load posts from a certain category. There are multiple ways to achieve it.

// 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;
});

Attachment and Revision

Getting the attachment and/or revision from a Post or Page.

$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);

Thumbnails

Getting the thumbnail for a Post or Page.

$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;

To retrieve a particular thumbnail size you may call the ->size() method on the thumbnail object and pass in a thumbnail size string parameter (e.g. thumbnail or medium). If the thumbnail has been generated, this method returns an array of image metadata, otherwise the original image URL will be returned as a fallback.

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'));
}

Options

In previous versions of Corcel this classe was called Options instead of Option (singular). So take care of using always this class in the singular form starting from v2.0.0.

The Option::getAll() method was removed in Corcel 2+, in favor of Option::asArray($keys []).

You can use the Option class to get data from wp_options table:

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

You can also add new options:

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

You can get all options in a simple array:

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

Or you can specify only the keys you want to get:

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

Menu

To get a menu by its slug, use the syntax below. The menu items will be loaded in the items variable (it's a collection of Corcel\Model\MenuItem objects).

The currently supported menu items are: Pages, Posts, Custom Links and Categories.

Once you'll have instances of MenuItem class, if you want to use the original instance (like the original Page or Term, for example), just call the MenuItem::instance() method. The MenuItem object is just a post with post_type equals 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
}

The instance() method will return the matching object:

  • Post instance for post menu item;
  • Page instance for page menu item;
  • CustomLink instance for custom menu item;
  • Term instance for category menu item.

Multi-levels Menus

To handle multi-levels menus, loop through all the menu items to put them on the right levels, for example.

You can use the MenuItem::parent() method to retrieve the parent instance of that menu item:

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

To group menu items according their parents, you can use the ->groupBy() method in the $menu->items collection, grouping menu items by their $item->parent()->ID.

To read more about the groupBy() method take a look on the Laravel documentation.

Users

You can manipulate users in the same manner you work with posts:

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

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

Authentication

Using Laravel

If you're using Laravel 5.4 or older, make sure you have the CorcelServiceProvider provider registered.

And then, define the user provider in config/auth.php to allow Laravel to login with WordPress users:

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

Now you can use the Auth facade to authenticate users:

Auth::validate([
    'email' => '[email protected]', // or using 'username' too
    'password' => 'secret',
]);

To make Laravel's Password Reset work with Corcel, we have to override how passwords are stored in the database. To do this, you must change Auth/PasswordController.php from:

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

class PasswordController extends Controller
{
    use ResetsPasswords;

to

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;
    }

Not using Laravel

You can use the AuthUserProvider class to manually authenticate a user :

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

Remember you can use both username and email as credentials for a User.

Running Tests

To run the phpunit tests, execute the following command :

./vendor/bin/phpunit

If you have the global phpunit command installed you can just type:

phpunit

All tests were written using Sqlite with :memory database, so it runs in your memory. All tests use factories and migrations. Take a look on tests/database/factories and tests/database/migrations directories for more information.

Contributing

All contributions are welcome to help improve Corcel.

Before you submit your Pull Request (PR) consider the following guidelines:

  • Fork https://github.com/corcel/corcel in Github;

  • Clone your forked repository (not Corcel's) locally and create your own branch based on the version you want to fix (2.1, 2.2, 2.3, 2.4 or 2.5): git checkout -b my-fix-branch 2.5;

  • Make all code changes. Remember here to write at least one test case for any feature you add or any bugfix (if it's not tested yet). Our goal is to have 100% of the code covered by tests, so help us to write a better code ;-) If you don' have experience with tests it's a good opportunity to learn. Just take a look into our tests cases and you'll see how simple they are.

  • Run the unit tests locally to make sure your changes did not break any other piece of code;

  • Push your new branch to your forked repository, usually git push origin HEAD should work;

  • In GitHub again, create a Pull Request (PR) from your custom my-fix-branch branch (from your forked repository) to the related branch (corcel:2.5, for example, not corcel:master, please;

  • Wait for the approval :-)

Licence

MIT License © Junior Grossi

Comments
  • Corcel with UserFrosting

    Corcel with UserFrosting

    i couldn't make Corcel work with UserFrosting.I am sure i am making a simple mistake because i am a newbie for php. I couldn't find any documents. I need just an example, thats all. how can i add second connection for wordpress in Slim Framework(UserFrosting uses Slim)? i can share ftp/db/wordpress credentials if necessary.

    opened by bsoner 33
  • Can't get Featured image

    Can't get Featured image

    I have a custom post type called "dicono-di-noi" and if I try to get the entries with:

    $dicono_di_noi = DiconoDiNoi::published()->with('attachment')->orderBy(DB::raw('RAND()'))->get();
    

    I'm not able to get the image.

    This is my view:

     @foreach($dicono_di_noi as $dicono)
            <div class="item">
                {!! $dicono->image !!}
            </div>
      @endforeach
    

    I used $dicono->image according to this issue: https://github.com/jgrossi/corcel/issues/94 but this is the result:

    SQLSTATE[42S02]: Base table or view not found: 1146 Table 'testsite.postmeta' doesn't exist (SQL: select * from `postmeta` where `post_id` is null and `post_id` is not null)
    
    opened by ChristianGiupponi 28
  • Issue with laravel v5.2.32

    Issue with laravel v5.2.32

    When upgrading to laravel v5.2.32 from v5.2.31 I get an error.

    When doing a composer update I noticed the version of laravel changed. Upon doing nothing but changing the version of laravel I get the following error.

    ErrorException in Model.php line 3467:
    Undefined property: App\Model\Post::$meta
    
    ErrorException in Model.php line 3467:
    Undefined property: App\Model\Post::$meta
    
    in Model.php line 3467
    at HandleExceptions->handleError('8', 'Undefined property: App\Model\Post::$meta', '/var/www/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php', '3467', array('key' => 'meta', 'this' => object(Post))) in Model.php line 3467
    at Model->__isset('meta') in Post.php line 198
    at Post->__get('meta') in Post.php line 199
    at Post->__get('softDelete') in Post.php line 182
    at Post->newQuery() in Model.php line 3498
    at Model->__call('taxonomy', array('category', 'learn'))
    at Post->taxonomy('category', 'learn')
    at call_user_func_array(array(object(Post), 'taxonomy'), array('category', 'learn')) in Model.php line 3514
    at Model::__callStatic('taxonomy', array('category', 'learn')) in BlogController.php line 20
    at Post::taxonomy('category', 'learn') in BlogController.php line 20
    at BlogController->home()
    at call_user_func_array(array(object(BlogController), 'home'), array()) in Controller.php line 80
    at Controller->callAction('home', array()) in ControllerDispatcher.php line 146
    at ControllerDispatcher->call(object(BlogController), object(Route), 'home') in ControllerDispatcher.php line 94
    at ControllerDispatcher->Illuminate\Routing\{closure}(object(Request))
    at call_user_func(object(Closure), object(Request)) in Pipeline.php line 52
    at Pipeline->Illuminate\Routing\{closure}(object(Request))
    at call_user_func(object(Closure), object(Request)) in Pipeline.php line 103
    at Pipeline->then(object(Closure)) in ControllerDispatcher.php line 96
    

    If I downgrade back to v5.2.31 the error goes away. I was in a rush to finish a project for a client so I just downgraded laravel, but I figured I would post here in case anybody else runs into the same issue.

    opened by go-nut 27
  • Undefined property: Corcel\Post::$meta

    Undefined property: Corcel\Post::$meta

    Hi!! I am trying to install the package but I get this error:

    Undefined property: Corcel\Post::$meta
    ********
    public function __get($key)
        {
            if (!isset($this->$key)) {
              -->ERROR IS HERE?  return $this->meta->$key;    
            }
    ********
    

    Can you guide me where can be the error?

    I have this code:

    $params = array(
                'database'  => 'syscover-wp',
                'username'  => 'carlos',
                'password'  => '33527667Sb',
            );
            \Corcel\Database::connect($this->params);
            $post = Post::published()->get();
    

    thanks!!

    bug 
    opened by carlospalacin 27
  • menu doesn't work as expected

    menu doesn't work as expected

    as per this post https://github.com/jgrossi/corcel/issues/9, when creating menu items $item->title or $item->post_title does not pull through the expected menu entry. also $item->slug pulls through the slug of the menu item, not the post it relates to

    the following issues seem to be present

    • menu item does not show title unless it is changed from the original page name
    • WP creates a nav_menu_item entry in wp_posts so using $item->slug etc gets the slug of the menu item, not the slug of the post the menu item is meant to point to

    for every menu item I ended up creating a custom link (instead of a Page/Post/Category menu item) and then linking to $item->meta->_menu_item_url

    what would be the correct way to loop through a WP menu with Corcel and get the links to my pages?

    thanks j

    opened by codemonkeynorth 26
  • Validate users passwords againt saved passwords by wordpress

    Validate users passwords againt saved passwords by wordpress

    Hi,

    I've implemented the users authentication but it seems that the check is not working with users passwords but the tests are working. So i dig into the password service provider, and i found that you use BcryptHasher to check the password if it's not an MD5, then made a little test:

    • I've create a user in "wp admin" using "admin" as username and "admin" as password.
    • Then i've checked the database to get the hashed password : $P$BrYiES.08ardK6pQme0LdlmQ0idrIe/
    • It's not an MD5, so i've used BcryptHasher to check it:

    $hasher = new BcryptHasher(); dd($hasher->check('admin', '$P$BrYiES.08ardK6pQme0LdlmQ0idrIe/'));

    And the result is false.

    opened by oayoub84 22
  • Multilanguage

    Multilanguage

    Hello,

    It would be cool to integrate a multilanguage feature. The task would be, find a good multilanguage plugin, and get the posts in different languages. I think this would be great, as we could ask for posts in different languages. The problem is we will be stuck with the dependence of one particular plugin.

    What do you think?

    opened by codeserk 20
  • multi-site

    multi-site

    Hi,

    Thanks for a great project!

    If I am connecting to a multi-site wordpress, is there a way for me to change the prefix without needing to run \Corcel\Database::connect($params); again with the new prefix specified? This is for a project where I am connecting to our wordpress and posting articles to hundreds of sites.

    opened by AlexECP 20
  • Post method __get extremely slow

    Post method __get extremely slow

    I've been having some troubles with the __get($key) method in the Post model.

    It makes a queries looking for metas every time a key is not found in the post model. This is very time consuming and avoids any possible cache (I have a cache and still have like 750 queries to meta files)

    screen shot 2016-02-12 at 01 06 02

    I'd suggest another approach, removing the __get method and getting all the needed information with accessors like done before.

    What do you think?

    opened by codeserk 18
  • Yoast SEO

    Yoast SEO

    Hello,

    I normally use Yoast SEO plugin for WP and it's quite handy. However, getting all the metas, one by one can be a pain in the ass, as they are like _yoast_wpseo_focuskw and awful things like that... I'm definitely going to translate that to something more legible. The question is if that would make sense in your project, or if I should do that in an upper layer in my projects.

    My idea for your project was creating a new field called seo in Posts which contained all the meaningful data taken from Yoast (title, description, keywords, ...)

    What do you think about this?

    opened by codeserk 18
  • wanting to use different db prefix for laravel tables and wp tables

    wanting to use different db prefix for laravel tables and wp tables

    i want to create my tables like this

    lar_campaign
    lar_campaign_tag
    

    etc

    thing is when i change database.php

            'mysql' => [
                'driver' => 'mysql',
    ...
                'prefix' => 'wp_',
            ],
    
    

    too

            'mysql' => [
                'driver' => 'mysql',
    ...
                'prefix' => 'lar_',
            ],
    
    

    and open the page

    it explodes with

    
    SQLSTATE[42S22]: Column not found: 1054 Unknown column 'user_registered' in 'order clause' (SQL: select * from `lar_users` order by `user_registered` desc)
    
    

    am i missing something?

    so i guess now laravel looks up the table with prefix lar_ instead of going to the wp_users tables...

    opened by torian257x 17
  • Missing PhpOption\Option dependencies on CakePHP

    Missing PhpOption\Option dependencies on CakePHP

    • Corcel Version: 6.0.0
    • Framework Name & Version: CakePHP 4.4
    • PHP Version: 8.0.26

    Description:

    I required jgrossi/corcel on a fresh install of CakePHP. I didn't even get to actually using any of the corcel classes. The base application stopped working throwing the below error:

    PHP message: PHP Fatal error: Uncaught Error: Class "PhpOption\Option" not found in /var/www/example/vendor/illuminate/support/Env.php:76 Stack trace: 0 /var/www/example/vendor/illuminate/support/helpers.php(137): Illuminate\Support\Env::get() 1 /var/www/example/config/app.php(19): env() 2 /var/www/example/vendor/cakephp/cakephp/src/Core/Configure/Engine/PhpConfig.php(89): include('...') 3 /var/www/example/vendor/cakephp/cakephp/src/Core/Configure.php(341): Cake\Core\Configure\Engine\PhpConfig->read() 4 /var/www/example/config/bootstrap.php(81): Cake\Core\Configure::load() 5 /var/www/example/vendor/cakephp/cakephp/src/Http/BaseApplication.php(173): require_once('...') 6 /var/www/example/src/Application.php(47): Cake\Http\BaseApplication->bootstrap() 7 /var/www/example/vendor/cakephp/cakephp/src/Http/Server.php(109): App\Application->bootstrap() 8 /var/www/example/vendor/cakephp/cakephp/src/Http/Server.php(79): Cake\Http\Server->bootstrap()

    Steps To Reproduce:

    1.  composer create-project --prefer-dist cakephp/app:4.* example
      
    2.  composer require jgrossi/corcel
      

    What I tried

    Ideas from https://laracasts.com/discuss/channels/testing/class-phpoptionoption-not-found-when-running-phpunit:

    • composer clear-cache - no effect
    • composer install - no effect
    • composer require 'phpoption/phpoption' - the error changes to:

      PHP message: PHP Fatal error: Uncaught Error: Class "Dotenv\Repository\RepositoryBuilder" not found in /var/www/example/vendor/illuminate/support/Env.php:55 Stack trace: 0 /var/www/example/vendor/illuminate/support/Env.php(76): Illuminate\Support\Env::getRepository() 1 /var/www/example/vendor/illuminate/support/helpers.php(137): Illuminate\Support\Env::get() 2 /var/www/example/config/app.php(19): env() 3 /var/www/example/vendor/cakephp/cakephp/src/Core/Configure/Engine/PhpConfig.php(89): include('...') 4 /var/www/example/vendor/cakephp/cakephp/src/Core/Configure.php(341): Cake\Core\Configure\Engine\PhpConfig->read() 5 /var/www/example/config/bootstrap.php(81): Cake\Core\Configure::load() 6 /var/www/example/vendor/cakephp/cakephp/src/Http/BaseApplication.php(173): require_once('...') 7 /var/www/example/src/Application.php(47): Cake\Http\BaseApplication->bootstrap() 8 /var/www/example/vendor/cakephp/cakephp/src/Http/Server.php(109): App\Application->bootstrap()

    One would think the dependencies should have been loaded automatically?

    opened by mehov 0
  • Add autoload and update support for option

    Add autoload and update support for option

    Here's a simple example :

            $debugPrint = function (Option $option) {
                dump([
                    "option_id" => $option->option_id,
                    "option_name" => $option->option_name,
                    "option_value" => $option->option_value,
                    "autoload" => $option->autoload,
                ]);
            };
            Option::add("hellooo", "ok");
            $debugPrint(Option::where("option_name", "hellooo")->first());
            Option::add("hellooo", "ok2");
            $debugPrint(Option::where("option_name", "hellooo")->first());
            Option::add("hellooo", "ok3", false);
            $debugPrint(Option::where("option_name", "hellooo")->first());
            exit(0);
    

    Output:

    array:4 [
      "option_id" => 4736
      "option_name" => "hellooo"
      "option_value" => "ok"
      "autoload" => "yes"
    ]
    array:4 [
      "option_id" => 4736
      "option_name" => "hellooo"
      "option_value" => "ok2"
      "autoload" => "yes"
    ]
    array:4 [
      "option_id" => 4736
      "option_name" => "hellooo"
      "option_value" => "ok3"
      "autoload" => "no"
    ]
    
    opened by Stevemoretz 0
  • Corcel acf plugin not installable

    Corcel acf plugin not installable

    With Laravel 9, Corcel ^6.0

    Issue:

    Problem 1 - Root composer.json requires corcel/acf ^4.0 -> satisfiable by corcel/acf[4.0.0]. - corcel/acf 4.0.0 requires jgrossi/corcel ^4.0|^5.0 -> found jgrossi/corcel[v4.0.0, v4.0.1, 4.0.x-dev, v4.1.0, v5.0.0, 5.0.x-dev, v5.1.0, v5.1.1] but it conflicts with your root composer.json require (^6.0).

    Use the option --with-all-dependencies (-W) to allow upgrades, downgrades and removals for packages currently locked to specific versions. You can also try re-running composer require with an explicit version constraint, e.g. "composer require corcel/acf:*" to figure out if any version is installable, or "composer require corcel/acf:^2.1" if you know which you need.

    opened by PiyushKumarDongre 0
  • How to query for Posts with updated_at field ?

    How to query for Posts with updated_at field ?

    Hi,

    I want to get all Posts that are updated after a particular timestamp. What will be the syntax ? I have tried

    \App\Models\WPPost2::all(['updated_date']);
    

    'updated_at'

    but both returns error.

    Thanks.

    opened by pkd2989 0
  • Menu doesn't return Product Categories added to WordPress menus

    Menu doesn't return Product Categories added to WordPress menus

    • Corcel Version: ^6.0
    • Framework Name & Version: Laravel ^9.19
    • PHP Version: ^8.0.2
    • Database Driver & Version: MySQLi - mysqlnd8.1.10

    Description:

    I'm trying to get "Product Categories" I added to the new menu. So, I created a menu and named it "newnavmenu". Instead of adding Pages, I want to add "Product categories" that I created in WooCommerce Categories. Now, when I loop through items, the instance() method returns null and there is not specific information about menu items. I can see basic information about newnavmenu itself but nothing related to "Product categories" items I added before.

    Steps To Reproduce:

    So basically I do exactly what I found in documentation:

    Route::get('/', function () {
        $menu = Menu::slug('newnavmenu')->first()->items;
    
        return view('welcome', compact(
            'menu'
        ));
    });
    

    And I try to loop through items in blade file:

    @foreach ($menu as $item)
                {{$item->instance()}}
    @endforeach
    

    Even if I return $item without insance() method, none of categories is available:

    @foreach ($menu as $item)
                {{$item)}}
    @endforeach
    

    How do I return "Product Categories" I added to new created menu? Anyone can help please?

    opened by haghanihakimi 0
Releases(v2.8.1)
Owner
Corcel PHP
Use WordPress with any PHP application easily
Corcel PHP
This is code to create a new user as admin use for Wordpress FrontEnd Developer to prevent any scaming from clients

theme-setup This is code to create a new user as admin use for Wordpress FrontEnd Developer to prevent any scaming from clients How to use Just copy c

Abdul Razzaq 1 Nov 27, 2021
WordPress plugin that lets you use Discourse as the community engine for a WordPress blog

WP Discourse Note: the wp-discourse plugin requires >= PHP-5.4.0. The WP Discourse plugin acts as an interface between your WordPress site and your Di

Discourse 497 Dec 10, 2022
Adds a dashboard widget that allows admins to quickly open the edit screen for any WordPress post type- including orders, products, and subscriptions.

Quick Open Dashboard Widget Requires PHP: 7.0 WP requires at least: 5.7 WP tested up to: 5.7 WC requires at least: 5.6.0 WC tested up to: 5.8.0 Stable

Universal Yums 4 Nov 11, 2021
A library to allow the use of PHP attributes for WordPress hooks

WordPress Hook Attributes This library should be considered experimental and not production ready. Installation composer require boxuk/wp-hook-attribu

Box UK 9 Nov 23, 2022
A PHP client for Wordpress websites that closely implement the XML-RPC WordPress API

Wordpress XML-RPC PHP Client A PHP client for Wordpress websites that closely implement the XML-RPC WordPress API Created by Hieu Le MIT licensed. Cur

Hieu Le 112 Nov 10, 2022
Automattic 10.7k Jan 2, 2023
The easiest to use WordPress option framework.

Titan Framework The easiest to use WordPress options framework. Titan Framework allows theme and plugin developers to create admin pages, options, met

Gambit Technologies 374 Nov 14, 2022
WordPress plugin people can use to embed to their website: a Mintbase NEAR NFT and Mintbase NEAR store

mintbase-embed WordPress plugin people can use to embed to their website: a Mintbase NEAR NFT and Mintbase NEAR store This is demo plugin that allows

null 3 Oct 1, 2021
Beauty and simple Wordpress video player plugin. Powerfull and lite in use.

Sonic Spectre Video Player Beauty and simple Wordpress video player plugin. Powerfull and lite in use. Quick Start: Download plugin from this repo and

Halcyon 1 Jan 4, 2022
A WordPress plugin to re-use the same domain name for both your website and your Rebrandly links

By installing this plugin and configuring it to connect with your Rebrandly account, you will be able to create branded links using the same domain yo

null 3 Jan 19, 2022
A custom WordPress nav walker class to fully implement the Twitter Bootstrap 4.0+ navigation style (v3-branch available for Bootstrap 3) in a custom theme using the WordPress built in menu manager.

WP Bootstrap Navwalker This code in the main repo branch is undergoing a big shakeup to bring it in line with recent standards and to merge and test t

WP Bootstrap 3.3k Jan 5, 2023
A curated list of Awesome WordPress Theme, Plugins and Framework development Resources and WordPress Communities.

Awesome WordPress A curated list of Awesome WordPress Theme, Plugins and Framework development Resources and WordPress Communities. Inspired by bayand

Dropndot Limited 91 Dec 26, 2022
The Pronamic WordPress Basecone plugin allows you to connect your WordPress installation to Basecone.

Pronamic WordPress Basecone The Pronamic WordPress Basecone plugin allows you to connect your WordPress installation to Basecone. Table of contents Au

Pronamic 1 Oct 19, 2021
A WordPress plugin to suspend WordPress sites automagically. Simple and lightweight, no annoying ads and fancy settings.

Suspend WP A WordPress plugin to suspend WordPress sites automagically. Simple and lightweight, no annoying ads and fancy settings. ?? Demo (coming so

Waren Gonzaga 3 Nov 15, 2021
Twenty Twenty-Two, the default WordPress theme that will launch with WordPress 5.9.

Twenty Twenty-Two Welcome to the development repository for the default theme that will launch with WordPress 5.9. About Twenty Twenty-Two is designed

null 414 Nov 28, 2022
Easy handle APlayer on WordPress. A shortcode for WordPress to using APlayer.

Description Easy handle APlayer on WordPress. A shortcode for WordPress to using APlayer. Support [audio] tag, compatible with AMP. Requirement WordPr

Karl Chen 24 Nov 3, 2022
WordPress & TypeScript. Simple starter template for WordPress projects

WordPress & TypeScript. Simple starter template for WordPress projects that want to use TypeScript in combination with @wordpress/scripts

Make it WorkPress 11 Sep 27, 2022
Simple WordPress plugin to learn how to understand WordPress Crons and the Action Scheduler library.

Simple WordPress plugin to learn how to understand WordPress Crons and the Action Scheduler library. Import Jamendo playlists with tracks in WordPress posts.

Pierre Saikali 3 Dec 7, 2022
Laravel Blog Package. Easiest way to add a blog to your Laravel website. A package which adds wordpress functionality to your website and is compatible with laravel 8.

Laravel Blog Have you worked with Wordpress? Developers call this package wordpress-like laravel blog. Contact us for any customization: contact@binsh

Binshops 279 Dec 28, 2022