Web-To-Lead Verify Captcha

Do you have a web-to-lead form on your website? Do you get annoyed that people can still submit the form without verifying the captcha? Sure it looks like it went through, but no record are added to Salesforce. Which is good, but if an actual user submits a form and they just forgot the captcha, it’ll look like it went through to them, but nothing is created….

A good way to approach this is disable the submit button until the captcha is verified. Great! So how do we do that?

As is the answer to most dev questions these days…… JavaScript…..

Don’t worry, it’s very little JS, and we’ll even use jQuery to make it even simpler!

First, we should know that Google gives us a callback we can hook into for the captcha called data-callback. By passing it a function, we can call that function once the captcha returns.

Next, lets disable the submit button by adding disabled="disabled". The submit button should be close to the end of the generated form code:

<input disabled="disabled" class="submit-button-captcha" type="submit" name="submit">

This is what the captcha tag will look like when Salesforce generates a web-to-lead form:

<div data-sitekey="YOUR_SITE_KEY"></div><br>

Now, we just need to add the callback to it. We’re also going to add a class to it so we can target the element in JS:

<div class="g-recaptcha" data-sitekey="YOUR_SITE_KEY" data-callback="recaptcha_check"></div><br>

So far so good! Next up is the callback function itself. It’s very simple, just grab that submit button and remove disabled:

function recaptcha_check(){
    jQuery(".submit-button-captcha").removeAttr('disabled');
}

And that’s it! That JS function can either go in your /js/scripts.js or directly after the generated form code itself with <script></script> tags.

And some quick bonus tips for styling. We can target the disabled/enabled submit button in CSS. This is good if you want to grey out the text, or remove hover animations to help drive home that it’s disabled. The next couple of snippets are for example and the important part is the selector itself so you will know how to target it.

/* 
    only when enabled, pseudo selector :enabled 
*/
form input[type=submit]:enabled {
    border: 1px solid #00b7ea;
}

/* 
    lets scale the button up a touch and play with the background
    on hover ONLY when submit is enabled 
*/
form input[type=submit]:hover:enabled {
    transform: scale(1.1);
    background: #424242;
}

Sending and Testing Emails in Apex

Sometimes you just need to send a simple confirmation email to let users know something worked. Usually with some kind of contact form or job application form for example. Users also REALLY like to know what they sent worked and was received, which is where sending a simple email message from Apex will work just fine.

First, lets create the sending class and method

public class EmailSend {

    public static void sendEmail(String candidate){
        Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
        mail.setToAddresses(new String[]{candidate});
        mail.setReplyTo('hr_address@my_company.com');
        mail.setSubject('Thank You');

        // https://help.salesforce.com/articleView?id=000340122&type=1&mode=1
        // org-wide email address needs to be set
        OrgWideEmailAddress[] owea = [SELECT Id FROM OrgWideEmailAddress WHERE Address = 'hr_address@my_company.com'];
        if ( owea.size() > 0 ) {
            mail.setOrgWideEmailAddressId(owea.get(0).Id);
        }

        mail.setHtmlBody('<p>Your message has been recieved</p>');

        mail.setPlainTextBody('Your message has been recieved');

        Messaging.sendEmail(new Messaging.SingleEmailMessage[]{mail});
    }

}

Gist Link

Great! Now all we need to do to call this is pass it an email address we’re sending to.

EmailSend.sendEmail('contact@kbcarte.com');

To use this, I set an Organization-Wide email address. This is usually a catchall HR email address. And only really used for the From address.

Now, how do we test it? Great question! We’ll use governor limits. By getting the email invocations from the Limits class, we can check to make sure one was sent.

@isTest
public class TestEmailSend {
    @isTest
    static void testTheEmail(){
        Test.startTest();
            // the method we're testing
            // https://gist.github.com/techb/7519e95bac3caa2b8adb3f65d2dc2dc8
            EmailSend.sendEmail('test@test.com');
        
            // we assert buy what governor limits say 
            Integer invocations = Limits.getEmailInvocations();
        Test.stopTest();
        System.assertEquals(1, invocations, 'Email has not been sent');
    }
}

Gist Link

That wasn’t so bad was it? Now the send email method has 100% coverage and can be deployed.

Get Permission Set’s User email addresses

Have a need to get all the email addresses of users who are assigned a Permission Set?

It was something I ran into when needing to send emails from a Trigger.

Your use case is more than likley different, but here is a method to get a List<String> of email addresses by Permission Set.

To use the method, just pass in the API name of your PermSet:

Setup > Users > Permission Sets > [your permission set] > API Name in the top right. Ex: Expense_Approver_Final

// Get list of email addresses by Permission Set
public static List<String> getEmailByPermSet(String permsetname){
    List<Id> just_ids = new List<Id>();
    List<PermissionSetAssignment> users = [
        SELECT AssigneeId 
        FROM PermissionSetAssignment 
        WHERE PermissionSet.Name = :permsetname
    ];
    for(PermissionSetAssignment uid: users){
        just_ids.add(uid.AssigneeId);
    }

    List<String> just_email = new List<String>();
    List<User> email_list = [SELECT Email FROM User WHERE User.Id IN :just_ids];
    for(User usr: email_list){
        just_email.add(usr.Email);
    }

    return just_email;
}

Github Link

JS Array to CSV Download

Recently I was tasked with generating a CSV file using the data from a table. Normally I would do this in php where the actual data was coming from, but I didn’t see the need to go hacking around on the back-end when this could be done in JS after all the data was loaded. The data was loaded via AJAX, so it took a bit to populate.

The table also uses DataTables to make it pretty, sortable, and paged, but since it was paged I couldn’t just grab the data from the <td>’s. So instead I made an array, then pushed the ‘row’ data to it inside the ajax call. Once all the data is in, the download button appears and you get a CSV file.

Note: This is mostly pulled from a gist example, link is commented in the snippet below.

var csv_arr = [];
// add header first before pushing data
csv.push(["Bruh", "Data", "Date", "Ect"]);

// push some data, I did this inside the ajax call
// mentioned in the copy above
for(var i = 0; i <= somedata.length; i++){
    csv_arr.push(somedata[i]);
}

// found: https://gist.github.com/yangshun/01b81762e8d30f0d7f8f
document.querySelector("#muh_epic_button").addEventListener("click", function (){
    var csvString = csv_arr.join('\r\n'); // Windows newline
    var a = document.createElement('a');
    a.href = 'data:attachment/csv,' + csvString;
    a.target = '_blank';
    a.download = 'data.csv';
    document.body.appendChild(a);
    a.click();
});

GitHub Link

Colored CLI Feedback

I make quit a few command line apps to help with daily tasks. It helps to have meaningful feedback and reporting while these are running. Adding color helps with quickly identifying issues or just keeping quick tabs on the running scripts.

run = '\033[1;97m[~]\033[1;m'
bad = '\033[1;31m[-]\033[1;m'
good = '\033[1;32m[+]\033[1;m'
info = '\033[1;33m[!]\033[1;m'
que = '\033[1;34m[?]\033[1;m'

GitHub Link

These escape codes go well beyond just simple colors though. Check this link below for more CLI goodies.

http://www.lihaoyi.com/post/BuildyourownCommandLinewithANSIescapecodes.html

Add subdomains to Let’s Encrypt Certbot

If you already have a certificate issued from Let’s Encrypt for your current site, but added a new subdomain and want it to also use ssl, here is the command to do so.

Example:
current cert for -> example.com, www.example.com
new subdomain [no cert] -> dev.example.com

To add ssl with certbot to dev.example.com, run the following command.

certbot -d example.com,www.example.com,dev.example.com --expand

*Note that there are no spaces between the domain names and commas.

WordPress All Page Listings ShortCode

For when you need a list of all the pages on a WordPress website. Add this to functions.php and use the shortcode [page_listing] to a new Page. This will also create a CSV file in the theme’s directory so you can easily import it into a spreadsheet program like Google Sheets.

<?php 
function page_listing(){
    $pages = get_pages();
    $html = '<ul>';
    $csv_arr = array();
    $csv_arr[] = array("Title", "Permalink", "In Progress", "New/Revised Content Added", "Links Added and Tested", "SEO", "Hero Photo Placed/Cropped Appropriately", "Styling", "Needs Added to Navigation", "Reviewed by NAME (desktop/mobile)", "Reviewed by NAME/NAME", "Assigned to", "Notes", "Page needs to be deleted", "Final Notes Before Launch", "Reviewed by Dev Team");
    foreach($pages as $page){
        $html .= '<li>';
        $html .= $page->post_title .',   <a href="'.get_permalink($page->ID).'">'.get_permalink($page->ID).'</a>';
        $html .= '</li>';
        $csv_arr[] = array($page->post_title, get_permalink($page->ID));
    }
    $html .= '</ul>';
	$fp = fopen(get_template_directory().'/page_listings.csv', 'w');
    foreach($csv_arr as $row){
	    fputcsv($fp, $row);
    }
    fclose($fp);
    return $html;
}
add_shortcode("page_listing", 'page_listing');

GitHub Link

Python Check for 301 redirects

In web development, moving from staging to production servers, it’s useful to check that staging is pointing to production after the DNS changes.  Simple to check all urls if the site you’re working on only has few pages. A simple curl -I http://your.url.here.com will work just fine.

But what if you have a hundred or more pages to check? If I was paid by the hour, yeah I would copy/paste each url into a terminal and check, but I’m salary. So here’s a quick python script to check them for me.

You need to provide it a text file with all the urls on their own line. Easy if the urls are in a spread sheet, simple copy/paste into the text file and off to the races. This code will account for white-space and empty lines, however, it will not account for missing http/https prepends.  So far testing shows compatible with Python2 and Python3. Requires the requests library.

# requires requests lib
# - pip install requests
import requests
import sys
def redirectTest(url):
    with open("no_redirects.txt", "a") as no_redirect:
        try:
            r = requests.head(url, allow_redirects=False)
            if (r.status_code == 301):
                print("+ %s :: %d" % (url, r.status_code))
            else:
                print("- WARNING: %s :: %d" % (url, r.status_code))
                no_redirect.write("%s :: %d\n" % (url, r.status_code))
        except requests.exceptions.RequestException as e:
            print("! Error with request: %s :: %s" % (url, e))
def load_urls(urlfile):
    # clean urls of white space and remove empty lines
    # this does not prepend http/https to urls missing them
    clean_urls = []
    with open(urlfile) as f:
        urllist = f.readlines()
    for i in urllist:
        i = i.strip()
        if i:
            clean_urls.append(i)
    return (clean_urls)
args = sys.argv
if len(args) < 2:
    print("! Error: Missing arguments.\n\nUsage: python check301.py urls.txt")
else:
    try:
        l = load_urls(args[1])
        for i in l:
            redirectTest(i)
    except Exception as e:
        print("Something went wrong: %s" % e)

Feel free to change, modify, use, extend, and improve this code. You can find it on GitHub here.

This link will 301 to my About page.

Death of Adobe Flash and Falling Numbers

Adobe Flash has been around for a long time now. Back when the internet was lacking any real interactivity, Adobe stepped up to the plate with a solution. Flash had been almost a standard in the web ecosystem. With websites such as NewGrounds and other portals hosting seemingly exclusive Flash content created by users. Many game designers and media creators got their start with Flash.

Continue reading “Death of Adobe Flash and Falling Numbers”

Google adding engineers to WordPress development

At the beginning of February, an article was posted describing Google adding engineers to work on the WordPress core and ecosystem.

Google is looking to push for faster speeds for mobile across the web. Sounds good right? Well, to do this, it seems they are really pushing Accelerated Mobile Pages Project (AMP). While it has been shown an effective boost for mobile browsing, it also means that your content will be served on Googles network instead of your own.

There is a divide in what people are saying about this. While large companies and corporate people in charge are yelling it’s faster, they are only looking at that aspect of it, and not accounting for anything else. There are more and more people stating this is a bad thing.

Continue reading “Google adding engineers to WordPress development”