• Skip to main content
  • Skip to primary sidebar

Ani's Webdev Blog

A learning diary of website development

Blog

[HTML, CSS] Make a sticky announcement bar with Bootstrap

Task requirements

  • A Bootstrap-style announcement/information bar that is fixed to the top, including one text string and one button
  • Makes the button in the bar to become a link in mobile view

Create an announcement bar with Bootstrap alert class (HTML, CSS)

We can have an announcement bar in a few lines of code using Bootstrap’s dismissible alert class:

<div class="alert alert-warning alert-dismissible fade show" 
     role="alert">
  <strong>Here comes the content</strong>
  <button type="button" class="close" data-dismiss="alert" aria-label="Close">
    <span aria-hidden="true">×</span>
  </button>
</div>

Make the announcement bar to stick to the head of the web page

Method one: using Bootstrap’s “fixed-top” class

To make this sticky position, you can use “fixed-top” class by Bootstrap. However, the alert element will overlap with the content below. To prevent it to overlap with the next element, you can provide a margin.

First, add “fixed-top” class to the alert element:

<div class="alert alert-warning alert-dismissible fade show fixed-top" 
     role="alert">

Then, provide a margin:

margin-top: 80px;

This is not a good way because the margin is not a dynamic value. If the alert element is higher than the value provided, it will overlap again. But it is a fast method because it make advantages of Bootstrap and would fit nicely if you always know the height of the announcement bar.

Method two: using “position: sticky”

Another way to stick the bar to the head of the page is to use the “position: sticky” and then set the position of the bar in relation with the whole document so that when visitor scroll down the page, the bar will follow.

So let’s add our custom CSS class:

<div class="alert alert-warning alert-dismissible fade show announcement-top-bar" 
     role="alert">
.announcement-top-bar {
  position: -webkit-sticky;
  position: -moz-sticky;
  position: -ms-sticky;
  position: -o-sticky;
  position: sticky;
  top: 0;
}

Center the Bootstrap dismiss close button vertically

This is quite a small detail. As you might notice, the close (x) element of the alert class is not vertically centered. It only has a padding. This is perfect if you have only 1 line of information to show on the bar. But what if your bar has more text and the height increases? Then the close button is not centered anymore.

To make this vertically center no matter how high the bar is, simply use “transform: translate“.

.announcement-top-bar.alert-dismissible .close {
   top: 50%;
   transform: translateY(-55%);
}

Make the button to become a link in mobile view

This is another small thing that does not need to be done on every project. But I prefer the info bar to look a bit cleaner on mobile devices and so I would like to replace the button with a simple link.

So the way to do it: have in the html both link and button. By default hide the link and display the button. Hide the button and display the link in the mobile view.

This is a quite ugly method but it works and does not take much time to implement. With Bootstrap it is very easy to do using .d-none and .d-block.

<div class="alert alert-primary fade show announcement-top-bar d-none d-md-block" 
     role="alert">
  <strong>Here comes the content</strong>
  <button type="button" class="close" data-dismiss="alert" aria-label="Close">
    <span aria-hidden="true">×</span>
  </button>
 </div>

.announcement-top-bar p {
  margin: 0;
}

Code and result

reCaptcha v3: How to implement on WordPress custom forms to stop bot signups

Including reCaptcha as a security layer is one way to fight against bots. In this article, let’s discuss how to implement reCaptcha v3 on a custom forms. Also, we will take a look what are the differences among the reCaptcha versions.

Task description

  • Install reCaptcha v3 in the page only where there is a registration form. The form includes fields such as name, website url, email, text areas, a selection field, phone number field which have some basic jQuery validation.
  • Test if the reCaptcha is installed correctly.

By installing the reCaptcha only when there is the form that needs to be checked, we save time and http request for a better performance.

I think this is a good habit for WordPress users to remove unnecessary things because as you might notice, whenever installing a new plugin, more or less there will be custom js and css files to load with your page not care about does the page needs it or not, which increases the http requests and makes the website slowlier.

We will need a Site Key and a Secret Key to use the reCaptcha. This is free to setup and retrieve so you can go to the dashboard and register your website here. After that you can have 1 Site Key and 1 Secret Key.

recaptcha site keys and secret keys

reCaptcha v2 and v3: What are the differences?

Which types of reCaptcha to choose from? What are their differences?

So when registering a new domain name, you will be asked to choose the type of reCaptcha to be implemented. Most of the time I was confusing with reCaptcha v3, and reCaptcha v2: I’m not a robot and Invisible reCaptcha badge. Let’s have a quick look how they are different.

recaptcha types

Some images of reCaptcha.

google early captcha
The early captcha which brings about bad user experiences.
I'm not a robot
The common “I’m not a robot” reCaptcha which can be seen in many websites nowadays.
recaptcha challenges
reCaptcha v2 I’m not a robot extra challenges.

So basically:

  • reCaptcha v3 does not require users to do anything themselves, but instead give a score based on their behavior with the web page. The lower the score, the higher the possibility it is a bot.
  • reCaptcha v2 sometimes let user pass without doing anything, or with checking the box “I’m not a robot”, sometimes ask for extra puzzle solving.
  • With reCaptcha v2, if the system suspects that you are a bot, you still can prove that you are human with extra challenges e.g image selection.
  • With reCaptcha v3, if you are not a bot and google thinks you are a bot, you can’t do anything. But, this strictness level can be customized with a lower threshold score.
v3 - Invisible reCaptchav2- I'm not a robotv2- Invisible Badge
How it worksObserves user behaviors and interactions with the page and then return a score reflecting how likely this user is a bot or human.Requires user to click a checkbox to verify that he / she is not bot. It will give extra puzzle to solve in case of suspection.Invokes when user clicks on an existing button or via Javascript API call. It will give extra puzzle to solve in case of suspection.
Extra challenges in case of suspectionNot naturally, but developers can suggest an action for the user based on the score returns.YesYes
Requires user to click on checkboxNoYesNo
Returns valuea json object including scores and success (true | false)NoNo
Further actions can be implemented based on the validationYesNoYes
Shows a reCaptcha badge on your websiteYesNo, only display the checkbox.Yes
Requires a JavaScript callbackNoNoYes

Implementing reCaptcha v3 on WordPress

There are two ways that the reCaptcha can be implemented on WordPress: using a plugin or code it yourself.

Using plugin: Invisible reCaptcha for WordPress

Notice: Some form plugins for WordPress already have the reCaptcha integration, so if you only want for e.g Contact Form 7 you don’t need to download any extra plugin because the form itself will let you paste in the Site Key and Secret Key for spam prevention.

For Gravity Forms, Contact Form 7, WooCommerce or common WordPress forms like login or register, you can have a look at Invisible reCaptcha for WordPress by Mihai Chelaru. The plugin has quite straightforward instructions on how to implement the invisible reCaptcha on WordPress.

So if you have many forms and want a quick way to do this, then just go ahead and download the plugin, then go to the Settings and input your Site Key and Secret Key and you’re ready to go.

It is easy if you want to integrate it with Contact Form 7, or Gravity Forms as you only need to tick the buttons in the plugin’s settings page. But if you would like to have it on a custom form which is custom coded, there are some hooks that you can use, as reference from the plugin developer. For basic setup, we can use the google_invre_render_widget_action action and google_invre_is_valid_request_filter.

So to the theme’s functions.php:

function add_recaptcha() {
    // Only place the script where we need it
    if(!is_single('new')) return; 
    do_action('google_invre_render_widget_action');
}
/** 
 * Validate with Invisible reCaptcha
 * Returns bool
 */
function recaptcha_validate() {
    $is_valid = apply_filters('google_invre_is_valid_request_filter', true);
    return $is_valid;
}

On the HTML page template of the form, add this before the </form> closing tag:

<?php add_recaptcha(); ?>

Alternatively, you also can add the code straight to the page template before the form closing tag. This is a faster way to do and also ensures that you only have the code on the form page.

do_action('google_invre_render_widget_action');

If doing it correctly we can see the reCaptcha badge on the form page, bottom right. Then, in the PHP processing file, validate the form with recaptcha before processing it.

if ( !recaptcha_validate() ) {
    http_response_code(400);
    echo 'Spam check fails. Please contact us.';
    exit;
}
// continue to retrieve and process data

Depending on your structure it might look different, but in a nutshell what we have to do:

  • Call do_action(‘google_invre_render_widget_action’); to add the recaptcha possibility to the form.
  • Write a function with google_invre_is_valid_request_filter to check if the form return is not submitted by a bot.

So hope it helps. I did not process far with this setup because it has conflicts with jQuery validation, where the form submitted with only reCaptcha validation and ignore other validation. So I switch to the code solution.

Without plugin: reCaptcha v3 with PHP and Javascript

The steps are quite similar as to use the plugin. Basically what we need to do is:

  • Add a reCaptcha token to the form
  • Check with Google if the form submission looks legit, based on the token
  • Refuse or pass based on the result that Google returns

Add reCaptcha token to the form

Let’s add a hidden field before the form closing tag:

<input type="hidden" name="token" id="token">

Next, add the value of the form to be equal to the token that is provided by the reCaptcha. We will do it with this piece of javascript, as instructions on the reCaptcha docs:

<script src='https://www.google.com/recaptcha/api.js?render=_reCAPTCHA_site_key={KEY}</script>
<script>
function() {
    grecaptcha.execute('_reCAPTCHA_site_key_', {
        action: 'homepage'}).then(function(token) {
            document.getElementById('token').value = token; 
        });
    });
}
</script>

If doing it correctly we can see the reCaptcha badge on the form page, bottom right.

recaptcha badge
The reCaptcha badge.

Now if you inspect the hidden field with the browser console, you can see a string of token attached to it. This string will change everytime the form loads.

recaptcha token string
A string of token.

Check with Google if the form submission looks legit, based on the token

Depending on your file structure, you can write this as a private function in a class or if you do not have any structure, you can paste this to your functions.php.

Google will return with a json object.

'success': true|false, // whether this request was a valid reCAPTCHA token for your site
'score': number, // the score for this request (0.0 - 1.0)
'action': string, // the action name for this request (important to verify)
'challenge_ts': timestamp, // timestamp of the challenge load (ISO format yyyy-MM-dd'T'HH:mm:ssZZ)
'hostname': string, // the hostname of the site where the reCAPTCHA was solved
'error-codes': [...] // optional

Because we only need to check is it legit or not, let’s just take the “success”. So it will return true or false, and we based on that to continue processing the form or to stop.

function recaptcha_check() {
    if( !isset($token) )) return false;
    $siteverify = 'https://www.google.com/recaptcha/api/siteverify';
    $response = file_get_contents($siteverify . '?secret=' _YOUR_SECRET_KEY_ . '&response=' .  $token);
    $response = json_decode($response, true);
    return $response['success'];
}

Validate before processing the form:

if ( !recaptcha_validate($_POST['token'] ) ) {
    http_response_code(400);
    echo 'Spam check fails. Please contact us.';
    exit;
}
// continue to retrieve and process data

[CSS] Make equal-height Bootstrap columns and vertically align content with Flexbox

Task description

  • Make columns in a row from Bootstrap to have equal height no matter how much content is inside.
  • Make a CSS class so that this equal-height element can be reuse throughout the project on different rows.
  • Center the content in the columns vertically.

How to do it

Create a CSS class for the equal-height columns

Let’s call our class .equal-height-row, and it should be applied to a row in which the columns should be of equal height. Using Flexbox, it is quite simple to do.

Brief intro about Flexbox

What is Flexbox and why use it?

So earlier front-end people have difficulties in structuring a page layout with pure CSS. The most common method is using tables or float but it is not the optimal way to do it. Basically Flexbox is a CSS layout module to help better and easier positioning the element within a webpage with ease.

Which browser supports Flexbox?

Most common browsers such as Firefox, Chrome, Opera, Safari, etc. supports Flexbox. Internet Explorer 9 and below does not.

How to use Flexbox?

In this post I’ll show you how to use Flexbox to make the columns of equal height and vertically center it. But for further understanding, check this guide.

Code

Please notice that the columns will collapse at sm breakpoint (576px), so if you see the JSFiddle result, make sure you have correct view size to see them line up in one row.

Result: see in JSFiddle.

[PHP] Get rid of multi-layered if-else nested conditions

So I used to write codes like this:

if(condition1) {
    if(condition2) {
        if(condition3) {
            // some tasks that are overwritten everywhere
        } else {
        }
    } else {
    }
}

And it is not only 3 layers, but many!

What are the issues of doing like this?

  • Hard to follow: Huge blocks of code is very difficult to read.
  • Difficult to maintain: After a time when coming back to the project again, I would not remember what I did because logic and functions overlapping each other everywhere. When I want to modify something or add new features it seems to be impossible.
  • Looks really bad and stressful: Every time looking at this code I just want to ignore everything and go to sleep.

Here are some ways to fix this:

Write tasks into functions

Each tasks can be written into a function. This prevents code duplication and easy to follow what tasks are called in which conditions.

So the key point here is not to over-complicate your functions. Each function should only do one task, whether to validate or to get information.

No need to include “else” all the time

Just get rid of them to have peace of mind if you don’t know what to do in the else case.

Returns early

Returns when the conditions do not match. It is better than setting up the whole conditions block and includes an else for the case that does not match.

So, instead of the example code blocks above, it can be like, just for example:

if ( !check_security() ) {
    // stop the program right when security check failed
    return;
}
$user_input = get_user_input();
if ( empty($user_input) || !check_valid_input($user_input) ) {
    // stop the program right when user inputs are invalid
    return;
}
// this line only executes when all the conditions meet.
set_prefix($information);
// The functions list.
function check_security ( $args ) {
    // returns true or false for security check
}
function get_user_input ( $args ) {
    // return user inputs
}
function check_valid_input ( $args ) {
    // returns true or false for user input validation
}
function set_prefix () {
    // add prefix to the input, or modify the user input as you want
}

The benefits:

  • Get rid of the annoying multi-layered nested functions.
  • Tasks are written into functions so it is easier to debug or add features.
  • Returns early so the program never has to execute codes before it realizes the case does not match.
  • The code is cleaner and easier for team collaboration.

[WordPress] How to make the functions.php less messy

I have been working with WordPress for a while and one thing that irritates me is that the functions.php contains a lot of codes. This makes the file looks messy and hard to follow. There are some methods to improve this, which I have learnt from KnowTheCode to make this file looks cleaner. Briefly what I do:

  • Break one functions.php file into smaller files based on the purposes. Save them in a functions folder.
  • Define constants to save computing time.
  • Add a config.php file to store enqueued JS and CSS.

Let’s go into details.

Break functions.php into smaller files based on the purposes

So this is quite straight forward. I just categorized the functions into smaller purposes. Depending on your theme and your functions it will look different than mine. Here are the categories that I come up with:

  • styles-scripts-fonts.php: Enqueue styles, scripts and fonts.
  • custom-post-types.php: Defines and functions for custom post types.
  • post.php: functions used on blog posts (e.g query latest posts, get related posts, etc.).
  • remove-scripts.php: WordPress has lots of unnecessary functions that I don’t use and this file shut it down for better web speed.
  • third-parties: for example Google Tag Manager scripts installed.

I will not go into the details of each file here because your case will be totally different than mine. Just make sure that you analyze the functions before making a file for each. After categorizing scripts into the right file, let’s include them in the functions.php:

// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) exit;
include_once 'functions/styles-scripts-fonts.php';
include_once 'functions/custom-post-types.php';
include_once 'functions/post.php';
include_once 'functions/remove-scripts.php';
include_once 'functions/third-parties.php';

Now it looks much cleaner!

Define constants to save computing time

Defining constants saves computing time. For example, the get_stylesheet_directory_uri() will be defined into a constant, so that whenever the theme needs, it does not need to do the whole process before getting the result.

define ( 'CHILD_THEME_DIR', get_stylesheet_directory_uri() );

So instead of looking for and implement this function in the theme, now only a string will need to be retrieved. When enqueueing styles and scripts, this constant will be called all the time.

The second thing that can be defined is the theme version.

$the_theme = wp_get_theme();
define ( 'THEME_VERSION', $the_theme->get( 'Version' ));

The last constant is a list of three latest posts because they are written in the footer section of the website. So I think making them into an array constant will make website faster than querying them all over again.

define ( 'THREE_LATEST_POSTS', ak_query_latest_posts(3) );

And in the post.php, the function will look something like:

// Query latest blog posts
function ak_query_latest_posts($number_of_posts) {
    $posts = array();
    $args = array(
        'numberposts' => $number_of_posts,
        'orderby' => 'post_date',
        'order' => 'DESC',
        'post_type' => 'post',
        'post_status' => 'publish'
    );
    $recent_posts = wp_get_recent_posts($args);
    
    if(is_wp_error($recent_posts) || empty($recent_posts)) return;
    foreach ( $recent_posts as $recent ) {
        $single_post = array(
             'link' => get_permalink($recent['ID']),
             'title' => $recent['post_title'],
             'thumb' => get_the_post_thumbnail_url($recent['ID']),
        );
        $posts[] = $single_post;
    }
    wp_reset_query();
    return $posts;
}

Add a config.php file to add/remove enqueued styles and scripts

It’s not comfortable to repeat all the time the wp_enqueue_style() and wp_enqueue_script(). So there should be a file that contains all the styles and scripts with configuration. Then, in the styles-scripts-fonts.php file it will loop through all the items and add them accordingly.

// This file contains configuration for CSS, JS and fonts
if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly.
$fonts = array(
    'body-fonts' => array(
        'src' => 'https://fonts.googleapis.com/css?family=Montserrat:400,700|Work+Sans:300,400,700',
        'page_template' => null,
    ),
    'fontawesome' => array(
        'src' => 'https://use.fontawesome.com/releases/v5.1.0/css/all.css',
        'page_template' => null,
    ),
);
$css = array(
    'main-styles' => array(
        'src' => CHILD_THEME_DIR . '/css/main.min.css',
        'page_template' => null,
        'version' => '6.4.0'
    ),
    'lity-css' => array(
        'src' => CHILD_THEME_DIR . '/css/lity.min.css',
        'page_template' => array(
          'page-templates/some-page.php',
          'page-templates/video-tutorials.php',
          'page-templates/webinars.php',
        ),
        'version' => '0.1'
    ),
    'cocoen-css' => array(
        'src' => CHILD_THEME_DIR . '/css/cocoen.min.css',
        'page_template' => 'page-templates/gallery-page.php',
        'version' => '0.1'
    )
);
$js = array(
    'lity-js' => array(
        'src' => CHILD_THEME_DIR . '/js/lity.min.js',
        'page_template' => array(
          'page-templates/video-tutorials.php',
          'page-templates/some-page.php'
        ),
        'defer' => '',
        'in_footer' => true,
        'version' => '1'
    ),
    'cocoen-js' => array(
        'src' => CHILD_THEME_DIR . '/js/cocoen.min.js',
        'page_template' => 'page-templates/gallery.php',
        'defer' => '',
        'in_footer' => false,
        'version' => '1.2'
    ),
    'main-scripts' => array(
        'src' => CHILD_THEME_DIR . '/js/main.min.js',
        'page_template' => null,
        'defer' => '#defer',
        'in_footer' => true,
        'version' => '5.4.4'
    )
};

You can see that the constants CHILD_THEME_DIR and THEME_VERSION are used quite often.

Here comes the styles-scripts-fonts.php:

add_action( 'wp_enqueue_scripts', 'ak_theme_enqueue_styles' );
/**
 * Enqueue css and js filtered by pages
 * To add or remove file, do it in functions/config.php
 */
function ak_theme_enqueue_styles () {
    wp_enqueue_script('jquery');
    include_once 'config.php';
    foreach ($fonts as $handle => $value) {
        if($value['page_template'] == null) {
            wp_enqueue_style($handle, $value['src'], array(), null);
        }
        else {
            if (is_page_template($value['page_template'])) {
                wp_enqueue_style($handle, $value['src'], array(), null);
            }
        }
    }
    foreach ($css as $handle => $value) {
        if($value['page_template'] == null) {
            wp_enqueue_style($handle, $value['src'], array(), $value['version']);
        }
        else {
            if (is_page_template($value['page_template'])) {
                wp_enqueue_style($handle, $value['src'], array(), $value['version']);
            }
        }
    }
    foreach ($js as $handle => $value) {
        if($value['page_template'] == null) {
            wp_enqueue_script($handle, $value['src'] . $value['defer'], array(), $value['version'], $value['in_footer']);
        }
        else {
            if (is_page_template($value['page_template'])) {
                wp_enqueue_script($handle, $value['src'] . $value['defer'], array(), $value['version'], $value['in_footer']);
            }
        }
    }
}

Note: So when adding script/style into config.php, there is page_template required. This prevents the item to display in pages where they are not needed. For example, the cocoen is only needed for the gallery page, there is no idea to include them (two .js files and one .css file) to every page. This will make the website loads faster due to decrease in HTTP requests.

Conclusion

There will be many other effective ways to make the functions.php less messy and above are just a few. Thanks for reading and I hope this post is helpful to you.

[CSS] Simple slide up and fade text animation [Code + Demo]

Here is a simple slide up and fade text animation with CSS3 and HTML.

There will be four phrases of text, wrapped in four div classes with the ids, and it slides up in fading animation after several seconds.

The animation will run infinitely.

Code and result:

  • « Go to Previous Page
  • Go to page 1
  • Go to page 2
  • Go to page 3
  • Go to page 4
  • Go to page 5
  • Go to page 6
  • Go to page 7
  • Go to Next Page »

Primary Sidebar

Hi! I am a Vietnamese coder living in Oulu, Finland. Currently I am working with PHP, MySQL, HTML, CSS, and JavaScript. This blog is my learning diary, in which I share knowledge from my own experience or research. Hopefully you can find something useful here and don’t hesitate to open a discussion or leave a feedback!

My Blog

A learning diary
#wordpress #javascript #php #vue #css

Highlights

  • [WordPress] 5 Ways to Migrate Sites
  • [WordPress] Customizing Themes: Basic Principles & Examples
  • reCaptcha v3: How to implement on WordPress custom forms to stop bot signups
  • [WordPress] How to make the functions.php less messy
  • [CSS] Simple parallax [Code + Demo]

Latest

  • WordPress + Gumlet + S3: Resizing images from server side and upload to S3
  • [WordPress] Using Child Themes
  • [WordPress] Using Code Snippets to Modify Themes Without Child Theme
  • [WordPress] Let’s Make Plugin E01: A Simple View Count Plugin
  • [WordPress] Create custom post type programmatically
Anh Karppinen, personal web, version 1.0.0
  • Privacy Policy