Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

sogeniusio's avatar

Remove category_id from post when category is deleted

I'm working on a blog and would like to be able to delete categories on the fly. I'd then like to find all associated posts and remove the category_id from the row.

CategoryController.php

    /**
     * Remove the specified resource from storage.
     *
     * @param  int $id
     * @return \Illuminate\Http\Response
     */
    public function destroy($id)
    {
      $category = Category::find($id);
      $category->posts()->delete();
      $category->delete();
      Session::flash('success', 'The tag was successfully deleted.');

      return redirect()->route('categories.index');
    }

Post.php

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Post extends Model
{
    protected $table = 'posts';

    protected $fillable = [
      'title',
      'excerpt',
      'body',
      'slug',
      'category_id',
    ];

    public function category()
    {
        return $this->belongsTo('App\Category');
    }
    
    public function tags()
    {
        return $this->belongsToMany('App\Tag');
    }
}

Category.php

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Category extends Model
{
    protected $table = 'categories';

    protected $fillable = [
        'name',
    ];

    public function posts()
    {
        return $this->hasMany('App\Post');
    }
}

Any ideas on how to make this work. Please advise!

0 likes
6 replies
Cronix's avatar

Not sure, but you might want to have an "uncategorized" category and run an update to change all the posts with the old category to that one. Then delete the category.

dawiyo's avatar

Assuming the category_id column on your posts table is nullable:

/**
 * Remove the specified resource from storage.
 *
 * @param  int $id
 * @return \Illuminate\Http\Response
 */
public function destroy($id)
{
    $category = Category::find($id);
    $category->posts()->delete(); // See below
    $category->delete();

    Post::whereCategoryId($id)->update(['category_id' => null]);

    Session::flash('success', 'The tag was successfully deleted.');

    return redirect()->route('categories.index');
}

$category->posts()->delete(); would delete all of the posts associated with that category. However, in your description, you don't mention that. Just don't want you to have an oh crap moment.

sogeniusio's avatar

Thanks for your suggestions guys.

I will consider having an Uncategorized category. I'd have to do some changing within my code to not show if it is set to uncategorized.

@dawiyo I'd try this option but it looks like it'll delete the post. The most important thing I'd like to do is keep all posts but detach the category_id and possibly set it to NULL. Maybe what @Cronix suggested would be best...

Here's my migration:

create_categories_table.php

<?php

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreateCategoriesTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('categories', function (Blueprint $table) {
            $table->increments('id')->unsigned();
            $table->string('name');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('categories');
    }
}

create_posts_table.php

<?php

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreatePostsTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('posts', function (Blueprint $table) {
            $table->increments('id');
            $table->integer('category_id')->nullable()->unsigned();
            $table->string('title');
            $table->string('excerpt')->nullable();
            $table->text('body');
            $table->string('slug')->unique();
            $table->string('feat_image')->nullable();
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('posts');
    }
}
dawiyo's avatar

If you want to retain the posts, you'll need to remove the $category->posts()->delete(); line.

sogeniusio's avatar

Thanks. I'm able to keep the posts. But it doesn't remove the category_id.

dawiyo's avatar

Like I mentioned above, have you tried:

Post::whereCategoryId($id)->update(['category_id' => null]);

Please or to participate in this conversation.