Tworzenie bloków Gutenberga w motywie WordPressa – przygotowanie

Strona główna / Blog / Wordpress / Tworzenie bloków Gutenberga w motywie WordPressa – przygotowanie

To nie będzie kolejny wpis o tym jak zacząć tworzenie nowych bloków w WordPressie za pomocą create-guten-block. Dla mnie osobiście przełączanie się pomiędzy wtyczką a motywem, między webpackiem a gulpem byłoby nieco uciążliwe. Zapragnąłem mieć wszystko w jednym miejscu.

I tak zaczęło się poszukiwanie rozwiązań, które nie dawały mi 100% satysfakcji, gdyż nie były stabilne. Za to bardzo obiecująca jest poniższa konfiguracja. Ale od początku…

Celem jaki sobie postawiłem, było umożliwienie tworzenia bloków Gutenberga w dowolnym motywie i utworzenie przy tym stabilnego środowiska developerskiego. Podszedłem do tego, jak to w przypadku historyka, jako badacz, a nie ekspert. Istotą problemu, z jakim musiałem się zmierzyć to umożliwienie pisania kodu w JSX przy jednoczesnej kompilacji go do standardu ES5. Najpierw były nieudane próby z gulpem. Potem idąc torem create-guten-block próbowałem stworzyć motyw w oparciu o webpack. Też bezskutecznie. Działał zbyt wolno. Okazało się, że idealnym rozwiązaniem dla mnie było połączenie gulpa z webpackiem.

Ale zaraz. Jak tworzyć bloki w motywie? Przecież wszyscy rekomendują tworzenie wtyczki. A czy nie fajnie byłoby mieć wszystko w jednym? Do zrobienia tej konfiguracji pomogło mi właśnie narzędzie create-guten-block.

Przekształcając funkcję i umieszczając ją do pliku functions.php. Umożliwia ona rejestrację zarówno wynikowego skryptu (app.js) jak i styli.

wp_enqueue_script( 'wp-api' );
// Register block editor script for backend.
wp_enqueue_script(
	'blocks-js', // Handle.
	get_template_directory_uri() . '/dist/app.js',
	array( 'wp-blocks', 'wp-i18n', 'wp-element', 'wp-editor' ), // Dependencies, defined above.
	null, // filemtime( plugin_dir_path( __DIR__ ) . 'dist/blocks.build.js' ), // Version: filemtime — Gets file modification time.
	true // Enqueue the script in the footer.
);


function blocks_assets() {
	// Styles.
	wp_enqueue_style(
		'blocks-css', // Handle.
		get_template_directory_uri() . '/blocks.css',
		array( 'wp-editor', 'wp-edit-blocks' ) // Dependency to include the CSS after it.
		// filemtime( plugin_dir_path( __DIR__ ) . 'dist/blocks.style.build.css' ) // Version: File modification time.
	);
}
// Hook: Frontend assets.
add_action( 'enqueue_block_assets', 'blocks_assets' );



register_block_type(
	'cgb/block-lub-blocks', array(

		// Enqueue blocks.build.js in the editor only.
		'editor_script' => 'blocks-js',
		'style' => 'blocks-css',
    'editor_style' => 'blocks-css',

	)
);

Następnie musimy zainstalować w folderze naszego motywu potrzebne paczki. Tworzymy package.json:

{
    "name": "wp-lubstarterdev",
    "version": "1.0.0",
    "description": "Lubstarter Dev Theme Sass Compiler",
    "main": "index.js",
    "scripts": {
        "test": "echo \"Error: no test specified\" && exit 1"
    },
    "author": "Biuro REKLAMA",
    "license": "ISC",
    "devDependencies": {
        "@babel/core": "^7.5.5",
        "@babel/plugin-proposal-class-properties": "^7.7.4",
        "@babel/plugin-syntax-dynamic-import": "^7.7.4",
        "@babel/preset-env": "^7.5.5",
        "@babel/preset-react": "^7.0.0",
        "@fortawesome/fontawesome-free": "^5.9.0",
        "babel-core": "^6.26.3",
        "babel-loader": "^8.0.6",
        "babel-preset-es2015": "^6.24.1",
        "babel-preset-latest": "^6.24.1",
        "babel-preset-react": "^6.24.1",
        "bootstrap": "^4.3.1",
        "browser-sync": "^2.26.7",
        "del": "^3.0.0",
        "gulp": "^4.0.2",
        "gulp-autoprefixer": "^5.0.0",
        "gulp-concat": "^2.6.1",
        "gulp-connect-php": "^1.0.2",
        "gulp-cssnano": "^2.1.3",
        "gulp-jshint": "^2.1.0",
        "gulp-open": "^3.0.1",
        "gulp-ruby-sass": "^3.0.0",
        "gulp-sort": "^2.0.0",
        "gulp-sourcemaps": "^2.6.4",
        "gulp-uglify": "^3.0.2",
        "gulp-util": "^3.0.8",
        "gulp-zip": "^4.2.0",
        "node-bin-setup": "^1.0.6",
        "popper.js": "^1.14.7",
        "react": "^16.12.0",
        "react-dom": "^16.12.0",
        "react-router-dom": "^5.1.2",
        "run-sequence": "^2.2.1",
        "sequence": "^3.0.0",
        "webpack": "^4.41.2",
        "webpack-stream": "^5.2.1"
    },
    "dependencies": {
        "@fancyapps/fancybox": "^3.5.6",
        "animate.css": "^3.7.0",
        "axios": "^0.19.0",
        "jquery": "^3.4.1",
        "jshint": "^2.10.1",
        "owl.carousel": "^2.3.4",
        "rellax": "^1.8.0",
        "wow.js": "^1.2.2"
    }
}

Następnie za pomocą wiersza poleceń wpisujemy:

npm install

i klikamy ENTER.

Teraz pora na konfigurację pliku gulpfile.js:

'use strict';

var gulp = require('gulp'),
    gutil = require('gulp-util'),
    cssnano = require('gulp-cssnano'),
    sass = require('gulp-ruby-sass'),
    sort = require('gulp-sort'),
    runSequence = require('run-sequence'),
    connect = require('gulp-connect-php'),
    sourcemaps = require('gulp-sourcemaps'),
    autoprefixer = require('gulp-autoprefixer'),
    concat = require('gulp-concat'),
    uglify = require('gulp-uglify'),
    webpack = require('webpack'),
    webpackStream = require('webpack-stream'),
    browserSync = require('browser-sync').create();


var supported = [
    'last 2 versions',
    'safari >= 8',
    'ie >= 10',
    'ff >= 20',
    'ios 6',
    'android 4'
];

var build_files = [
    '**',
    '!node_modules',
    '!node_modules/**',
    '!build',
    '!build/**',
    '!src',
    '!src/**',
    '!.git',
    '!.git/**',
    '!package.json',
    '!.gitignore',
    '!gulpfile.js',
    '!.editorconfig',
    '!.jshintrc'
];


// Defining base paths
var basePaths = {
    js: './js/',
    node: './node_modules/',
    dev: './src/',
    css: './css/'
};



gulp.task('browser-sync', function () {
    browserSync.init({
        proxy: "localhost/blocks",
        browser: "google chrome"
    });

});

gulp.task('webpacks', function () {
    return gulp.src('blocks/src/app.js')
        .pipe(webpackStream({
            config: require('./app.config.js'),
            watch: true
        }))
        .pipe(gulp.dest('dist/'))
        .pipe(browserSync.stream())

});

gulp.task('sass', () =>
    sass('src/sass/**/*.scss', { sourcemap: true })
        .pipe(autoprefixer())
        .on('error', sass.logError)
        .pipe(sourcemaps.write())
        .pipe(cssnano({
            autoprefixer: { browsers: supported, add: true }
        }))
        .pipe(sourcemaps.write('maps', {
            includeContent: false,
            sourceRoot: 'src/sass'
        }))
        .pipe(gulp.dest('./'))
        .pipe(browserSync.stream()) 
);




 
gulp.task('watch', function () {
    gulp.watch('src/sass/**/*.scss', gulp.series('sass'));
    gulp.watch('blocks/src/**/*.js', gulp.series('webpacks'));
    gulp.watch('**/*.php').on('change', function () {
        browserSync.reload();
    });
});


gulp.task('copy-assets', function () {
    var stream = gulp.src(basePaths.node + 'bootstrap/dist/js/**/*.js')
        .pipe(gulp.dest(basePaths.js + 'bootstrap'));
    gulp.src(basePaths.node + 'bootstrap/dist/css/**/*.css')
        .pipe(gulp.dest(basePaths.css + 'bootstrap'));
    return stream;

});

gulp.task('copyfonts', function () {
    var stream = gulp.src(basePaths.node + '@fortawesome/fontawesome-free/webfonts/**/*.{ttf,woff,woff2,eof,svg}')
        .pipe(gulp.dest('./fonts/fontawesome'));
    gulp.src(basePaths.node + '@fortawesome/fontawesome-free/css/**/*.css')
        .pipe(gulp.dest(basePaths.css + 'fontawesome'));
    return stream;
});

gulp.task('copypopper', function () {
    var stream = gulp.src(basePaths.node + 'popper.js/dist/umd/popper.min.js')
        .pipe(gulp.dest('./js'));

    gulp.src(basePaths.node + 'popper.js/dist/umd/popper.js')
        .pipe(gulp.dest('./js'));
    return stream;
});

gulp.task('owl', function () {
    var stream = gulp.src(basePaths.node + 'owl.carousel/dist/owl.carousel.min.js')
        .pipe(gulp.dest('./js'));

    gulp.src(basePaths.node + 'owl.carousel/dist/assets/owl.carousel.min.css')
        .pipe(gulp.dest('./css'));
    return stream;
});
gulp.task('animate', function () {
    var stream = gulp.src(basePaths.node + 'animate.css/animate.min.css')
        .pipe(gulp.dest('./css'));
    return stream;
});

gulp.task('rellax', function () {
    var stream = gulp.src(basePaths.node + 'rellax/rellax.min.js')
        .pipe(gulp.dest('./js'));
    return stream;
});

gulp.task('wow', function () {
    var stream = gulp.src(basePaths.node + 'wow.js/dist/wow.min.js')
        .pipe(gulp.dest('./js'));
    return stream;
});

gulp.task('fancybox', function () {
    var stream = gulp.src(basePaths.node + '@fancyapps/fancybox/dist/jquery.fancybox.min.js')
        .pipe(gulp.dest('./js'));

    gulp.src(basePaths.node + '@fancyapps/fancybox/dist/jquery.fancybox.min.css')
        .pipe(gulp.dest('./css'));
    return stream;
});


var defl = gulp.parallel(['sass', 'webpacks', 'watch', 'browser-sync']);
var ini = gulp.parallel(['copy-assets', 'copyfonts', 'copypopper', 'animate', 'wow', 'owl', 'rellax', 'fancybox']);

gulp.task(defl);
gulp.task('default', defl);
gulp.task(ini);
gulp.task('init', ini);

Jak widać w kopilacji z JSX do ES5 pomagają takie pluginy jak webpack i webpack-stream, które „łączą się” z plikiem app.config.js i dają wynikowy kod ES5 w dist/app.js, przy jednoczesnym podglądzie poprawności kodu (watch). W moim motywie bloki Gutenberga w JSX tworzę w folderze „blocks”. O jego strukturze napiszę w niedalekiej przyszłości.

A właśnie. Aby wszystko zadziałało, musimy jeszcze utworzyć wspomniany app.config.js. To tam dzieje się ta MAGIA.

module.exports = {
    output: {
        filename: 'app.js',
    },
    module: {
        
        rules: [
             
            {
                test: /\.(js|jsx)$/,
                exclude: /(node_modules)/,
                loader: 'babel-loader',
                options: {
                    presets: ['@babel/preset-env',
                        '@babel/preset-react'],
                    plugins: [
                        "@babel/plugin-syntax-dynamic-import",
                        "@babel/plugin-proposal-class-properties"
                    ]
                },
                
            },
        ],
    }, 
    watch: true
}; 

To jest nic innego jak część kofiguracji webpacka. W nazwie dałem app, tak dla zmyłki 🙂

Oczywiście przy konfiguracji swoich motywów, musicie wziąć pod uwagę strukturę folderów. Ja bazowałem na motywie twenty sixteen. Rozwiązanie jest w fazie testów. Liczę też na waszą pomoc i wskazówki.

,