Jump to content
digitex

Stumped on two issues

Recommended Posts

Sorry, couldn't come up with a more descriptive subject.

I have built most of a site with processwire and I'm thrilled by the power of it but I've encountered two issues that I can't get my head around.

The site is a tourist accommodation site in which individual cottage owners list their properties for rent during tourist months. They all rent from Saturday to Saturday through the summer but start and end dates can vary. Each property owner edits and keeps track of availability on their individual sites where an availability table displays the period (e.g. September 17 to September 24) cost, deposit and whether it's booked or not.

Problem 1: each member edits their own info and I figure the owner role would be the best way to allow each member to edit only their page but how to set that up? Do I have to create the user account, log in under that name, set up the page for them? I'd like to be able to set a user as owner of a page but that doesn't seem possible.

Probem 2: How to set up availability? The booked or not booked is easy, a simple checkbox field would do but how can I set up a fieldset with a date range, cost, deposit cost and checkbox for if it's available and make it searchable? We need site visitors, looking for accommodation to be able to search a particular date range (September 17 to 24) and have all cottages with availability during the time period show up in search results. Of course there's also the fact that some cottage owners have multiple units available for rent.

Does any of this make sense and is there a way it can be done in a way that will be somewhat user friendly to property owners that are not computer savvy?

Any insight would be very appreciated.

Share this post


Link to post
Share on other sites

There are probably a hundred different approaches here. The truth is that unless you go out and buy a system designed specifically for owner online property and booking availability management, it's going to involve a lot of customization and code on your part. So I think that how you approach this in ProcessWire is probably not going to be all that different from how you'd approach it outside of ProcessWire (or in another platform). I think it would also be worth looking at full blown frameworks like CodeIgniter, CakePHP or one of the others too. But if you like the way ProcessWire handles everything else, then I think you'll find it to be a very solid foundation to build such features from.

Problem 1: each member edits their own info and I figure the owner role would be the best way to allow each member to edit only their page but how to set that up? Do I have to create the user account, log in under that name, set up the page for them? I'd like to be able to set a user as owner of a page but that doesn't seem possible.

With regard to an owner role for editing: there is no owner role in ProcessWire at present. Though the framework is in place to easily support one (and there used to be one in earlier versions). If you are seeing an owner role in your system, you may want to get the latest version of ProcessWire (2.1) as a lot has changed. But unless your site is very small scale and the owners are a trusted group of peers, I wouldn't suggest setting them up with admin account… you certainly could, but you no longer control the experience. And the experience in PW admin is tailored more towards general site management than a specific purpose like yours. Instead, it's better to give them forms on the front-end where you can tailor the experience to the need and control access. ProcessWire's API is designed for this usage and makes this sort of thing much easier. For instance, you might want to reserve some fields on your property page for you to manage, and others for the user to manage. You could have a page reference field to /processwire/access/users/ that would enable you to select what user(s) had access to change what pages.

<?php
// $page->owner is a page reference field you have added
if($page->owner->id == $user->id) {
    // user may edit 
    // output a form of just the fields you want them to edit and/or process them
} else {
    // user may not edit
}

The owner field doesn't necessarily need to be on the active page (like if you don't want to manage this stuff on a page-by-page basis). It could be on some parent. That's up to you to determine what access check works best for you.

Probem 2: How to set up availability? The booked or not booked is easy, a simple checkbox field would do but how can I set up a fieldset with a date range, cost, deposit cost and checkbox for if it's available and make it searchable? We need site visitors, looking for accommodation to be able to search a particular date range (September 17 to 24) and have all cottages with availability during the time period show up in search results. Of course there's also the fact that some cottage owners have multiple units available for rent.

The way I've accomplished this on other sites is to build a custom Fieldtype for managing rates. Unfortunately it's not code that I can share because I don't have permission to. But Fieldtypes that extend FieldtypeMulti are a great fit for this sort of need. PW supports Fieldtypes with any number of subfields, and in any quantity. This is one of the reasons (of many) why PW uses one table per field, rather than one table per template. Every subfield is automatically searchable by PW's selector engine (though you do want to choose the appropriate indexes in your DB schema to keep your searches fast). For an example, a selector to perform the search you inquired about might look like this:

<?php
$date_from = strtotime("10/10/2011");
$date_to = strtotime("10/24/2011"); 
$max_cost = 500; 
$cottages = $pages->find("rates.available=1, rates.date_from>=$date_from, rates.date_to<=$date_to, rates.cost<=$max_cost"); 

Of course, you can add in any other fields from your 'cottage' template to search at the same time.

As a good starting point, I would suggest looking at the existing FieldtypeMulti types, like FieldtypeComments and FieldtypeFile. These give some insight on how to structure a Fieldtype to carry more complex data types (with any number of subfields) in any quantity. If you are comfortable attempting a custom Fieldtype I'll be happy to help with any questions you have along the way.

  • Like 1

Share this post


Link to post
Share on other sites

Thanks for the reply Ryan. I am completely out of my comfort zone here. The idea about making the editable content a form is a good one. i will try to get that going.

As for the search, I think I understand what you're saying and I will see if I can get my frontal lobes around it. Not sure how to go about building a custom fieldtype but will look where you suggest and see what I can make of it.

Thanks again.

Share this post


Link to post
Share on other sites

I've completely failed. I have to stress I'm not a programmer, just a frontend developer. I can do enough PHP to configure the scripts and apps that others create and have been able to make processwire do some cool things but creating a custom fieldtype to allow property owners to maintain their own availability is way beyond me. I've been looking at different ways to do what I need for a month in between completing other work and I've gotten nowhere. I believe that if I can do a custom fieldtypemulti as Ryan suggests and populate it via a form that owners can access through a login that I'll be most of the way there but I need some kind of help. I don't even know where to begin.

Share this post


Link to post
Share on other sites

Digitex, you shouldn't feel bad about this and you shouldn't say that you failed. Creating things like custom availability/inventory management systems, custom booking engines, and property management tools are very programming oriented tasks. If you are wanting to do something that is by nature a very programming oriented task, and you are not a programmer, then it's going to be a challenge. While I'm certain you could figure it out with enough time, you always have to compare that relative to your own time and budget.

I suggest it would be good to hire a programmer to build this for your client. Or, you may be able to find an existing web service or system that can be adapted to your needs. But chances are that it ultimately comes down to putting in the time to code it the way you and your client want it. I would offer to help you more in this regard except that I'm under a non-compete agreement that crosses over with the tools you are wanting to build. However, there may be others here that you could hire to help build this.

Share this post


Link to post
Share on other sites

I've never before run into a situation in which I couldn't figure out the problem. Without delving into PHP and learning to program I doubt I have the skills to do what I need here even if the deadline wasn't looming. So I feel bad from that point of view. Can't help it.

I doubt a little cottage rental website in Ontario Canada is competition to your clients but I respect your ethical integrity in not wishing to violate your commitment to them Ryan. Thanks for your help on this.

Anyone else who might be interested, please post or PM me and I'll give you details for you to quote. This is a serious offer and time is becoming more of an issue. Thanks in advance.

Share this post


Link to post
Share on other sites

Digitex, I'd agree with Ryan, sounds like custom programming using 'pure' framework may well be best for that part of the functionality; and not to feel bad about it. A good friend of mine, Wayne at ChilliNut Software http://www.chillinut.com.au/about/ is a very good programmer and specialises in PHP booking systems - so might be worth making contact...

Share this post


Link to post
Share on other sites

Thanks Martin.

I have been thinking of this problem in terms of integrating it into processwire in order to make use of the current templates I built for displaying search results. In order to do that I think I would need a custom fieldtype to store dates, fees and the booked/not booked toggle. It seems, as you and Ryan have both suggested, I need to think instead of a completely separate system that I can include on the availability page. It would solve the problem of user/owner login and editing but would mean I need to rethink the search unless I can get processwire to handle the search with an independent booking system.

I will contact Wayne and reference your name by way of introduction if you don't mind.

Share this post


Link to post
Share on other sites

Yes, that's fine by me. I think he's planning on a longish trip to Europe soon so probably best to get in touch sooner rather than later, since PW can be bootstrapped into other scripts could still be you can look at a hybrid solution...

Share this post


Link to post
Share on other sites

Wayne declined. He said he might be able to do it if it was based in Wordpress but he didn't know processwire. Oh well.

I decided to go the bootstrap way. I found a booking system that uses the Smarty template system. It's very robust, far more so than I need or want but with the templates, which are html files I can include or exclude what I want.

Now of course I have a new problem. I think it needs a new thread.

Thanks for the help Martin and Ryan.

Share this post


Link to post
Share on other sites

Well, it's been almost a year since I posted in this thread. Yikes.

To keep things short, I ended up putting the site up using a 3rd party booking system to track availability for the members and it worked fine-ish and everyone was happy. The big problem was that it wasn't searchable in the way we wanted so I never really let it go. Once Repeater fields were introduced into processwire I came back to the site and built a user interface for members that allowed booking info to be stored in the database, making it searchable...with the right selector. Now my problem is:

The availability search, which I talked about in the first post of this thread mostly works. A user inputs a date range and it finds all pages with availability in that range, almost.

I have this:

$matches = $pages->find("template=property_availability, rental_period.date_from>=$fromvalue, rental_period.date_to<=$tovalue, rental_period.booked=1, include=hidden");

But it returns any page with booked=1 even when the date is not in the range searched. I've tried a number of things but so far nothing's worked.

I took the input value for both dates and used strtotime to convert to a timestamp but since the date value stored on the database is a string (11/22/2012) I think it's getting stumped. Can I use strtotime on the "rental_period.date_from" in the selector or filter the results after the find to weed out the out-of-range results or even store the date info as a timestamp?

Or am I missing something easy. I feel like I'm close and can finally put this one to bed.

Disregard that. Not working but not for reason stated above.

Share this post


Link to post
Share on other sites

Your selector looks good to me, assuming the repeater field is named rental_period. If it's not working, you may want to check what values you are providing to date_from and date_to, just to make sure they are either a unix timestamp or some other recognized date format string. Longer term, you'll probably want to be careful with repeaters for this particular purpose because it seems like quantities could grow quite large (over time) in terms of repeater items per property. You may want to setup an automated process to remove expired rental periods. I had a similar need when setting up a property availability system, but opted for a separate /properties/ and /reservations/ structure, where the /reservation/items each had page references to a /property/. So far this has worked well in the application where I'm using it.

Share this post


Link to post
Share on other sites

Hey Ryan.

Thanks for the feedback. The date input is done using a javascript pop up similar to the one built-in to pw and I made sure the the format matched the format stored in the repeater fields. The selector, at least that part, does work. When searching for dates outside the range, it returns no results found which is expected.

The only problem, which is killing me because it does seem like it should work and is the last part of the project, is that it returns any property with a booked status regardless of the date searched (if it's within the available range). My layman's theory is that it's not seeing each rental_period repeatable item as separate and is treating them as one. In other words "the dates are present and it says booked so it's valid" even though week 1 is booked and the date searched is week 8. Is that possible?

On the other point, I agree, we keep the repeater items contained. There's never more than 10 items per property and at the end of each season they are turned over to the 10 items for next season. What would you say is the upper limit for repeaters? I use them on another site and it's crossed my mind to wonder how many I can add before it becomes a problem.

Share this post


Link to post
Share on other sites
My layman's theory is that it's not seeing each rental_period repeatable item as separate and is treating them as one. In other words "the dates are present and it says booked so it's valid" even though week 1 is booked and the date searched is week 8. Is that possible?

Your theory is correct. When you search fields in a repeater, it is returning the pages that match, not the individual repeater items that match. So your search will be returning pages that have at least one of the repeater items matching your search. Once you've got one of those pages, you'd still need to determine which of the repeater items matched.

What you may want to do is aim to match the individual repeater items instead.

$matches = $pages->find("template=repeater_rental_period, date_from>=$fromvalue, date_to<=$tovalue, booked=1, include=all");

Then there's the question of how to determine which 'property' pages have the items you matched above. This is a relatively uncommon scenario, so I don't yet have a pretty solution for this. But you can determine the the property (as in real estate property) from each matching repeater item like this:

foreach($matches as $item) {
 $property = $pages->get((int) substr($item->parent->name, 9)); 
 if(!$property->viewable()) continue; // skip if property is unpublished or something
 // now you have the $property and the matching repeater $item
}

That solution comes via Soma, Diogo and Antti:

I'll come up with something built-in for this soon, but until then the above is probably the best way to go.

  • Like 1

Share this post


Link to post
Share on other sites

You guys keep taking me to school. Thanks Ryan. And also thanks to Soma, Diogo and Antti. :-* I haven't been following the repeater thread and should be I suppose.

This solution works great. I feel a lot lighter now. ^-^

  • Like 1

Share this post


Link to post
Share on other sites

Okay, now I'm nitpicking but here goes.

The solution above works great...unless someone searches for a date range of more than 1 week. The site does cottage rentals for 1 week at a time but on occasion a renter does a 2 week stay. If searching for e.g. 07/13/2013 to 07/27/2013 the search returns incorrect results again.

So, what would be easier: restricting searches to 1 week at a time which I can do with the popup calendar? or is there a way to adjust the selector or filter results to allow for a extended span of time?

Either would be ok with me but I have a pathological urge to try to be as thorough as possible.

Share this post


Link to post
Share on other sites

I'm not sure I understand the 1 week vs 2 week thing. It really shouldn't matter whether the range is days, weeks, months, years, etc. There are no 1-week dependencies that I can see in any of the code in this thread so far. You should be able to provide any date range in your selector.

$fromvalue ="2013-07-13"; 
$tovalue = "2013-07-27"; 

or

$fromvalue = strtotime("2013-07-13"); 
$tovalue = strtotime("+2 weeks", $fromvalue); 
I don't yet have a pretty solution for this.

Also wanted to add, I have a better solution for this now (on the latest commit to the dev branch). You can now do this, where $item is a repeater item:

$property = $item->getForPage(); 
  • Like 1

Share this post


Link to post
Share on other sites

OK. Then the problem is in my code somewhere or in my set up. I'm not using strtotime I'm just formatting the input value to match the date format stored on the database. It works when the search is confined to one, let's call it "rental term" (which is a 7 day period from saturday to saturday set up in the admin as a repeater with a start date, an end date and a status of booked: yes/no) but if the search encompasses two rental terms it returns a positive result even if only one of the rental terms is available in the date range when it should only return a positive result if both rental terms are available.

I don't know if I'm making sense. I have restricted the search to only one rental term but that may frustrate anyone who might be looking for a longer stay.

edit: BTW

$property = $item->getForPage(); 

great news!!

Share this post


Link to post
Share on other sites

@digitex: You may have a logical problem, if I've understood you right. Let's say you've got rental periods like this:

A1: 2013-01-05 ... 2013-01-12, cottage A, booked: 0
B1: 2013-01-05 ... 2013-01-12, cottage B, booked: 0
A2: 2013-01-12 ... 2013-01-19, cottage A, booked: 1
B2: 2013-01-12 ... 2013-01-19, cottage B, booked: 0

Now if you're targeting the repeater items with a selector like this (left some details out) "date_from>=$fromvalue, date_to<=$tovalue, booked=0" to find out which cottages are available from 2013-01-05 to 2013-01-19, you'd get items A1, B1 and B2. Then, using the method Ryan described in post #14 of this thread, it's easy to find those items correspond to cottages A and B. But this does not mean both of those cottages are available for the whole period, just like you're saying.

So, if the rental period (say 14 days) spans over more than one rental term (7 days), it's necessary to repeat the procedure for each of the terms individually and only then you're able to see which cottages appear in the results for all the terms. Combining all of the above, I'm suggesting something like this (haven't tested so no guarantees):

// rental terms of the desired period in a handy structure
$termsInPeriod = array(
 array(
   'start' => '2013-01-05',
   'end' => '2013-01-12'
 ),
 array(
   'start' => '2013-01-12',
   'end' => '2013-01-19'
 )
);

$cottages = array();
foreach($termsInPeriod as $term) {
 // find matches for this term
 $matches = $pages->find("template=repeater_rental_period, date_from>={$term['start']}, date_to<={$term['end']}, booked=0, include=all");

 // no matches this round --> no matches on the whole, no matter what may have been found before
 if(!count($matches)) {
   $cottages = array();
   break;
 }

 // array to hold found cottages for this term
 $termCottages = array();

 foreach($matches as $item) {
   $property = $pages->get((int) substr($item->parent->name, 9));
   if(!$property->viewable()) continue; // skip if property is unpublished or something

   // now you have the $property and the matching repeater $item
   $termCottages[] = $item->id;
 }

 // some results from previous rounds?
 // - yes, then find out common matches
 // - nope, first round --> use the results as is
 if(count($cottages)) $cottages = array_intersect($cottages, $termCottages);
 else $cottages = $termCottages;
}

In the end $cottages should hold all the cottages available for the given period. I'm using $item->id because of the array_intersect(). I'll leave it to you to form a structure like $termsInPeriod from your input - and probably this is fuel for your own thinking at most anyway. :)

  • Like 3

Share this post


Link to post
Share on other sites

Thanks Nik.

You've given me something new to wrap my head around.

I will give this a try and see what I can work out. Appreciate your help.

Share this post


Link to post
Share on other sites
$selector = 'template=chalet, fireplace=1';
$allresults = wire('pages')->find($selector);

$availability = $allresults->find("template=repeater_calendar, checkin=17.11.2013, booked=0, include=all");

foreach($availability as $item) {
  	$availability = $item->getForPage();
  	$content .= renderItem($availability);
}

Hello!

I try to find some repeater from another selector, but nothing happens. Find for repeater works fine, but not for $allresults (only for $pages). Can you tell what I'm doing wrong? 

Share this post


Link to post
Share on other sites

$allresults is a PageArray having Pages where "template=chalet" and "fireplace=1". There's no way a search with "template=repeater_calendar" could match that set, as the template is different.

I'm not sure I understand what you're trying to achieve exactly, but it looks like there's a little confusion between regular pages and repeater items (which are stored as pages as well). You could try and find the matching repeater items first (replace $allresults with wire('pages')) and then use only those matches that have the right properties for the page itself. If repeater "calendar" exists only in template "chalet" you'd only need to filter out those results where property "fireplace" does not match 1. And of course skip unpublished repeater items at once (see the code example in my previous post in this thread).

Hope this helps (if I even understood you right). :)

  • Like 2

Share this post


Link to post
Share on other sites

Nik, thanks for your clarification. I feel that two deferent templates in one selector is not good idea.

I tried another way, but it also return not correct result (without "booked" checking). 

$pa = $pages->find("template=property, calendar.checkin_1=16.11.2013, fireplace=1");
foreach ($pa as $p) {

    foreach($p->calendar->find('booked=0') as $r) {
        $r = $r->getForPage();
        $content .= renderItem($r);
    }

}

Using the occasion, I want to thank you for great "selector test" module. It's really helpful. 

Share this post


Link to post
Share on other sites

So does this

$p->calendar->find('booked=0')

Not returning correct results? What does it return? Or not anything at all?

Does the $pages->find return correct results?

Also wanted to note that $r->getForPage(); is returning what you already got with $p. The page the repeater is living on.

Share this post


Link to post
Share on other sites

So does this

$p->calendar->find('booked=0')

Not returning correct results? What does it return? Or not anything at all?

Does the $pages->find return correct results?

Also wanted to note that $r->getForPage(); is returning what you already got with $p. The page the repeater is living on.

As find result $pa=5773|5789 and this is correct. 

But $p->calendar->find('booked=0')  return r=5773 r=5773 r=5773 r=5789, that is $r — all entry of booked=0 in repeater, and I need only for select date.

Sorry for difficult explain. 

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.


  • Recently Browsing   0 members

    No registered users viewing this page.

×
×
  • Create New...