Wednesday, 2 September 2015

The New Lightning Experience, in New Trailhead modules!

As the new Lightning Experience begins to make bigger and bigger waves through the IT community, you know there is always going to be one piece of the platform way ahead of the game... Trailhead. No sooner had the Lightning Experience been announced, than they were announcing new modules, new points and new badges to be earnt - along with the kind of high quality, test-assured knowledge that Trailhead has become reknown for.

So with the introduction of three new super modules, it seemed kind of obvious which one I would throw myself at first.

Developer Trail - Lightning Experience ?

Admin Trail - Starting with Lightning Experience ?

Admin Trail - Migrating to Lightning Experience  ?

I'm going head first into the developer module. Though it must be noted I will absolutely continue on to complete the admin modules too, as it's all super relevant information.

Actually, the most exciting bit about these modules is.. they (currently) have a safe harbour statement.


You don't get much more wild than that, we really are trekkin' into unexplored territory. I best get my Trailblazer armour on in case we encounter any wild bugs.

So now I'm fully kitted out, lets do this module!

(by the way, if you think this post is long, it really did take me the full 8+ hours to work through this module. We ain't kidding around no more).

Starting with "Getting Started with the Salesforce Lightning Experience" - this is very much a module for totally new entrants to Salesforce, so I won't lie - I skimmed it a little bit, but even I was forced to stop every now and then and just absorb the screenshots of the new interface. It's really exciting taking in all the new buttons, layouts and "curvey borders" the Lightning Experience is bringing to the Salesforce front end.

Time for a test now though, not too challenging on this introduction module, but a couple of options that will make you smile.. such as what is the difference between Lightning and Classic: "One makes you shockingly productive, while the other remains classically amazing." - I personally think this is technically true, so chew that over when you are picking your option on the test!

Anyway, I nailed my 100 points. Obviously...

(I love how people actually tweet these boxes! #SoProud)


The next chapter "Deciding If Lightning Experience Is Right for You" is actually a really interesting for myself, as a developer on many different client orgs. This is a huge question for every developer, and every business currently on Salesforce. Of course, there is going to come a time when the Lightning Experience will have to be right for you, but at the moment, and for the foreseeable future, this is a decision you need to make yourself. If you want to know the pros-and-cons of the switch in a nice, concise (mostly tabular) format.. this module will teach you a lot of what you need to know. Issues such as Reports, Javascript and what will happen to your Visualforce and Apex are all accounted for here.

Once you have digested all the information, prove yourself once again with a quick exam at the bottom of the module. Remember, on the final question for adoption, you are looking for the RIGHT answer - not the one that will almost certainly happen in most businesses (confetti optional).


The final chapter of the developer track Introduction to Lightning Experience is how you actually enable it. Assuming the previous modules made you suitably excited, you'll need to know how to get your hands on it, and also the limitations (and incredible powers) you have regarding its roll out.

Preparing your org, and using the switcher is going to be a hectic day in anyones office, so being best prepared with the knowledge (and the gotchas) is going to be a good idea. Read this chapter carefully, pass the 2 question exam - and prepare the fanfare:


!!! BADGES !!!


And that, ladies and gentlemen is how we pass the basic module! We now know what Lightning Experience is, whether it is right for us, and if so, how to turn it on.

But the fun doesn't end there!

Next up,  Lightning Experience Development. I'm going to throw in right at the top of this chapter... that things get serious from here on in. No more joke answers about Windows 10 or Confetti, so put those reading glasses on and get learning fast. Just to prove this fact (and I did this just for you, reader)...

I got completely flumoxed by the first test and made a right mess of it.

#NowhereToHide

I don't even know why they put "Who hoo" on the 25 point DIV... *grump*


Moving through the Development module, you encounter a great (and honest) list of "what does work" and "what doesn't work". Salesforce have been really good here, putting their hand up when needed to admit some features are missing in this early release, and other areas where they have made technical descisions to cut access to client and server side features we may have previously depended on.. like access to the page global Window properites in Javascript - in favour of native Lightning library commands.

Next, we encounter Lighning Components - and their distinction from the Lightning Experience, before moving onto ISVs and Packaging, in which I think there is an interesting double negative hurdle in one of the test questions (but I am a part time Grammar Policeman).

The last chapter in this modle is Understanding the Changes to the other development tools (note, this is not about IDEs like I thought!) This module covers all the other considerations you didn't even realise you hadn't thought about - like existing packages, Apex API versions and so on. Upon completion of this module. You are a bad ass development ready Lightning brain.

The third module, is Using Visualforce in the Lightning Experience.There is a really curious question in the test for the first chapter in module, so pay attention to the material, and do a lot of scrolling up and down as you consider you answers! These modules really take you deep into the nuances of developing Visualforce in the new Lightning Experience. You thought you knew it all? Think again! I dropped points again on this chapter due to a (perhaps) cocky approach to the tests. Come on Simon, knuckle down!

Luckily for me, the next chapter on sharing the UX between the different experiences was fairly concise, and the questions directly (and with no double negatives!) related to the material. I'm back on the 100 points bus. Here, I found it interesting to learn that the UX a user has in their settings might also/still be affected by what browser (specifically, old browsers) they are using. Worth noting on that first support call to a government agent complaining their IE 4.0 "Lightning Experience" is a little more like drizzle.

The Navigating chapter tells us all about how we can move users about in the new UX. This chapter had my favourite pairing of questions - as the options were the same, making you directly realise the difference between the two modes, and also immediatly see the overlapping technology in the options applicable to both.

I blitzed through the last two modules on design considerations (which I genuinly always enjoy) and the intreging "Features to avoid" module, which very honestly highlights the problems with certain related lists, Javascript functions and Visualforce customisations that we may be used to, but that don't play nice with the Lightning Experience.

Time for another badge though! I can now use Visualforce in the Lightning Experience.

Are you still with me here? You're doing well!

The fourth module is a daunting 9 chapter one, estimated at 4 hours work - It's Lightning Components..This module has been around for a little while now, in the other Tracks, but it finally now has context! This is also where we are really getting into the guts of developing in the new Lightning world. The is also the end of the Multiple Choice tests, and now you are forced to connect you developer edition and actually make this stuff happen! By the end of this module, you can actually say "I have made a Lightning Component". You can lean back, be proud, and stick that badge on your chest like the medal it is, because everyone loves Lego™!!


As you stride into the fifth, and final module of this Trail, The Lightning Design System you might feel a little sad, but you probably feel more exhausted than anything else..  fear not though, the finish line is in sight. Here we introduce best practises for designing, and also examine how Salesforce bakes accesibility and responsive design into the component structure without you lifting a finger. We also look into BEM - and this is one of the few times I've actually been off and done the associated reading too - to find out about the cool CSS architecture that has been adopted.

Next we move onto Grids - and some terminology and design patterns that date back to the start of Computer Science itself, there is a reason these ideas have done so well though, so take your time to learn the basics of component layout work here.

By now your eyes are fully in code-reading mode, and that's good, because it's getting geekier and geekier in these modules, take a peak at the middle of the Salesforce Data chapter to see what I mean...


Ophh! Time to book that eye check ;)

What we are looking at here though is the new Salesforce data integration code though. What good is a sexy component if it can't interact with your Salesforce data?


The penultimate module is on introducing graphics and rich media into your components, and we even get to have a dig at Internet Explorer (oops, I may have given a hint to one of the answers there...). It's also nice to see that the author went that extra mile with their test data for the screen shots... I think I remember this account from the Developer Edition standard data records.

The final chapter, titled Laying out a Record Home Page and Using Advanced Components and with nothing less than a heading of "The Grand Finale" provides exactly what one would expect of such an EPIC trailhead module. It leads you down bringing all of the component work you have done over the last few hours (few, ha!) and you finally build a full and complete record home page for your Account objects. Look at it, beautiful:

Two more questions and you are done! Take that module badge with pride, go and tell your boss you are now a fully experienced "Lightning Component Developer", put it in your family newsletter, or even better - go get a tattoo*. (now that would be a first!)

If you really made it all the way to the end - drop me a tweet @srlawr - and I will give you an awesome shout out for your efforts!!


* don't get a tattoo...


Wednesday, 5 August 2015

Blazing away with Trailhead Event Monitoring

If you work with, or within Salesforce - and you don't live under a rock - you must by now be familiar with the revolutionary interactive training tool called TRAILHEAD. This gamified, dynamic, challenging and rewarding tool provides chapters of training material and automated testing tools to lead developers and admins through the new (and core) features of the Salesforce platform.


We have recently used Trailhead to onboard some new starters at Desynit, and they have been absolutely blown away by the quality of the material - and you know the best thing? New material is being published ALL THE TIME so even veterans of the Force like myself can keep learning, and scoring on Trailhead.

For one, I have just this very minute finished writing up my own Trailhead content which I hope will be delivered at Dreamforce 2015 in San Francisco, but besides myself and my fellow MVPs, the Trailhead team have just release three whole new modules for the world to complete.

These are:

Admin Trail - CRM

Dreamforce Trail with Get Ready for Dreamforce module

Event Monitoring module


I was personally particularly interested in the Event Monitoring module, a large part of my role these days is supporting and maintaining what are now considered large, and legacy Salesforce implementations, I spend a lot of time investigating and monitoring our client work for bugs and issues, and monitoring adoption and usage, so event monitoring is a big part of my life.

This module drew my attention to the fact that there are some cool new tools to assist me in this, and I am keen to get that "Sherlock Holmes" badge on my profile.

Here is the module overview - three lovely bitesize pieces of work to introduce me to this new world of sleuthing.



The first module "Getting Started" is exactly that - I immediately learnt a lot about the new logging features, and I'm immediately inspired to find out more about how I can use them in my day to day life. First though - I need to finish this module and pass the test. This is a multiple choice exam module (all the Event Monitoring modules are) so it's time to put my thinking hat on...

(if you are hoping for the answers here - think again!)


Boom. 100 points. This still gives me such a thrill as I stack up my score.

This module took me about 15 minutes, exactly as estimated on the dashboard.

Delving into the second module for Querying Event Log Files - you better be prepared for some slightly more hardcore questioning! (I'm not saying I got one wrong - but READ THE QUESTIONS CAREFULLY!). I learnt about using SOQL and the REST API to tug on my event information, and find out how we can monitor Logout events in my developer edition. This was a bit more of a technical module, and it appealed greatly to my developer side... A slightly quieter boom goes off as I earn another 50 points.

Finally - Downloading and Visualizing logs, took me a little longer than the 15 minutes, as there is quite a lot of material, so overall I would say this module took me just under an hour. Not bad for 250 points though (ahem) - and I get that badge on my profile!!


Wondering how to get started on Trailhead?

If getting into Trailhead is proving difficult for you, or you find these more advanced modules difficult or daunting - make sure you look into finding your local Developer User Group there are over 130 of them around the world, most meeting 6 - 12 times a year to talk about Salesforce, and the Force.com development experience.

I run the Developer User Group in Bristol - down in the South West of England, and in July 2015 we held a Trailhead Developer night. A dozen of us got together, opened up our laptops (and opened up some beer and pizza) and had a 3 hours blast at Trailhead, earning over 35,000 points between us in the night.


It was a great way to earn some points and badges, and we even got a little competitive and awarded cool "Trailhead Hoodies" to the highest achieving users. find your local DG and sign up to their next meetup here.



Friday, 12 December 2014

Happy Christmas!

Wow, it hardly seems like two years since Desynit produced our "Merry Christmas" video (which you can find on my Blog Post from 2012 here) but it has been. Since then, we've grown so much as a company we have had to move office. We now have our own meeting room, two front doors and "Mac" users in the company. Things are changing fast.


One thing that hasn't changed though is our creative, and fun brand promotion and marketing initiatives. It seems almost every week these days I'm "borrowed" from my desk to snap a quick picture, proof-read a blog post, or take part in some complicated stunt to help promote a tweet, user group event or any one of the many channels of activity Desynit are involved in.

Luckily, this year, our Christmas message was a little easier than donning the old itchy beard... all I had to do was give away a bottle of craft beer in fact! On the run in to Christmas (the last 12 working days) each of the team here is featuring in a social media post with a piece of seasonal technology advice, as a gift to the community. My top tip was for the best service "remember to shop small and local". I am a big advocate of using local businesses and services, and believe that knowing the people you are dealing with is really important. It's definitely something I advocate here at Desynit, always making sure to phone clients when needed/possible and make sure they are comfortable with their projects, and know the people behind the work - we're not just some factory churning out pages of code.

https://www.facebook.com/Desynit/photos/a.142715185831664.18297.114710818632101/529701483799697/

Anyway, if you are reading this, you are too late to win the bottle of beer - that went to Python developer Tom Blockley, from Team Rubber but you can still have a laugh at a "Elffed" up picture of me on the facebook post here.

So Happy Christmas everyone, I hope you have a prosperous 2015!

Tuesday, 23 September 2014

Service Cloud's Support.EmailTemplateSelector Example

A cool feature for Salesforce Service agents is being able to send e-mails back to customers directly from the Case Feed using the "Email" publisher action.

Using things like Auto-response rules and Quick Text allows agents to manage customer queries with incredible power and ease, but one case scenario I found that has come up a number of times is wanting to have almost case specific boiler plate text pre-filled in the e-mail, such as salutations and signatures.

It is definitely not uncommon to have more than one "product" or "channel" being managed through Service Cloud support cases, often by the same group of agents, changing their hats as different cases need attention, and so presenting the most appropriate Email Template for them to "fill in" as a response to a customer comes down to the "Enable Default Email Templates" feature..


This can be found and enabled in Setup > Customise > Cases > Support Settings towards the bottom.. but don't go over then enabling it just yet, as you need to do some ground work first.

Once enabled, this setting lets you use an Apex Class to determine which Email template you will use for this specific case. This literally throws the full power of Apex into the decision engine you are about to craft.

I am going to talk you through using this feature to deliver two different e-mail templates which can be used depending on whether a case was delivered to the system by email-to-case or web-to-case.. and this assumes you have configured these two channels to set the "Origin" of the case to Email and Web. In each case we want to salute the customer, thank them for engaging on the relevant channel and then sign off with a different help desk name. The middle of the e-mail will be left blank for the agent to fill in their response.

So

Step 1. Make the e-mail templates
I won't molly coddle you through this process. Go into Setup > Communication Templates > Email Templates and using your favourite format, folder structure and style, craft two different e-mail templates for your support staff. My Email support one looks like this:



Once you have them...

Step 2. Create your Apex Class
Now this really is the crux of it. You have to provide an Apex Class that implements the Support.EmailTemplateSelector interface, and implements the global method global ID getDefaultEmailTemplateId(ID caseId) in it. This returned ID is the template that will be placed into the Email box when a case is loaded into the Case Feed.

So here is where you can get complicated, there are examples using dozens of templates, custom objects and custom settings to determine what template to load, so go nuts! In this simple example though, I am going to use the Case Origin to load a relatively named template, or return null (which will just use the default email format).

This is all my class contains:

global class DefaultCaseEmailTemplates implements Support.EmailTemplateSelector {
 
    global ID getDefaultEmailTemplateId(ID caseId){
        // Load the relevant case details
        Case thisCase = [SELECT Origin FROM Case WHERE Id=:caseId];
        
        // Concatenate the "matching" support e-mail name
        String templateName = thisCase.Origin.replace(' ', '_') + '_Support';
                
        // Load the template Id by this name
        List emailTemplate = [SELECT id 
                              FROM EmailTemplate 
                              WHERE DeveloperName =  :templateName];
        
        // If we got one, return it, otherwise return null
        if (!emailTemplate.isEmpty()) {
            // return the template Id
            return emailTemplate.get(0).Id;
        } else {
            // returning null means the system just presents a blank response template
            return null;
        }
    }
}

And it is as simple as that for this case scenario. "Web" origin will load a template called "Web_Support" and "Email" Origin will load "Email_Support" - if the user wants to add more channels to the origin, they can do so, and either add a new template (with "_Support" at the end) or just let it fall to the default. Lovely.

Step 3. Test that class
Now, personally, I do test driven development, so this would be step 1.5 technically in this flow, but I have included it after the Apex Class, because I know how to keep an audience interested ;-)

Testing this class isn't too difficult, but there is a trick or two - due to some old friends such as setting up system objects and user records in the same context.  

(One short fall of this test class is that it requires a user in the System Administrator profile to be available... I personally consider that a given though)

Here is the simplest (single pass, positive scenario) test class for this. I suggest you augment this a little for your own implementation if you believe in good testing!

@isTest
public class DefaultCaseEmailTemplatesTest {

    @isTest
    static void LoadEmailTemplates_SuccesfulScenario_ReturnsTemplateId() {
 
        Id templateId;
    
        User thisUser = [SELECT Id FROM User WHERE profile.name ='System Administrator' LIMIT 1];
        System.runAs(thisUser) {
            templateId = insertTemplate();
        }
        
        Id caseId = insertCase();
        
        DefaultCaseEmailTemplates dcet = new DefaultCaseEmailTemplates();

        Id result = dcet.getDefaultEmailTemplateId(caseId);
        
        System.assertEquals(templateId, result);
        
    }

    private static Id insertTemplate() { 
  
        EmailTemplate emailTemplate = new EmailTemplate(DeveloperName='test', Name='test', FolderId=UserInfo.getUserId(), TemplateType='Text');
        insert emailTemplate;
        
        return emailTemplate.Id;
    }

    private static Id insertCase() {
 
        Case testCase = new Case(Origin='Email Just Ingredients');
        insert testCase;
        
        return testCase.Id;    
    }
}


Ahh. I love it when a test class ends up 10 times the length of the code it is testing!

Step 4. Enable this class
Now it is time to head back over to  Setup > Customise > Cases > Support Settings and set "Enable Default Email Templates" at this point it will ask for your class, so point it at it using the lookup box.,

Step 5. Test it out
Head over to your Case page, or Case Feed page, for a case that has one of the Origins you specified, and click to open the Email publisher action (if you don't have this action, you will have to Google how to do that! (hint: it's under Actions on the Page Layout Editor) - and if everything has gone right, you should see you e-mail template loaded into the box, ready to be completed!


If you load a case from a different origin, you will either get their adjusted template, or no template at all. Easy!

Now - go make that Apex Class over-complicated!

Wednesday, 13 August 2014

Why you should absolutely let your employees attend Dreamforce

Dreamforce, the Salesforce flagship annual event is slowly getting closer and closer, and no doubt if you employ Salesforce administrators, developers, or anyone who engages the platform on a regular basis, they are probably just itching to be able to attend.

Trouble is, it's a long event, a long way away (from anywhere that is not San Francisco) and not a cheap ticket... so how can you justify sending them?

You could use this "ROI of Dreamforce" calculator and it'll probably tell you your staff will be 28.3% more productive, or profitable, or something.. but if you want to really know why you should let your employees attend Dreamforce, here are a few hints..

They will absorb knowledge, inspiration and enthusiasm from some of the greatest minds on the planet. Entrepreneurs and world leaders, talking to a room of tens of thousands of delegates. They will see demonstrations of products and platform developments they can hear no where else on Earth at that time.

Your staff will high-five strangers mid presentation, and they will come back to work and they will high-five you.
Learning directly from their peers.. there are literally thousands of sessions going on at Dreamforce, the schedule planner is a heartbreaking exercise of realising there is only one of you to go to Dreamforce! You want to be everywhere. If you do choose to send people to Dreamforce, buy them extra notepads. Hell buy them iPads, and they will come back with more knowledge and tricks of the trade than they will get from a dozen "Pop up workshops" in awkward working lunch breaks...
Win a car! Why not. No-one leaves Dreamforce without at least some cool swag. I got some Dre.Beats Headphones last year, for winning a challenge.. a challenge which taught me a world about DocuSign. I have now implemented this in my working life a number of times, and would never have been as capable to if it wasn't for Dreamforce. DocuSign also gave me a hoody, so I even look like a bad-ass professional now too.

You want your staff looking like bad-ass professionals? Of course you do!
Memories. You know that sighing noise some people make at 5:15 when they realise there is still quarter of an hour to go in the day? We don't have that at Desynit, we do things like smiling, fist-bumps and sometimes Shaun does a handstand walk across the office. This is all because we get to share in the awesome experience that is Dreamforce, and every time we tell people about it, they say "Wow, where you work must be really cool"

And I just say "Hell yeah".

Be that boss.

Do not delay, get booked in and en route to Dreamforce today!

Why you should absolutely attend Dreamforce - For you

This is one of a pair of Blog posts, branded "for you" and "for your boss" - this is the "for you" edition.. "For your boss" can be found here:

Why you should absolutely let your employees attend Dreamforce

So why would you want to attend Dreamforce? Well, let me explain it to you with a couple of pictures...

Dreamforce turns downtown San Francisco into a technology playground. Every corner has a Salesforce flag, and almost every hotel can be dropped into to catch a session on Case Management, Community, Development, Certification and so on. You might think you'd get sick of seeing the logo at every turn, but trust me, you actually slowly fall in love with it.

You become literally surrounded in Salesforce knowledge and enthusiasm.

The bits of San Francisco that Dreamforce doesn't turn into a technology playground, it turns into a music festival! Metallica, RHCP, Green Day, Blonde, and this year Bruno Mars all rock out 40ft stages, with free food and drink at the Dreamforce gala, where you will make more friends and connections than any stuffy "Speed Networking" event at your local town hall...

Ever wondered why there is no heavily publicised "VIP" pass for Dreamforce? Everyone is a VIP!!

You will learn like, a thousand new things - and that is not hyperbole! Every corner, every desk, every wall is plastered in screens, books and projectors. If you can carry them, there is a library of workbooks and the latest Fundamentals up for grabs (whilst stocks last) and with three main stages in the Developer Zone, and about 8 break out rooms, there are more sessions and presentations going on that you could see in a month, let alone 4 days.
At my first Dreamforce I didn't leave the Developer Zone all conference!
Make your dreams come true, meet influential people, maybe meet some idiots who  make you feel better about how good you are at what you do(!!) but get on it and have a good time. If you try to attend every session in your schedule you will leave with a notepad full of notes. If you spend more time in the breakouts, you'll meet tonnes of amazing people (get a sweet photo with SaaSy) and STILL leave with a notepad full of notes, contacts and developer friends for life..

Your face will hurt from the smiling by the time you are on the plane home.

Do not delay, get booked in and en route to Dreamforce today!

Thursday, 24 July 2014

Adding a picture to a record in Salesforce

The concept of "Profile pictures" is pretty common these days, and default pictures of products or locations are standard fare for most CMS systems and websites. Getting a default picture displayed directly on a Salesforce record can be a little tricky. In this blog post I am going to talk through how I added my own, user manageable contact picture directly on the Contact record page (but you can re-purpose it however you like to other object types).

[Incidentally I am aware of Social-Contact settings, but more often than not this doesn't provide a "suitable" photo of a contact - my facebook picture certainly isn't! - and it only works for Accounts and Contacts of course]

Here is the goal we are after then:


You can see the cool picture associated with the Contact there, and a button to "Upload new photo". Lets walk through the other cool functions of this simple feature, and then I'll tell you how I did it (copy-pastas can just scroll down for the code snippets).

When you first create/arrive at a contact page without a picture, you are presented with this:


Clicking the "Upload photo" button presents this standard form:


Which in turn allows a user to select a local file and "Save" it to the Salesforce record. Now whenever they view the record, they will be presented with this photo, and a button to overwrite this file with a new photo, which takes them via the same form as above.

The process actually taken here is that the form uploads a file to the "Notes and Attachments" of the record, with a specific filename (set in the Controller). The controller is careful to make sure there is only ever one of these files (in the obscure case another file is added manually, the first is retrieved by the page, and next time the profile picture is updated, it will clear out all spurious files)


By doing this, we don't need any new "rich text fields" on our record, or indeed anything more complicated than a Visualforce snippet and Apex Controller extension.

The visualforce page:


<apex:page standardController="Contact" extensions="ContactPhotoUploadController" showHeader="false" standardStyleSheets="true" sidebar="false">

<apex:form id="contentForm">
<div style="height:170px;">
    <apex:pageBlock mode="maindetail">
    
        <apex:pageblocksection columns="1" rendered="{!displaying}">
            <apex:image height="150" value="{!URLFOR($Action.Attachment.Download, currentPicture)}" rendered="{!currentPicture != null}"/>
            <apex:outputPanel rendered="{!currentPicture == null}"><em>No picture currently available</em></apex:outputPanel>
        </apex:pageblocksection>
        
        <apex:pageblocksection columns="1" rendered="{! !displaying}">
            <p>Use the button to below to select a new file and then press "Save"</p>
            <apex:inputFile value="{!profilePicFile}" />
            <p>Or press Cancel to return.</p>
        </apex:pageBlockSection>
        
    </apex:pageBlock>
</div>
    <apex:commandButton value="Upload new photo" action="{!toggle}" rerender="contentForm" rendered="{!displaying && currentPicture!=null}"/>
    <apex:commandButton value="Upload photo" action="{!toggle}" rerender="contentForm" rendered="{!displaying && currentPicture==null}"/>
    <apex:commandButton value="Cancel" action="{!toggle}" rendered="{! !displaying}"/>
    <apex:commandButton value="Save" action="{!saveFile}" rendered="{! !displaying}"/>
</apex:form>
  
</apex:page>

This handles the display (or not) of the picture, form and relevant buttons.. and also sets the height that we will be working with (which is relevant when we come to add this to the page layout in a second).

Here is the controller extension that facilitates the uploading of the file and retrieving it when the page is loaded:
public with sharing class ContactPhotoUploadController {

    Private Static FINAL String fixedFileName = 'profilePhoto.jpg';

    public boolean displaying { get; set; }
    public Contact pageContact;
    public Blob profilePicFile { get; set; }
    public Id currentPicture { get; set; }
    
    /** Constructor, grab record, and check/load an existing photo */
    public ContactPhotoUploadController(ApexPages.StandardController controller) {
        pageContact = (Contact)controller.getRecord();
        
        List<attachment> currentPictures = [SELECT Id FROM Attachment WHERE parentId = :pageContact.Id AND name = :fixedFileName LIMIT 1];
        if(currentPictures.size() != 0) {
            currentPicture = currentPictures.get(0).Id;
        }
        
        displaying = true;
    }

    /** toggle switches between the photo display and photo upload form */
    public void toggle() {
        displaying = !displaying;
    }
    
    /** saveFile clears any existing profile picture, retrieves the data from the form, and saves it under the relevant filename*/
    Public Pagereference saveFile() {

        // first, we cannot have any conflicting files
        List<attachment> savedPicture = [SELECT Id, name, body FROM Attachment WHERE parentId = :pageContact.Id AND name = :fixedFileName];
        if(savedPicture.size() > 0) {
            delete savedPicture;
        }
       
        // Now, we save the new blob
        Attachment a = new Attachment(parentId = pageContact.Id, name = fixedFileName, body = profilePicFile);
        insert a;
        
        currentPicture = a.Id;
        
        displaying = true;
        return null;
    }
    

}

Once you have this basic Visualforce page up and running, all you need to do is go over and configure your Contact (in this case) Page Layout, and add the Visualforce page to the screen, and set it to a height of 30px greater than the style height of the div - this is to fit the buttons in underneath.



Boom, there you go, now users can add and edit a default photo on any kind of record page (you just need to tweak the controller to use the standard controller of another object).

Please note, in this blog post example I have neglected to address any kind of permissions or security considerations.. so remember if you decide to implement this to think about which users should be able to load, or upload photos to records. That's the kind of rich, useful developer love you would get from a Desynit based implementation ;-)

If you have any queries about this, or would like a complete implementation of this brought to your Salesforce org. Please don't hesitate to get in touch with me directly, or give Desynit a call and we can sort you out!