Composr Tutorial: Integration of Composr and other installed scripts/applications

Written by Chris Graham
This tutorial will provide details on how to integrate Composr with another web system (known henceforth as the 'other system') installed for your website.

Please note that many systems, especially complex ones, will not easily integrate without reprogramming. In this event, you may wish to hire a company for professional assistance. Even the kinds of integration here usually require a high level of skill in web technologies and Composr technologies.


Linking

The simplest form of integration is by simply placing a link on your menu. There is nothing stopping you having multiple systems installed on your website as long as they do not have conflicting file/directory structures.

Embedding a simple HTML page

If you don't need to integrate a full web application, just a simple HTML page, this can be done without much trouble.

The careful way

The two main issues that present themselves are:
  1. HTML files tend to have associated data files, and the path these are read from when integrated into Composr will not be the same as the path of the HTML file itself (as page files are located in a different location to where the index.php file that handles the page request is located)
  2. HTML files contain surrounding mark-up that must be stripped, because Composr already provides it

Note

Relative URLs are normally read relative to the path the referencing page is in. However, this behaviour can be changed using an HTML tag base, but Composr does not use this by default; you may place a base into Composr in HTML_HEAD.tpl if you wish, to create a common location for relative-URLs to be relative to. This is possible in Composr as Composr itself only uses absolute URLs.


The best way I can explain how to integrate an HTML page is by presenting a simple scenario.

In this scenario, a HTML page named mypage.html has been made in an editor, and it contains a file myimage.png that is referenced by a relative URL with no path (i.e. it is assumed to be in the same directory as the mypage.html file).

Imagine mypage.html contains…

Code (HTML)

<html>
        <head>
                <title>This is my page</title>
        </head>
        <body>
                <img src="myimage.png" />
        </body>
</html>
 

To integrate this page as site:mypage, the following steps would need to be taken:
  • Strip down the file to only contain <img src="myimage.png" />.
  • Place myimage.png in the site directory (this assumes that 'URL Schemes' are turned off – if you have a URL Scheme enabled then it is best to just use absolute URLs instead)
  • Rename the file to mypage.htm (HTML pages in Composr must end .htm, not .html or anything else)
  • Place mypage.htm in site/pages/html_custom/EN/

The magical way

Composr can actually handle most things for you if you want to defer control to it:
  1. Copy any .htm files into the pages/html_custom/EN/ directory (.html files should be renamed to .htm files)
    • Unless the file is meant to be located in a subdirectory and Composr has a zone with the same name as that subdirectory. In this case, you'd place it in the equivalent directory of that zone so that Composr can better automatically rewrite any links to the page:
      • For example, don't upload pages/html_custom/EN/example/test.htm if you have a zone named example. Put the file in example/pages/html_custom/EN/
      • If the directories go more than one level deep, Composr will translate / to _ when matching against a zone name (e.g. site/more would be considered a zone named site_more)
  2. Copy any non-.htm files (images, etc) into uploads/website_specific
  3. Your pages should then show up as normal Composr entry-points in the menu editor
  4. Go through the pages in Composr to find any broken links and adjust them so that they work. Composr can't perfectly fix your links for you every-time, but it does do a pretty good job. Read on for more information how link rewriting works.

Composr link alternation works by replacing simple patterns to local relative links. For example, a link site/mypage.htm would go to the Composr site:mypage entry point. If the mypage.htm file had been correctly copied to pages/html_custom/EN/ then Composr would actually load it up as intended.
A link mypage.htm would go to the Composr :mypage entry point.

As Composr can only rewrite the simple links, the process of fixing broken links is often a matter of simplifying them. For example:
  • http://yourbaseurl/mypage.htm could not be fixed by Composr, because it is not a local link. Change it to mypage.htm.
  • ../mypage.htm might be used from a page located in a subdirectory. Unfortunately Composr can't realistically recognise this, so it can't translate this link. In this case, you would need to replace the link with the proper Composr page-link.

To clarify, the following linking situations confuse Composr:
  • full links to local pages
  • page trees that go more than one level deep
  • links that go back up a page tree

If you need advanced parsing functionality, whether to rewrite links/HTML in other ways or to do other processing, you can write hooks under sources_custom/hooks/systems/site_html_pages. It accepts a run() method which receives the parameters $html (passed by reference, so you can modify the HTML output), $string (relative path to the page), and $file_base (base path used to access the page).

Embedding into Composr

If you wish for the other system to appear directly inside Composr, much like a Composr page, this is a lot more awkward.

iframe

Image

Creating a new Comcode page to place the iframe

Creating a new Comcode page to place the iframe

(Click to enlarge)

An iframe is an HTML construct that allows you to place one site inside a region ('frame') of another. There are a few main drawbacks with frame based approaches however:
  • the browser back button will send the whole Composr site back, not the embedded site. In other words, if you have made clicks inside the embedded system, and then click 'back' in your browser, Composr will move back, with the likely result being the embedded section is no longer the display Composr page
  • sometimes web browser bugs can cause rendering problems, especially when it comes to scrollbars
  • the title-bar titles would not be reflected in the browser title-bar

To place an iframed system into Composr, the easiest way is to make a new Comcode page which will contain the frame, link that onto your menu, and place the following Comcode into the page:

Code

[html]
<iframe frameBorder="0" scrolling="no" title="whatever the embedded system is" src="whatever the system URL is" style="width: 100%; height: whatever height you want px;">whatever the embedded system is</iframe>
[/html]

Where the following are appropriately replaced:
  • whatever the embedded system is (e.g. 'Something web system')
  • whatever the system URL is (e.g. {$BASE_URL}/somethingwebsystem/)
  • whatever height you want (e.g. '900')

If the embedded system has a non-predictable height, then under normal circumstances, an extra set of scroll-bars would be rendered around it when your pre-set height is exceeded. In order to avoid this without needing to choose an excessive default height, special code must be written that will regularly resize the iframe element placed in Composr so it has the same height as the actual contents of the frame – hence eliminating the need for a vertical scrollbar. Note that if you do this, the embedded system must be on the exact same domain as Composr, or web browser security will prevent the height detection from working.

Code

[html]
<script>
// <![CDATA[
function resizeEmbeddedFrame()
{
   var frame=document.getElementById('frame');
   if ((frame) && (top.frames['frame'].document.body))
   {
      if (top.frames['frame'].document.body.offsetHeight+'px'!=frame.style.height)
      {
         frame.style.height=top.frames['frame'].document.body.offsetHeight+'px';
         frame.scrolling='no';
      }
   } else clearInterval(tid);
}
//]]></script>
</script>

<iframe frameBorder="0" scrolling="no" title="<whatever the embedded system is>" name="frame" id="frame" src="<whatever the system URL is>" style="width: 100%; height: 900px;"><whatever the embedded system is></iframe>

<script>
// <![CDATA[
   var tid=window.setInterval(function() { resizeEmbeddedFrame(); },500);
//]]></script>
[/html]

The drawback on relying on this auto-resizing method is that it is somewhat computationally intensive on users' web browsers (doing a check twice a second). It is likely that users will not notice, however. When Composr does its own iframes it actually ties in a bit of code to anything that would change the frame height, to make it resize on demand, rather than routine checking – but this is not really very easy to do if you are working with someone else's code.

Naturally

The most preferable method of getting the other system to display inside Composr is to 'port' it to Composr, as a properly constructed module, mini-module, block or mini-block. This would be very possible for most systems, but also a very significant programming effort.

The quickest way is to use mini-modules/mini-blocks. These are simplified equivalents to the normal Composr blocks and modules – anything echoed out is put into the output stream in the place you'd expect. They are placed in the correspondingly named directories in Composr's file-system, and then you can just use them as normal pages/blocks.

Composr is written so that it treats 'PHP notices' as fatal errors. This is a part of our quality standards. Some poorly written PHP code, however, is designed for PHP configurations that suppress these notices. To work around this we turn off a lot of our standard checking settings when mini-modules or mini-blocks are loaded.

Integrations via direct PHP code

You may wish to integrate with another database (i.e. not Composr's main database), third-party web-services, or other programming languages.

These complexities can be dealt with in the same way as any PHP programmer would deal with them, while making use of Composr's APIs only as is convenient.

For example, you can use:
  • standard PHP database functionality to open a new connection (MySQL, SQL Server, Oracle, …)
  • PHP's file_get_contents function to download from REST web services
  • PHP's file_get_contents function to download from scripts written in another language, bridging their output over into the Composr page
  • PHP's SOAP support to integrate with more complex REST services (assuming the PHP SOAP extension is installed)
  • PHP's COM support to integrate to ASP code (assuming the PHP COM extension is installed)

Example
This simple example shows how to bridge one web system, to another. The example embeds DuckDuckGo (a search engine) into your page. Naturally, this is a silly example, but the same technique can be used to bridge your own scripts, should you be more comfortable programming in a language other than PHP.

Code (PHP)

<?php

echo '<div style="position: relative; overflow: hidden">';
echo file_get_contents('https://duckduckgo.com/');
echo '</div>';
 

Note I had to add a little CSS to stop DuckDuckGo trying to render parts of its layout on-top of the Composr website.

Third-party APIs (for developers)

If you are using a third-party API with Composr, you can upload all the PHP files to the sources_custom directory.

Before calling the third-party code it is advisable to call these lines of PHP code:

Code (PHP)

require_code('developer_tools');
destrictify();
 

These lines will turn off a lot of Composr strictness, and allow include-paths to work better (many PHP files will make assumptions that they are running from inside the include-path).

To load up them use either normal PHP code, or like require_code('example'); (for sources_custom/example.php).

Code-based relay

A compromise between a naturally ported system and a framed system would be to actually write a Composr module that loads the web pages from the other system and puts their output directly into Composr's output stream. Composr has a special API for this, in the 'integrator' source file.

There are two major problems with this approach:
  1. The embedded system would always see the server's IP address instead of the clients; this could lead to security issues if it uses IP addresses as a part of its security model
  2. It would be ugly (e.g. mixed visual styles), unless extra work was done to clean things up

RSS/Atom

If you are trying to integrate a system that is non-interactive, and outputs all important information in either the RSS or Atom families of feed formats, you may be able to perform an integration by simply using the main_rss block in combination with the feed URL (or if it is date based information, overlaying the feed URL onto the calendar).
This form of integration is most appropriate for news and calendars, although other forms of information do sometimes fit it well.

You can also export Composr data using RSS.

Use of RSS is documented in the Advanced News tutorial.

Integrating JavaScript libraries into Composr

There are a number of different techniques you can use.

A direct reference by URL

If you are simply themeing your own site then the simplest thing to do is to just insert a <script> element to the HTML_HEAD.tpl template or the GLOBAL_HTML_WRAP.tpl template (near the footer).

JavaScript libraries usually advise following a process like this because it's pretty standard. They will usually tell you whether to place in the header or the footer. Things go in the header when they are needed for the main HTML to be viable, while things that add to the page (i.e. can be loaded secondarily) go near the footer.

You may choose to reference the JavaScript library as a remote URL. Using a CDN (e.g. cdnjs - The #1 free and open source CDN built to make life easier for developers) improves performance because the visitor may well already have the JavaScript library cached in their browser.

You may also host the JavaScript library as local URLs. By convention we put them in uploads/website_specific/, but you may put them somewhere else if you prefer.

Copy & pasting into the global JavaScript code

There's a special process for this:
  1. Go to override the global.js template in your theme
  2. Blank out your overridden version
  3. Put /*{+START,INCLUDE,global,.js,javascript}{+END}*/ at the top
  4. Paste all the JavaScript next

This works by including the default code in, then your code follows.

Adding formally to the Composr theme system

If you are a programmer writing an addon, you should add the JavaScript as a proper theme resource, and then do an include command to include it.
This way, the JavaScript code can be overridden within themes, optimised by Composr, and generally will be consistent with how Composr's native JavaScript is handled.

We'll assume the JavaScript file is example.js.

Copy the example.js file to themes/default/javascript_custom/example.js.
If there is both a minified (compressed) and non-minified version, use the non-minified version. Composr does its own minification automatically, and it's better you be able to read the JavaScript code properly. Additional this way is it less likely the Tempcode parser will accidentally try and interpret parts of the code as Tempcode constructs.

You may wish to edit the file to include this at the top:

Code (CSS)

/*{$,parser hint: pure}*/
 
This code will turn off Tempcode parsing ("pure"), so that bits of JavaScript that look like Tempcode will not be treated as such.

If you are doing a really tidy job you'll want to leave Tempcode parsing on, and ensure the file does parse as Tempcode (maybe you need to add some slashes or spaces to make that work right).
An advantage of supporting Tempcode is then you can use language string and theme image references within the file, so that it works seamlessly to Composr's standard architecture.

If you want to include the JavaScript library from PHP code, do:

Code (PHP)

require_javascript('example');
 

If you want to include the JavaScript library from a template, do:

Code

{$REQUIRE_JAVASCRIPT,example}

With Tempcode parsing

As mentioned above, you can use Tempcode so that text and images go through the normal Composr architecture.

You may find you need to put some "" symbols before some "{" symbols, to stop certain bits being parsed as Tempcode.
For example, if the file contained {Example}, you'd need to change it to \{Example} because to Composr this looks like a template parameter.

Let's say that example.js contains:

Code (JavaScript)

var ex_alert_string='An error has happened.';
 
We could either try and match this to an existing Composr language string, or make a new one. Let's make a new one.
We create lang_custom/EN/example.ini:

Code (INI)

[strings]
EX_ALERT_STRING=An error has happened.
 
And then change the code in example.js to:

Code (JavaScript)

var ex_alert_string='{example:EX_ALERT_STRING;}';
 

Let's say that example.js also contains:

Code (JavaScript)

var ex_alert_image='images/alert.png';
 
We could copy the images directory from the JavaScript library as themes/default/images_custom/example, and then change the code in example.js to:

Code (JavaScript)

var ex_alert_image='{$IMG;,example/alert}';
 

As you can see, we are now managing the resources for the JavaScript library with full internationalisation and theme image support!

Ad-hoc code inclusion from PHP code

If you're working on an addon but for some reason do not want to formally add JavaScript to the Composr theme system, you will want to code it into your addon to insert the necessary code into the header and footer dynamically (because overriding core templates in an addon ties the end-user down too much).
You can do this by calling attach_to_screen_header with whatever HTML is required. Typical code will look like:

Code (PHP)

attach_to_screen_header(make_string_tempcode('Extra code goes here'));
 

You could inject a JavaScript element that includes an external URL, or a JavaScript element including actual JavaScript code. There are no constraints, it simply adds whatever you specify to the predetermined spots in the head/footer.

There is an equivalent attach_to_screen_footer function.

Integrating CSS libraries into Composr

There are a number of different techniques you can use.

A direct reference by URL

If you are simply themeing your own site then the simplest thing to do is to just insert a <link> element to the HTML_HEAD.tpl template.

By convention we put CSS files in uploads/website_specific/, but you may put them somewhere else if you prefer.

Copy & pasting into the global CSS

You may edit the global.css file for your theme and paste all the CSS in there.
Only do this if you are making your own theme or your own site, it's not appropriate for an addon that you share with others.

Adding formally to the Composr theme system

If you are a programmer writing an addon, you should add the CSS as a proper theme resource, and then do an include command to include it.
This way, the CSS can be overridden within themes, optimised by Composr, and generally will be consistent with how Composr's native CSS is handled.

We'll assume the CSS file is example.css.

Copy the example.css file to themes/default/css_custom/example.css.
If there is both a minified (compressed) and non-minified version, use the non-minified version. Composr does its own minification automatically, and it's better you be able to read the CSS code properly.

If you want to include the CSS library from PHP code, do:

Code (PHP)

require_css('example');
 

If you want to include the CSS library from a template, do:

Code

{$REQUIRE_CSS,example}

Look and feel when integrating into Composr

The other system is unlikely to naturally fit in with your Composr theme: therefore you may need to make an effort to make them look alike. This would either involve changing Composr, changing the other system, or changing both to coalesce visually.

It is important to understand that it is impossible for two web systems to 'share' a theme, as themes are designed to theme specific content structures. It is so unlikely as to be essentially impossible by chance, for two different systems to have compatible layout structure.

Sharing members

It can be a bit tricky to share members between Composr and another system. There are many ways to go about it:
  1. Make/have-made a Composr forum driver that is for the other system (as Composr can support different member systems through a forum driver). This is only appropriate if either the other system actually is the forum you will be using, or you are not actually wanting a forum for your site
  2. Reprogram the other system so that it uses the same member system that Composr uses (be that Composr's own, or that of a third party system); you might be able to find a modification for the other system that does it already (for instance, if you are using a widespread forum like phpBB, and want to integrate an external system, it is possible that the other system already has a modification to allow it to tie itself to phpBB)
  3. Disable joining of members in the other system, and make it so that login checks against whatever member system Composr is using; maintain a separate member database in the other system, but effectively tie it in to whatever Composr is using
  4. Use LDAP or HTTP-auth for all systems, with each setting up their own separate 'extra' member information scheme; Composr supports LDAP and HTTP-auth, but systems that do are in the minority so it may be a lot of work bringing other involved systems 'up to speed'
  5. Manually synchronise via spreadsheet imports from one system to another
  6. Use the user_sync non-bundled addon to programmatically import from one database to another (requires some limited PHP programming to customise it)
  7. Use the user_simple_spreadsheet_sync non-bundled addon to tie together spreadsheet import/export between Composr and another system (requires some limited PHP programming to customise it)

These are all very technical tasks, so we do not expect that many users will have the experience to easily carry them out themselves.

Directing external systems to log in a user to a Composr site

Composr handles log in anywhere as a part of the framework (i.e. any request Composr is handling).
It triggers if these post parameters are present:
  • username (required)
  • password (required)
  • remember (optional, set to '1' if cookies should be saved)
  • login_invisible (optional, set to '1' if the login should be invisible)

(the login page in Composr is mostly a front-end, and doesn't handle log in itself)

If posting from a different domain name then the 'Form-posting partner sites' option must be set to include the domain name you're using.

For completeness, this is what the login page does do:
  • Shows error messages if a log in fails
  • Performs after-login redirects
  • Handles log outs
  • Performs after-logout redirects
  • Handles Conceded mode
  • Handles "Become invisible" toggle

If coding a system to create a Composr login automatically (i.e. without needing to direct the user to a POST request) you'd need to set the session cookie to a random number, and then insert a row into the Composr sessions table to match against it.

Creating new forms in HTML but not PHP

You may need to tune the "Pages without security tokens" configuration option (Admin Zone > Setup > Configuration > Security options > Advanced) if you are setting up pages with custom forms but not going through the full Composr forms API.

General integration for external systems to access Composr

As Composr is Open Source, you can add whatever integration code you wish to it so that other systems have a way in.

However, the framework for this has been done for you with the endpoints API, and Composr Mobile SDK provides a ready-made set of endpoints covering many common use cases.
New endpoint hooks can be created by a PHP programmer easily, providing whatever custom REST API integration is required.


See also


Feedback

Please rate this tutorial:

Have a suggestion? Report an issue on the tracker.