Project

General

Profile

Actions

Task #48

open
MF

Start developing a mu plugin

Task #48: Start developing a mu plugin

Added by Maurizio Folini about 1 month ago. Updated about 1 month ago.

Status:
New
Priority:
Normal
Assignee:
-
Start date:
05/07/2026
Due date:
% Done:

0%

Estimated time:

Description

Better approach: develop it directly as one MU plugin, but build and test it one feature at a time.

Do not build many separate WPCode snippets and merge them later, except for very small experiments.

  1. Best workflow

Create one MU plugin like:

```text
wp-content/mu-plugins/
ydb-fluentsupport-tools.php
ydb-fluentsupport-tools/
concurrency.php
ticket-ui.php
logs.php
helpers.php
```

The main file only loads the modules:

```php
/** * Plugin Name: YDB FluentSupport Tools * Description: Custom FluentSupport extensions for ticket handling.
*/

if (!defined('ABSPATH')) {
exit;
}

require_once DIR . '/ydb-fluentsupport-tools/helpers.php';
require_once DIR . '/ydb-fluentsupport-tools/concurrency.php';
require_once DIR . '/ydb-fluentsupport-tools/ticket-ui.php';
require_once DIR . '/ydb-fluentsupport-tools/logs.php';
```

Then we develop things one by one:

1. Concurrency / ticket lock
2. Show who is viewing or replying
3. Assign ticket to current agent
4. Ticket history/audit log
5. Better frontend/agent page, if needed
6. Search/filter helpers

  1. Why this is better than snippets

Snippets are useful for testing simple things, but this project will probably need:

  • database tables or options
  • AJAX or REST endpoints
  • JavaScript loaded only on FluentSupport pages
  • user/ticket state tracking
  • cleanup logic
  • reusable helper functions
  • debugging and logging

That becomes messy very quickly with many snippets.

  1. When to use snippets

Use snippets only to answer questions like:

```text
Does this FluentSupport hook fire?
Can I detect the ticket ID here?
Can I get the current agent ID?
Can I add something to this admin screen?
```

Once confirmed, move the code immediately into the MU plugin.

  1. My recommendation

Start directly with the MU plugin.

For each feature, we make one module file and keep it disabled/enabled with a simple constant if needed:

```php
define('YDB_FS_ENABLE_CONCURRENCY', true);
define('YDB_FS_ENABLE_LOGS', false);
```

For your case, because ticket concurrency is serious, I would not build it as scattered snippets. It should be treated as a proper small plugin from the start.

MF Updated by Maurizio Folini about 1 month ago Actions #1

Yes. We start with Step 1 only: create a safe MU plugin skeleton.

The purpose of Step 1 is not yet concurrency. It is to create a stable place where all future code will live, confirm WordPress loads it, and avoid breaking FluentSupport while we are still experimenting.

WordPress MU plugins are automatically enabled from `wp-content/mu-plugins`, cannot be disabled from the normal plugin screen, and WordPress only auto-loads PHP files directly inside that folder, not files hidden inside subfolders. So we use one root loader file, then load our organized module files from a subfolder. ([WordPress Developer Resources]1)

FluentSupport also officially exposes action hooks, filter hooks, helper classes, utility functions, and REST/API-related extension points, so this is the correct direction for extending it without editing the plugin itself. ([Fluent Support Developers]2)


  1. Step 1 — Create the MU plugin skeleton
  1. 1. Create this folder structure

Inside your WordPress site:

```text
wp-content/
mu-plugins/
ydb-fluentsupport-tools.php
ydb-fluentsupport-tools/
includes/
admin-page.php
helpers.php
config.php
```

Important: the file directly inside `mu-plugins` is:

```text
ydb-fluentsupport-tools.php
```

That is the file WordPress will auto-load.


  1. 2. Create the main MU plugin loader

Create this file:

```text
wp-content/mu-plugins/ydb-fluentsupport-tools.php
```

Put this inside:

```php
/** * Plugin Name: YDB FluentSupport Tools * Description: Custom site-specific tools for FluentSupport, including ticket concurrency handling. * Author: YDB * Version: 0.1.0 * * This is a Must-Use plugin. * * Important MU plugin notes: * - It is loaded automatically by WordPress. * - It cannot be activated/deactivated from the normal Plugins screen. * - WordPress only auto-loads PHP files directly inside wp-content/mu-plugins. * - For that reason, this file acts as a loader for the real files inside the folder.
*/

if (!defined('ABSPATH')) {
exit;
}

/** * Main plugin constants. * * We use constants so every module can safely refer to the same paths.
*/
define('YDB_FS_TOOLS_VERSION', '0.1.0');
define('YDB_FS_TOOLS_FILE', FILE);
define('YDB_FS_TOOLS_DIR', DIR . '/ydb-fluentsupport-tools');
define('YDB_FS_TOOLS_URL', content_url('mu-plugins/ydb-fluentsupport-tools'));

/** * Safety check. * * If the plugin folder is missing, we stop quietly. * This prevents fatal errors if files are uploaded in the wrong order.
*/
if (!is_dir(YDB_FS_TOOLS_DIR)) {
return;
}

/** * Load configuration first. * * Feature flags will live here. * This lets us enable/disable modules without deleting code.
*/
require_once YDB_FS_TOOLS_DIR . '/includes/config.php';

/** * Load helper functions. * * Helpers should contain small reusable functions only. * No heavy logic here.
*/
require_once YDB_FS_TOOLS_DIR . '/includes/helpers.php';

/** * Load admin diagnostic page. * * This gives us a visible confirmation that the MU plugin is working.
*/
require_once YDB_FS_TOOLS_DIR . '/includes/admin-page.php';
```


  1. 3. Create the config file

Create this file:

```text
wp-content/mu-plugins/ydb-fluentsupport-tools/includes/config.php
```

Put this inside:

```php
/** * YDB FluentSupport Tools - Configuration * * This file contains feature flags. * We keep them here so we can safely turn features on/off during development.
*/

if (!defined('ABSPATH')) {
exit;
}

/** * Enable admin diagnostic page. * * Keep this true while developing. * Later we can disable it if you do not want this page visible.
*/
define('YDB_FS_TOOLS_ENABLE_ADMIN_PAGE', true);

/** * Enable ticket concurrency module. * * Not used yet. * We will enable this only after the skeleton is confirmed working.
*/
define('YDB_FS_TOOLS_ENABLE_CONCURRENCY', false);

/** * Enable debug logging. * * When true, our plugin can write messages to the WordPress debug log. * Only useful if WP_DEBUG_LOG is enabled in wp-config.php.
*/
define('YDB_FS_TOOLS_ENABLE_DEBUG_LOG', true);
```


  1. 4. Create the helpers file

Create this file:

```text
wp-content/mu-plugins/ydb-fluentsupport-tools/includes/helpers.php
```

Put this inside:

```php
/** * YDB FluentSupport Tools - Helpers * * This file contains small reusable helper functions. * No feature-specific logic should live here.
*/

if (!defined('ABSPATH')) {
exit;
}

/** * Write a debug message to the WordPress debug log. * * This only writes if: * - our debug flag is enabled * - WP_DEBUG is enabled * * Usage: * ydb_fs_tools_log('Something happened');
*/
function ydb_fs_tools_log($message, array $context = array()) {
if (!defined('YDB_FS_TOOLS_ENABLE_DEBUG_LOG') || !YDB_FS_TOOLS_ENABLE_DEBUG_LOG) {
return;
}

if (!defined('WP_DEBUG') || !WP_DEBUG) {
return;
}
if (!empty($context)) {
$message .= ' | Context: ' . wp_json_encode($context);
}
error_log('[YDB FluentSupport Tools] ' . $message);
}

/** * Check whether FluentSupport appears to be active. * * We keep this deliberately simple for now. * Later, if needed, we can replace this with a deeper FluentSupport-specific check.
*/
function ydb_fs_tools_is_fluentsupport_active() {
if (!function_exists('is_plugin_active')) {
require_once ABSPATH . 'wp-admin/includes/plugin.php';
}

return is_plugin_active('fluent-support/fluent-support.php');
}

/** * Get a readable yes/no value for admin display.
*/
function ydb_fs_tools_yes_no($value) {
return $value ? 'Yes' : 'No';
}
```


  1. 5. Create the admin diagnostic page

Create this file:

```text
wp-content/mu-plugins/ydb-fluentsupport-tools/includes/admin-page.php
```

Put this inside:

```php
/** * YDB FluentSupport Tools - Admin Diagnostic Page * * This page confirms that: * - the MU plugin is loaded * - our helper files are loaded * - FluentSupport appears active * - debug constants are visible
*/

if (!defined('ABSPATH')) {
exit;
}

if (!defined('YDB_FS_TOOLS_ENABLE_ADMIN_PAGE') || !YDB_FS_TOOLS_ENABLE_ADMIN_PAGE) {
return;
}

/** * Add a simple admin page under Tools. * * We use manage_options so only administrators can see it.
*/
add_action('admin_menu', function () {
add_management_page(
'YDB FluentSupport Tools',
'YDB FluentSupport Tools',
'manage_options',
'ydb-fluentsupport-tools',
'ydb_fs_tools_render_admin_page'
);
});

/** * Render the admin diagnostic page.
*/
function ydb_fs_tools_render_admin_page() {
if (!current_user_can('manage_options')) {
wp_die('You do not have permission to access this page.');
}

$fluent_active = ydb_fs_tools_is_fluentsupport_active();
?>
<div class="wrap">
<h1>YDB FluentSupport Tools</h1>
<p>
This page confirms that the custom MU plugin is loaded correctly.
</p>
<table class="widefat striped" style="max-width: 900px;">
<tbody>
<tr>
<th scope="row">Plugin version</th>
&lt;td&gt;<?php echo esc_html(YDB_FS_TOOLS_VERSION); ?>&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th scope=&quot;row&quot;&gt;Plugin directory&lt;/th&gt;
&lt;td&gt;<?php echo esc_html(YDB_FS_TOOLS_DIR); ?>&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th scope=&quot;row&quot;&gt;FluentSupport active&lt;/th&gt;
&lt;td&gt;
<?php echo esc_html(ydb_fs_tools_yes_no($fluent_active)); ?>
<?php if (!$fluent_active): ?>
&lt;p style=&quot;color:#b32d2e;&quot;&gt;
FluentSupport does not appear active using the standard plugin path check.
If FluentSupport is active but this says No, we will adjust the detection method later.
&lt;/p&gt;
<?php endif; ?>
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th scope=&quot;row&quot;&gt;Concurrency module enabled&lt;/th&gt;
&lt;td&gt;<?php echo esc_html(ydb_fs_tools_yes_no(YDB_FS_TOOLS_ENABLE_CONCURRENCY)); ?>&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th scope=&quot;row&quot;&gt;Debug logging enabled in our plugin&lt;/th&gt;
&lt;td&gt;<?php echo esc_html(ydb_fs_tools_yes_no(YDB_FS_TOOLS_ENABLE_DEBUG_LOG)); ?>&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th scope=&quot;row&quot;&gt;WP_DEBUG&lt;/th&gt;
&lt;td&gt;<?php echo esc_html(ydb_fs_tools_yes_no(defined('WP_DEBUG') && WP_DEBUG)); ?>&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th scope=&quot;row&quot;&gt;WP_DEBUG_LOG&lt;/th&gt;
&lt;td&gt;<?php echo esc_html(ydb_fs_tools_yes_no(defined('WP_DEBUG_LOG') && WP_DEBUG_LOG)); ?>&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2&gt;Next planned modules&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Ticket view heartbeat: detect which agent is viewing a ticket.&lt;/li&gt;
&lt;li&gt;Ticket reply lock: warn if another agent is already replying.&lt;/li&gt;
&lt;li&gt;Optional assignment helper: assign ticket to current agent from the ticket screen.&lt;/li&gt;
&lt;li&gt;Audit log: record who opened, replied, assigned, or changed a ticket.&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
<?php
}
```

  1. 6. Check that it loaded

Go to:

```text
WordPress Admin → Tools → YDB FluentSupport Tools
```

You should see a diagnostic table.

Also check:

```text
WordPress Admin → Plugins → Must-Use
```

You should see:

```text
YDB FluentSupport Tools
```


  1. 7. What this step gives us

At this point we have:

```text
A safe MU plugin
A clean file structure
Feature flags
A debug helper
A diagnostic admin page
A place to add concurrency code next
```

We have not touched FluentSupport behavior yet.

That is intentional.

For ticket concurrency, the next step will be to add a module like:

```text
wp-content/mu-plugins/ydb-fluentsupport-tools/includes/concurrency.php
```

But first confirm that the diagnostic page appears correctly.

[1]: https://developer.wordpress.org/advanced-administration/plugins/mu-plugins/ "Must Use Plugins – Advanced Administration Handbook | Developer.WordPress.org"
[2]: https://developers.fluentsupport.com/ "Fluent Support Developers"

Actions

Also available in: PDF Atom