Skip to content

Instantly share code, notes, and snippets.

@vHeemstra
Last active November 11, 2024 15:20
Show Gist options
  • Save vHeemstra/39e747eede1d0c10d0350e189f5d7724 to your computer and use it in GitHub Desktop.
Save vHeemstra/39e747eede1d0c10d0350e189f5d7724 to your computer and use it in GitHub Desktop.
Importing Font Awesome 6 as Custom Icon set in Elementor Pro

Using Font Awesome 6 as Custom Icon set in Elementor

As many already know, Elementor is very reluctant to stay up-to-date with their CMS. It still uses Font Awesome version 5 and if you don't have a Pro license for Font Awesome, it is very difficult to integrate FA6 as icons.

So to help fellow developers, here is how you can do it!

In Elementor you can import icon sets that are exported by Fontello (as ZIP).

Because Fontello does not support FA6, you have to generate this ZIP file yourself.

We will do this using Node and Gulp.

Step 1 - Create a (local) project folder

a. Create a new folder

b. Inside this folder, initiate a new NPM project that uses Gulp by following the installation documentation here.

c. Install the following dependencies:

npm install --save-dev gulp-concat gulp-rename del sass gulp-sass gulp-postcss postcss-url autoprefixer cssnano gulp-zip

Step 2 - Collect the proper Font Awesome 6 files

Download the full Font Awesome 6 repository as ZIP and extract these files to you project folder:

  • /scss/*
  • /webfonts/*
  • /metadata/icon-families.json

Step 3 - Adjust some variables

At the end of scss/_variables.scss, add these variables:

$fa-css-prefix: fa6;
$fa-font-path: "../font";
$fa-font-display: swap; // Optional

Step 4 - Add style variable declaration to each font style's SCSS at the bottom:

For example, for sharp light:

.fasl,
.#{$fa-css-prefix}-light {
  --#{$fa-css-prefix}-style: 300; // <-- Add this line with the correct font-weight number
  font-weight: 300;
}

at the end of scss/sharp-light.scss.

Do this for all font/icon styles you need.

Step 5 - Create the Gulp tasks file

Copy the source code from the gulpfile.mjs below and save this file in your project folder.


Your project folder should now look like this:

metadata/icon-families.json
node_modules/**
scss/*.scss
webfonts/*.(ttf|woff2)
package.json
gulpfile.mjs

Step 6 - Run the default Gulp task

gulp

If all goes well, you now have an output folder containing folders for each Font Awesome icon set and their zipped version.

output/brands.zip
output/brands/config.json
output/brands/css/brands.css
output/brands/font/fa-brands*

output/regular.zip
...etc

Step 7 - Import the icon sets in Elementor

Import the ZIP file of each icon set following the steps mentioned here.

DONE!

Now you can finally enjoy the latest Font Awesome icons inside your Elementor website:

image

(Although odds are Elementor will find a way to mess up their code and this will not work anymore..🤷‍♂️)

import { writeFileSync, readFileSync } from 'node:fs';
import gulp from 'gulp';
import concat from 'gulp-concat';
import rename from 'gulp-rename';
import { deleteAsync as del } from 'del';
import * as dartSass from 'sass';
import gulpSass from 'gulp-sass';
import postcss from 'gulp-postcss';
import url from "postcss-url";
import autoprefixer from 'autoprefixer';
import cssnano from 'cssnano';
import zip from 'gulp-zip';
const {
series,
parallel,
src,
dest,
} = gulp;
const sass = gulpSass(dartSass);
const pluginDir = `./`;
const outputDir = `${ pluginDir }output/`;
const iconsJSON = JSON.parse(
readFileSync(
new URL(`${ pluginDir }metadata/icon-families.json`, import.meta.url)
)
);
const fonts = [
// Free icons
'brands',
'solid',
'regular',
// Pro icons
'light',
'thin',
'duotone',
'sharp-solid',
'sharp-regular',
'sharp-light',
'sharp-thin',
].map(name => ({
name,
sources: [
`${ pluginDir }scss/fontawesome.scss`,
`${ pluginDir }scss/${name}.scss`,
name === 'duotone' ? `${pluginDir}scss/_${name}-icons.scss` : '',
].filter(s => s.length > 0),
fonts: `${ pluginDir }webfonts/fa-${name}-*`,
destination: `${ outputDir }${name}/`,
}));
// This task copies the font files and compiles the CSS for each icon set/variant.
const fontsTasks = fonts.map( font => {
const copyTask = (cb) => src( font.fonts )
.pipe( dest( `${font.destination}font/` ) )
;
copyTask.displayName = `copy font ${font.name}`;
const scssTask = () => src( font.sources )
.pipe( concat(`${font.name}.scss`) )
.pipe( sass( {
includePaths: [
`${ pluginDir }scss/`,
],
} ).on( 'error', sass.logError ) )
.pipe( postcss( [
url( {
url: "rebase"
} ),
autoprefixer( {
overrideBrowserslist: [ 'last 2 versions' ]
} ),
cssnano()
] ) )
.pipe( rename( { extname: '.css' } ) )
.pipe( dest( `${font.destination}css/` ) )
;
scssTask.displayName = `scss font ${font.name}`;
return parallel(
copyTask,
scssTask
);
});
// This task creates config JSON files for each icon set/variant.
const taskCompileConfigs = (cb) => {
const configs = fonts.map(f => f.name)
.reduce((acc, v) => {
acc[v] = {
"name": v,
"css_prefix_text": `fa${v
.split("-")
.map((vv) => vv.slice(0,1))
.join("")
} fa6-`,
"css_use_suffix": false,
"hinting": true,
"units_per_em": 1000,
"ascent": 850,
"glyphs": []
};
return acc;
}, {});
Object.entries(iconsJSON).forEach(([k, icon]) => {
const names = [k, ...(icon?.aliases?.names ?? [])];
const styles = [
icon?.svgs?.classic?.brands ? "brands" : false,
icon?.svgs?.classic?.solid ? "solid" : false,
icon?.svgs?.classic?.regular ? "regular" : false,
icon?.svgs?.classic?.light ? "light" : false,
icon?.svgs?.classic?.thin ? "thin" : false,
icon?.svgs?.duotone?.solid ? "duotone" : false,
icon?.svgs?.sharp?.solid ? "sharp-solid" : false,
icon?.svgs?.sharp?.regular ? "sharp-regular" : false,
icon?.svgs?.sharp?.light ? "sharp-light" : false,
icon?.svgs?.sharp?.thin ? "sharp-thin" : false,
].filter(s => s !== false);
const code = parseInt(icon.unicode, 16);
styles.forEach(style => {
names.forEach(name => {
configs[style].glyphs.push({
code,
css: name,
src: "fontawesome6"
});
})
});
});
Object.entries(configs).forEach(([font, configJSON]) => {
writeFileSync(`${ outputDir }${font}/config.json`, JSON.stringify(configJSON));
});
cb();
};
const zipTasks = fonts.map((font) => {
const zipTask = (cb) =>
src(`${outputDir}${font.name}/**`)
.pipe(zip(`${font.name}.zip`))
.pipe(dest(outputDir));
zipTask.displayName = `zip font ${font.name}`;
return series(zipTask);
});
// This task deletes the output folder before doing the other tasks.
const taskCleanTemp = (cb) => del( `${outputDir}/**` );
const taskDefault = series(
taskCleanTemp,
parallel( ...fontsTasks ),
taskCompileConfigs,
parallel( ...zipTasks ),
);
export {
taskDefault as default,
taskCleanTemp as clean,
taskCompileConfigs as compile,
}
@sylvaing26
Copy link

sylvaing26 commented Nov 2, 2023

Hi dear,
many thanks for your code !
I'me now anable to import AF6 into Elementor.

I've modify your code to use directly metatada/icons.json
icon-families.json on Awesome repo do not include Pro icons list.

Sorry for my bad english ;)

import { writeFileSync, readFileSync } from 'node:fs';
import gulp from 'gulp';
import concat from 'gulp-concat';
import rename from 'gulp-rename';
import { deleteAsync as del } from 'del';
import * as dartSass from 'sass';
import gulpSass from 'gulp-sass';
import postcss from 'gulp-postcss';
import url from "postcss-url";
import autoprefixer from 'autoprefixer';
import cssnano from 'cssnano';

const {
  series,
  parallel,
  src,
  dest,
} = gulp;
const sass = gulpSass(dartSass);

const pluginDir = `./`;
const outputDir = `${ pluginDir }output/`;

const iconsJSON = JSON.parse(
  readFileSync(
    new URL(`${ pluginDir }metadata/icons.json`, import.meta.url)
  )
);

const fonts = [
  // Free icons
  'brands',
  'regular',
  'solid',
].map(name => ({
  name,
  sources: [
    `${ pluginDir }scss/fontawesome.scss`,
    `${ pluginDir }scss/${name}.scss`,
  ],
  fonts: `${ pluginDir }webfonts/fa-${name}-*`,
  destination: `${ outputDir }${name}/`,
}));

// This task copies the font files and compiles the CSS for each icon set/variant.
const fontsTasks = fonts.map( font => {
  const copyTask = (cb) => src( font.fonts )
    .pipe( dest( `${font.destination}font/` ) )
  ;
  copyTask.displayName = `copy font ${font.name}`;

  const scssTask = () => src( font.sources )
    .pipe( concat(`${font.name}.scss`) )
    .pipe( sass( {
      includePaths: [
        `${ pluginDir }scss/`,
      ],
    } ).on( 'error', sass.logError ) )
    .pipe( postcss( [
      url( {
        url: "rebase"
      } ),
      autoprefixer( {
        overrideBrowserslist: [ 'last 2 versions' ]
      } ),
      cssnano()
    ] ) )
    .pipe( rename( { extname: '.css' } ) )
    .pipe( dest( `${font.destination}css/` ) )
  ;
  scssTask.displayName = `scss font ${font.name}`;

  return parallel(
    copyTask,
    scssTask
  );
});

// This task creates config JSON files for each icon set/variant.
const taskCompileConfigs = (cb) => {
  const configs = fonts.map(f => f.name)
    .reduce((acc, v) => {
      acc[v] = {
        "name": v,
        "css_prefix_text": `${v.split('-').map(vv => `fa6-${vv}`).join(' ')} fa6-`,
        "css_use_suffix": false,
        "hinting": true,
        "units_per_em": 1000,
        "ascent": 850,
        "glyphs": []
      };
      return acc;
    }, {});

  Object.entries(iconsJSON).forEach(([k, icon]) => {
    const names = [k, ...(icon?.aliases?.names ?? [])];

    const styles = icon.styles;

    const code = parseInt(icon.unicode, 16);

    styles.forEach(style => {
      names.forEach(name => {
        configs[style].glyphs.push({
          code,
          css: name,
          src: "fontawesome6"
        });
      })
    });
  });

  Object.entries(configs).forEach(([font, configJSON]) => {
    writeFileSync(`${ outputDir }${font}/config.json`, JSON.stringify(configJSON));
  });

  cb();
};

// This task deletes the output folder before doing the other tasks.
const taskCleanTemp = (cb) => del( `${outputDir}/**` );

const taskDefault = series(
  taskCleanTemp,
  parallel( ...fontsTasks ),
  taskCompileConfigs,
);

export {
  taskDefault as default,
  taskCleanTemp as clean,
  taskCompileConfigs as compile,
}

@toineenzo
Copy link

Heel nice! Thanks voor dit :)

@RobinMokry
Copy link

Thank you, it's very helpful and works great!

The latest Font Awesome 6.5.1, including PRO fonts, can be downloaded here - https://github.com/eliyantosarage/font-awesome-pro.

In the gulpfile.mjs file you need to add the font sharp thin (on 2 places).

@RobinMokry
Copy link

RobinMokry commented Feb 10, 2024

Hi,
I found out I have a problem.
When I upload the fonts to the icon set, everything displays correctly, but when I want to insert an icon on the site, the icon sets are named differently than they should be, some are blank and some have only a fraction of the icons.
What to do?
Thanks!

@vHeemstra
Copy link
Author

@RobinMokry ✔️ Added sharp-thin

@vHeemstra
Copy link
Author

Hi, I found out I have a problem. When I upload the fonts to the icon set, everything displays correctly, but when I want to insert an icon on the site, the icon sets are named differently than they should be, some are blank and some have only a fraction of the icons. What to do? Thanks!

You could check if the class names on the element are correct (and not overruled by anything else).
And also make sure the loaded font files are not cached previous versions (which might not include that icon yet).

@vHeemstra
Copy link
Author

✔️ Added zipping of output folders

@RobinMokry
Copy link

Hi,
I've created a brand new installation, installed elementor and inserted the icon sets. It's a bit better now, when pasting everything shows up fine, but when selecting an icon in the editor it looks like this. Any idea?
fa_

@RobinMokry
Copy link

For example, Sharp thin looks like sharp solid, but I get that - .fa6-sharp {font-weight: 900} has more priority than .fa6-thin {font-weight: 100}, but why don't sharp regular and sharp light show up at all?
Thank you.

@vHeemstra
Copy link
Author

vHeemstra commented Feb 10, 2024

Ok, I got the same results in a new install as well. I will investigate further.

@RobinMokry
Copy link

RobinMokry commented Feb 10, 2024

Yes, I did.
I've deleted .fa6 { font-weight: var(--fa6-style, 900)} and .fa6-sharp, .fass { font-weight: 900} from all .css files, so the display font thickness in the administration is fine now.
But I created 2 more installations and each time 2 of the 8 (random) fonts don't show up at all. Very strange. But I guess I'll make do without the sharp version.
Maybe it could be because I'm using the unofficial https://proelements.org/.

@vHeemstra
Copy link
Author

vHeemstra commented Feb 11, 2024

So, there are 2 issues that disturb the normal use of custom icons:

1) Incorrect setting and overwriting of CSS classes and declarations

a. Elementor (as it would..) has a very faulty and inconsistent way of loading these icons, making it like tip-toeing to get it to work.

  • There are certain names you can't use, because apparently they are use behind the scenes for the included free FA 5 icons (which you can't disable).

  • The icon list sets the icon's classes to prefix+name and adds prefix_wituout_dashes (when there is no displayPrefix, like with the FA 5 ones) just to f*ck with all devs (see source code here and here).

    Example: (correct) fa6-solid fa6-360-degrees + (incorrect) fa6solid fa6 = fa6solid fa6 fa6-solid fa6-360-degrees

    This additional fa6 class is what makes the same font show for different icon styles (see next point).

b. Font Awesome's weight declarations

  • In the way FA is set-up, the font-weight attribute is overwritten by the general .fa6 class (from above).
  • This class uses the variable --fa6-style variable (fa6 is chosen prefix).
  • None of the individual styles' SCSS files use this variable, or set it to the appropriate weight number for that style (e.g. 100 for thin, etc).

To fix this, add the variable declaration to each individual font style SCSS.
Here is the example for sharp light at the bottom of scss/sharp-light.scss:

.fasl,
.#{$fa-css-prefix}-light {
  --#{$fa-css-prefix}-style: 300; // <-- Add this with the weight from below
  font-weight: 300;
}

2) Some limitation in Elementor's editor

The editor throws an error when loading the icons picker tool in the side menu.

image

It seems the amount of icons is simply too much for this editor to handle.

In my case, sharp thin and duotone where empty/could not load. (Even though both display correctly in the WP admin backend.)

Maybe just choosing to add only the icon styles you need, might fix this issue?

Either way, this is simply ridiculous, but since Elementor is scripted by AI or Microsoft's Clippy, it's up to us to make it decent and working. Good luck!💪

@RobinMokry
Copy link

Thank you for your comprehensive reply.
I solved it so that I don't need duotone, sharp light or sharp regular.
I have found that for some reason it probably has an effect on what fonts don't load depending on what order I load them into the elementor.
This particular order has ensured that all fonts work for me except those mentioned.

sharp thin
sharp solid
thin
light
regular
solid
sharp light // does not work
sharp regular // does not work
brands

@sylvaing26
Copy link

Hi dear,
I've tested your new script with Font Awesome 6.5.1 from @RobinMokry but width WP 6.5.2 and Elementor Pro 3.20.3, no icons work :(

@troycono
Copy link

troycono commented Jun 5, 2024

@sylvaing26 - Same here, Elementor Pro v3.21.3, Font Awesome 6.5.2, WordPress 6.5.3.

After uploading a single icon set, in this case "thin," all other Font Awesome icon sets now look like this:

Screenshot 2024-06-05 at 3 55 26 PM

And the "thin" icon set displays no previews whatsoever:

Screenshot 2024-06-05 at 3 55 36 PM

@github-lobster
Copy link

As @sylvaing26 and @troycono I faced issues with FontAwesome 6.5.x.

But finally I found out that the font files in the output folder are corrupt. I have no idea why as they are only copied by the gulp task!?

So I deleted the files in the “font” folder in the ZIP archive \output\brands.zip (using “brands” as an example) and replaced them with the original files from the FontAwesome repository. Now the display of the icons in the Elementor backend (Custom Icon Sets) also works.

@sylvaing26
Copy link

As @sylvaing26 and @troycono I faced issues with FontAwesome 6.5.x.

But finally I found out that the font files in the output folder are corrupt. I have no idea why as they are only copied by the gulp task!?

So I deleted the files in the “font” folder in the ZIP archive \output\brands.zip (using “brands” as an example) and replaced them with the original files from the FontAwesome repository. Now the display of the icons in the Elementor backend (Custom Icon Sets) also works.

Oh yeah very good.
Thanks !

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment