Allow FrontEnd Users to edit specific content pages

Every now and then questions about Front End editing of pages in CMSMS appear, so in this post we will have a look at how you can easily create Front End content management for FEU user and specify which Pages a user may actually edit.

I am not really a fan of Front end editing and if it really has to be a feature for the Project then it is best that you choose a system which supports this by default and was actually built with this behavior.
But as our Developer life is not a straight line and every now and then situation happens where you are in the middle of finalizing a Project but then suddenly you are faced with this unexpected Client wish, it would be to late to start searching for a proper tool and thats how this blog post happens to be here.

First let's see what we will need for our task:

frontend_edting.jpg

 

As first you will have to install Modules as listed above. As InlineEdit is fairly large i would suggest you download the package from forge instead of installing it through ModuleManager.

Note: InlineEdit is not that activly maintained and i had to do few minor modifications  to have it running properly  which i am not going to explain here, you allways have an option to contact Module Developer for updates or contribute to Project on GitHub.
With a donation or sponsoring drive i bet you would motivate some of Developers.

Preparing FrontEndUsers Module

After you have installed these Modules go to "Users & Groups » FrontEndUser Management" and add "User Properties".
This part is mostly up to you what you actually need, but you will need one text field for example called "pages" that will be used later on to list Pages for FrontEnd editing.

Interface of User Properties

After you have added all user properties that you might need you will also have to add a Group that you intend to use for FrontEnd editing.
Click on "Groups" tab in FEU module and add a group. 
In "Add Group" interface choose "pages" user property to be "hidden", as you will not need this for exmaple in Edit User form or similar.

Create new FEU group 

When you are done by configuring your Group, create new FEU user in backend as you will need one for testing anyway. 
In step two of Add/Edit User you will see all user properties that you have chosen for selected User Group.
Now inspect "pages" field either with "Developer Tools" or "Firbeug" Browser plugin to find out "name" attribute of that field.
Inspect input field As you can see name attribute of this field is "m1_input_pages" and this is what you will need in next step.

Preparing Pagelist

So far FEU is prepared but something important is missing. Correct you will need a list of pages so these can actually be selected for each user.
This step is actually extremly simple, all you need is a MenuManager Template, yes thats right, no complex UDT or Module hacking just a simple MenuManager Template.

Go to "Layout » MenuManager" and click on "Add Template", name it FEU_backend and simply create a Template with <select> field as following.

<select size='10' class='cms_select' name='m1_input_pages[]' multiple='multiple'>
{foreach from=$nodelist item=node}
    <option value='{$node->id}'>{$node->menutext}</option>
{/foreach}
</select>

So there is no magic as you can see, just a multiselect field.
As i mentioned before you will need name attribute of user property field you have created, this is now used in <select> field as name attribute as well but with small difference, as you might want to select more then one pages you will need [] to actually specify that selected options are array, means from "m1_input_pages" became "m1_input_pages[]".

Now that MenuManager Template is prepared, we continue now to next step, which is a great CMSMS feature. What i am talking about is "module_custom".

Folder structureWith "module_custom" you can easily change appearance of any Module backend template as well as change language strings, without fearing of future upgrades, well as long there are no significant changes. 
To achieve this you will need following folder structure in your CMSMS root (where CMSMS is installed) "module_custom/FrontEndUsers/templates".
After you have created this folder structure, go to "modules" folder, search for "FrontEndUsers/templates" and copy "adduser2.tpl" file.
Insert that file in your newly created "module_custom/FrontEndUsers/templates" folder. 

Content of "adduser2.tpl" file looks by default like this:

<h3>{$title}</h3>
{if isset($username)}<h3>{$edittext}: {$username}</h3>{/if}
{if isset($message) }
  {if isset($error) }
    <p><font color="red">{$message}</font></p>
  {else}
    <p>{$message}</p>
  {/if}
{/if}
{$startform}
{if $controlcount > 0}
{foreach from=$controls item=control}
  <div class="pageoverflow">
    <p class="pagetext">{$control->hidden}<font color="{$control->color}">{$control->prompt}{$control->marker}</font></p>
    <p class="pageinput">{$control->control}</p>
  </div>
  {if isset($control->image)}
    <div class="pageoverflow">
      <p class="pagetext">&nbsp;</p>
      <p class="pageinput">{$control->image}</p>
    </div>
  {/if}
  {if $control->required != true}
     {if isset($control->control2)}
       <div class="pageoverflow">
         <p class="pagetext">&nbsp;</p>
         <p class="pageinput">{$control->prompt2}&nbsp;{$control->control2}</p>
       </div>
     {/if}
  {/if}
{/foreach}
<br/>
{/if}
  <div class="pageoverflow">
    <p class="pagetext">&nbsp;</p>
    <p class="pageinput">{$hidden|default:''}{$hidden2|default:''}{$back}{$submit}{$cancel}</p>
  </div>
{$endform}

Now to display MenuManager based multiselect field you will need to check against "Prompt" name of user property field and display menu instead of FEU field.
At the end template should look like this:

<h3>{$title}</h3>
{if isset($username)}<h3>{$edittext}: {$username}</h3>{/if}
{if isset($message)}
  {if isset($error)}
    <p><font color="red">{$message}</font></p>
  {else}    
<p>{$message}</p>
  {/if}
{/if}

{* get user id and assign it to a variable *}
{assign var='get_userid' value=$mod->GetUserID($username)}
{* now from user_id variable get value of pages user property *}
{assign var='selected_pages' value=$mod->GetUserPropertyFull('pages', $get_userid, '')}

{$startform}
{if $controlcount > 0}
{foreach from=$controls item=control}
{* check here against user property Prompt name and output MenuManager *}
{if $control->prompt == 'Select Pages'}
  <div class="pageoverflow">
    <p class="pagetext">{$control->hidden}<font color="{$control->color}">{$control->prompt}{$control->marker}</font></p>
    <p class="pageinput">{menu template='FEU_backend'}</p>
  </div>{else}  <div class="pageoverflow">
    <p class="pagetext">{$control->hidden}<font color="{$control->color}">{$control->prompt}{$control->marker}</font></p>
    <p class="pageinput">{$control->control}</p>
  </div>{/if}
  {if isset($control->image)}
    <div class="pageoverflow">
      <p class="pagetext">&nbsp;</p>
      <p class="pageinput">{$control->image}</p>
    </div>
  {/if}
  {if $control->required != true}
     {if isset($control->control2)}
       <div class="pageoverflow">
         <p class="pagetext">&nbsp;</p>
         <p class="pageinput">{$control->prompt2}&nbsp;{$control->control2}</p>
       </div>
     {/if}
  {/if}
{/foreach}
<br/>
{/if}
  <div class="pageoverflow">
    <p class="pagetext">&nbsp;</p>
    <p class="pageinput">{$hidden|default:''}{$hidden2|default:''}{$back}{$submit}{$cancel}</p>
  </div>
{$endform}

If you followed everything so far and i didn't have to much typos you should already be able to see a multiselect field with Content pages listed inside and you should also be able to save selected options for a user, but i assume you would like to see previously selected pages as well in case you need to edit a user.

To achieve this, go back to MenuManager and open "FEU_backend" template. All that is needed in that template is check against page id and selected values from FEU.
This is where {ldelim}$selected_pages{rdelim} variable that was assigned in copied FEU adduser2.tpl template comes in play.
To compare these values i used stristr PHP function as Smarty modifier.
Final outcome of the template looks like this: 

<select size='10' class='cms_select' name='m1_input_pages[]' multiple='multiple'>
{foreach from=$nodelist item=node}
    <option value='{$node->id}'{if $selected_pages|stristr:"`$node->id`"} selected{/if}>{$node->menutext}</option>
{/foreach}
</select>

Now when you would edit a FEU user you should see something like this.

Edit user

Putting it all together

So far Backend is prepared and ready for action but there is still some work left, as you need a logic that will check for logged in user and properties.
First thing to do now is prepare InlineEdit module.

TouchInline SettingsGo to "Extensions » TouchInlineEdit" and click on "Permissions" tab. From "Allow FEU" dropdown choose Yes and select appropriate FEU group from multiselect field below. Optionaly you can also allow CMSMS Admins to use FrontEnd editing, but in this case i chose not to.


Now open your Page Template that is used on your Website and edit the top section as following (example code is from default NCleanBlue template) :

{strip}{process_pagedata}
{FrontEndUsers form='silent' assign='FEU'} {* call FEU module, there is no need to actually assign it but in case you need more functions there is $FEU available as object *}

{/strip}<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
{* Change lang="en" to the language of your site *}
{* note: anything inside these are smarty comments, they will not show up in the page source *}
  <head>
    {cms_module module="touchInlineEdit"} {* call InlineEdit module *}
<!-- and so on -->  

These changes will provide us variables from FrontEndUsers Module and embed InlineEdit Module scripts when needed.
After you have done these changes go back to InlineEdit Module in CMSMS backend and edit  "touchInlineEdit.button" and "touchInlineEdit.nicedit.header" Templates in InlineEdit Templates tab.

Basically all you have to do is check if user is logged in and compare allowed pages against current content id as following:

{if (isset($userid) && isset($pages)) && ($pages|stristr:"`$content_id`")}
      <button class="P{$content_id} B{$tieCurrentBlock} touchInlineEditButton">{$tie->touch->get('feEditButtonText')}</button>
{/if}

Same with head Template

{if (isset($userid) && isset($pages)) && ($pages|stristr:"`$content_id`")}
<!-- {$tie->getName()} :: {$tie->plugin->displayName} module -->
<script src="{$tie->plugin->path}/js/{$tie->plugin->name}.js" type="text/javascript"></script>
{if $tie->plugin->get('jquery_load')}
<script src="{$tie->plugin->path}/js/jquery.js" type="text/javascript"></script>
{/if}
<script src="{$tie->touch->path}/js/touchInlineEdit.js" type="text/javascript"></script>
<script src="{$tie->plugin->path}/js/touchInlineEditInstance.js" type="text/javascript"></script>
<script type="text/javascript" charset="utf-8">
  {$tieExtraScript}
  var touchInlineEdit = new touchInlineEdit(
    {$tie->getContentId()},
    "{$tie->touch->getRequestUri()}",
    "{$tie->touch->get('feUpdateAlertMessage')}",
    {$tie->touch->get('feEditOnDblClick')}
  );
{foreach from=$tie->plugin->getSettings() key=name item=value}
  touchInlineEdit.setParam("{$name}","{$value}");
{/foreach}
</script>
<!-- {$tie->getName()} :: {$tie->plugin->displayName} module -->

{/if}

Thats it, almost ready. All you need now is Login Form from FEU Module and displaying a list of pages that logged in user may edit.
Adding a login form should be fairly straight forward, simply add {FrontEndUsers} where you want it to appear.
For example i used "Sidebar" in NCleanGrey Template: 


<div class="sbar-top">
              <h2 class="sbar-title">Login</h2>
</div>
            <div class="sbar-main">
              <div id="news">
              {FrontEndUsers}
              </div>
             </div>
<span class="sbar-bottom"> </span>

As a demo i have simply used "Logout" FEU Template to display pages that a logged in user may edit, so my Template looks like this:

{* logout form template *}
{if isset($message)}
<div class="message">{$message}</div>
{/if}

<p>{$prompt_loggedin}&nbsp;<strong>{$firstname} {$lastname}</strong></p>
<h3>Following pages are available for editing</h3>
<ul>{assign var='editable' value=','|explode:$pages}
{foreach from=$editable item='one'}
     <li>{cms_selflink page=$one}</li>
{/foreach}
</ul>
<p><a href="{$url_logout}" title="{$mod->Lang('info_logout')}">{$mod->Lang('logout')}</a></p>

After user has logged in, log in form will be replaced with content of the Template above.
As on top of Page Template {FrontEndUsers form='silent'} was used, there are FEU variables already available so {$firstname} and {$lastname} variables come from firstname and lastname user properties i created in FEU as well as {$pages} variable.
Because "pages" contains content id's in a comma separated list as a string you need to explode it first and then use each value as {cms_selflink}

Thats it, my outcome then looks like this.

Logout template 

There is one small disadvantage with this method, as Image filepicker doesn't work in FrontEnd but you could for example create another page where User could upload images or files by using Uploads module.
If you follow Adding Uploads Module categories dynamically post it should be fairly easy to connect both methods and then display available Files on another FEU enabled page or with some magic and imagination you could also use Ajax Tools or Xajax Tools plugins and load Uploads module fiellist with some fancy ajax. 

ALL-INKL.COM - Webhosting Server Hosting Domain Provider

Comments