With the solution below I'm assuming that you're wanting to use your custom filesystem plugin just for the custom media field alone, So that if you select an image in the Article Images and Links tab instead then for that you want to use the default joomla filesystem plugin.
Solution Background
Within the admin Article edit form, in the Images and Links tab, when you click on the Select button it generates an HTTP GET to the server with query parameters something like
option=com_media&view=media&tmpl=component&mediatypes=0&asset=91&author=604
&fieldid={field-media-id}&path=local-images:/sampledata/cassiopeia
The response enables the javascript code in media-manager.js to create the modal window for displaying the images which the user can select. On the left hand side are shown the folders, which are generated by the filesystem plugins (known as providers), and the information for displaying these is returned in the response to the above HTTP GET.
The Joomla field type within the edit Article Images and Links tab is a media
field. So if you define a custom field as a 'media' type field, you're going to get the same media
field underneath, and you'll get the same providers back.
So the solution proposed is the following:
- Create a new custom field type – I've called my 'mymedia', based on a new field type which I've called
restrictedmedia
.
- Define the
restrictedmedia
field type (piggy-backing on the Joomla media
field type) and get it to send a different HTTP request to the server – so that the server can determine whether the request is from an ordinary media
field, or from the restrictedmedia
field. To do this I've injected an extra query parameter "restrictedmedia=1" in the URL when it's the restrictedmedia
field type.
- Change code on the server to recognise the extra URL query parameter and adjust what providers get returned to the client js code.
Create a mymedia custom field type
This involves writing a plugin which creates a subfolder mymedia under plugins/fields. In a folder plg_mymedia, I have got mymedia.xml which has:
<?xml version="1.0" encoding="UTF-8"?>
<extension type="plugin" group="fields" method="upgrade">
<name>plg_fields_mymedia</name>
<author>Robbie</author>
<description>My media plugin</description>
<namespace path="src">Robbie\Plugin\Fields\Mymedia</namespace>
<files>
<folder plugin="mymedia">services</folder>
<folder>src</folder>
</files>
</extension>
And in plg_mymedia/services/provider.php – almost identical to plugins/fields/media/services/provider.php:
use Joomla\CMS\Extension\PluginInterface;
use Joomla\CMS\Factory;
use Joomla\CMS\Plugin\PluginHelper;
use Joomla\DI\Container;
use Joomla\DI\ServiceProviderInterface;
use Joomla\Event\DispatcherInterface;
use Robbie\Plugin\Fields\Mymedia\Extension\Mymedia;
return new class () implements ServiceProviderInterface {
public function register(Container $container)
{
$container->set(
PluginInterface::class,
function (Container $container) {
$dispatcher = $container->get(DispatcherInterface::class);
$plugin = new Mymedia(
$dispatcher,
(array) PluginHelper::getPlugin('fields', 'mymedia')
);
$plugin->setApplication(Factory::getApplication());
return $plugin;
}
);
}
};
The main plugin code is in plg_mymedia/src/Extension/Mymedia.php. This is basically the same as in plugins/fields/media/src/Extension/Media.php, except make the following changes.
At the top add your namespace and the fully qualified classname of FormHelper:
namespace Robbie\Plugin\Fields\Mymedia\Extension;
use Joomla\CMS\Form\FormHelper;
and in the function onCustomFieldsPrepareDom replace
$fieldNode->setAttribute('type', 'media');
with
$fieldNode->setAttribute('type', 'restrictedmedia');
FormHelper::addFieldPrefix('Robbie\Plugin\Fields\Mymedia\Field');
This means that we're basing the mymedia custom field type upon a custom field type of 'restrictedmedia'. (Yes, it's unfortunate that 'custom field type' is used to mean different things in Joomla).
We also need to tell the Joomla Form where to find the definition of the restrictedmedia
field type, via the addFieldPrefix call. From the manifest file line
<namespace path="src">Robbie\Plugin\Fields\Mymedia</namespace>
'Robbie\Plugin\Fields\Mymedia' will map to plugins/fields/mymedia/src. So Joomla will expect to find the class Robbie\Plugin\Fields\Mymedia\Field\RestrictedmediaField in the file plugins/fields/mymedia/src/Field/RestrictedmediaField.php.
Define the RestrictedmediaField type
The definition of the 'restrictedmedia' field type is in plg_mymedia/src/Field/RestrictedmediaField.php. It's defined to be the same as the MediaField class in libraries/src/Form/Field/MediaField.php except that we inject an extra item into the $data.
namespace Robbie\Plugin\Fields\Mymedia\Field;
use Joomla\CMS\Form\Field\MediaField;
class RestrictedmediaField extends MediaField
{
protected $type = 'Restrictedmedia';
public function getLayoutData()
{
$data = parent::getLayoutData();
$data['restrictedmedia'] = true;
return $data;
}
}
The media
field type (and our restrictedmedia
field type) is rendered in layouts/joomla/form/field/media.php, so we just need to change this so that the URL sent has the extra parameter if it's our restrictedmedia
field type. With the admin System / Templates / Atum Details and File create an override for that layout, and change the code as follows.
Below the lines
// The url for the modal
$url = ($readonly ? ''
: ($link ?: 'index.php?option=com_media&view=media&tmpl=component&mediatypes=' . $mediaTypes
. '&asset=' . $asset . '&author=' . $authorId)
. '&fieldid={field-media-id}&path=' . $folder);
add the lines:
if (isset($restrictedmedia)) {
$url .= '&restrictedmedia=1';
}
When the user clicks on the Select button then this is the URL which is sent to the server to get the data to build the modal window.
Adjust the providers sent in the response
The response to the HTTP GET is in administrator/components/com_media/tmpl/media/default.php. The data includes the filesystem providers, which are sent down to the javascript code in a $config
array using addScriptOptions.
So you need to create another override for that file. Above the line populating the media $config
, add the lines:
if ($input->getCmd('restrictedmedia')) {
foreach ((array)$this->providers as $key => $provider) {
if ($provider->name === "local") {
unset ($this->providers[$key]);
}
}
}
So if it's the case that the URL has "restrictedmedia=1" then these lines will remove the default local filesystem provider.
Inside your custom filesystem plugin, within onSetupProviders you could also examine the URL and determine whether you wanted to register your filesystem provider.
By the way, testing this code I found at one point an error reported in the modal window "Account not found". If this occurs, then clear your session cookies via your browser devtools. There was a Joomla bug which caused this message, and it's maybe not totally sorted.