Jump to content
MarkE

Split website structure?

Recommended Posts

I'm building a holiday cottage management system and website. It's coming along very nicely. Originally the plan was for it to be fully integrated - i.e. public website in the same PW site as the booking admin app. As a temporary integration of the availability calendar from the admin site into the existing public site, I used the PW API as documented here. It works very well - see the calendar embedded here. That got me thinking that perhaps it would be better to keep the two sites separate in any case, even after re-engineering the public site into PW (for its better CMS capability). Having the sites separate would make maintenance easier as well as not confusing the two environments (one on Bootstrap, the other on UIKit, for example).

Two questions arise:

  1. Has anyone else done something similar (i.e. split website and web app in PW) or otherwise have any views on the pros and cons?
  2. More specifically: How do I address the namespace issues when I have one PW site accessing the API of another? It isn't a problem at the moment because the public website is not in PW.

Share this post


Link to post
Share on other sites

 

38 minutes ago, MarkE said:

More specifically: How do I address the namespace issues when I have one PW site accessing the API of another? It isn't a problem at the moment because the public website is not in PW.

I haven't done this before (split websites) but what you describe seems doable using ProcessWire's multi-instance capability.  That would require that both sites are on the same server though.

https://processwire.com/blog/posts/multi-instance-pw3/

  • Like 1

Share this post


Link to post
Share on other sites

Thanks @kongondo, the standard API only works on the same server anyway - that works now with the non-pw site. I’ve used multi-site before, but I don’t see how I could access the API of the other site without namespace confusion. 

Share this post


Link to post
Share on other sites
1 hour ago, MarkE said:

I’ve used multi-site before, but I don’t see how I could access the API of the other site without

I am talking about multi-instance 😄 not multi-site. They are two different things.

// public site
$somePage = $pages->get('/some/page/');

// second site
// create instance
$site = new ProcessWire('/path/to/www/', 'http://domain.com/'); 
$stuffFromSecondSite = $site->pages->find("template=very-important-stuff,sort=-created, limit=3"); 
// do whatever with $stuffFromSecondSite

No namespace issues using above.

  • Like 2

Share this post


Link to post
Share on other sites
6 minutes ago, kongondo said:

I am talking about multi-instance 😄 not multi-site.

😳 Whoops! Many thanks - I wasn't aware of that - I'll read up on it.

Share this post


Link to post
Share on other sites

I've now implemented a multi-site and multi-instance setup and it mostly works. For some reason, the 2nd site cannot access select options fields on pages on the 1st site - I changed these to page reference fields and that works. The only major problem so far is with runtime markup fields, which are pretty crucial to my app (great module btw @kongondo 🙂 ). These don't seem to be accessible by the 2nd site at all - either directly or via $page->render(). Curiously, I had no problem accessing them from a non-PW site (on the same server).

  • Like 1

Share this post


Link to post
Share on other sites
Posted (edited)
49 minutes ago, MarkE said:

I've now implemented a multi-site and multi-instance setup and it mostly works.

Thanks for reporting back. Glad it works 🙂 

49 minutes ago, MarkE said:

the 2nd site cannot access select options fields on pages on the 1st site - I changed these to page reference fields and that works.

 

49 minutes ago, MarkE said:

These don't seem to be accessible by the 2nd site at all

Hmm. I'm wondering whether its because of some module method that these two fields (RM and Options). Have you been able to debug? Any errors or notices?

Edit: In addition, how are you implementing RM's code? i.e. via a file render or code directly in the field config?

Edited by kongondo

Share this post


Link to post
Share on other sites
7 minutes ago, kongondo said:

Have you been able to debug? Any errors or notices?

Used Tracy. The field is just shown as empty.

Other fields from the same page are all OK.

8 minutes ago, kongondo said:

how are you implementing RM's code? i.e. via a file render or code directly in the field config?

As a separate php file. 

plus I can see that it all renders OK on site 1.

Share this post


Link to post
Share on other sites
13 minutes ago, MarkE said:

Other fields from the same page are all OK.

I am very curious about this. I am curious why both Options and RM are not working. What do they have in common? RM, as you know does not access the database and I wonder whether that is something multi-instance requires? 

15 minutes ago, MarkE said:

As a separate php file. 

OK. Are you able to do a quick test for me please? Could you try a test RM instance with some simple return 'hello world'; using the paste PHP option please? Thanks.

Share this post


Link to post
Share on other sites
1 hour ago, kongondo said:

Could you try a test RM instance with some simple return 'hello world'; using the paste PHP option

That works fine!

EDIT But if it's in a php file then it doesn't work

Share this post


Link to post
Share on other sites

Additional info. I have the RM module in both sites. It seems like the site 2 module is attempting to run the site 1 field.

(EDIT - Background - I thought I'd try a work-round by putting a function call to the php in the paste PHP box. The page and RM field are in site 1 so that's where the PHP file and function are. However, the work-round fails because of "undefined function"  being called from the RM module in site 2. I'm not sure how modules are supposed to operate in a multi-instance set-up, but it seems that any modules necessary to process site 1 fields need to be in site 2 as well and somehow be "multi-instance aware").

FURTHER EDIT! - The above is not entirely correct. If I remove the site 2 module, the site 1 module will run (in Paste PHP mode only).

Share this post


Link to post
Share on other sites
51 minutes ago, MarkE said:

That works fine!

EDIT But if it's in a php file then it doesn't work

Aha. OK, we are getting somewhere. I am wondering if this has to do with the new silly bug I introduced (new RuntimeMarkupUtilities) but have never gotten round to fixing. Conversely, multi-instance may still have issues with $files variable.

Here's another test for you please, if you don't mind. Could you try the following (one at a time) in the test RM instance please? Instead of echoing, call your file like so:

$filename = 'something';// // file will be in /site/templates/
return wireRenderFile($filename);
return ProcessWire\wireRenderFile($filename);
//return $files->render($filename);// @note: this SHOULD NOT work since RM doesn't know 'files' yet
return wire('files')->render($filename);

 

Are you using the Master or Dev version of RM? I haven't looked at it in a while so I am not sure what the differences are though 😄 

 

15 minutes ago, MarkE said:

Additional info. I have the RM module in both sites. It seems like the site 2 module is attempting to run the site 1 field.

Hmm. I have no clue about this one.

Share this post


Link to post
Share on other sites

OK. Results as follows:

  1. Undefined function
  2. Filename does not exist (it is looking on site 2, not site 1 - where the page and field are)
  3. render() on null
  4. call to undefined function wire()

I tried them all with and without RM module in site 2. The results are exactly the same (if the site 2 module is present it will run that, otherwise it will run the site 1 module).

If I put the file in site-2/templates then alternative (2) works (with and without the module in site 2). (But it makes no sense to have the file in a different site from the page and field).

Share this post


Link to post
Share on other sites

Thanks for the info.

It seems that $files is only reading what is locally available to it. i.e. if I invoke $files in site-1 (where RM is) but use site-2 like so, $site1->rm_field, $files will look for the file RM is trying to render from its own file system, i.e. /site-2/templates/ instead of /site-1/templates/. This supposition is sort of supported by this: https://processwire.com/api/ref/wire-file-tools/render/

Quote

This is a shortcut to using the TemplateFile class.

File is assumed relative to /site/templates/ (or a directory within there) unless you specify a full path. If you specify a full path, it will accept files in or below any of the following:

  • /site/templates/
  • /site/modules/
  • /wire/modules/

What we want is probably an absolute path to the file in site-1, maybe using $files->include(). https://processwire.com/api/ref/wire-file-tools/include/

I don't want to bother you further with more tests 🙂 . I'll look into this when I get a moment.

Share this post


Link to post
Share on other sites

By the way, I am wondering why you need to use RM in a multi-instance setup. Is you intention to output RM markup from site-1 in site-2? My understanding of multi-instance setups is a way to easily pass data (not markup) between sites. If you can, please also show me the code you are using to invoke RM in the second site. Thanks.

Share this post


Link to post
Share on other sites
21 minutes ago, kongondo said:

Is you intention to output RM markup from site-1 in site-2?

Yes. To explain further: Site 1 is a web app which handles the bookings. Site 2 is the public website for the property. I need to publish the availability from 1 to 2. The result is the availability table you see at https://www.bawdhall.co.uk/prices. The admin app will handle multiple properties, each with their own availability page. The availability page in the admin app hosts the RM field. It is intended that the publishing of availability could take place in one of 3 ways:

  1. iframe in the public site (which could be anywhere). The availability template in the admin app provides the rendering for this (using the RM field).
  2. access the admin app PW API from a non-PW site on the same server (this is the method used for the link given above and works very well using the RM field on the admin site).
  3. access the admin app PW API from another PW instance (what I am now trying to do). 

The code for the RM field is really rather big and accesses a lot of data from across the admin site (site 1), not just the (non RM) fields on the availability page. As well as the table you see, it also hosts a booking form. You will realise from the above that this code needs to sit within the admin site to handle cases 1 and 2 - I really don’t want to replicate it in a slightly different form for case 3 to access all the underlying data directly and re-build the table. Besides, it seems nonsensical that case 2 should work “out of the box” but not case 3. 
I don’t know if I have made things harder by putting both sites in a multi-site setting. Maybe it would help if they were completely separate sites, whilst still on the same server. However, I read Ryan’s comment that it would be good to use the same PW version so I though that multi-site was a sure way to achieve that. 
I’ll answer the last point on code in a later post. 

Share this post


Link to post
Share on other sites

Thanks for the explanation.

10 minutes ago, MarkE said:

The code for the RM field is really rather big and accesses a lot of data from across the admin site (site 1), not just the (non RM) fields on the availability page.

Sorry, I should have been clearer 😄 I didn't mean that RM field. I meant the test one I requested you to set up.

12 minutes ago, MarkE said:

I’ll answer the last point on code in a later post. 

Or, maybe you didn't misunderstand me... 😄 

13 minutes ago, MarkE said:

The availability page in the admin app hosts the RM field.

Hmm. I am sure you have put a lot of thought into this and it does sound like a complex setup but just wondering if it would be better for the Admin App to only provide data and have a RM field in site 2 (public site) consume the data (and render it)? Of course I can't see the whole picture so my thoughts might be off base 🙂 .

Share this post


Link to post
Share on other sites
1 hour ago, kongondo said:

just wondering if it would be better for the Admin App to only provide data and have a RM field in site 2 (public site) consume the data (and render it)

That might be possible, if that were to be the only method. However, methods 1 and 2 require the data to be processed in the admin app as the front-end for those methods is not PW (and both these methods work well). In any case, I have been experimenting a bit with your suggestion, by putting my RM code on site 2 (since that is where the module is looking for it) and have been running into problems with selectors not working properly - will continue to investigate this.

2 hours ago, kongondo said:

If you can, please also show me the code you are using to invoke RM in the second site.

Excerpts of code are given below. The page is rendered using the markup regions strategy. _init.php is loaded first, the template is in Prices.php and the rendering is via _main.php.

In _init.php 

$admin = new ProcessWire($config->paths->root . 'site/');

In _main.php

        <div id="wrapper">
            <!-- content replaced by template -->
        </div>

In Prices.php

<div id="wrapper">
  .......
                  <div id="availability">
                      <?php
                      $adminPage = $admin->pages->get("template=Availability, name=bawd-hall-availability");
                      $availabilityTable = $adminPage->runtime_markup_availability;
                      bd($adminPage, 'admin page');
                      bd($adminPage->availabilityColumns, 'admin page columns');
                      bd($availabilityTable, 'admin page runtime');
                      ?>
                      <?= $adminPage->title ?>
                      <?= $adminPage->runtime_markup_test ?>
                      <?= $availabilityTable ?>
                  </div>
  ----
</div>

The bardumps illustrate that the other fields appear OK (as do $adminPage->title and $adminPage->runtime_markup_test {your test field - only works with the PHP placed in site-2/templates}).

$availabilityTable (the original RM field) does not work even after placing a copy of the php in site-2/templates and modifying the $pages-> to invoke the site-1 instance, owing to the selector issue mentioned above, which I am investigating.

EDIT: The selector issue is my code, I think. I got the field to render eventually in site 2 (minus a lot of css) with replicating all the PHP for the field in site-2/templates and modifying $pages etc. to pick up the right instances. Part of the issue seemed to be the need to explicitly set the $user in site 1, otherwise the field could not pick up the required data. I was assuming that since the API was all in PW that superuser in site-2 would allow API access in site-1; it doesn't!

 So, if we can get the RM module to pick up the code from the correct place, it may all work nicely.

Share this post


Link to post
Share on other sites
11 hours ago, MarkE said:

 So, if we can get the RM module to pick up the code from the correct place, it may all work nicely.

A suggestion:

In FieldTypeRuntimeMarkup.module, getDefaultPath method, set an additional parameter $page (and update references), then use the following:

        $rootPath = preg_replace('/assets.*/m','',$page->filesPath());
        $config->setPath('templates', $rootPath . '/templates/');

(and similarly for /modules/ and $config->urls)

This will set the paths for templates etc. relative to the site which hosts $page, rather than the originating site.

There may be a better way of getting the root path without having to do the preg_replace, but I can't see one at the moment.

EDIT: Then you need to use 

$defaultPath =  $config->paths->templates;

etc. I'll try and work this up more fully, but for my code to work properly, I also need to make my PHP for the RM field "multi-instance aware".

Share this post


Link to post
Share on other sites
37 minutes ago, MarkE said:

This will set the paths for templates etc. relative to the site which hosts $page, rather than the originating site.

Haven't had my coffee yet so not thinking clearly. I thought the original intention was for site 2 (the public site) to pick RM output from site 1 (app/originating site)? I thought site 1 has the RM code. Please clarify.  

Share this post


Link to post
Share on other sites
2 minutes ago, kongondo said:

Haven't had my coffee yet

Me too! But to clarify. The code I suggest will set the template path to that which hosts the page with the RM field (site 1 - the app - in this case, but should make no difference in a single-instance case). By the originating site, I meant site 2 - the public site.

Share this post


Link to post
Share on other sites

So, currently, this is what is happening:

  • App (site-1 [bookings]) has /site-1/templates/some-rm-script.php
  • Public (site-2 [property]) when instancing site-1, is trying to read 'some-rm-script.php' FROM its own file system, i.e. /site-2/templates/some-rm-script.php

Is that it?

Share this post


Link to post
Share on other sites
13 minutes ago, kongondo said:

Is that it?

Correct.

Share this post


Link to post
Share on other sites
Posted (edited)
1 hour ago, MarkE said:

Correct.

I thought so, thanks. That means $files (the API that RM uses) is restricting itself to its own file system (for security!) as stated in the docs:

Quote
filename string

Assumed relative to /site/templates/ unless you provide a full path name with the filename. If you provide a path, it must resolve somewhere in site/templates/, site/modules/ or wire/modules/.

However, and I hesitate to mention this for potential security reasons, there is this option:

Quote

allowedPaths (array): Array of paths that are allowed (default is templates, core modules and site modules)

Having said that, I suspect $files will still not go outside its own /site-*/

Are you using multi-instance this way?

Quote

While optional, we also recommend providing the URL to the installation as the second argument (preferably including the scheme and hostname). That way if you make any $page->url() or $page->httpUrl() calls, it will know where to point them to:


$site = new ProcessWire('/path/to/www/', 'http://domain.com/'); 

i.e., including the domain parameter?

Thinking out loud, if you had a RM field in site-2(public) whose render PHP file would do a PHP include('/path/to/site-1/scipt.php') of your RM script in site-1(app), that could possibly work but it means your included site-1 script would not be in context. It wouldn't know $site_1->page for instance, unless you pass it to it maybe. Seems hacky though and somewhat defeats the purpose of RM in site-1.

Edited by kongondo

Share this post


Link to post
Share on other sites

As I mentioned earlier, this:

        $rootPath = preg_replace('/assets.*/m','',$page->filesPath());
        $config->setPath('templates', $rootPath . '/templates/');

works. as $page is in the site-1 context.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Recently Browsing   0 members

    No registered users viewing this page.

×
×
  • Create New...