(un)dynamic Media Sources!

Hello everybody!

The media browser makes out of a dynamic scource a fixed path and I would like to know, if there is any workaround for this.

The story:
In several posts here and else are discussions about dynamic Media Sources. The easiest way to do this should be the usage of “MIGx” - so they say. Especially the Snippet “migxResourceMediaPath” is the friend and should be placed in the URL fields of media sources like this (as an example):
[[migxResourceMediaPath? &pathTpl=assets/images/{id}/]]

Result (so they say): The Snippet should dynamically insert individual source paths depending on the current resource-ID. By switching between different resources, the media browser should then automatically point to the reffering/different image folder.

How it works:
What MIGx does is not a miracle: it just returns a path - that’s all! This could also be realized with other techniques like Chunks, TV’s or own, crazy snippets - why not.

Why I say “should”:
The above described functionality works only so fare, as you don’t save any files into such “dynamic” Folder. Since you did that, the mediabrowser converts the placeholder within the URL into a
fixed path - good bye dynamics!

The (!)-Command hase no effect and it dosn’t matter if you use MIGx, Chunks, TVs, Snippets or what ever - they all will become fixed path after a while!

Is there a trick, to prevent this behavior of the media browser??

Thanks in advance for your replay (and please excuse my uggly english).

Have a nice day - and greetings from Dresden (Saxonia, Germany):

I don’t understand what you’re trying to do. I’m also not familiar with the migxResourceMediaPath snippet. Are you needing the path to include the ID of the current resource? If so I don’t think you need any snippets or chunks. It’s been a while since I worked with dynamic media source paths but IIRC you can just enter assets/images/[[*id]]/ as the field value. I’m not certain that syntax is correct–it may use fenom instead–but it’s something along those lines if it’s not. If you’re trying to do more than that I’ll need some further explanation to understand.

Thank you for your quick reply. I try again to explain (I know: my english :nauseated_face: !!)
Let’s take your example, just entering assets/images/[[*id]]: This dynamic path will be converted by the mediabrowser into a fixed path like "assets/images/69" (assuming the current ID was “69”) just in the moment, you do something within this path (renaming files, uploading files, whatever) - the dynamic part is gone forever!
Whats all about - the circumstances:
I’m relative new to MODX but right from the start i was excited, that MODX can administer several contexts (which are “projects” for me). I work with my “developer server” in the moment simultaneous with 9 different projects spread over several MODX context’s (and there will be a lot more in future). When I finished with a project I went to the “public server”, install a new MODX for my customer and just copy the finished developer files into the public installation. Until then - during developing - I login into MODX on my “developer server” via different virtual hosts using the same MODX machine/database. This works with the simple plugin “ContextRouter”: it switches between the different contexts regarding on the current host - thrilling! Then I created different user accounts with restrictions on other contexts of the one part - but administrator rights of the other part. Now I work with this self-limitting user accounts on my “developing server” during the creation and designing phase of new or raw contexts. When I’m finished I copy them to the public and start with my next project - and so on. This trick works fine for me (so far).

The purpose:
I use my special file organization system on the server to keep the overview of all the lots of documents, photos, etc. belonging to each project. Therefore I have different main folders for each project (= context). Those folders (= media sources) are target of the media browser for each project. As you can guess: this accumulates after a while! So I’m wondering, making just one single shared media source with a “dynamic” path. This means: The path changes when logged in as another user resp. on another host. Therefore I tried to insert a placeholder in the URL fields of the media sources - but this works only for a while as I described above!
If my idea works, there is only one media source for each user and there is no need defining individual restrictions to different folders (media sources) in the media browser because all the others are just not available / not visible - thats my goal!

Please not more than necessary:
Because I’m new to MODX I don’t want to overload it with strange plugins before I deeply know what they are doing. First I want to push the limits of the origin MODX!

Yes, I know: much writings - I hope everybody understands halfway what I mean :roll_eyes:
Greatings from Dresden (Saxonia): ejomi

Hello everybody!
I would like to mark my post as “solved - programatically” - how can I do this?
My soloution: I took the “ContextRouter” from Mark Hamstra and added a few code lines into it. Now the script overwrites the URL of the media source during runtime. This works fine for me - unless someone has a better idea! Here the code I like to share (please look for the comments within the code to understand how it works). You may shorten the code by deleting all the error logs and comments - I did this only to keep control of all actions during developing.
Have fun:

 * "ContextRouterExt" by E.J.Minhorst
 * based on ContextRouter 1.2.0-pl from Mark Hamstra
 * Purpose: Provides beside the standard operation of ContextRouter
 * a new functionality for dynamic changable source paths during login.
 * (Changes/Extensions: see remarks "EJM" below!)
 * How to work with:
 * Step 1:
 *   Each context should have it's own folder for page contents of all kinds (= medias) on the file server!
 * Step 2:
 *   In MODX create a new media source (menu: media -> media sources) and name it e.g. "My Media" or decide,
 *   which of your already existing media sources should be "dynamic" for the future - and remember it's ID!
 * Step 3:
 *   Proceed to the system settings of MODX and create a new system key named "source_id_of_myimages"
 *   and apply the memorised ID of your dynamic media source (like decided in step #2).
 * Step 4 to x:
 *   Go into each MODX context setting and create there a ney key named "rel_path_of_myimages".
 *   Apply to each key the path pointing to the suitable folder created in step #1.
 *   When you (as a admin) loggin in to the MODX manager via a virtual (or real) host
 *   the target of the dynamic media source will change immediately to the reffering folder.
 *   Therefore you don't need to administrate dozens of media sources for each context:
 *   only one single source called "My Media" is your friend for the future - that's the trick! 
 * Have fun!
 * @var modX $modx
 * @var array $scriptProperties

// Declare the name of the key holding the ID of a dynamic changable media source (defined as a global system setting):
$srcid_imgs = 'source_id_of_myimages';

// Declare the name of the key holding the individual media paths (defined within each context settings):
$myimgpath = 'rel_path_of_myimages';

// Set the following switch to FALSE if you want the original functionality
// of the ContextRouter again (e.g. for debugging etc.):
$dynswitch = true;

// Set this (temporarily) TRUE to write detailed informations about all actions into the error log:
$debug = false;

// Internal flag for cache refresh during runtime (leave it FALSE):
$updatecache = false;

// --------- PROGRAM START (Original ContextRouter) --------------
$event = $modx->event->name;
switch ($event) {
    case 'OnContextSave':
    case 'OnContextRemove':
    case 'OnSiteRefresh':
        /* @var ContextRouter $contextRouter */
        $core_path = $modx->getOption('contextrouter.core_path', null,
            $modx->getOption('core_path').'components/contextrouter/') . 'model/';
        $contextRouter =& $modx->getService('contextrouter','ContextRouter',
            $core_path, $scriptProperties);
        if (!$contextRouter) {
            $modx->log(modX::LOG_LEVEL_ERROR, 'Error instantiating ContextRouter class from ' . $core_path);
    case 'OnHandleRequest':
    case 'OnMODXInit':
        // EJM - Switch back to the original "ContetxtRouter" behavior if desired by user:
        If (!$dynswitch && $modx->context->key == 'mgr') return;
        // Continue original coding:
        $routes = $modx->cacheManager->get('contextrouter', array());
        if (!is_array($routes)) {
            /* @var ContextRouter $contextRouter */
            $core_path = $modx->getOption('contextrouter.core_path', null,
                $modx->getOption('core_path').'components/contextrouter/') . 'model/';
            $contextRouter =& $modx->getService('contextrouter','ContextRouter',
                $core_path, $scriptProperties);
            if (!$contextRouter) {
                $modx->log(modX::LOG_LEVEL_ERROR, 'Error instantiating ContextRouter class from ' . $core_path);
            $routes = $contextRouter->getRoutes();
        /* Do the actual routing. */
        $host = $_SERVER['HTTP_HOST'];
        if (empty($host)) return;
        /* --------- EJM - new functionality (if not disabled): -------- */
        If ($dynswitch) {
            $ctxname = "";
            foreach ($routes as $key => $val) {
                // Get the name of the context which is responsible for the current called host address
                // (criteria is the host name defined with key "http_host" within context settings): 	
                if ($key == $host) {
                    $ctxname = $val;
            if ($ctxname == "") {
                // No context for the current host found - nothing to do.
                if ($debug) $modx->log(modX::LOG_LEVEL_ERROR, 'No suitable context for host \''. $host . '\' (maybe key "http_host" not defined?)');
            } else {
                // ------- Provide the "dynamic path functionality" only in manager mode: -------
                if ($modx->context->key == 'mgr') {
                    // Check if the expected context exists:
                    $ctxobj = $modx->getContext($ctxname);
                    // Get the individual settings of the selected context:
                    if (!$ctxobj) {
                        // Error: Context object not determinable!
                        if ($debug) $modx->log(modX::LOG_LEVEL_ERROR, 'The expected context \''. $ctxname . '\' is not determinable!');
                    } else {
                        // Check if there is a source for "My Images" declared as "dynamic" (= it's a global system setting):
                        $srcid = intval($modx->getOption($srcid_imgs));
                        if (($srcid)<2) {
                            // Prevent lookup to sorce "filesystem" (ID 1) or faulty zero ID's:
                            if ($debug) $modx->log(modX::LOG_LEVEL_ERROR, 'No dynamic source defined with \'' . $srcid_imgs . '\' (see: system settings!).');
                        } else {
                            if ($debug) $modx->log(modX::LOG_LEVEL_ERROR, 'Source ID ' . $srcid . ' defined as "dynamic" due system setting \'' . $srcid_imgs . '\'.');
                            // Get the individual path setting of the selected context:
                            $newpath = trim($ctxobj->getOption($myimgpath, null, 'default'));
                            if (!$newpath) {
                                // No path defined - nothin to do.
                                if ($debug) $modx->log(modX::LOG_LEVEL_ERROR, 'No individual path defined with key \'' . $myimgpath . '\' in context \'' .  $ctxname . '\'');
                            } else {
                                if ($debug) $modx->log(modX::LOG_LEVEL_ERROR, 'New path \'' . $newpath . '\' required');
                                // Get the media source object which has to be changed dynamically:
                                $srcobj_1 = $modx->getObject('modMediaSource', $srcid);
                                if (!$srcobj_1) {
                                    // Unknown source ID (wrong system setting)!
                                    if ($debug) $modx->log(modX::LOG_LEVEL_ERROR, 'Source ID \'' . $srcid . '\' doesn\'t exist!');
                                } else {
                                    $srcprop_1 = $srcobj_1->getProperties();
                                    $actpath = $srcprop_1['basePath']['value'];
                                    $acturl = $srcprop_1['baseUrl']['value'];
                                    if ($debug) $modx->log(modX::LOG_LEVEL_ERROR, 'Old source path \'' . $actpath . '\'');
                                    // Check if the required path is different from the current setting:
                                    if ($actpath == $newpath) {
                                        // No difference - nothing to do.
                                        if ($debug) $modx->log(modX::LOG_LEVEL_ERROR, 'Kept old path \'' . $actpath . '\' unchanged');
                                    } else {
                                        // Change the path of the dynamic declared media source:
                                        $srcprop_1['basePath']['value'] = $newpath;
                                        $srcprop_1['baseUrl']['value'] = $newpath;
                                        $updatecache = true;
                                        if ($debug) $modx->log(modX::LOG_LEVEL_ERROR, 'Changed path to \'' . $newpath . '\'');
                        // Update the system_settings cache and resource cache if required:
                        if ($updatecache) {
                            // Clear the cache (system_settings cache and resource cache) to make above settings happen:
                            $cacheRefreshOptions = ['system_settings' => [], 'resource' => []];
                } else {
                    // It's a call from the world - change only the context (= default behavior of "ContextRouter"):
            // --------- EJM - End of "New functionality"  -------- */ 				
        } else {
            // EJM - Original function of "ContextRouter":
            if (array_key_exists($host, $routes)) {