Forums / Setup & design / Personalised content

Personalised content

Author Message

Andy Woods

Sunday 13 March 2011 9:21:55 am

I would like to enable users who have logged into our web site the facility to select (from a form) which things interest them, ie. sport, music, dancing, drama etc.
I would then like to able to add event info to the site that can be categorised using the above topics ie. sport, music etc.

When the users log in they will be shown the events that match their interests.

Is there an extension that does this or can you tell me of a way that this can be done?

Thanks,

Andy

Benjamin Lorteau

Monday 14 March 2011 7:57:39 am

Hello Andy,

I don't recall any extension doing this, but I had already thought about such a system. Here's how I would do it :

  • Create full arborescence for every topic, each topic would have its folder and subtree in which you could categorize articles (even multi-categorize with multi-positioning) ;
  • Use the User Preferences to store user's choice of topic. You would probably have to create a custom view to store values efficiently ;
  • The frontpage would use the value(s) of the User Preferences and only show selected topics.

Using User Preferences allows caching display of frontpage for each possible choices, minimizing performance impact. You would have to modify INI setting CachedViewPreferences in ContentSettings group of site.ini file for this system to work. You can see an example in standard admin siteaccess site.ini settings.

eZ Publish personal project : http://www.aeriesguard.com [fr]

Marko Žmak

Thursday 17 March 2011 7:19:48 am

Another way to do it would be like this:

  • create the event categories as Benjamin described
  • modify the "User" class and add an "Object relations" attribute (note the plural of the attribnute type), let's call it "Subscribed categories"
  • allow users to modify their user object and create a template fo editing it where you create an interface for adding objects to "Subscribed categories" attribute
  • disable view caching for your frontpage (which is a common case anyway) and create cache blocks in the frontpage template for the parts where you present the events to the user. Use the categories node ids from the "Subscribed categories" attribute as keys for the cache block. Also set an expiration time for the cache block.

Both this and Benjamin's idea are valid solutions, which one suits you best depends on your specific case.

--
Nothing is impossible. Not if you can imagine it!

Hubert Farnsworth

Andy Woods

Thursday 17 March 2011 10:08:56 am

Thankyou for your replies - unfortunately I don't really understand what you're both suggesting.

I've tried to come up with my own solution which looks like this:
I've added 3 checkboxes to the ezcalendar event class. They are called:
sport
music
dance

I've added some events and selected one or more of each checkbox in each event.

I then added 3 checkboxes with the same names to the user class.

I am now trying to use 'fetch' to select calendar events that have checkbox values that match the user's checkbox values, ie. if a user has selected the sport checkbox it will only list events that have had the sport checkbox selected.

I would be extremely grateful if you could send me some code that would do this fetch.

Yours 'hopefully',

Andy

Marko Žmak

Monday 21 March 2011 2:52:04 am

"

Thankyou for your replies - unfortunately I don't really understand what you're both suggesting.

"

What we have suggested is to form the structure of your site like this:

- Events
  - Sport
  - Dance
  - Music

and then put the events in the appropriate category. But wether you should use this implementation depends on your specific needs...

"

I've tried to come up with my own solution which looks like this:
I've added 3 checkboxes to the ezcalendar event class. They are called:
sport
music
dance

"

Did you add this three checkboxes as 3 new attributes of did you use a Selection attribute?

"

I am now trying to use 'fetch' to select calendar events that have checkbox values that match the user's checkbox values, ie. if a user has selected the sport checkbox it will only list events that have had the sport checkbox selected.

"

Could you paste the code of your fetch?

--
Nothing is impossible. Not if you can imagine it!

Hubert Farnsworth

Andy Woods

Monday 21 March 2011 4:17:33 am

Hi Marko,

I simply added 3 standard checkboxes from the list of attributes in the Event and User class pages.

Here is the fetch code I was trying to use:

{def $attribute_filter = concat( 'array('event/sport', '=', '1')', ','array('event/music', '=', '1')' )
$nodes=fetch( 'content', 'list',
hash( 'parent_node_id', 111,
'sort_by', array( 'attribute', true(), 'event/from_time'),
'attribute_filter', array('or',
$attribute_filter
)

) )}
{foreach $nodes as $node}
{$node.name|wash}<br />
{/foreach}
{undef}

My plan was to dynamically build the $attribute_filter string based on the checkboxes the user has selected in their 'My profile' page. I'm not sure how to do this yet - but I assume it's possible.

I know that I haven't formed the $attribute_filter string properly because ez shows an error message when it gets to this line in the code.

I'd be very grateful if you were able to tell me how I could do both these things.

Thank you,

Andy

Marko Žmak

Monday 21 March 2011 5:29:43 am

"

Hi Marko,

I simply added 3 standard checkboxes from the list of attributes in the Event and User class pages.

"

That's not the right way to do it, for example if you want to add more categories you'll have to add more attributes, and adding attributes that are not really needed is bad practice.

You should use instead the "Selection" attribute where you can define as many values as you want all in one attribute.

"

Here is the fetch code I was trying to use:

{def $attribute_filter = concat( 'array('event/sport', '=', '1')', ','array('event/music', '=', '1')' )
$nodes=fetch( 'content', 'list',
hash( 'parent_node_id', 111,
'sort_by', array( 'attribute', true(), 'event/from_time'),
'attribute_filter', array('or',
$attribute_filter
)

) )}

"

There are several errors:

- you have put the array() declartion in quotes, so it will not be evaluated as an array buth as a sting containing the word "array" and the parenthesis etc.

- also you cannot put single quotes inside single quotes

- when filtering on checkbox attribute you have to compare it with true() of false()

So the right way to do it would be like this:

{def $attribute_filter=array(
  'or',
  array( 'event/sport', '=', true() ),
  array( 'event/music', '=', true() )
 )
}

{def $nodes=fetch( 'content', 'list',
 hash( 'parent_node_id', 111,
 'sort_by', array( 'attribute', true(), 'event/from_time'),
 'attribute_filter', $attribute_filter
))
}

So building the attribute filter out of the values in the user attribute can be done, but it has to be done right. When coding this part I suggest that you try {$attribute_filter|attribute(show)} to make sure that you got it right.

P.S. Note that attribute filtering can sometimes be really slow and have an impact on your site performance. So I suggest you to consider also the ideas that Benjamin and I gave...

--
Nothing is impossible. Not if you can imagine it!

Hubert Farnsworth

Andy Woods

Tuesday 22 March 2011 1:39:38 am

Hi Marko,

I'm going to use the method that Benjamin suggested to store the events, ie using folders and subtrees.

I'm also going to use the Selection attribute with multiple choices in the User page (that you suggested) so that the users can select which categories they like when they edit 'My Profile'.

However - I'm not sure how to determine which choices a user has made within the selection attribute. I'm also not sure how I would use this to build up the $attribute_filter string.

Would you be able to send me some sample code that would do this?

Thanks,

Andy

Marko Žmak

Tuesday 22 March 2011 2:47:37 am

Andy, if you're going to use the suggested method of storing events in different folders, tha I suggest that you use an "Object relations" attribute in the User class. So the User class will be connected via that attribute to the categories the user is following.

Also, using this approach, you won't be needing the attribute filter, you'll just have to fetch the events from the folder user is "subscribed" to (related to via the object relations attribute).

The fetch would go something like this:

{* get the nodes ids of the folders to which user object is related to. Let's say we store it in array variable $related_nodes_ids *}
 
{def $nodes=fetch( 'content', 'list',
 hash( 'parent_node_id', $related_nodes_ids,
 'sort_by', array( 'attribute', true(), 'event/from_time')
))
}

You get the picture?

--
Nothing is impossible. Not if you can imagine it!

Hubert Farnsworth

Andy Woods

Tuesday 22 March 2011 4:01:29 am

Hi Marko,

Thank you for your continued support - I really appreciate it.

I'm a very experienced PHP developer (10 years) but it's been hard trying to understand a new language and architecture. I find that if I can see 'worked examples' of code then I'm able to learn faster. Are there any links to sites that show worked examples of how to use the template language?

I don't fully understand how to create the 'Object Relations' attribute but I do understand how to use the 'Selection' attribute with multiple selections. So - I'd be happy to revert back to using the 'Checkboxes' in the Event class to categorise the event rather than using folders. However I could still do with knowing how to fetch which options the user has selected in their 'My Profile' and then forming the $attribute_filter string.

If you were able to send me an example of the fetch code that would enable me to form the $attribute_filter string I woudl be very grateful (again ;-).

Thank you,

Andy

Marko Žmak

Tuesday 22 March 2011 5:48:49 am

It's really not that hard to create an "Object relations" attribute, here's the docs:

  • http://doc.ez.no/eZ-Publish/Technical-manual/4.x/Reference/Datatypes/Object-relations

As for how to use it in templates, here's an example:

{def $current_user=fetch(user, current_user}
{def $user_object=$current_user.contentobject}

{def $related_nodes_ids=array()}

{foreach $user_object.data_map.subscribed_categories.content.relation_list as $relation_item}
 {set $related_nodes_ids=$related_nodes_ids|append($relation_item.node_id)}
{/foreach} 

{def $nodes=fetch( 'content', 'list',
 hash( 'parent_node_id', $related_nodes_ids,
 'sort_by', array( 'attribute', true(), 'event/from_time')
))
}

This is based on my proposed idea and the assumption that you have added to the User class the "Object relations" attribute with an identifier "subscribed_categories".

--
Nothing is impossible. Not if you can imagine it!

Hubert Farnsworth

Andy Woods

Tuesday 22 March 2011 12:23:08 pm

Thanks Marko,

I'll give it a try.

Andy

Andy Woods

Monday 04 April 2011 3:20:41 am

Hi Marko & Benjamin,

I've finally got round to looking at this again (now that I've finished my other project).

I've created the following structure:

/event calendar/
/sport
/event item
/music
/dance
/event item

where 'sport', 'music' and 'dance' are folders underneath the default 'event calendar' item.

I'd like to be able to display all the events in the event calendar but it only shows the events that are located directly within the 'event calendar' section.

Can you tell me how I can modify the fetch command to select events that are located in folders beneath 'event calendar' please?

I assume I need to modify the following:

$events=fetch( 'content', 'list', hash(
'parent_node_id', $event_node_id,
'sort_by', array( 'attribute', true(), 'event/from_time'),
'class_filter_type', 'include',
'class_filter_array', array( 'event' ),
'main_node_only', true(),
'attribute_filter',
array( 'or',
array( 'event/from_time', 'between', array( sum($first_ts,1), sub($last_ts,1) )),
array( 'event/to_time', 'between', array( sum($first_ts,1), sub($last_ts,1) )) )
))

Thanks,

Andy

Andy Woods

Monday 04 April 2011 5:01:49 am

Whilst waiting for some help on how to display 'all' the events in the sub-folders when browsing to the 'Event Calendar' I have just successfully got your code to work that displays the events that match the user's interests as specified using the Object relations" attribute in the User class!

Thank you very much for your help with that.

Andy

Marko Žmak

Monday 04 April 2011 6:09:51 am

"

Can you tell me how I can modify the fetch command to select events that are located in folders beneath 'event calendar' please?

I assume I need to modify the following:

$events=fetch( 'content', 'list', hash(
'parent_node_id', $event_node_id,
'sort_by', array( 'attribute', true(), 'event/from_time'),
'class_filter_type', 'include',
'class_filter_array', array( 'event' ),
'main_node_only', true(),
'attribute_filter',
array( 'or',
array( 'event/from_time', 'between', array( sum($first_ts,1), sub($last_ts,1) )),
array( 'event/to_time', 'between', array( sum($first_ts,1), sub($last_ts,1) )) )
))

"

You need to use content,tree fetch function instead of content,list if you want to fetch nodes from all levels. Here's the doc about both fetch functions:

  • http://doc.ez.no/eZ-Publish/Technical-manual/4.x/Reference/Modules/content/Fetch-functions/tree
  • http://doc.ez.no/eZ-Publish/Technical-manual/4.x/Reference/Modules/content/Fetch-functions/list

--
Nothing is impossible. Not if you can imagine it!

Hubert Farnsworth

Andy Woods

Monday 04 April 2011 9:33:45 am

Hi Marko,

Thanks - that worked fine for me.

Andy

Andy Woods

Monday 18 April 2011 11:36:47 am

Hi Marko,

My users are currently able to delect and de-select their "subscribed_categories" when they edit their Profile.

As you know from this page they're able to edit their various profile details such as First Name, Last Name, Password etc

I'd like to display a page that only displays their "subscribed_categories" with the facility to change them.

Can you tell me how I can do this please?

Thanks,

Andy