Docs Home Install Upgrade Troubleshoot Customize Admins Devs Content Query Templates Commands Skins


Adding a dynamic feature that has anything to do with user generated content will almost certainly involve the combination of the query and template components of ccHost. In fact, the query+template combination is invoked over 100 times in ccHost as the basis for most user-facing features.

Creating your own custom query templates is a skill that once you learn, you will start to apply in all kinds of places.

Query-graphic-cqt.png

The graphic above represents the basic relationship between various ccHost components. This section of the documentation will be dealing with the areas connected with the red arrows.

Prerequisites

If you only know HTML and CSS you can get very far but for more efficient code it will definitely help to have some basic PHP and SQL knowledge.

You should get familiar the Query API which comes with your ccHost installation - browse to <your_installation_root>/query-api.

Since we will be expecting to see results from queries it would be best to have at least about 10 uploads in your system, tagged in various ways. Having this test data in the system will make things a lot clearer than working with just 1 or 2 uploads.

A Walk Through

Hello World Template

To give you a quick idea of what we're talking about, let's jump in:

Create a template file called <local_files>/skins/hello_world.tpl with just:

 Hello World! from ccHost

Now, browse to <your_installation_root>/api/query?t=hello_world

You should see your ccHost installation with our message in the client area.

Add File Looping

By default, every query template is passed a list records that meet the criteria of the query. Add these lines to our hello world template:

     %loop(records,R)%
       Hello: %(#R/upload_name)%<br />
     %end_loop%

Now, browse again to <your_installation_root>/api/query?t=hello_world

You should see a list of names of the latest uploads to your system with the newest at the top. This is because the default query is all uploads, sorted by latest first. To limit the results and reorder them try:

<your_installation_root>/api/query?t=hello_world&tags=<some_relevant_tag>&sort=name&ord=asc

Debug Inspect a Record

You can dump the contents of a record in order to get an idea of what's possible by adding a call to the %inspect% macro.

     %loop(records,R)%
       %inspect(#R)%
       Hello: %(#R/upload_name)%<br />
     %end_loop%

And don't forget about variable dumps.

Beefing up the Listing

Once you've dumped the record using the %inspect% macro you'll see there is a lot useful information in the default record. You can, for example, start making useful links:

     %loop(records,R)%
       <a href="%(#R/file_page_url)%">%(#R/upload_name)%</a> by 
           <a href="%(#R/artist_page_url)%">%(#R/user_real_name)%<br />
     %end_loop%

Details View

You can create a feature that focuses on just one upload by using the map template macro. Put the following code into <local_files>/skins/hello_world_detail.tpl

     %map(#R,records/0)%

     "%(#R/upload_name)%" is copyright %(#R/user_name)%<br />
     Licensed under: <a href="%(#R/license_url)%">%(#R/license_name)%</a>

To specify just one upload use the ids query parameter. Browse to: <your_installation_root>/api/query?t=hello_world_detail&ids=<upload_id>

Master/Details

We can now modify the original hello_world template to link to details view:

 %loop(records,R)%
   %(#R/upload_name)% 
   <a href="%(query-url)%t=hello_world_detail&ids=%(#R/upload_id)%">details...</a><br />
 %end_loop%

Note the use of the %(query-url)% as the base of the query URL.

Browse to <your_installation_root>/api/query?t=hello_world to see the results. When you click on the 'details' link you see that this takes you to another page and to get back to the listing you must use your browser's 'Back' button. In the next section we'll do the fancy AJAX version that let's you see the detail on the same page as the listing.

Fancy AJAX Master/Detail

Now we can combine the two templates with some of the ccHost javascript framework to make a single master/detail view.

By changing the format from the default 'page' format (implied in all our queries until now) to the 'html' format, we can get a return that is just the query results of our template without the rest of the skin wrapped around it. Try it now by browsing to <your_installation_root>/api/query?t=hello_world_detail&ids=<upload_id>&f=html

So we can take advantage of that to put those query results into a 'DIV'. Here's the new hello_world:


   <script type="text/javascript">
   function fill_detail(upload_id)
   {
       var url = query_url + 't=hello_world_detail&f=html&ids=' + upload_id;
       new Ajax.Updater( 'details', url, { method: 'get' });    
   }
   </script>

   <div style="float:right;width:50%" id="details">
    </div>

   %loop(records,R)%
     %(#R/upload_name)% 
     <a href="javascript://" onclick="fill_detail(%(#R/upload_id)%)" >details...</a><br />
   %end_loop%

Add Paging

When using the 'page' format as we have been for the hello_world template, there are paging features built directly in to the system. (This is where having a lot of sample data to work with comes in handy!). By adding the following line to the end of hello_world.tpl file these features will be enabled:

   %call(prev_next_links)%

Changing Dataviews

Note this documentation assumes v5.0.1 or later

The source of material used in a query is called a dataview. The Query API determines which records to pass to the template, but it's the dataview that determines exactly what fields are available for each of those record and where they came from.

A Hello World for Users

Up until now we've been using the default dataview which can be found in your installation at ccdataviews/default.php. It uses the uploads tables (along with some information from the licenses and users tables).

If you wanted to do a similar feature with your user's data you would need to tell the query engine to use a different dataview.

Let's create a new template called <local_files>/skins/hello_people_detail.tpl. At the top we'll put the following:

 %%
   [meta]
      dataview = user_basic
      type = format
   [/meta]
 %%

Then, we'll put this template code below that.

   %map(#R,records/0)%

   <img src="%(#R/user_avatar_url)%" />
   <b>%(#R/user_real_name)%</b> has been a member since %(#R/user_registered)%

By now, the syntax of the this snippet should be familiar, we are basically using the same ideas from the uploads version, but now we are using fields from the user_basic dataview. (Don't forget you can use the %inspect(#R)% macro syntax to peek into the available fields.)

To view that template browse to <your_installation_root>/api/query?t=hello_people_detail&user=<your_user_name>

You make a people listing template by making the same types of changes to the uploads listing file. Create a file <local_files>/skins/hello_people.tpl that looks like this:

   %%
   [meta]
      dataview = user_basic
      type = format
   [/meta]
   %%

   <script type="text/javascript">
   function fill_user_detail(user_name)
   {
       var url = query_url + 't=hello_people_detail&f=html&user=' + user_name;
       new Ajax.Updater( 'user_details', url, { method: 'get' });    
   }
   </script>

   <div style="float:right;width:50%" id="user_details">
    </div>
 
   %loop(records,R)%
     %(#R/user_name)% 
     <a href="javascript:// no comment" onclick="fill_user_detail('%(#R/user_name)%')" >details...</a><br />
   %end_loop%
 
   %call(prev_next_links)%

To call this template, browse to <your_installation_root>/api/query?t=hello_people. The sort will be according to last registration date. To make it alphabetical add &sort=user&ord=asc to the query.

A Hello World for Topics

Of course you can create the same type of feature for topics. Here would be <local_files>/skins/hello_topic_detail.tpl

   %%
   [meta]
     dataview = topics
      type = format
   [/meta]
   %%
   %map(#R,records/0)%

   Posted: %(#R/topic_date_format)%<br />
   <div style="border:black solid 1px;padding:3px">%(#R/topic_text_plain)%</div>

And this is what could pass for <local_files>/skins/hello_topics.tpl

  %%
   [meta]
      dataview = topics
      type = format
   [/meta]
   %%

   <script type="text/javascript">
   function fill_topic_detail(topic_id)
   {
       var url = query_url + 't=hello_topic_detail&f=html&ids=' + topic_id;
       new Ajax.Updater( 'topic_details', url, { method: 'get' });    
   }
   </script>

   <div style="float:right;width:50%" id="topic_details">
    </div>

   %loop(records,R)%
     "%(#R/topic_name)%" by %(#R/user_name)%
     <a href="javascript:// no comment" onclick="fill_topic_detail('%(#R/topic_id)%')" >details...</a><br />
   %end_loop%

   %call(prev_next_links)%

Topic queries take a special type parameter that can narrow the topics to something useful. For example, to limit the feature to just reviews you browse to <your_installation_root>/api/query?t=hello_topics&type=reviews The actual list of types is controlled by admins by way of the Content Manager.