baleethai / filament-thailand-location-picker
FilamentPHP plugin for picking Thailand region/province/district/subdistrict
Package info
github.com/baleethai/filament-thailand-location-picker
pkg:composer/baleethai/filament-thailand-location-picker
Requires
- php: ^8.2
- filament/filament: ^5.0
- illuminate/database: ^11.0|^12.0|^13.0
- illuminate/support: ^11.0|^12.0|^13.0
Requires (Dev)
- orchestra/testbench: ^9.0|^10.0|^11.0
- pestphp/pest: ^3.0|^4.0
- pestphp/pest-plugin-laravel: ^3.0|^4.0
- pestphp/pest-plugin-livewire: ^3.0|^4.0
README
FilamentPHP v5 plugin สำหรับเลือกที่อยู่ในประเทศไทยแบบ cascading dropdown — ภาค (Region) → จังหวัด (Province) → อำเภอ (District) → ตำบล (Subdistrict) — พร้อมข้อมูลที่อยู่ครบทั้งประเทศและรหัสไปรษณีย์ ไม่ต้องพึ่ง API ภายนอก
ทำไมต้องใช้
ทุกโปรเจกต์ที่มีฟอร์มที่อยู่ไทย มักต้องทำงานซ้ำ ๆ กัน: สร้างตารางภาค/จังหวัด/อำเภอ/ตำบล, หา seed data, และเขียน reactive logic ให้ dropdown แต่ละระดับกรองตามระดับก่อนหน้า แพ็กเกจนี้รวมทุกอย่างไว้ให้ ติดตั้งครั้งเดียวใช้ได้ทุกโปรเจกต์
Features
- Cascading select 4 ระดับ: ภาค → จังหวัด → อำเภอ → ตำบล (reactive ด้วย Livewire, กรองตัวเลือกอัตโนมัติเมื่อระดับก่อนหน้าถูกเลือก)
- ข้อมูลที่อยู่ครบทั้งประเทศ พร้อมใช้ทันทีผ่าน
php artisan thailand:seed(6 ภาค, 77 จังหวัด, 930 อำเภอ, 7,452 ตำบล) - เติมรหัสไปรษณีย์ให้อัตโนมัติเมื่อเลือกตำบล
- รองรับสองภาษา (
th/en) ตั้งค่าได้ทั้งระดับ global และรายฟิลด์ พร้อมคำแปล label ของฟิลด์ให้ทั้งen/thในตัว (publish แก้ไขเองได้) - เปิด/ปิดฟิลด์ ภาค (Region) ได้ทั้งระดับ global (config) และรายฟิลด์
- Component สำเร็จรูป
ThailandLocation(ที่อยู่ + 4 dropdown + รหัสไปรษณีย์ในตัวเดียว) หรือใช้ select แต่ละตัวแยกกันเพื่อคุมเลย์เอาต์เอง - Table column
ThailandLocationColumnแสดงที่อยู่แบบเต็ม (ตำบล, อำเภอ, จังหวัด, ภาค) จาก relationship เดียว พร้อม eager loading ป้องกัน N+1 - ชื่อตารางและชื่อฟิลด์ configurable ผ่าน
config/thailand-plugin.php
Requirements
- PHP 8.2+
- Laravel (illuminate/database, illuminate/support) 11.x, 12.x หรือ 13.x
- FilamentPHP 5.x
Installation
composer require baleethai/filament-thailand-location-picker
Publish และรัน migrations:
php artisan vendor:publish --tag="thailand-plugin-migrations"
php artisan migrate
Seed ข้อมูลที่อยู่ทั่วประเทศ:
php artisan thailand:seed
(ถ้าต้องการแก้ไข config เช่นชื่อตารางหรือ locale เริ่มต้น ให้ publish config เพิ่ม)
php artisan vendor:publish --tag="thailand-plugin-config"
ลงทะเบียน Plugin ใน Panel (ถ้าต้องการ)
use Baleethai\ThailandPlugin\ThailandPlugin; public function panel(Panel $panel): Panel { return $panel ->plugins([ ThailandPlugin::make(), ]); }
Usage
1. วิธีที่ง่ายที่สุด — component เดียวจบ
ThailandLocation วาง address line 1/2, ภาค, จังหวัด, อำเภอ, ตำบล และรหัสไปรษณีย์ ให้ในครั้งเดียว พร้อม cascading logic ระหว่างกันทั้งหมด:
use Baleethai\ThailandPlugin\Forms\Components\ThailandLocation; public static function form(Schema $schema): Schema { return $schema->components([ ThailandLocation::make(), ]); }
ค่าเริ่มต้นจะเก็บลงฟิลด์เหล่านี้:
| Field | Default column |
|---|---|
| Address line 1 | address_line_1 |
| Address line 2 | address_line_2 |
| Region (ภาค) | geo_id |
| Province (จังหวัด) | province_id |
| District (อำเภอ) | district_id |
| Subdistrict (ตำบล) | subdistrict_id |
| Zip code | zip_code |
กำหนดชื่อฟิลด์เอง หรือปิดใช้งานบางอย่างได้:
ThailandLocation::make() ->geoField('region_id') ->provinceField('province_id') ->districtField('district_id') ->subdistrictField('subdistrict_id') ->zipField('postal_code') ->required() ->searchable() ->locale('en'),
ปิดฟิลด์ ภาค (Region) ทิ้งไปได้ทั้งแบบรายฟิลด์ หรือตั้ง default ผ่าน config:
ThailandLocation::make() ->geoEnabled(false),
2. ใช้ select แยกทีละตัว — คุม layout เอง
ใช้เมื่อไม่ต้องการ address line / zip code ในตัว หรือต้องการจัดวางเอง โดยแต่ละ select ต้องบอกว่าอ้างอิงฟิลด์ระดับก่อนหน้าชื่ออะไร:
use Baleethai\ThailandPlugin\Forms\Components\GeoSelect; use Baleethai\ThailandPlugin\Forms\Components\ProvinceSelect; use Baleethai\ThailandPlugin\Forms\Components\DistrictSelect; use Baleethai\ThailandPlugin\Forms\Components\SubdistrictSelect; use Filament\Schemas\Components\Grid; Grid::make(4)->schema([ GeoSelect::make('geo_id') ->required(), ProvinceSelect::make('province_id') ->geoField('geo_id') ->required(), DistrictSelect::make('district_id') ->provinceField('province_id') ->required(), SubdistrictSelect::make('subdistrict_id') ->districtField('district_id') ->zipField('zip_code') // เติมรหัสไปรษณีย์อัตโนมัติเมื่อเลือก, ไม่ใส่ก็ได้ถ้าไม่ต้องการ ->required(), ]),
3. แสดงในตาราง (Table Column)
ThailandLocationColumn อ่านค่าจาก relationship ที่ชี้ไปยัง Subdistrict แล้วไล่ขึ้นไปแสดงตำบล, อำเภอ, จังหวัด, ภาค รวมกันเป็นข้อความเดียว โดย default จะเดา relationship name จากชื่อคอลัมน์ (ตัดท้าย _id ออก) หรือระบุเองก็ได้:
use Baleethai\ThailandPlugin\Tables\Columns\ThailandLocationColumn; ThailandLocationColumn::make('subdistrict_id') ->label('ที่อยู่') ->subdistrictRelationship('subdistrict'), // optional ถ้าชื่อ relationship ไม่ตรงกับที่เดาไว้
4. ภาษา (Locale)
Locale เริ่มต้นมาจาก config('thailand-plugin.locale') (ค่า default คือ th) แต่ override ได้ทั้งใน ThailandLocation, select แต่ละตัว หรือ ThailandLocationColumn:
GeoSelect::make('geo_id')->locale('en'); ThailandLocation::make()->locale('en'); ThailandLocationColumn::make('subdistrict_id')->locale('en');
Locale ข้างบนนี้ควบคุมว่าจะดึงชื่อจากคอลัมน์ name_th หรือ name_en (ข้อมูลในฐานข้อมูล) — คนละส่วนกับภาษาที่ label ของฟิลด์ (เช่น "Region", "Province") แสดงผล ซึ่งมาจาก app locale (App::getLocale()) ของโปรเจกต์ตามปกติ แพ็กเกจนี้มีคำแปลให้ทั้ง en และ th ในตัว ถ้าต้องการแก้ไขคำแปลเอง ให้ publish ไฟล์ translation ออกมา:
php artisan vendor:publish --tag="thailand-plugin-translations"
เปิด/ปิดฟิลด์ ภาค (Region)
ปิดใช้งานฟิลด์ ภาค ทั้งโปรเจกต์ได้ผ่าน config, หรือ override เป็นรายฟิลด์ด้วย ->geoEnabled(false) (ดูตัวอย่างในหัวข้อก่อนหน้า) เมื่อปิดใช้งาน ProvinceSelect จะแสดงทุกจังหวัดโดยไม่กรองตามภาค
Configuration
// config/thailand-plugin.php return [ 'tables' => [ 'geos' => 'geos', 'provinces' => 'provinces', 'districts' => 'districts', 'subdistricts' => 'subdistricts', ], 'searchable' => true, // 'th' | 'en' 'locale' => 'th', // Show/hide the Region (Geo) select in the ThailandLocation component. 'enable_geo' => true, ];
Data Structure
| Table | Columns | Rows after seeding |
|---|---|---|
geos |
id, name_th, name_en |
6 |
provinces |
id, geo_id, name_th, name_en |
77 |
districts |
id, province_id, name_th, name_en |
930 |
subdistricts |
id, district_id, name_th, name_en, zip_code |
7,452 |
ชื่อตารางแก้ได้ผ่าน config('thailand-plugin.tables') — โมเดลทุกตัว (Geo, Province, District, Subdistrict) จะ resolve ชื่อตารางจาก config นี้เสมอ
Development
cd packages/baleethai/filament-thailand-location-picker
composer install
vendor/bin/pest
License
MIT License.