Chiang Mai Trip - Back to Bangkok
Author: Scott Hadfield
Taken: 26 Sep 2011 - 6:12pm
You can also read my previous two posts on Chiang Mai.
Waking up to cool drops of water hitting my face may have been the nicest part of the trip. The day had been quite hot and the train was extremely humid. It was just past midnight so that meant I'd been sleeping for roughly 30 minutes. When I opened my eyes I noticed that the car was completely swarming with insects, primarily little gnats, mosquitos, dragon flies and crane flies. After being freezing cold in the A/C car on the way up to Chiang Mai I decided to travel 2nd class fan car not particularly thinking through the logistics of the situation. The lights are never turned off in the cars at night and at 30 degrees with 95% humidity all the windows were opened as wide as they go. As the sun began setting at around 6pm the insects started filling up the car. I loaded up with bug repellant but unfortunately that just caused the bugs to stick to the repellant.
It was then that I noticed it wasn't just droplets of water landing on my face, but also a few of the gnats had begun dying and falling onto me as well. I checked the time at it was now 12:10am... scheduled arrival was about 4:30am, but since the train was 4 hours delayed coming out of Chiang Mai I'd be looking at more like 8:30am.
The car I was in looked like it would have been beautiful when it was first built, wooden paneling throughout, upholstered separated seats. But over time the wood had begun to deteriorate, the ceiling fans were mostly rusted out and the grease had started to turn tar-like which didn't help, the upholstering on the seats were mostly warn through and probably about half the seats on the train were broken, either permanently fully reclined or just lopsided. Since the train was only a quarter full at best it was still comfortable enough for everyone.
Title: Chiang Mai to Bangkok 2nd class non-AC carAuthor: Scott Hadfield
Taken: 26 Sep 2011 - 9:33pm
(It looks much nicer in the picture than I described it. It really wasn't that bad and I'd gladly take it again if not for the insects :) ).
Of course I could have easily flown back to Bangkok, but I love trains and it's a great time to get some reading and raw thinking done. Kinda like in the bathroom, only longer and surrounded by more people. I've also been trying to travel more like locals travel in recent trips if possible. I was perfectly content with the state of the car, it was even a bit comforting. The Thai's on the train were extremely friendly and helpful too (I couldn't actually figure out how to open the window or rotate the seat when I boarded without their help :) ).
I've been trying to challenge myself to get out of my comfort zone a bit more recently and actually almost opted for the 3rd class car. When I noticed the number of cockroaches scurrying along the floor harvesting the insects that had missed me on their fall to death I had definitely been successful in escaping my comfort zone. All of the rest of the passengers had come prepared with shoes, socks, pants, jackets and towels to cover their face with. With my sandals, shorts and t-shirt, I definitely felt underprepared. I thought to myself I could just put a shirt over my face and try sleeping. Normally insects don't bother me, I'm one of those lucky people who never gets harassed by mosquitos. But, as Sam knows all too well, once the bugs hit a certain threshold I start to freak out. The average external observer would never notice this but my mind goes berserk at the thought of bugs crawling on me, particularly while I'm asleep.
No matter how hard I tried to focus I wasn't going to be sleeping that night. The inside of the train was a full swarm of bugs. I knew the sun would start rising at about 5am at which point the insects would either be mostly dead or have left and I decided I'd sleep then for a few hours before our arrival into Bangkok. I read my book and listened to music for the next few hours, covering up as much of my skin as possible and keeping my entire body and belongings off of the ground. At one point in the night I picked my bag up from the ground and a dozen or two roaches ran from underneath to find new cover.
Title: Dragon fly on the trainAuthor: Scott Hadfield
Taken: 26 Sep 2011 - 7:49pm
(I kept this guy close)
Around 2:30am a German guy stumbled through the train looking for someone to share his whisky with, as I was the only other white person on board he naturally decided to stop and harass me a bit. The offer was tempting, but adding a mini-hangover to my day didn't seem too appealing at the moment. We chatted for a minute until a Thai guy burst into our car and yelled at him in Thai, the only thing I could understand was "my whisky!" Apparently the German thought the Thai had left the train when he'd only gone to the toilet, dude had taken his whisky to find someone else to continue getting drunk with. Upon returning from the toilet the Thai was obviously upset to see that his booze had been taken, and now mostly finished. Fortunately the German offered to buy him another bottle and the friendship was immediately mended :).
The sun began to rise, and though the flying insects were now mostly dissipated and the cockroaches, mostly about 0.5-1.5cm in size had covered the floor cleaning the remaining insect carcasses. It was no matter though as they left me alone on my chair as long as I didn't lean against the wooden wall. The train had been stopped for about 30 minutes in what appeared to be the middle of a lake. The tracks were barely high enough to make it through the flooding that had been plaguing the country. I thought I remembered this area from the ride up north. I closed my eyes and fell asleep with my music still playing.
Title: Train stationAuthor: Scott Hadfield
Taken: 27 Sep 2011 - 11:35am
I woke up to people on the train talking far too loudly with each. Few people had been talking the previous evening and now, when I wanted to sleep it seemed like everyone had decided to pipe up.
It was 8am. I looked out the window and the train was still in the same place as when I closed my eyes. It hadn't moved. FUCK! I felt absolutely disgusting. My skin was covered in a layer of sweat, bug repellant, dead gnats, and a thin layer of dirt from the dust of the train tracks. I still had cell signal and decided to send a string of profanities to Sam. I was in a state of complete despair. I couldn't believe it, I was actually trapped. There was water surrounding us for miles, I couldn't have got out to find alternative transport if I'd wanted to. We were actually stopped at a rural train station which itself was now an island. The train wasn't moving and I had no idea when, or if, it would again. I was unable to communicate with anyone on the train enough to have any idea what was going on. But regardless, it was more likely than not that they had no idea either. Were they waiting for something? Could the train drive in reverse all the way back to Chiang Mai? I couldn't bear the thought of having to spend another night on that train. Everything on the train, myself, my bag, my seat, the floor, everything was covered in dead or mostly dead insects. I just wished the train would start moving, in any direction at all.
Title: Railway crossingAuthor: Scott Hadfield
Taken: 27 Sep 2011 - 11:25am
The railway crossing was the highest ground, so this is where everyone parked there cars in an attempt to keep them dry.
I looked up walking directions on my phone to Bangkok. We were 270km away, I could walk there in about 48h... seriously considered it. Normally I don't mind delays as I can just pop out my laptop and do some work, but my phone was almost dead and I needed the power to recharge my phone, my last connection to the outside world, which I felt I desperately needed at that moment. I chatted to sam for about an hour which mostly calmed me down. Then I decided to investigate a bit further and stepped off the train.
I couldn't believe my eyes... the train contained only 4 cars!! There were 14 when we left. The engine and 10 of the cars had continued on and just 4 were left behind. Now I was really confused, I could only assume it was due to the flooding and they were moving the cars across the worst part of the line in small sections. Who knows. The engine returned at about 10am and after going forward and backwards for about an hour a cargo train came by and we started moving forward. We were now up to 10h of pure delay on a trip that was only suppose to take 10h. I couldn't care less, we were moving again and it really started to seem like we were going to make it to Bangkok that day.
Title: Some weeds caught up under the trainAuthor: Scott Hadfield
Taken: 27 Sep 2011 - 11:18am
I was thankful again for the non-AC car as it meant fresh air and better photos since the windows could open. There were 5 fans in the car, 4 of which had seized overnight and 1 that barely spun. The lady who was sitting across from me kept farting and people were casually tossing trash into the newly formed lake outside of the train. The train was inching along, and though I could probably swim faster I was starting to feel in a much better headspace. We pulled into a train station that was like a mini-city on a mini-island. They must have been waiting there for at least 5h for the train.
Title: IMG_2221Author: Scott Hadfield
Taken: 27 Sep 2011 - 11:15am
The train finally arrived at about 5pm that day. If there's one thing I learned... 27h of train travel on a relatively hard bench is really hard on the ass!
Chiang Mai - Baan Chang Elephant Park
I let out a yell of joy as we swam down the rapids, having just jumped out of the raft on a relatively calmer part of the river. The scenery was unbelievable and we were swimming down a white water river nestled into a steep, lush, green valley in north west Thailand roughly 50 kilometres north of Chiang Mai and our trip was just about over. We'd ridden and bathed elephants, drank Thai whiskey, eaten sticky bamboo rice with the Mahouts (elephant trainers), swam in water falls, and now white water rafting back towards Chiang Mai.
Title: Bathing the elephantsAuthor: Scott Hadfield
Taken: 24 Sep 2011 - 2:12pm
Duane and I had made it up to Chiang Mai for a quick weekend side-trip, not totally sure what we were going to do when we got there but with some vague ideas. We found out about Baan Chang Elephant Park online after we arrived. We wanted to ensure we would be somewhere that the elephants were treated respectfully. Most places where you see elephant treks offered you can almost guarantee they're being poorly treated. Fortunately in the north of Thailand this is much more rare. Asian elephants live for 60-80 years and the mahouts are basically paired with an elephant for life. If your elephant moves to another park, you move with it. The day prior to our arrival one of the mahouts was ill and the elephant was so distraught she refused to do anything. There really appeared to be a loving relationship between each mahout and elephant. I didn't observe this kind of dynamic between elephants and guides anywhere else in Thailand.
Title: Me and Duane on our elephantAuthor: Scott Hadfield
Taken: 24 Sep 2011 - 1:09pm
The first thing we did after arriving at the camp was to feed each elephant a bunch of bananas. Each of us needed to feed each elephant so they could smell us and familiarize themselves with us. Apparently after they smell you once, they will remember you for at least 6 months (or was it 2 years?). Elephants are also one of the most intelligent animals on the planet, right next to dolphins.
Title: Holding on with our livesAuthor: Scott Hadfield
Taken: 24 Sep 2011 - 1:13pm
"Bai Bai Bai!!" our mahout yelled repeatedly ("go" in Thai). Our elephant was a bit touchy and had stopped to eat again. As much as the mahouts attempted to get her to move, she wasn't budging. Both Duane and I held on with our lives and wailed with laughter as she grabbed a branch of sugar cane with her trunk and yanked and swung her head. We were in the middle of a jungle, riding bareback on an elephant... two days into the side trip to Chiang Mai and it was turning out to be more amazing than I could have imagined.
Title: Muay Thai FighterAuthor: Scott Hadfield
Taken: 23 Sep 2011 - 9:27pm
The previous night we'd been out to watch a Muay Thai fight, and truth be told I think both our heads felt a bit like we'd actually partaken in the match. The Changover was in full effect. Fortunately it wore off quite quickly as soon as we got into the fresh air at the park. The entire area is lush green, tall grasses, bamboo, sugar cane, banana plantations, and mud everywhere else. The air was as fresh as anywhere I've been in Thailand, in spite of the fact that there was the excrement from a dozen elephants to take care of.
We were spending the night at the camp along with three girls from Paris who were also going rafting the next day. The cabins were partway up the side of the valley and had an amazing view over the mostly undisturbed rain forest. We spent the evening drinking Thai whiskey, releasing wish lanterns, and singing/playing songs around a camp fire. Most of the workers in that area of Thailand are Burmese and can't speak any English but after a few bottles of whiskey communication barriers mostly fall down.
Title: Lighting the wish lanternsAuthor: Scott Hadfield
Taken: 24 Sep 2011 - 8:10pm
Title: Nam way playing a song
Author: Scott Hadfield
Taken: 24 Sep 2011 - 10:27pm
The next morning we headed out for a 2h hike to a waterfall and natural pool followed by a river rafting trip down the Mae Tang river. Almost on queue as we climbed out of the water, the skies opened and it poured most of the way back to Chiang Mai.
Title: Heading back home in the rainAuthor: Scott Hadfield
Taken: 25 Sep 2011 - 2:49pm
I was heading back to Bangkok the following day on what I thought would be about a 10h train ride. Things didn't go quite as planned though...
Trip to Chiang Mai - Day 1
I wrote these posts on the trip to Chiang Mai, but just never got around to posting them. Part lazy, part shy, and part not totally how to approach the trip. I'm just trying out different styles of writing right now so hopefully I'm not too tedious :). There are two more yet to come covering my trip to northern Thailand.
Day 1:
My alarm clock was buzzing in my ear, I rolled over and shut it off. It was 6:30am and I needed to head out to catch the 8:30 train to Chiang Mai. Had a shower and packed my things and 15 minutes later I was on a tuk-tuk to the nearest metro station. I love the metro system in Bangkok, it's fast, clean, and efficient, more so than the metro systems in many other more "western" cities I've been to. I'm sure the fact that the "skytrain" was modeled after the bombardier version used in Vancouver gives me an unconscious comfort helps.
I checked my watch as I walked into the railway station.. 7:24, damn, could have slept for another half hour. I've been trying to speak a lot more Thai, so I'd already made the decision not to speak any English today. I walked up to the ticket station and asked "koh too-ah chee-ang mai pai" (can I have a ticket to Chiang Mai), he responded with a confused look and "Chiang Mai? Morning train? Six hundred eleven baht. Platform Ten. Car three.". I've gotten use to people responding in English, though most people seem to appreciate my attempts regardless.
After getting some snacks for the ride I found a seat on platform 10 and read a book while waiting for the train. The station was quiet. Midday Bangkok is a constant wall of heat, noise, and smells so this was actually quite refreshing. At 8 o'clock the speakers above my head started belting out a ridiculous high pitched racket, I soon realized it was synthesized church bells. Eight rings. After the bells finished the man next to me coughed, tossed his cigarette on the tracks and stood up. I noticed everyone had stood up.. there was a song playing, must be the Thai national anthem. I followed suit and stood as well. I was reminded of elementary school when we sang the national anthem every morning, though no one was singing here, most just looked a bit bored.
The train pulled in. It was bizarrely short. Three cars (including the engine). Well, who travels on a 12h train on a Thursday morning anyhow? There had been mass flooding in the north last week and these trains had been cancelled so I had some concern I wouldn't be able to get a ticket now that things had cleared. The train ended up being mostly empty. I found my seat and got comfortable. There were only Thai's with the exception of myself and a backpacker. The backpacker promptly passed out in her seat.
I had been looking forward to this trip for some time, getting to see another part of the country. I'd heard the north is suppose to be even more beautiful than the south. The train was nice. My armrest was broken and the seatback table in front of me had a piece of ribbon tied to it to prevent it from falling apart. The plastic on the arm rests had began deteriorating and my seat didn't appear to be screwed to the ground on one side. It was old, but it was more or less clean and still quite nice. The seat was comfy enough and reclined. So I got snuggled into my window seat with my eyes and camera ready for whatever may pass by.
Someone was shaking my knee... I abruptly woke to a stewardess offering me drinks. There were free drinks and snacks on this ride, hard to believe. So hard that I quickly grabbed my wallet to pay for the coke, at which she signalled at me to put it back away. I looked out and we were passing mostly "jungle" and bright green rice paddies. But the further north we went, the more water seemed to appear. We were maybe 200km north of bangkok, 500km south of chiang mai. These people had not been spared the flood water that ran down towards the ocean after the chiang mai flooding last week. We were driving through a lake, dotted with half drowned power lines and trees. Some houses were on stilts, but all that was left of many were corrugated steel roofs. I'd seen flooding like this on TV, but never in person. Many people paddled around in home made kayaks, their hands as their oars. Lots simply waded through the water. The railway tracks were like a magnet for everything living, people, shacks, ducks, cattle, boats, all moored up against the tracks which appeared to be the only dry land for miles. A few km's later the tracks themselves began to dip under water creating a small wake behind us. I picked my bag up off the floor, assuming that water would come pouring in at any moment :).
The scene repeated itself for the next several hundred km, slightly drying up the further north we drove. At noon the stewardess came through with our meal. It was some meat product, a bit of curried chili oil, and something battered on the middle of a dish of rice. I didn't know what it was, but it was good. Duane was probably eating his airplane meal at the same time on his flight up there. I'd be meeting him tonight, but I didn't think he'd be too keen on my no English policy ;).
At about 17:30 or so the sun began to set, we were going through a mountain pass. I noticed something move on the wall next to me... a cockroach had just climbed out of the wall, and a second was following it. As the night progressed more kept appearing, scurrying across the floor and walls. No one else in the car seemed to take notice or mind, I suppose they're just a part of life.
I exited the station expecting to be mauled by touts, but it was surprisingly quiet, the fact that all I had was a small laptop shoulder bag probably helped disguise me from the other tourists. I found a friendly tuk-tuk driver and heading into Chiang Mai. The driver had been living in Chiang Mai driving tuk-tuk's for 10 years.
I caught up with Duane and we headed out for some Thai food and beer and to plot our next few days in and around the city.
Last update from Thailand
Sam and I fly out tomorrow, so this will be my last update from Thailand! As sad as it is to be leaving, I'm definitely looking forward to seeing friends in South Africa again, spending some more time in our place in Cape Town, and planning for a Bloody Huge Party in March ;-).
Thailand really is an amazing country with a culture I've really come to respect. Almost all of the Thai people I've met have been extremely friendly and accommodating. There's always the few that will try to take advantage of tourists but they're definitely in the minority. And really, why not try and take advantage of tourists if you've got the chance ;-).
FloodingWith all our travels in the past few years we've always managed to avoid major political and environmental disasters. This has been the first trip where we got right in the middle of one. The Thai floods have been quite devastating to a lot of the country and a lot of peoples' livelihoods will be very negatively impacted by the flooding for years to come. One thing I haven't been able to wrap my head around is just how resilient the Thai people are. Imagine the water level being as high as the first floor of your house (or higher) and living in it for two months or more. This is what so many people in the country have to go through, wade or swim through disgusting water (where is sewage suppose to go?) to get anywhere and never being able to dry anything off. Damage caused to your house and business that you can do nothing about until the water finally decides to recede. It's a level of discomfort so foreign to me that I can't even comprehend it even after spending several hours in it myself while our train was stuck on the way to Bangkok.
Title: At least some are having a good time :)Author: Scott Hadfield
Taken: 27 Sep 2011 - 11:41am
Yet somehow most of the people there are able to move on and go on with their daily lives. Even smiling and enjoying themselves! And yet, in my 10+ hours stuck in it I was practically ready to arrange for a helicopter to come and pick me up just so I could get out of it and I wasn't even wet! (though all my clothes were due to my own stupidity). The water has apparently begun to recede now so hopefully it's not long before things are back to normal.
Thai LanguageMy Thai language learning went extremely well over the past month as I found someone to help me learn! He helped me with Thai, and in exchange, I gave him Drupal lessons so it worked out great! :). In the end I mostly accomplished my goals which were:
1. Be able to read thai script. My gauge for success with this goal was to be able to read a sentence of Thai that I'd never seen before to a native Thai speaker and have them actually understand it. In the end I was able to read a sentence, but it took me probably 3 minutes, and I'm certain was excruciatingly painful for Zak to listen to :). He also helped me with a couple of words.
2. Interact with a server at a restaurant. Though my vocabulary for food is extremely limited, I can mostly do this. I still struggle to understand responses from the servers.
3. Negotiate prices at a market. This is quite easy for me now. I've gotten quite good with my numbers and asking questions about products.
4. Be able to identify tones. This one is very challenging, and I could easily spend another three months on tones alone.
5. Initially I don't think I thought I'd be able to give an update on my blog in Thai. In the end I'm 50% there... I've written what I want to say, and recorded it, but I'm too embarrassed to put it online :). I realize the original goal was to make a fool of myself, but I just can bring myself to it yet. I'm simply reading my script in the video anyway, so it's not too interesting.
I'd say overall I was very successful, even better than I'd originally imagined. I also learned a lot about language learning and I believe that every language after this will be significantly easier for me.
The rest of the tripI haven't written a lot on this trip so far, I guess a lot of the time I've been either busy with work or busy being a tourist. I do have more to write about, and also some more photos to upload. Overall the trip was really awesome, and I hope it won't be long before we venture back for another stint in south east asia!
Custom steps and forms in a D7 install profile
In the last post I demonstrated creating a very basic install profile in Drupal 7. It was more or less a stripped down version of the standard profile with a few very minor additions.
I've been getting some great comments on my posts and one I wanted to note was from @david regarding the Profiler project. I've not had a chance to use it yet but it looks very promising. The profiler module provides an improved API and tools to vastly simplify what's necessary in writing your install profiles. While I would guess some more complex tasks still require you to use the raw Drupal API, this tool looks like it could give you a huge head start.
So, in the previous post, one of the additions I wanted to make but couldn't, was to create the default client user. The client name and email address will obviously differ on all sites we build. For this we need to add a new step in the install process to allow us to configure the client account prior to it's creation. All of the code from here on out will sit in our .profile file (recall that this is equivalent to a .module file, but for install profiles).
The first thing we need to do is define our profile tasks.
/** * Implements hook_install_tasks(). */ function brochure_install_tasks() { $tasks = array( 'brochure_client_form' => array( 'display_name' => st('Setup Client'), 'type' => 'form', ), ); return $tasks; }hook_install_tasks() allows us to create new steps in the install process. Each task more or less maps to a function in your .profile - in this case brochure_client_form. The display_name is used as the text displayed in the sidebar with the install profile steps as can be seen in the screenshot below.
If you're wondering about the st() function, it's basically equivalent to the t() function but used in a context where the localization system may not yet be available. You should generally use st() in your install profile where t() would normally be used.
Install profile tasks can be far more complex than what I've presented here and I'd strongly recommend reading through official documentation on install profiles or the API docs for hook_install_tasks().
The only other thing left to do here is to define our form API handler. This is done the same as any other Drupal module with _form(), _form_validate(), and _form_submit() functions inside your .profile file. There's nothing specific to install profiles here.
function brochure_client_form() { $form = array(); $form['intro'] = array( '#markup' => '<p>' . st('Setup your default client account below.') . '</p>', ); $form['client_name'] = array( '#type' => 'textfield', '#title' => st('Client Username'), '#required' => TRUE, ); $form['client_mail'] = array( '#type' => 'textfield', '#title' => st('Client E-mail Address'), '#required' => TRUE, ); $form['client_pass'] = array( '#type' => 'password', '#title' => st('Client Password'), ); $form['submit'] = array( '#type' => 'submit', '#value' => st('Continue'), ); return $form; } function brochure_client_form_validate($form, &$form_state) { if (!valid_email_address($form_state['values']['client_mail'])) { form_set_error('client_mail', st('Please enter a valid email address')); } } function brochure_client_form_submit($form, &$form_state) { $values = $form_state['values']; // Setup the user account array to programatically create a new user. $account = array( 'name' => $values['client_name'], 'pass' => !empty($values['client_pass']) ? $values['client_pass'] : user_password(), 'mail' => $values['client_mail'], 'status' => 1, 'init' => $values['client_mail'], ); $account = user_save(null, $account); // Assign the client to the "administrator" role. $role = user_role_load_by_name('administrator'); db_insert('users_roles') ->fields(array('uid' => $account->uid, 'rid' => $role->rid)) ->execute(); }By using tasks you have the ability to do some very customized stuff out of the box for your profile. Creating a client user and assigning a role to them (as done in this example) takes maybe 15 seconds to do for each site. If you create say 3 brochure client sites a month that's about 9 minutes of savings per year! That's enough time to take at least 2 showers!
A basic install profile
This is the second post in my series on install profiles. It covers the anatomy of an install profile and creating .install and .profile files. We create a simple brochure style install profile which is based on the standard D7 profile with a few customizations of my our own.
If you haven't already, take a look at my last post on install profiles and create the folder structure described there. Don't worry about the files as we'll create them in this post.
The folder structureFor reference, the structure will be as follows (I've added "libraries" since the last post):
profiles/brochure profiles/brochure/libraries profiles/brochure/modules profiles/brochure/modules/contrib profiles/brochure/modules/custom profiles/brochure/modules/features profiles/brochure/themesI've found splitting the modules up into the folders as shown here to work best while developing drupal sites. The contrib folder will store any contrib modules we use, the custom folder will be all custom modules we write (I also use this for contrib modules that I'm a maintainer of), and features will store any Drupal features that we create.
brochure.infoJust as with any theme or module we'll need to start with a .info file. Basing this off of the minimal.info we might have something such as:
name = Brochure description = Install a basic brochure style of website core = 7.x ; Core modules dependencies[] = block dependencies[] = dblog dependencies[] = field_ui dependencies[] = file dependencies[] = help dependencies[] = image dependencies[] = menu dependencies[] = number dependencies[] = options dependencies[] = path dependencies[] = taxonomy dependencies[] = toolbar dependencies[] = rdf ; Sub core modules dependencies[] = boxes dependencies[] = context dependencies[] = ctools dependencies[] = features dependencies[] = libraries dependencies[] = pathauto dependencies[] = strongarm dependencies[] = token dependencies[] = views ; Development tools dependencies[] = devel files[] = brochure.profileI personally prefer to split up my modules by an arbitrary category. In this case "sub core" modules are all of the modules that I tend to use on almost all of my sites, like views and ctools. I also generally will use certain modules during development that would be disabled when the site is ready to go live, like devel or even dblog.
I'm not sure the files[] = brochure.profile strictly needs to be defined here as that's normally used for defining files that contain classes, but since both minimal and standard do it, it's probably a good idea.
Download all of the contrib modules specified in the .info file above and drop them into profiles/brochure/modules/contrib/.
brochure.installAgain, the easiest thing to do here will be to base your custom
profile off of minimal.install (or standard.install). In fact, we want everything that the minimal.profile has so you can just copy that straight out and change "function minimal_install()" to "function brochure_install()".
The first part of the file defines the blocks to use on the site. For the moment there's no reason we can't just go with the default blocks.
function brochure_install() { // Enable some standard blocks. $default_theme = variable_get('theme_default', 'bartik'); $values = array( array( 'module' => 'system', 'delta' => 'main', 'theme' => $default_theme, 'status' => 1, ....The default theme being used is bartik, which again, is fine for the moment. As we're just going to be installing the site by hand (i.e. not using Aegir), we can just change that theme after install since each brochure site will likely have it's own custom theme.
Looking through the minimal install profile we can see that it defines the following blocks for display:
Module Block (delta) Region system main content user login sidebar_first system navigation sidebar_first system management sidebar_first system help helpIf you want to remove or add blocks just copy the way they've done it here. Of course, if you're using contexts and features this becomes unnecessary.
The next thing done in the .install is setting the variables and permissions, and that's about it.
The standard.install takes this stuff to the next level. It does the following:
- Defines filter formats
- Sets the default theme
- Sets up the blocks
- Creates two node types (page and article)
- Sets up RDF mappings
- Configures node options, comments, and user profile stuff
- Creates a taxonomy vocabulary called "tags"
- Creates and adds a taxonomy reference field to the article type
- Creates and adds an image field to the article type
- Sets up user role permissions
- Adds a main menu to the site
- Enables and sets a default administrative theme
Looking through the standard.profile the first time was a bit of overwhelming, particularly with the image field aspect of it (more so because at the time I had no experience with entities or fields). If you take some time going over the rest of the code you'll notice it's all actually quite straight forward module development stuff.
Building a complex install profile requires a very strong knowledge of the Drupal API or at least willingness to learn and spend hours in frustration banging your head on the table when things don't work (I have the bruises to show for it). However, if you're not a strong programmer but relatively comfortable working with features, in one of my next posts I'll try and demonstrate how to completely replace the standard.install using features, so you may find that much more enjoyable :).
Now as it turns out, the standard install profile already gives us the basics for a simple brochure style website! Who'd a thunk!? All we need to do is remove a couple things provided in there and add a few tricks of our own.
At this point, all I want is a few pages of text (i.e. a brochure) for the website. No blog necessary. So copy everything into brochure.install with the exception of the article node type and any fields added to it, the taxonomy field, the article specific rdf mapping, and the comment settings. Also remove the comment related permissions since comment isn't being installed in this profile either. If you don't remove the comment related permissions, your install profile will fail.
brochure.profileFor now we can simply copy minimal.profile (which is identical to standard.profile) and rename the function to start with brochure_ instead of profile_. All this is doing is setting the default site name on install form.
Additions to the install profileThere are still a number of customizations I'll want on a basic brochure site including:
- More customized initial install form.
- A WYSIWYG editor
- A customized set of shortcuts for the client
- Adding a client user account
- Roles for the client to use (content editor, for example)
When building an install profile in practice I will always start with a base site and then configure it as I want it to be. I add every single little configuration step back into the install profile as I go. For many of the configurations I want to do I need to browse through the core code to understand how components are added and updated. That's how I solved #3 below, for example.
1. When installing a new site you're presented with a form that you must fill in the site mail, account name and mail, country, and timezone. 95% of all of the sites I would build with a profile like this would have the exact same options on the initial install page, so why should I manually fill them in each time. The standard and minimal profiles automatically set the site name, but I'll take this one step further. In my brochure.profile I've added the following:
function brochure_form_install_configure_form_alter(&$form, $form_state) { // Pre-populate the site name and email address. $form['site_information']['site_name']['#default_value'] = $_SERVER['SERVER_NAME']; $form['site_information']['site_mail']['#default_value'] = 'admin@hatchwebstudio.com'; // Account information defaults $form['admin_account']['account']['name']['#default_value'] = 'admin'; $form['admin_account']['account']['mail']['#default_value'] = 'admin@hatchwebtudio.com'; // Date/time settings $form['server_settings']['site_default_country']['#default_value'] = 'CA'; $form['server_settings']['date_default_timezone']['#default_value'] = 'America/Vancouver'; // Unset the timezone detect stuff unset($form['server_settings']['date_default_timezone']['#attributes']['class']); // Only check for updates, no need for email notifications $form['update_notifications']['update_status_module']['#default_value'] = array(1); }The last item there changes the update settings so that I won't receive an email for security updates but a message will still be displayed on the site.
2. Adding a wysiwyg to the site is fairly simple. Install something like ckeditor to profiles/brochure/modules/contrib and download the ckeditor library to profiles/brochure/libraries. (Yes, we could use the wysiwyg module for this too, and in fact in practice that's probably what you should choose. However, wysiwyg profiles can be tedious to setup in install profiles and work to make them exportable in features is still underway http://drupal.org/node/624018).
dependencies[] = ckeditor
If you install the ckeditor 3rd party code into your libraries folder you'll also need to add the following line to your .install:
variable_set('ckeditor_path', 'profiles/brochure/libraries/ckeditor');
The reason you need to hardcode the ckeditor path is because ckeditor does not properly support librares (see this issue for more details). This means that it doesn't know to find libraries in profiles (and thus will never find your ckeditor 3rd party code). You could simply install the 3rd party code into the ckeditor module folder itself, but the "clean" way is to use libraries.
These kinds of problems are by no means unique to ckeditor and you'll more than likely run into them as you customize your profiles. Many modules will work perfectly fine until you want to use them in an install profile. The best way of getting around it is to find and fix the issue and submit a patch.
3. For my shortcuts I'll simply use the core shortcut module with an additions. I want to add a quicker way to add a new page from the shortcuts bar. I've added the following code to do just that into my .install.
module_load_include('inc', 'shortcut', 'shortcut.admin'); $shortcut_set = shortcut_set_load('shortcut-set-1'); $shortcut_link = array( 'link_title' => 'Add page', 'link_path' => 'node/add/page', 'menu_name' => $shortcut_set->set_name, ); shortcut_admin_add_link($shortcut_link, $shortcut_set, shortcut_max_slots()); shortcut_set_save($shortcut_set);Ensure this code goes after the page content type is created and after menu_rebuild() to ensure that the 'node/add/page' path exists.
4. For every brochure site I create I will need a client account, so I'd like to automate the creation of that as well. Unfortunately the client name and email address won't be identical between each site, so we'll need some user input for that. This will be a focus of the next post.
5. Though not strictly necessary for such a simple site, it makes sense to put our client into some sort of a role besides "authenticated user". This can be done in an identical manner to the way the 'administrator' role was created in standard.install.
$client_role = new stdClass(); $client_role->name = 'content editor'; $client_role->weight = 3; user_role_save($client_role); user_role_grant_permissions($client_role->rid, array('administer nodes', 'create url aliases', 'customize shortcut links', 'administer site configuration', 'access site in maintenance mode', 'view the administration theme', 'access site reports', 'block IP addresses', 'administer taxonomy', 'access toolbar', 'administer users'));My goal here isn't to lock out the client account, but instead remove obvious access to parts of the site that they won't need to use.
ConclusionWhen it comes down to it creating an install profile can be as simple or complicated as you want to get. The more complicated the more tedious it will become, but also the more you'll be able to do (and learn). Install profile skills translate right back into module development anyway.
Initially it may seem that unless you plan on creating dozens of sites under the same profile the ROI on building an install profile will not be high. However, as I'll get into later you can use the install profiles as a best practice to help with automating updates to your production site such that it will make sense even if you only ever have a single installation on your profile.
In the next post I'll write more about adding additional site customizations, additional steps, and forms directly into your install profile so that you will get a much more streamlined site out of the box.
AttachmentSize brochure.info_.txt786 bytes brochure.install.txt6.84 KB brochure.profile.txt1.06 KBAn overview of D7 install profiles
Yet another key component to the Drupal Platform is the install profile and it's another one that deserves a few posts to cover it adequately. The goal of this series of posts will be to build an install profile capable of creating a basic brochure-style website - more or less what WordPress's core functionality offers (ok, we'll be doing a bit less for this example ;-)).
Drupal 7 install profiles differ quite significantly from Drupal 6 install profiles so a lot of the material covered here won't necessarily apply if you're working on D6 only. There's already a lot of great documentation to help get you started. Drupal.org has an overview of install profiles that's worth taking a read through, for example. The Drupal documentation also covers all of the common hooks that you may want to use in your profile. But the best place, without question, is just reading through the Drupal core profile code (no, I'm not joking). Check out profiles/minimal, and profiles/standard folders that come with Drupal, particularly the .info, .profile, and the .install files.
To be upfront about things here, I've personally never built an install profile in Drupal 7 so this is a bit of a learning experience for me as well. I know that a lot of the limitations that existed in Drupal 6 have been solved so hopefully the process will be smoother. As always, if you notice anything I've done wrong or could do better please leave a comment as I want to promote best practices for building platforms.
There are a few differences between an installation profile that you'll run manually as you install Drupal (an option that would sit next to minimal or standard in the Drupal install process) versus an install profile to be used for automatically creating sites through Aegir. The primary difference is that an install profile to be used in Aegir should have no options that the user needs to fill out or answer. Defaults are important here. Any kind of setup that the user must do will need to be done after the site it created, not before, possibly with some sort of configuration wizard for this which I'll hopefully write more on later.
For this post I'm only going to run through a typical install profile as opposed to an Aegir-specific one which I'll write on later (and conveniently, can be much simpler than a standard profile).
Anatomy of an install profile:The initial setup for the install profile is quite trivial. All you need to do is create the folder and the files, and then list out the modules you wish to be enabled on site creation. Basically a combination of creating a new site in a multisite setup and creating a module.
Start with this folder structure in your D7 site:
profiles/brochure profiles/brochure/brochure.info profiles/brochure/brochure.install profiles/brochure/brochure.profile profiles/brochure/modules profiles/brochure/modules/contrib profiles/brochure/modules/custom profiles/brochure/modules/features profiles/brochure/themesAll the non-core modules used on your site will now go into the installation profiles' folder as opposed to sites/all. This isn't required, but will make your install profile more complete and is a good way to keep things organized.
.infoUnlike in D6 install profiles, you define the modules you want to install with your profile in the .info file as a dependency, just as you would with a standard drupal module. This makes install profiles much more consistent with how the rest of drupal packages work, and more importantly, makes our life easier.
.profileThe .profile file is equivalent to the .module file in a module or template.php in a theme. This is where you'll define any hooks required for your profile. Unlike Drupal 6, install profiles in Drupal 7 now have the privilege of running under a fully bootstrapped Drupal. This is a huge benefit, and makes the life of an install profile in D7 much more enjoyable than those poor D6 profiles.
.installThe tough part comes in the .install file. Take a look at the profiles/standard/standard.install file. It starts by defining and creating filter formats and then blocks. It also includes the creation of content types, fields, rdf mappings, roles, and menus.
The good news is that a huge percentage of this, the heavy lifting, can be removed by the use of features. For example, we don't need to create content types, fields, roles, menus, etc. by hand as they're all defined and created by the features we use on our site (see A simple feature for reference).
The bad news is that for more complex profiles you will need to get into the nitty gritty of the Drupal API. In some cases the install profile api (http://drupal.org/project/install_profile_api) can simplify things for you (at the time of writing there is not yet a D7 version), but for most things you should look at other install profiles for examples.
In my next post I'll demonstrate creating the skeleton of a basic profile based off of the Drupal minimal and standard profiles as well as a little pinch of our own special sauce.

