create-wp-custom-theme 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/create-wp-theme.js +66 -0
- package/package.json +28 -0
- package/src/git.js +22 -0
- package/src/index.js +52 -0
- package/src/logger.js +9 -0
- package/src/scaffold.js +64 -0
- package/src/tailwind.js +83 -0
- package/src/woocommerce.js +50 -0
- package/template/404.php +25 -0
- package/template/assets/css/main.css +28 -0
- package/template/assets/js/main.js +7 -0
- package/template/footer.php +28 -0
- package/template/functions.php +14 -0
- package/template/header.php +47 -0
- package/template/inc/enqueue.php +22 -0
- package/template/inc/setup.php +44 -0
- package/template/index.php +31 -0
- package/template/page.php +41 -0
- package/template/screenshot.png +0 -0
- package/template/style.css +13 -0
- package/template/templates/parts/content.php +38 -0
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { Command } from 'commander';
|
|
4
|
+
import inquirer from 'inquirer';
|
|
5
|
+
import chalk from 'chalk';
|
|
6
|
+
import path from 'path';
|
|
7
|
+
import fs from 'fs-extra';
|
|
8
|
+
import { run } from '../src/index.js';
|
|
9
|
+
import { fileURLToPath } from 'url';
|
|
10
|
+
|
|
11
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
12
|
+
const __dirname = path.dirname(__filename);
|
|
13
|
+
|
|
14
|
+
// Read package.json for version
|
|
15
|
+
const pkgPath = path.resolve(__dirname, '../package.json');
|
|
16
|
+
const pkg = JSON.parse(await fs.readFile(pkgPath, 'utf8'));
|
|
17
|
+
|
|
18
|
+
const program = new Command();
|
|
19
|
+
|
|
20
|
+
program
|
|
21
|
+
.name('create-wp-theme')
|
|
22
|
+
.description('Scaffold a production-ready custom WordPress theme')
|
|
23
|
+
.version(pkg.version)
|
|
24
|
+
.argument('<theme-name>', 'Name of the WordPress theme (directory name)')
|
|
25
|
+
.option('--woocommerce', 'Include WooCommerce setup hooks')
|
|
26
|
+
.option('--tailwind', 'Include Tailwind CSS + Vite configuration')
|
|
27
|
+
.action(async (themeName, options) => {
|
|
28
|
+
console.log(chalk.bold.cyan('\n🚀 Welcome to create-wp-theme!\n'));
|
|
29
|
+
|
|
30
|
+
const prompts = [
|
|
31
|
+
{
|
|
32
|
+
type: 'input',
|
|
33
|
+
name: 'author',
|
|
34
|
+
message: 'Author Name:',
|
|
35
|
+
default: 'Your Name'
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
type: 'input',
|
|
39
|
+
name: 'description',
|
|
40
|
+
message: 'Theme Description:',
|
|
41
|
+
default: 'A custom WordPress theme.'
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
type: 'confirm',
|
|
45
|
+
name: 'git',
|
|
46
|
+
message: 'Initialize a Git repository?',
|
|
47
|
+
default: true
|
|
48
|
+
}
|
|
49
|
+
];
|
|
50
|
+
|
|
51
|
+
const answers = await inquirer.prompt(prompts);
|
|
52
|
+
|
|
53
|
+
const config = {
|
|
54
|
+
themeName,
|
|
55
|
+
textDomain: themeName.toLowerCase().replace(/[^a-z0-9]/g, '-'),
|
|
56
|
+
author: answers.author,
|
|
57
|
+
description: answers.description,
|
|
58
|
+
git: answers.git,
|
|
59
|
+
woocommerce: options.woocommerce || false,
|
|
60
|
+
tailwind: options.tailwind || false,
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
await run(config);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
program.parse(process.argv);
|
package/package.json
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "create-wp-custom-theme",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "A CLI tool to scaffold production-ready custom WordPress themes",
|
|
5
|
+
"main": "src/index.js",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"bin": {
|
|
8
|
+
"create-wp-theme": "./bin/create-wp-theme.js"
|
|
9
|
+
},
|
|
10
|
+
"scripts": {
|
|
11
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
|
12
|
+
},
|
|
13
|
+
"keywords": [
|
|
14
|
+
"wordpress",
|
|
15
|
+
"theme",
|
|
16
|
+
"scaffold",
|
|
17
|
+
"generator",
|
|
18
|
+
"cli"
|
|
19
|
+
],
|
|
20
|
+
"author": "",
|
|
21
|
+
"license": "MIT",
|
|
22
|
+
"dependencies": {
|
|
23
|
+
"chalk": "^5.6.2",
|
|
24
|
+
"commander": "^14.0.3",
|
|
25
|
+
"fs-extra": "^11.3.4",
|
|
26
|
+
"inquirer": "^13.3.2"
|
|
27
|
+
}
|
|
28
|
+
}
|
package/src/git.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { execSync } from 'child_process';
|
|
2
|
+
import fs from 'fs-extra';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import { logger } from './logger.js';
|
|
5
|
+
|
|
6
|
+
export async function initGit(targetPath) {
|
|
7
|
+
try {
|
|
8
|
+
execSync('git init', { cwd: targetPath, stdio: 'ignore' });
|
|
9
|
+
|
|
10
|
+
// Create a basic .gitignore
|
|
11
|
+
const gitignoreContent = `
|
|
12
|
+
node_modules/
|
|
13
|
+
.DS_Store
|
|
14
|
+
dist/
|
|
15
|
+
.env
|
|
16
|
+
`;
|
|
17
|
+
await fs.writeFile(path.join(targetPath, '.gitignore'), gitignoreContent.trim());
|
|
18
|
+
logger.success('Initialized a git repository.');
|
|
19
|
+
} catch (error) {
|
|
20
|
+
logger.warn('Failed to initialize git repository.');
|
|
21
|
+
}
|
|
22
|
+
}
|
package/src/index.js
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import path from 'path';
|
|
2
|
+
import { createThemeDir, copyTemplate, replacePlaceholders } from './scaffold.js';
|
|
3
|
+
import { setupWooCommerce } from './woocommerce.js';
|
|
4
|
+
import { setupTailwind } from './tailwind.js';
|
|
5
|
+
import { initGit } from './git.js';
|
|
6
|
+
import { logger } from './logger.js';
|
|
7
|
+
import chalk from 'chalk';
|
|
8
|
+
|
|
9
|
+
export async function run(config) {
|
|
10
|
+
const targetPath = path.join(process.cwd(), config.themeName);
|
|
11
|
+
|
|
12
|
+
try {
|
|
13
|
+
// 1. Create directory
|
|
14
|
+
await createThemeDir(targetPath);
|
|
15
|
+
|
|
16
|
+
// 2. Copy base templates
|
|
17
|
+
await copyTemplate(targetPath);
|
|
18
|
+
|
|
19
|
+
// 3. Replace Placeholders
|
|
20
|
+
await replacePlaceholders(targetPath, config);
|
|
21
|
+
|
|
22
|
+
// 4. Optional features
|
|
23
|
+
if (config.woocommerce) {
|
|
24
|
+
await setupWooCommerce(targetPath, config.textDomain);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (config.tailwind) {
|
|
28
|
+
await setupTailwind(targetPath, config.themeName);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (config.git) {
|
|
32
|
+
await initGit(targetPath);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// 5. Summary
|
|
36
|
+
console.log('');
|
|
37
|
+
logger.success(chalk.bold('Theme scaffolding completed successfully!'));
|
|
38
|
+
console.log(`\nNext steps:\n`);
|
|
39
|
+
console.log(chalk.cyan(` cd ${config.themeName}`));
|
|
40
|
+
|
|
41
|
+
if (config.tailwind) {
|
|
42
|
+
console.log(chalk.cyan(` npm install`));
|
|
43
|
+
console.log(chalk.cyan(` npm run dev`));
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
console.log(`\nHappy coding! 🚀\n`);
|
|
47
|
+
|
|
48
|
+
} catch (error) {
|
|
49
|
+
logger.error(error.message);
|
|
50
|
+
process.exit(1);
|
|
51
|
+
}
|
|
52
|
+
}
|
package/src/logger.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
|
|
3
|
+
export const logger = {
|
|
4
|
+
info: (msg) => console.log(chalk.cyan(msg)),
|
|
5
|
+
success: (msg) => console.log(chalk.green('✔ ' + msg)),
|
|
6
|
+
error: (msg) => console.log(chalk.red('✖ ' + msg)),
|
|
7
|
+
warn: (msg) => console.log(chalk.yellow('âš ' + msg)),
|
|
8
|
+
plain: (msg) => console.log(msg),
|
|
9
|
+
};
|
package/src/scaffold.js
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import fs from 'fs-extra';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { fileURLToPath } from 'url';
|
|
4
|
+
import { logger } from './logger.js';
|
|
5
|
+
|
|
6
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
7
|
+
const __dirname = path.dirname(__filename);
|
|
8
|
+
const templateDir = path.resolve(__dirname, '../template');
|
|
9
|
+
|
|
10
|
+
export async function createThemeDir(targetPath) {
|
|
11
|
+
if (await fs.pathExists(targetPath)) {
|
|
12
|
+
throw new Error(`Folder ${targetPath} already exists. Please choose a different name or delete the folder.`);
|
|
13
|
+
}
|
|
14
|
+
await fs.ensureDir(targetPath);
|
|
15
|
+
logger.success(`Created directory ${targetPath}`);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export async function copyTemplate(targetPath) {
|
|
19
|
+
logger.info('Copying theme template files...');
|
|
20
|
+
await fs.copy(templateDir, targetPath);
|
|
21
|
+
logger.success('Template files copied.');
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
async function walkDir(dir) {
|
|
25
|
+
let results = [];
|
|
26
|
+
const list = await fs.readdir(dir);
|
|
27
|
+
for (let file of list) {
|
|
28
|
+
file = path.join(dir, file);
|
|
29
|
+
const stat = await fs.stat(file);
|
|
30
|
+
if (stat && stat.isDirectory()) {
|
|
31
|
+
results = results.concat(await walkDir(file));
|
|
32
|
+
} else {
|
|
33
|
+
results.push(file);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return results;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export async function replacePlaceholders(targetPath, vars) {
|
|
40
|
+
logger.info('Replacing placeholders in template files...');
|
|
41
|
+
const files = await walkDir(targetPath);
|
|
42
|
+
|
|
43
|
+
for (const file of files) {
|
|
44
|
+
// Only process text-based files
|
|
45
|
+
const ext = path.extname(file);
|
|
46
|
+
if (['.png', '.jpg', '.jpeg', '.gif', '.ico'].includes(ext)) {
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
try {
|
|
51
|
+
let content = await fs.readFile(file, 'utf8');
|
|
52
|
+
|
|
53
|
+
content = content.replace(/__THEME_NAME__/g, vars.themeName);
|
|
54
|
+
content = content.replace(/__AUTHOR__/g, vars.author);
|
|
55
|
+
content = content.replace(/__DESCRIPTION__/g, vars.description);
|
|
56
|
+
content = content.replace(/__TEXT_DOMAIN__/g, vars.textDomain);
|
|
57
|
+
|
|
58
|
+
await fs.writeFile(file, content, 'utf8');
|
|
59
|
+
} catch (e) {
|
|
60
|
+
// ignore read errors for binaries that might have slipped through
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
logger.success('Placeholders replaced dynamically.');
|
|
64
|
+
}
|
package/src/tailwind.js
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import fs from 'fs-extra';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { logger } from './logger.js';
|
|
4
|
+
|
|
5
|
+
export async function setupTailwind(targetPath, themeName) {
|
|
6
|
+
logger.info('Setting up Tailwind CSS and Vite...');
|
|
7
|
+
|
|
8
|
+
// 1. Create package.json
|
|
9
|
+
const pkgContent = {
|
|
10
|
+
"name": themeName.toLowerCase().replace(/[^a-z0-9]/g, '-'),
|
|
11
|
+
"version": "1.0.0",
|
|
12
|
+
"scripts": {
|
|
13
|
+
"dev": "vite",
|
|
14
|
+
"build": "vite build"
|
|
15
|
+
},
|
|
16
|
+
"devDependencies": {
|
|
17
|
+
"autoprefixer": "^10.4.16",
|
|
18
|
+
"postcss": "^8.4.31",
|
|
19
|
+
"tailwindcss": "^3.3.5",
|
|
20
|
+
"vite": "^5.0.0"
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
await fs.writeFile(path.join(targetPath, 'package.json'), JSON.stringify(pkgContent, null, 2));
|
|
24
|
+
|
|
25
|
+
// 2. Create tailwind.config.js
|
|
26
|
+
const twContent = `/** @type {import('tailwindcss').Config} */
|
|
27
|
+
module.exports = {
|
|
28
|
+
content: [
|
|
29
|
+
'./*.php',
|
|
30
|
+
'./templates/**/*.php',
|
|
31
|
+
'./inc/**/*.php',
|
|
32
|
+
'./template-parts/**/*.php',
|
|
33
|
+
'./assets/js/**/*.js'
|
|
34
|
+
],
|
|
35
|
+
theme: {
|
|
36
|
+
extend: {},
|
|
37
|
+
},
|
|
38
|
+
plugins: [],
|
|
39
|
+
}
|
|
40
|
+
`;
|
|
41
|
+
await fs.writeFile(path.join(targetPath, 'tailwind.config.js'), twContent);
|
|
42
|
+
|
|
43
|
+
// 3. Create postcss.config.js
|
|
44
|
+
const postcssContent = `module.exports = {
|
|
45
|
+
plugins: {
|
|
46
|
+
tailwindcss: {},
|
|
47
|
+
autoprefixer: {},
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
`;
|
|
51
|
+
await fs.writeFile(path.join(targetPath, 'postcss.config.js'), postcssContent);
|
|
52
|
+
|
|
53
|
+
// 4. Create vite.config.js
|
|
54
|
+
const viteContent = `import { defineConfig } from 'vite';
|
|
55
|
+
|
|
56
|
+
export default defineConfig({
|
|
57
|
+
build: {
|
|
58
|
+
rollupOptions: {
|
|
59
|
+
input: {
|
|
60
|
+
main: './assets/css/main.css',
|
|
61
|
+
script: './assets/js/main.js'
|
|
62
|
+
},
|
|
63
|
+
output: {
|
|
64
|
+
dir: 'dist',
|
|
65
|
+
entryFileNames: '[name].js',
|
|
66
|
+
assetFileNames: '[name].[ext]'
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
`;
|
|
72
|
+
await fs.writeFile(path.join(targetPath, 'vite.config.js'), viteContent);
|
|
73
|
+
|
|
74
|
+
// 5. Update main.css with Tailwind directives
|
|
75
|
+
const cssPath = path.join(targetPath, 'assets', 'css', 'main.css');
|
|
76
|
+
if (await fs.pathExists(cssPath)) {
|
|
77
|
+
const twCSS = `@tailwind base;\n@tailwind components;\n@tailwind utilities;\n\n`;
|
|
78
|
+
const existingCss = await fs.readFile(cssPath, 'utf8');
|
|
79
|
+
await fs.writeFile(cssPath, twCSS + existingCss, 'utf8');
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
logger.success('Tailwind CSS and Vite configuration added.');
|
|
83
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import fs from 'fs-extra';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { logger } from './logger.js';
|
|
4
|
+
|
|
5
|
+
export async function setupWooCommerce(targetPath, textDomain) {
|
|
6
|
+
logger.info('Setting up WooCommerce hooks...');
|
|
7
|
+
|
|
8
|
+
// 1. Create inc/woocommerce.php
|
|
9
|
+
const wooCommercePath = path.join(targetPath, 'inc', 'woocommerce.php');
|
|
10
|
+
const wooContent = `<?php
|
|
11
|
+
/**
|
|
12
|
+
* WooCommerce setup and hooks
|
|
13
|
+
*
|
|
14
|
+
* @package \${textDomain}
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
function \${textDomain}_woocommerce_setup() {
|
|
18
|
+
add_theme_support(
|
|
19
|
+
'woocommerce',
|
|
20
|
+
array(
|
|
21
|
+
'thumbnail_image_width' => 150,
|
|
22
|
+
'single_image_width' => 300,
|
|
23
|
+
'product_grid' => array(
|
|
24
|
+
'default_rows' => 3,
|
|
25
|
+
'min_rows' => 1,
|
|
26
|
+
'default_columns' => 4,
|
|
27
|
+
'min_columns' => 1,
|
|
28
|
+
'max_columns' => 6,
|
|
29
|
+
),
|
|
30
|
+
)
|
|
31
|
+
);
|
|
32
|
+
add_theme_support( 'wc-product-gallery-zoom' );
|
|
33
|
+
add_theme_support( 'wc-product-gallery-lightbox' );
|
|
34
|
+
add_theme_support( 'wc-product-gallery-slider' );
|
|
35
|
+
}
|
|
36
|
+
add_action( 'after_setup_theme', '\${textDomain}_woocommerce_setup' );
|
|
37
|
+
`.replace(/\$\{textDomain\}/g, textDomain);
|
|
38
|
+
|
|
39
|
+
await fs.writeFile(wooCommercePath, wooContent, 'utf8');
|
|
40
|
+
|
|
41
|
+
// 2. Add require line to functions.php
|
|
42
|
+
const functionsPath = path.join(targetPath, 'functions.php');
|
|
43
|
+
if (await fs.pathExists(functionsPath)) {
|
|
44
|
+
let functionsContent = await fs.readFile(functionsPath, 'utf8');
|
|
45
|
+
functionsContent += `\n// Load WooCommerce compatibility file.\nrequire_once get_template_directory() . '/inc/woocommerce.php';\n`;
|
|
46
|
+
await fs.writeFile(functionsPath, functionsContent, 'utf8');
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
logger.success('WooCommerce hooks added.');
|
|
50
|
+
}
|
package/template/404.php
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
<?php
|
|
2
|
+
/**
|
|
3
|
+
* The template for displaying 404 pages (not found)
|
|
4
|
+
*
|
|
5
|
+
* @package __THEME_NAME__
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
get_header();
|
|
9
|
+
?>
|
|
10
|
+
|
|
11
|
+
<main id="primary" class="site-main">
|
|
12
|
+
<section class="error-404 not-found">
|
|
13
|
+
<header class="page-header">
|
|
14
|
+
<h1 class="page-title"><?php esc_html_e( 'Oops! That page can’t be found.', '__TEXT_DOMAIN__' ); ?></h1>
|
|
15
|
+
</header><!-- .page-header -->
|
|
16
|
+
|
|
17
|
+
<div class="page-content">
|
|
18
|
+
<p><?php esc_html_e( 'It looks like nothing was found at this location. Maybe try a search?', '__TEXT_DOMAIN__' ); ?></p>
|
|
19
|
+
<?php get_search_form(); ?>
|
|
20
|
+
</div><!-- .page-content -->
|
|
21
|
+
</section><!-- .error-404 -->
|
|
22
|
+
</main><!-- #primary -->
|
|
23
|
+
|
|
24
|
+
<?php
|
|
25
|
+
get_footer();
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Base CSS File
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
:root {
|
|
6
|
+
--primary-color: #0073aa;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
body {
|
|
10
|
+
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
|
|
11
|
+
margin: 0;
|
|
12
|
+
padding: 0;
|
|
13
|
+
color: #333;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
a {
|
|
17
|
+
color: var(--primary-color);
|
|
18
|
+
text-decoration: none;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
a:hover {
|
|
22
|
+
text-decoration: underline;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
img {
|
|
26
|
+
max-width: 100%;
|
|
27
|
+
height: auto;
|
|
28
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
<?php
|
|
2
|
+
/**
|
|
3
|
+
* The template for displaying the footer
|
|
4
|
+
*
|
|
5
|
+
* @package __THEME_NAME__
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
?>
|
|
9
|
+
<footer id="colophon" class="site-footer">
|
|
10
|
+
<div class="site-info">
|
|
11
|
+
<a href="<?php echo esc_url( __( 'https://wordpress.org/', '__TEXT_DOMAIN__' ) ); ?>">
|
|
12
|
+
<?php
|
|
13
|
+
/* translators: %s: CMS name, i.e. WordPress. */
|
|
14
|
+
printf( esc_html__( 'Proudly powered by %s', '__TEXT_DOMAIN__' ), 'WordPress' );
|
|
15
|
+
?>
|
|
16
|
+
</a>
|
|
17
|
+
<span class="sep"> | </span>
|
|
18
|
+
<?php
|
|
19
|
+
/* translators: 1: Theme name, 2: Theme author. */
|
|
20
|
+
printf( esc_html__( 'Theme: %1$s by %2$s.', '__TEXT_DOMAIN__' ), '__THEME_NAME__', '<a href="__AUTHOR_URI__">__AUTHOR__</a>' );
|
|
21
|
+
?>
|
|
22
|
+
</div><!-- .site-info -->
|
|
23
|
+
</footer><!-- #colophon -->
|
|
24
|
+
</div><!-- #page -->
|
|
25
|
+
|
|
26
|
+
<?php wp_footer(); ?>
|
|
27
|
+
</body>
|
|
28
|
+
</html>
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
<?php
|
|
2
|
+
/**
|
|
3
|
+
* Theme functions and definitions
|
|
4
|
+
*
|
|
5
|
+
* @package __THEME_NAME__
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
if ( ! defined( 'ABSPATH' ) ) {
|
|
9
|
+
exit; // Exit if accessed directly.
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
// Include required setup files
|
|
13
|
+
require_once get_template_directory() . '/inc/setup.php';
|
|
14
|
+
require_once get_template_directory() . '/inc/enqueue.php';
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
<?php
|
|
2
|
+
/**
|
|
3
|
+
* The header for our theme
|
|
4
|
+
*
|
|
5
|
+
* @package __THEME_NAME__
|
|
6
|
+
*/
|
|
7
|
+
?>
|
|
8
|
+
<!doctype html>
|
|
9
|
+
<html <?php language_attributes(); ?>>
|
|
10
|
+
<head>
|
|
11
|
+
<meta charset="<?php bloginfo( 'charset' ); ?>">
|
|
12
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
13
|
+
<link rel="profile" href="https://gmpg.org/xfn/11">
|
|
14
|
+
|
|
15
|
+
<?php wp_head(); ?>
|
|
16
|
+
</head>
|
|
17
|
+
|
|
18
|
+
<body <?php body_class(); ?>>
|
|
19
|
+
<?php wp_body_open(); ?>
|
|
20
|
+
<div id="page" class="site">
|
|
21
|
+
<header id="masthead" class="site-header">
|
|
22
|
+
<div class="site-branding">
|
|
23
|
+
<?php
|
|
24
|
+
if ( has_custom_logo() ) :
|
|
25
|
+
the_custom_logo();
|
|
26
|
+
else :
|
|
27
|
+
?>
|
|
28
|
+
<h1 class="site-title"><a href="<?php echo esc_url( home_url( '/' ) ); ?>" rel="home"><?php bloginfo( 'name' ); ?></a></h1>
|
|
29
|
+
<?php
|
|
30
|
+
$theme_description = get_bloginfo( 'description', 'display' );
|
|
31
|
+
if ( $theme_description || is_customize_preview() ) :
|
|
32
|
+
?>
|
|
33
|
+
<p class="site-description"><?php echo $theme_description; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?></p>
|
|
34
|
+
<?php endif;
|
|
35
|
+
endif;
|
|
36
|
+
?>
|
|
37
|
+
</div><!-- .site-branding -->
|
|
38
|
+
|
|
39
|
+
<nav id="site-navigation" class="main-navigation">
|
|
40
|
+
<?php
|
|
41
|
+
wp_nav_menu( array(
|
|
42
|
+
'theme_location' => 'menu-1',
|
|
43
|
+
'menu_id' => 'primary-menu',
|
|
44
|
+
) );
|
|
45
|
+
?>
|
|
46
|
+
</nav><!-- #site-navigation -->
|
|
47
|
+
</header><!-- #masthead -->
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
<?php
|
|
2
|
+
/**
|
|
3
|
+
* Enqueue scripts and styles
|
|
4
|
+
*
|
|
5
|
+
* @package __THEME_NAME__
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
function __TEXT_DOMAIN___scripts() {
|
|
9
|
+
// Enqueue main stylesheet.
|
|
10
|
+
wp_enqueue_style( '__TEXT_DOMAIN___style', get_stylesheet_uri(), array(), '1.0.0' );
|
|
11
|
+
|
|
12
|
+
// Enqueue base CSS.
|
|
13
|
+
wp_enqueue_style( '__TEXT_DOMAIN___main-style', get_template_directory_uri() . '/assets/css/main.css', array(), '1.0.0' );
|
|
14
|
+
|
|
15
|
+
// Enqueue main JavaScript.
|
|
16
|
+
wp_enqueue_script( '__TEXT_DOMAIN___main-script', get_template_directory_uri() . '/assets/js/main.js', array(), '1.0.0', true );
|
|
17
|
+
|
|
18
|
+
if ( is_singular() && comments_open() && get_option( 'thread_comments' ) ) {
|
|
19
|
+
wp_enqueue_script( 'comment-reply' );
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
add_action( 'wp_enqueue_scripts', '__TEXT_DOMAIN___scripts' );
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
<?php
|
|
2
|
+
/**
|
|
3
|
+
* Theme setup functions
|
|
4
|
+
*
|
|
5
|
+
* @package __THEME_NAME__
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
if ( ! function_exists( '__TEXT_DOMAIN___setup' ) ) :
|
|
9
|
+
function __TEXT_DOMAIN___setup() {
|
|
10
|
+
// Add default posts and comments RSS feed links to head.
|
|
11
|
+
add_theme_support( 'automatic-feed-links' );
|
|
12
|
+
|
|
13
|
+
// Let WordPress manage the document title.
|
|
14
|
+
add_theme_support( 'title-tag' );
|
|
15
|
+
|
|
16
|
+
// Enable support for Post Thumbnails on posts and pages.
|
|
17
|
+
add_theme_support( 'post-thumbnails' );
|
|
18
|
+
|
|
19
|
+
// This theme uses wp_nav_menu() in one location.
|
|
20
|
+
register_nav_menus(
|
|
21
|
+
array(
|
|
22
|
+
'menu-1' => esc_html__( 'Primary Menu', '__TEXT_DOMAIN__' ),
|
|
23
|
+
)
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
// Switch default core markup for search form, comment form, and comments to output valid HTML5.
|
|
27
|
+
add_theme_support(
|
|
28
|
+
'html5',
|
|
29
|
+
array(
|
|
30
|
+
'search-form',
|
|
31
|
+
'comment-form',
|
|
32
|
+
'comment-list',
|
|
33
|
+
'gallery',
|
|
34
|
+
'caption',
|
|
35
|
+
'style',
|
|
36
|
+
'script',
|
|
37
|
+
)
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
// Add theme support for selective refresh for widgets.
|
|
41
|
+
add_theme_support( 'customize-selective-refresh-widgets' );
|
|
42
|
+
}
|
|
43
|
+
endif;
|
|
44
|
+
add_action( 'after_setup_theme', '__TEXT_DOMAIN___setup' );
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
<?php
|
|
2
|
+
/**
|
|
3
|
+
* The main template file
|
|
4
|
+
*
|
|
5
|
+
* @package __THEME_NAME__
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
get_header();
|
|
9
|
+
?>
|
|
10
|
+
|
|
11
|
+
<main id="primary" class="site-main">
|
|
12
|
+
<?php
|
|
13
|
+
if ( have_posts() ) :
|
|
14
|
+
while ( have_posts() ) :
|
|
15
|
+
the_post();
|
|
16
|
+
// Include the Post-Format-specific template for the content.
|
|
17
|
+
// You can create a template part for this like template-parts/content.php
|
|
18
|
+
the_title( '<h1 class="entry-title">', '</h1>' );
|
|
19
|
+
the_content();
|
|
20
|
+
endwhile;
|
|
21
|
+
|
|
22
|
+
the_posts_navigation();
|
|
23
|
+
|
|
24
|
+
else :
|
|
25
|
+
echo '<p>' . esc_html__( 'No content found', '__TEXT_DOMAIN__' ) . '</p>';
|
|
26
|
+
endif;
|
|
27
|
+
?>
|
|
28
|
+
</main><!-- #primary -->
|
|
29
|
+
|
|
30
|
+
<?php
|
|
31
|
+
get_footer();
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
<?php
|
|
2
|
+
/**
|
|
3
|
+
* The template for displaying all single pages
|
|
4
|
+
*
|
|
5
|
+
* @package __THEME_NAME__
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
get_header();
|
|
9
|
+
?>
|
|
10
|
+
|
|
11
|
+
<main id="primary" class="site-main">
|
|
12
|
+
<?php
|
|
13
|
+
while ( have_posts() ) :
|
|
14
|
+
the_post();
|
|
15
|
+
?>
|
|
16
|
+
<article id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
|
|
17
|
+
<header class="entry-header">
|
|
18
|
+
<?php the_title( '<h1 class="entry-title">', '</h1>' ); ?>
|
|
19
|
+
</header><!-- .entry-header -->
|
|
20
|
+
|
|
21
|
+
<div class="entry-content">
|
|
22
|
+
<?php
|
|
23
|
+
the_content();
|
|
24
|
+
wp_link_pages( array(
|
|
25
|
+
'before' => '<div class="page-links">' . esc_html__( 'Pages:', '__TEXT_DOMAIN__' ),
|
|
26
|
+
'after' => '</div>',
|
|
27
|
+
) );
|
|
28
|
+
?>
|
|
29
|
+
</div><!-- .entry-content -->
|
|
30
|
+
</article><!-- #post-<?php the_ID(); ?> -->
|
|
31
|
+
<?php
|
|
32
|
+
// If comments are open or we have at least one comment, load up the comment template.
|
|
33
|
+
if ( comments_open() || get_comments_number() ) :
|
|
34
|
+
comments_template();
|
|
35
|
+
endif;
|
|
36
|
+
endwhile; // End of the loop.
|
|
37
|
+
?>
|
|
38
|
+
</main><!-- #primary -->
|
|
39
|
+
|
|
40
|
+
<?php
|
|
41
|
+
get_footer();
|
|
File without changes
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Theme Name: __THEME_NAME__
|
|
3
|
+
Theme URI:
|
|
4
|
+
Author: __AUTHOR__
|
|
5
|
+
Author URI:
|
|
6
|
+
Description: __DESCRIPTION__
|
|
7
|
+
Version: 1.0.0
|
|
8
|
+
Tested up to: 6.4
|
|
9
|
+
Requires PHP: 7.4
|
|
10
|
+
Text Domain: __TEXT_DOMAIN__
|
|
11
|
+
License: MIT
|
|
12
|
+
License URI: https://opensource.org/licenses/MIT
|
|
13
|
+
*/
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
<?php
|
|
2
|
+
/**
|
|
3
|
+
* Template part for displaying posts
|
|
4
|
+
*
|
|
5
|
+
* @package __THEME_NAME__
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
?>
|
|
9
|
+
<article id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
|
|
10
|
+
<header class="entry-header">
|
|
11
|
+
<?php
|
|
12
|
+
if ( is_singular() ) :
|
|
13
|
+
the_title( '<h1 class="entry-title">', '</h1>' );
|
|
14
|
+
else :
|
|
15
|
+
the_title( '<h2 class="entry-title"><a href="' . esc_url( get_permalink() ) . '" rel="bookmark">', '</a></h2>' );
|
|
16
|
+
endif;
|
|
17
|
+
?>
|
|
18
|
+
</header><!-- .entry-header -->
|
|
19
|
+
|
|
20
|
+
<div class="entry-content">
|
|
21
|
+
<?php
|
|
22
|
+
the_content(
|
|
23
|
+
sprintf(
|
|
24
|
+
wp_kses(
|
|
25
|
+
/* translators: %s: Name of current post. Only visible to screen readers */
|
|
26
|
+
__( 'Continue reading<span class="screen-reader-text"> "%s"</span>', '__TEXT_DOMAIN__' ),
|
|
27
|
+
array(
|
|
28
|
+
'span' => array(
|
|
29
|
+
'class' => array(),
|
|
30
|
+
),
|
|
31
|
+
)
|
|
32
|
+
),
|
|
33
|
+
wp_kses_post( get_the_title() )
|
|
34
|
+
)
|
|
35
|
+
);
|
|
36
|
+
?>
|
|
37
|
+
</div><!-- .entry-content -->
|
|
38
|
+
</article><!-- #post-<?php the_ID(); ?> -->
|