Let's say you have a blog and have posts ordered by their published date. Later you decide you want to pin certain posts.
Pinned posts should be displayed before any other posts regardless of their published date.
The Solution
You can accomplish this by modifying the order clause in the query.
Take this order:
->orderBy('published_at', 'desc')
This will order posts by their published date in descending order.
Adding a second-order clause:
->orderBy('is_pinned', 'desc')->orderBy('published_at', 'desc');
This time ordered by a is_pinned column then order by the published_at column.
This will show the posts pinned first and then show the posts in their published order.
The Setup
Adding a migration to add a column called is_pinned to a posts table
php artisan make:migration add_pinned_field_to_posts
Migration
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class AddPinnedFieldToPosts extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('posts', function (Blueprint $table) {
$table->boolean('is_pinned')->default(false);
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('posts', function (Blueprint $table) {
$table->dropColumn('is_pinned');
});
}
}
Create a local scope
In the post model, create a local scope for the order.
public function scopeOrder($query)
{
return $query->orderBy('is_pinned', 'desc')->orderBy('published_at', 'desc');
}
Using the local scope
When querying the posts use the order scope to set the order for both is_pinned and published_at
Post::order()->paginate();