| Server IP : 52.25.153.185 / Your IP : 216.73.217.131 Web Server : Apache System : Linux ip-172-26-6-158 5.10.0-35-cloud-amd64 #1 SMP Debian 5.10.237-1 (2025-05-19) x86_64 User : daemon ( 1) PHP Version : 8.1.10 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : OFF | Sudo : ON | Pkexec : OFF Directory : /bitnami/wordpress/wp-content/plugins/fluent-crm/app/Http/Controllers/ |
Upload File : |
<?php
namespace FluentCrm\App\Http\Controllers;
use FluentCrm\App\Models\Meta;
use FluentCrm\Framework\Support\Arr;
use FluentCrm\Framework\Http\Request\Request;
class EmailPatternController extends Controller
{
private $objectType = 'email_pattern';
private $categoryObjectType = 'email_pattern_category';
public function index(Request $request)
{
$query = Meta::where('object_type', $this->objectType)
->orderBy('id', 'desc');
if ($search = $request->getSafe('search', 'sanitize_text_field')) {
$query->where('value', 'LIKE', '%' . $search . '%');
}
$patterns = $query->paginate();
$formattedPatterns = [];
foreach ($patterns as $pattern) {
$formattedPatterns[] = $this->formatPattern($pattern);
}
return $this->sendSuccess([
'patterns' => [
'data' => $formattedPatterns,
'total' => $patterns->total()
]
]);
}
public function show(Request $request, $id)
{
$pattern = Meta::where('object_type', $this->objectType)
->where('id', $id)
->firstOrFail();
return $this->sendSuccess([
'pattern' => $this->formatPattern($pattern)
]);
}
/**
* Return patterns in wp_block REST format for the editor middleware.
*/
public function indexWpFormat(Request $request)
{
$patterns = Meta::where('object_type', $this->objectType)
->orderBy('id', 'desc')
->get();
$categoryMap = $this->getCategoryMap();
$formatted = [];
foreach ($patterns as $pattern) {
$formatted[] = $this->formatAsWpBlock($pattern, $categoryMap);
}
return $formatted;
}
public function store(Request $request)
{
$this->validate($request->all(), [
'title' => 'required|string',
'content' => 'required|string',
]);
$title = sanitize_text_field($request->get('title'));
$content = wp_kses_post($request->get('content'));
$category = sanitize_text_field($request->get('category', ''));
$description = sanitize_text_field($request->get('description', ''));
$syncStatus = sanitize_text_field($request->get('sync_status', 'unsynced'));
$slug = 'fluentcrm/' . sanitize_title($title . '-' . uniqid());
$pattern = Meta::create([
'object_type' => $this->objectType,
'object_id' => get_current_user_id(),
'key' => $slug,
'value' => [
'title' => $title,
'content' => $content,
'category' => $category,
'description' => $description,
'sync_status' => $syncStatus,
],
]);
return $this->sendSuccess([
'message' => __('Pattern saved successfully', 'fluent-crm'),
'pattern' => $this->formatPattern($pattern),
]);
}
/**
* Store a pattern from wp_block format (called by editor middleware).
*/
public function storeWpFormat(Request $request)
{
$title = $request->get('title', '');
if (is_array($title)) {
$title = Arr::get($title, 'raw', '');
}
$title = sanitize_text_field($title);
$content = $request->get('content', '');
if (is_array($content)) {
$content = Arr::get($content, 'raw', '');
}
$content = wp_kses_post($content);
if (!$title && !$content) {
return $this->sendError([
'message' => __('Title or content is required', 'fluent-crm')
]);
}
if (!$title) {
$title = __('Untitled Pattern', 'fluent-crm');
}
$meta = $request->get('meta', []);
$syncStatus = Arr::get($meta, 'wp_pattern_sync_status', '');
$syncStatus = sanitize_text_field($syncStatus);
$categoryIds = (array) $request->get('wp_pattern_category', []);
$categoryName = $this->resolveCategoryName($categoryIds);
$slug = 'fluentcrm/' . sanitize_title($title . '-' . uniqid());
$pattern = Meta::create([
'object_type' => $this->objectType,
'object_id' => get_current_user_id(),
'key' => $slug,
'value' => [
'title' => $title,
'content' => $content,
'category' => $categoryName,
'description' => '',
'sync_status' => $syncStatus,
],
]);
$categoryMap = $this->getCategoryMap();
return $this->formatAsWpBlock($pattern, $categoryMap);
}
public function update(Request $request, $id)
{
$pattern = Meta::where('object_type', $this->objectType)
->where('id', $id)
->firstOrFail();
$value = $pattern->value;
if ($title = $request->get('title')) {
if (is_array($title)) {
$title = Arr::get($title, 'raw', '');
}
$value['title'] = sanitize_text_field($title);
}
if ($request->has('content')) {
$content = $request->get('content');
if (is_array($content)) {
$content = Arr::get($content, 'raw', '');
}
$value['content'] = wp_kses_post($content);
}
$value['category'] = sanitize_text_field($request->get('category', ''));
if ($request->has('wp_pattern_category')) {
$categoryIds = (array) $request->get('wp_pattern_category', []);
$value['category'] = $this->resolveCategoryName($categoryIds);
}
if ($request->has('description')) {
$value['description'] = sanitize_text_field($request->get('description'));
}
if ($request->exists('sync_status')) {
$value['sync_status'] = sanitize_text_field($request->get('sync_status'));
}
$meta = $request->get('meta', []);
if (is_array($meta) && isset($meta['wp_pattern_sync_status'])) {
$value['sync_status'] = sanitize_text_field($meta['wp_pattern_sync_status']);
}
if ($title = $request->get('title')) {
if (is_array($title)) {
$title = Arr::get($title, 'raw', '');
}
if ($title) {
$pattern->key = 'fluentcrm/' . sanitize_title($title . '-' . $pattern->id);
}
}
$pattern->value = $value;
$pattern->save();
return $this->sendSuccess([
'message' => __('Pattern updated successfully', 'fluent-crm'),
'pattern' => $this->formatPattern($pattern),
]);
}
public function delete(Request $request, $id)
{
Meta::where('object_type', $this->objectType)
->where('id', $id)
->firstOrFail()
->delete();
return $this->sendSuccess([
'message' => __('Pattern deleted successfully', 'fluent-crm'),
]);
}
public function handleBulkAction(Request $request)
{
$actionName = sanitize_text_field($request->get('action_name'));
if ($actionName !== 'delete_patterns') {
return $this->sendError([
'message' => __('Invalid action', 'fluent-crm')
]);
}
$query = Meta::where('object_type', $this->objectType);
if (filter_var($request->get('select_all'), FILTER_VALIDATE_BOOLEAN)) {
$search = $request->getSafe('search', 'sanitize_text_field', '');
if ($search !== '') {
$query->where('value', 'LIKE', '%' . $search . '%');
}
} else {
$patternIds = array_map('intval', (array) $request->get('pattern_ids', []));
if (empty($patternIds)) {
return $this->sendError([
'message' => __('No patterns selected', 'fluent-crm')
]);
}
$query->whereIn('id', $patternIds);
}
$count = $query->delete();
return $this->sendSuccess([
'message' => sprintf(__('%d pattern(s) deleted successfully', 'fluent-crm'), $count)
]);
}
/**
* CRUD for pattern categories (stored as fc_meta with separate object_type).
*/
public function getCategories()
{
// Collect unique category names from all patterns
$patterns = Meta::where('object_type', $this->objectType)->get();
$categories = [];
foreach ($patterns as $pattern) {
$cat = Arr::get($pattern->value, 'category', '');
if ($cat && !in_array($cat, $categories)) {
$categories[] = $cat;
}
}
sort($categories);
return $this->sendSuccess([
'categories' => $categories
]);
}
public function storeCategory(Request $request)
{
$name = sanitize_text_field($request->get('name', ''));
if (!$name) {
return $this->sendError(['message' => __('Category name is required', 'fluent-crm')]);
}
$slug = sanitize_title($name);
// Check for existing
$existing = Meta::where('object_type', $this->categoryObjectType)
->where('key', $slug)
->first();
if ($existing) {
return $this->formatCategoryAsWpTerm($existing);
}
$category = Meta::create([
'object_type' => $this->categoryObjectType,
'object_id' => 0,
'key' => $slug,
'value' => ['name' => $name],
]);
return $this->formatCategoryAsWpTerm($category);
}
public function deleteCategory(Request $request, $id)
{
Meta::where('object_type', $this->categoryObjectType)
->where('id', $id)
->firstOrFail()
->delete();
return $this->sendSuccess([
'message' => __('Category deleted successfully', 'fluent-crm'),
]);
}
/**
* Format a pattern Meta record as a wp_block REST response.
*/
private function formatAsWpBlock($meta, $categoryMap = [])
{
$value = $meta->value;
$title = Arr::get($value, 'title', '');
$content = Arr::get($value, 'content', '');
$syncStatus = Arr::get($value, 'sync_status', 'unsynced');
$category = Arr::get($value, 'category', '');
$categoryIds = [];
if ($category) {
$catSlug = sanitize_title($category);
if (isset($categoryMap[$catSlug])) {
$categoryIds[] = (int) $categoryMap[$catSlug];
}
}
return [
'id' => (int) $meta->id,
'date' => $meta->created_at ? $meta->created_at : gmdate('Y-m-d\TH:i:s'),
'date_gmt' => $meta->created_at ? $meta->created_at : gmdate('Y-m-d\TH:i:s'),
'modified' => $meta->updated_at ? $meta->updated_at : gmdate('Y-m-d\TH:i:s'),
'modified_gmt' => $meta->updated_at ? $meta->updated_at : gmdate('Y-m-d\TH:i:s'),
'slug' => $meta->key,
'status' => 'publish',
'type' => 'wp_block',
'link' => '',
'title' => ['raw' => $title],
'content' => ['raw' => $content, 'protected' => false],
'meta' => new \stdClass(),
'wp_pattern_sync_status' => $syncStatus ?: '',
'wp_pattern_category' => $categoryIds,
];
}
private function formatCategoryAsWpTerm($meta)
{
$value = $meta->value;
return [
'id' => (int) $meta->id,
'count' => 0,
'name' => Arr::get($value, 'name', $meta->key),
'slug' => $meta->key,
'parent' => 0,
];
}
private function formatPattern($meta)
{
$value = $meta->value;
return [
'id' => (int) $meta->id,
'slug' => $meta->key,
'title' => Arr::get($value, 'title', ''),
'content' => Arr::get($value, 'content', ''),
'category' => Arr::get($value, 'category', ''),
'description' => Arr::get($value, 'description', ''),
'sync_status' => Arr::get($value, 'sync_status', 'unsynced'),
'created_at' => $meta->created_at ? (string) $meta->created_at : '',
'updated_at' => $meta->updated_at ? (string) $meta->updated_at : '',
];
}
/**
* Build slug → id map for all pattern categories.
*/
private function getCategoryMap()
{
$categories = Meta::where('object_type', $this->categoryObjectType)->get();
$map = [];
foreach ($categories as $cat) {
$map[$cat->key] = $cat->id;
}
return $map;
}
/**
* Resolve category IDs back to a single category name.
*/
private function resolveCategoryName($categoryIds)
{
if (empty($categoryIds)) {
return '';
}
$categoryIds = array_map('intval', $categoryIds);
$category = Meta::where('object_type', $this->categoryObjectType)
->whereIn('id', $categoryIds)
->first();
if ($category) {
return Arr::get($category->value, 'name', $category->key);
}
return '';
}
/**
* Get patterns formatted for the block editor boot data.
*/
public static function getEditorPatterns()
{
$patterns = Meta::where('object_type', 'email_pattern')
->orderBy('id', 'desc')
->get();
$editorPatterns = [];
$categories = [];
$seenCategories = [];
foreach ($patterns as $pattern) {
$value = $pattern->value;
$title = Arr::get($value, 'title', '');
$content = Arr::get($value, 'content', '');
$category = Arr::get($value, 'category', '');
$description = Arr::get($value, 'description', '');
if (!$content) {
continue;
}
$patternCategories = [];
if ($category) {
$catSlug = sanitize_title($category);
$patternCategories[] = $catSlug;
if (!isset($seenCategories[$catSlug])) {
$seenCategories[$catSlug] = true;
$categories[] = [
'name' => $catSlug,
'label' => $category,
];
}
}
// Always include in the general fluentcrm-patterns category
$patternCategories[] = 'fluentcrm-patterns';
$editorPatterns[] = [
'name' => $pattern->key,
'title' => $title,
'content' => $content,
'description' => $description,
'categories' => $patternCategories,
'keywords' => ['fluentcrm', 'email'],
];
}
// Always add the root category
array_unshift($categories, [
'name' => 'fluentcrm-patterns',
'label' => __('My Patterns', 'fluent-crm'),
]);
return [
'patterns' => $editorPatterns,
'categories' => $categories,
];
}
}