Important announcements from CouchCMS team
80 posts Page 1 of 8
Previous 1, 2, 3, 4, 5 ... 8 Next
8 July 2015: This version of Couch has been promoted to become the release version 1.4.5 available from the main download page http://www.couchcms.com/products/

Hi everybody,

I know I owe an apology to everyone (especially cheesypoof) - it has been a terribly loooong time since I started work on the elusive version 1.4.5 and it really should have been released much earlier.

To tell you the truth, it still is not completely ready yet.
Not to prolong the wait too much, I decided to split the release in two parts.
Whatever has been implemented to date (along with all the bug-fixes since the last release) is being released here (RC1).

couchcms-1.4.5RC1.zip
(2.07 MiB) Downloaded 1671 times

users.zip
Sample templates
(4.44 KiB) Downloaded 2243 times

The next iteration (1.4.5RC2) will cover whatever is left.

Admittedly, the most anticipated feature of 1.4.5 is the new admin-panel. That, I am sorry to say, is not in this release. The next part will have it.

Some explanation for the delay is due -
For me, implementing the new admin-panel did not consist of simply replacing the current panel's HTML/CSS/JS with the one cheesypoof so painstakingly designed (had this been the case, it would have been a, comparatively, trivial task). The kind of new admin-panel I had in mind entailed much more than just cosmetic changes.

I wanted the admin-panel to be as extensible as the main web-site running under Couch where every bit of HTML markup used would be overridable by simple Couch tags that we know so well. Think about it - the possibilities are immense. You can design (that is, if you feel inclined to) an admin-panel that is 100% your own creation and the process would be almost the same as to what is used with the front-end site.

Anyway, I realized very early on that an admin-panel as flexible as this would require one specific functionality in Couch's core that, not surprisingly, imparts heavy-weights like Wordpress and Drupal the kind of legendary flexibility they are known for - this function is 'Events and Hooks'.

The basic idea is simplicity itself - the core code of the CMS raises events at every crucial point in its execution flow. Code external to the CMS (could be addons or third-party scripts) can then 'hook' into these events. By doing so, they can inject their custom code into the workflow or can even modify the original workflow itself. This single feature opens up any CMS to almost endless customization.

Couch now finally has this capability. The immediate reason for implementing it was making the new admin-panel design possible but it is sure to have a bearing on every single feature added to Couch from now on.

I am quite aware that for Couch's primary audience, i.e. the designer community, this 'events and hooks' affair won't have a 'direct' effect as not many are likely to get their hands dirty trying to code PHP addons and plugins. However, I am sure they'll appreciate the kind of powerful features that this functionality now makes possible.

Almost all the new features bundled with this release rely heavily on hooks and events and should bear testimony to above said point.

1. Extended Entities
Anyone who has worked with Couch for any length of time would realize that 'pages' are at the heart of almost everything that Couch does. There are other 'entities' available too namely 'folders', 'comments' and 'users' but when it comes to flexibility, these are almost second-grade citizens when compared to 'pages'. Quite unlike pages, none of the other entities allow any kind of customization to the data captured through them. For example, comments offer a fixed number of fields - take it or leave it. There is no provision for defining your own fields in comments.

'Users' suffer from the same problem. Almost all our community members would know that the 'Members' module (http://www.couchcms.com/forum/viewtopic.php?f=5&t=8063) attempted to alleviate this problem by replacing the system 'user' entity with those 'simulated' using normal cloned pages.

For most part it worked well but also brought in its own set of complications - we now had two set of 'users' to contend with in coding (the system 'users' and the custom 'members'). 'Members' did not replace 'users'. Rather the two co-existed in the same sphere often overlapping each other's functionality thus leading to confusion.

The 'extended' addon that ships with this release attempts to fix these problems by following a unique tack.
Like the 'members' module, it relies on normal cloned pages to do its job but, importantly, unlike the former the cloned pages do not try to 'simulate' the existing entities. Instead, they 'extend' them.

Allow me to explain (this is a bird's eye view. We'll go into the specifics later).
We use 'extended' addon to add custom fields to 'users', 'folders' and 'comments'.
To do so, we simply use a normal clonable template and associate it with the entity of our choosing.

Let us suppose, we do that with 'folders'. Now, any editable region we add to our template will *show up in the folders edit screen*. The system 'folder' object, in a sense, borrows the editable regions from our template and in this way the template 'extends' it.

What happens when we create a new folder? The system automatically creates in the background a hidden cloned-page associated with the folder. Delete a folder and the associated cloned page gets deleted automatically.

The same thing holds true for 'comments' and 'users' also.

Compare this approach to 'members' addon and you'll see that with the new approach, the cloned-pages play second fiddle to the core objects. They don't attemt to supplant or replace the original entities. Rather, they remain relegated to the background, working silently to enhance the entities they are associated with. The enhanced entities continue to work just the same as before (e.g. everything you know about working with 'users' remains unchanged) only now with additional features.

Now that we have a bird's eye view of the way 'extended' addon works, let us see in detail how to put it to use with each of the mentioned entities (have split these into separate pages to keep this post manageable).

Extended Users

Extended Folders

Extended Comments


2. Enhanced cms:pages tag

Some serious amout of rework has gone into the cms:pages tag to make it 'relation aware'.
This now makes it possible to query related pages (http://www.couchcms.com/docs/concepts/r ... ships.html) in ways that were hitherto unthinkable.

Let us assume we have two templates - 'students.php' and 'courses.php' with the students template being related to courses in a many-to-many relation named 'take' (i.e. a student can take many courses and a course can have many students). Following is the how the relation could be defined in students.php -
Code: Select all
<cms:editable 
    name='take'
    type='relation'
    masterpage='courses.php'
    orderby='page_title'
    order_dir='asc'
/>

Assuming there are courses (i.e. cloned pages) named 'maths', 'biology' and 'history', the following snippets will demonstrate the spectrum of queries now available to us

Simple queries

List all students who take maths:
Code: Select all
<cms:pages masterpage='students.php'  custom_field="take=maths"  >
    <a href="<cms:show k_page_link />"><h3><cms:show k_page_title /></h3></a>
</cms:pages>

List all students who do not take maths:
Code: Select all
<cms:pages masterpage='students.php'  custom_field="take!=maths"  >
    <a href="<cms:show k_page_link />"><h3><cms:show k_page_title /></h3></a>
</cms:pages>

List all students who take maths or history:
Code: Select all
<cms:pages masterpage='students.php'  custom_field="take=maths,history"  >
    <a href="<cms:show k_page_link />"><h3><cms:show k_page_title /></h3></a>
</cms:pages>

List all students who do not take maths or history:
Code: Select all
<cms:pages masterpage='students.php'  custom_field="take!=maths,history"  >
    <a href="<cms:show k_page_link />"><h3><cms:show k_page_title /></h3></a>
</cms:pages>

List all students who take maths and history:
Code: Select all
<cms:pages masterpage='students.php'  custom_field="take=maths | take=history"  >
    <a href="<cms:show k_page_link />"><h3><cms:show k_page_title /></h3></a>
</cms:pages>

List all students who do not take maths and do not take history (same as 'do not take maths or history' - De Morgan’s law):
Code: Select all
<cms:pages masterpage='students.php'  custom_field="take!=maths | take!=history"  >
    <a href="<cms:show k_page_link />"><h3><cms:show k_page_title /></h3></a>
</cms:pages>

List all students who take any course:
Code: Select all
<cms:pages masterpage='students.php'  custom_field="take=ANY"  >
    <a href="<cms:show k_page_link />"><h3><cms:show k_page_title /></h3></a>
</cms:pages>

List all students who do not take any course:
Code: Select all
<cms:pages masterpage='students.php'  custom_field="take!=ANY"  >
    <a href="<cms:show k_page_link />"><h3><cms:show k_page_title /></h3></a>
</cms:pages>

N.B. 'ANY' is a special keyword. It has to be used as a solitary value i.e. cannot be combined with other values e.g.
take='maths,ANY' will not work.

Aggregate queries (involving count) -

List all students who take exactly one course:
Code: Select all
<cms:pages masterpage='students.php' aggregate_by='take' custom_field='k_rel_count=1' orderby='k_rel_count'  >
    <a href="<cms:show k_page_link />"><h3><cms:show k_page_title /></h3></a>
</cms:pages>

List all students who take more than 2 courses:
Code: Select all
<cms:pages masterpage='students.php' aggregate_by='take' custom_field='k_rel_count>2' orderby='k_rel_count'  >
    <a href="<cms:show k_page_link />"><h3><cms:show k_page_title /></h3></a>
</cms:pages>

List all students who take less than 2 courses:
Code: Select all
<cms:pages masterpage='students.php' aggregate_by='take' custom_field='k_rel_count<2' orderby='k_rel_count'  >
    <a href="<cms:show k_page_link />"><h3><cms:show k_page_title /></h3></a>
</cms:pages>

N.B.
As seen above, if the 'aggregate_by' parameter is set to a relation field, cms:pages recognizes a variable named 'k_rel_count' that can be used in 'custom_field' and as 'orderby' too.

Please note that aggregate query has (as of now) a technical limitation - it cannot be used to list pages with a count of zero i.e. 'k_rel_count=0'. It shouldn't be a problem, though, as we can do that using 'ANY' as shown in the last simple query.

Composite queries
We can combine multiple queries to perform some pretty complex kind of queries e.g.

List all students who take only maths and no other courses:
Code: Select all
<cms:set take_only_one="<cms:pages masterpage='students.php' aggregate_by='take' custom_field='k_rel_count=1' ids_only='1' />" />

<cms:pages masterpage='students.php' custom_field="take=maths" id=take_only_one>
    <a href="<cms:show k_page_link />"><h3><cms:show k_page_title /></h3></a>
</cms:pages>

List all students who take only maths or Bio and no other courses:
Code: Select all
<cms:set take_only_one="<cms:pages masterpage='students.php' aggregate_by='take' custom_field='k_rel_count=1' ids_only='1' />" />

<cms:pages masterpage='students.php' custom_field="take=maths,biology" id=take_only_one>
    <a href="<cms:show k_page_link />"><h3><cms:show k_page_title /></h3></a>
</cms:pages>

List all students who take only Maths and Bio (exactly those two courses and no other courses):
Code: Select all
<cms:set take_only_two="<cms:pages masterpage='students.php' aggregate_by='take' custom_field='k_rel_count=2' ids_only='1' />" />

<cms:pages masterpage='students.php' custom_field="take=maths | take=biology" id=take_only_two>
    <a href="<cms:show k_page_link />"><h3><cms:show k_page_title /></h3></a>
</cms:pages>

List all students who take Maths or Bio but not both:
Code: Select all
<cms:set take_both="<cms:pages masterpage='students.php' custom_field='take=maths | take=biology' ids_only='1' />" />

<cms:pages masterpage='students.php' custom_field="take=maths,biology" id="NOT <cms:show take_both />">
    <a href="<cms:show k_page_link />"><h3><cms:show k_page_title /></h3></a>
</cms:pages>


A FEW NOTES:
1. The queries above assumed the relation field was defined in the students template itself.
We can also query for the 'reverse-related' pages i.e. where the relation field is defined in the temlate at the other end of the relationship. For example, assuming there was another template named 'clubs.php' that defined a relation named 'play', we can query the students based on club as follows

List all students who play for 'pegasus':
Code: Select all
<cms:pages masterpage='students.php'  custom_field="club.php::play=pegasus"  >
    <a href="<cms:show k_page_link />"><h3><cms:show k_page_title /></h3></a>
</cms:pages>

As you can see, quering a reverse-relation requires specifying the template containing the field e.g.
club.php::play

Similarly for 'aggregate queries' (i.e. involving count) discussed above, we can query the reverse-related template by explicitly specifying the name of the containing template with the relation field's name e.g. the following will list all courses with the number of students taking them -
Code: Select all
<cms:pages masterpage='courses.php' aggregate_by='students.php::take' custom_field="k_rel_count>1" orderby='k_rel_count' >
    <a href="<cms:show k_page_link />"><h3><cms:show k_page_title /> (<cms:show k_rel_count />)</h3></a>
</cms:pages>

2. In all the examples above we have used the names of the pages as parameter.
If required, we can also specify the page ids instead e.g.

List all students who take maths or history:
Using page_names, as we have already seen -
Code: Select all
<cms:pages masterpage='students.php'  custom_field="take=maths,history"  >
    <a href="<cms:show k_page_link />"><h3><cms:show k_page_title /></h3></a>
</cms:pages>

The same query using page ids -
Code: Select all
<cms:pages masterpage='students.php'  custom_field="take=id(383,384)"  >
    <a href="<cms:show k_page_link />"><h3><cms:show k_page_title /></h3></a>
</cms:pages>

As can be seen, specifying ids requires enclosing the values in 'id()'.
This can be useful when the ids are obtained programatically (as in some of the composite queries example above where cms:pages with ids_only='1' returns a comma-separated string containing the ids of a;; the pages fetched.

In closing, I am sure the examples given above would have made abundantly clear the querying power we now have at out disposal in Couch.

3. Some new tags
Before winding up, let us take a look at some utility tags that debut with this version

cms:else_if
With the current logic tags (cms:if and cms:else)it isn't uncommon to find oneself in a rather 'heavily-nested' situation. A lot of screen space is lost in the text editor and, more importantly, it can also make reading code somewhat challenging. Let's use Couch's standard view handling as an example:
Code: Select all
<cms:if k_is_page >
    Page
<cms:else />
    <cms:if k_is_home >
        Home
    <cms:else />
        <cms:if k_is_folder >
            Folder
        <cms:else />
            Archive
        </cms:if>
    </cms:if>
</cms:if>

While embedding snippets certainly helps to alleviate some of the aforementioned problems, it isn't always an appropriate solution.

The addition of cms:else_if tag to the suite of logic tags now transforms the previous code example to:
Code: Select all
<cms:if k_is_page >
    Page
<cms:else_if k_is_home />
    Home
<cms:else_if k_is_folder />
    Folder
<cms:else />
    Archive
</cms:if>

I am sure you'll agree, that is much cleaner.

cms:validate
There are situations where our code needs to deal directly with parameters provided by vistors through querystring (i.e. as URL's parameters). Security demands that such user-provided values must be treated with absolute suspicion and be thoroughly verified for their correctness before using them anywhere in the code.

Couch lends us a helping hand in this quest by sanitizing all GET parameters automatically. Further, the cms:gpc tag used to get the parameters also does the same. So the values are not likely to do any harm (e.g. result in XSS) but they still can be incorrect i.e. not what our code expects.

Validating the passed parameters required falling back on PHP so far.
Now we can use the cms:validate tag for doing this. An example -
Code: Select all
<cms:set get_id="<cms:gpc method='get' var='id' />"/>

<cms:if "<cms:validate get_id validator='non_zero_integer' />">
    ...
</cms:if>

The 'validator' parameter accepts the same values as accepted by the cms:editable tag (as documented at
http://www.couchcms.com/docs/tags-reference/editable/) e.g.
min_len
max_len
exact_len
alpha
alpha_num
integer
non_negative_integer
non_zero_integer
decimal
non_negative_decimal
non_zero_decimal
email
matches_field
regex

Again, apologies to all those who have waiting impatiently for the revamped admin-panel. I hope you realize that most of the features described above are preparing the way for the new admin panel.

Do try out this version (if nothing else, it is at least a stabler version of the current 1.4 as it contains fixes for all bugs reported so far).

As always, feedback solicited :)
When you think that the Coach can not be better, KK comes and shows it can! Amazing!

With this new method of comments is now possible to implement a "reply" natively ;)

Thanks KK
After some struggling (important note: Make sure you completely and utterly remove the members module before activating Extended Users), I'm thrilled to have a native way of having registered users.

And a question - is it possible to have <cms:process_login /> deposit the user somewhere other than the k_site_link? I'd love to have it bounce them to the registered-users-only area.

ETA: Or, more accurately, have <cms:process_login /> always take them to the same place.
@slink,
is it possible to have <cms:process_login /> deposit the user somewhere other than the k_site_link?
Certainly.
The cms:process_login tag accepts a parameter named 'redirect'.
The valid values for this parameter are an explicit URL, '0', '1' and '2'

Following will redirect to the specified URL (should be absolute and should belong to your site)
Code: Select all
<cms:process_login 
    redirect="http://www.yoursite.com/whateever.html"
/>

or a variation of above that redirects to the profile page
Code: Select all
<cms:process_login 
    redirect="<cms:link 'users/profile.php' />"
/>

Following will always redirect to the current page (i.e. refresh the page). Useful in cases where you embed the login-box as part of a bigger page (e.g. as often seen on homepages)
Code: Select all
<cms:process_login 
    redirect="1"
/>

Whereas following will expect a querystring parameter named 'redirect' that specifies the page to redirect to (this is the default and is how a dedicated login page works)
Code: Select all
<cms:process_login 
    redirect="2"
/>

And finally, following will not redirect at all (i.e. you need to do that with your own code. Can be useful, e.g. using AJAX)
Code: Select all
<cms:process_login 
    redirect="0"
/>

Hope this helps.
@KK

Simple and intuitive! Thanks, that's precisely what I needed.
Great news and nice job!
Thanks, KK, for moving forward in this incredible project!

I've tested the new features and they are great. Only thing I think becomes not useful is Extended Comments feature. If use Extended Users we can make a regular template for Comments with a relation to extended-users template and data-bound forms. You've also noticed it in the final section of ExtCom docs.

The only cons to use native comments is because they have a custom template in Admin panel and no need to manually associate all the fields (like username).

I also thought over "CMS builder" and "built-in features" concepts. The first tolds to keep Couch as clean as possible (and remove Comments feature, because it can be easily be added by template), but the second tolds that Comments out-of-box is nice. But if webmaster needs just a bit modified comments, he should make the same ExtCom template.

How do you see this points?
KK,

Or anyone who has installed the update, can you tell us how to implement this? What I mean is do we just unzip this and copy all the new files to the existing couch install? or do we need to delete the entire couch and then reinstall from scratch like when installing for the first time?

Still a newb :)
I am pasting the contents of UPGRADE.txt found in the current 1.4. version - the same steps will apply to 1.4.5 also
Code: Select all
UPGRADING
---------

For upgrading from a previous version of Couch to version 1.4:

1.  Unzip 'couchcms-1.4.zip' file to your local system.
    Within the 'couchcms-1.4' folder thus extracted will be found a folder named 'couch'.
    From within this 'couch' folder' -
    a.  Delete 'snippets' and 'uploads' folders.
    b.  Delete 'config.example.php' file.

2.  Rename the 'ckeditor' folder found in your *existing* Couch installation's 'includes' folder
    to 'ckeditor_old' (or delete it completely).
   
3.  Upload the remaining contents of the 'couch' folder of step 1 to
    your existing installation's 'couch' folder (or whatever you might have renamed it to).
    This way we'll be overwriting all existing Couch core files with the newer version
    while preserving anything you might have added to 'snippets' and 'uploads' folder.
   
4.  If you already have a commercial license for your website,
    append the following line to your site's couch/config.php file:

        define( 'K_PAID_LICENSE', 1 );

IMP. If you have chosen as a security measure to rename the 'index.php' to something else, do
make sure to delete your existing renamed index.php and then rename the new index.php to your
name of choice.

Hope this helps.
Thanks KK!!
... as ever thanks a big bunch KK for all the effort that's gone/going in to Couch - we all benefit from this!

The enhanced pages and folders tags seem of most interest to my own particular type of projects.

Excited by the prospect of the flexible AP to come. Thanks again.
Previous 1, 2, 3, 4, 5 ... 8 Next
80 posts Page 1 of 8