Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add generator for meta boxes #134

Merged
merged 2 commits into from
Nov 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ Out of the box, this template provides a minimal WordPress theme with basic supp
- Shortcodes
- Custom taxonomies
- Reusable patterns
- Meta boxes
- Sample custom blocks which you can reference to create your own custom blocks
- Code style rules that are enforced by language-specific linters
- GitHub Action workflows for code quality, release management, and deployment processes
Expand Down Expand Up @@ -453,6 +454,20 @@ The following files will be created based on your input:

See [custom block structure](#custom-block-structure) for more info on what these files are for.

### Meta Box

The generator for meta boxes will prompt you for a meta box name, a label for an input, which post type(s) the meta box should be enabled for, and where the box should be positioned based on context and priority. The generator only adds a single text input field for demonstration purposes. Different input types and advanced use cases will require developers to implement them. It may be better to use a plugin like [Advanced Custom Fields][advanced-custom-fields] for some situations, especially when a WordPress admin should be able to manage the fields without devloper help.

```sh
npm run generate:meta-box
```

The following file will be created based on your input:

- `src/php/inc/meta-boxes/class-<meta-box-name>.php`

[Meta Box documentation](https://developer.wordpress.org/plugins/metadata/custom-meta-boxes/)

## Plugins

### Installing Plugins
Expand Down
176 changes: 176 additions & 0 deletions generators/meta-box.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
const { writeFileSync } = require('fs');
const { join } = require('path');
const prompts = require('prompts');

const getScriptTemplate = ({
name,
label,
abstractClassName,
boxIdentifier,
postTypes,
context,
priority,
}) => `<?php
/**
* File for setting up the ${name} meta box.
*/

/**
* Class that handles all functionality for the ${name} meta box.
*/
abstract class ${abstractClassName} {
/**
* Set up and add the meta box.
*/
public static function add() {
/**
* Set up basic details about the meta box.
*
* @see https://developer.wordpress.org/reference/functions/add_meta_box/
*/
add_meta_box(
'${boxIdentifier}_id',
'${name}',
array( self::class, '${boxIdentifier}_html' ),
array( ${postTypes.map((postType) => `'${postType}'`).join(', ')} ),
'${context}',
'${priority}',
);
}

/**
* Save the meta box selections.
*
* @param int $post_id The post ID.
*/
public static function save( $post_id ) {
if ( ! isset( $_POST['${boxIdentifier}_nonce'] ) || ! wp_verify_nonce( sanitize_key( $_POST['${boxIdentifier}_nonce'] ), basename( __FILE__ ) ) ) {
return $post_id;
}

$post = get_post( $post_id );
$post_type = get_post_type_object( $post->post_type );
if ( ! current_user_can( $post_type->cap->edit_post, $post_id ) ) {
return $post_id;
}

if ( array_key_exists( '${boxIdentifier}', $_POST ) ) {
update_post_meta(
$post_id,
'_${boxIdentifier}',
sanitize_text_field( wp_unslash( $_POST['${boxIdentifier}'] ) )
);
}
}

/**
* Display the meta box HTML to the user.
*
* @param WP_Post $post Post object.
*/
public static function ${boxIdentifier}_html( $post ) {
wp_nonce_field( basename( __FILE__ ), '${boxIdentifier}_nonce' );
$value = get_post_meta( $post->ID, '_${boxIdentifier}', true );
?>
<div>
<label for="${boxIdentifier}">${label}</label>
<div>
<input id="${boxIdentifier}" type="text" name="${boxIdentifier}" value="<?php echo esc_attr( $value ); ?>">
</div>
</div>
<?php
}
}

add_action( 'add_meta_boxes', array( '${abstractClassName}', 'add' ) );
add_action( 'save_post', array( '${abstractClassName}', 'save' ) );
`;

const getDetails = async () => {
const questions = [
{
type: 'text',
name: 'name',
message: 'What should the meta box be called?',
},
{
type: 'text',
name: 'label',
message: 'What should be the label for the field?',
},
{
type: 'list',
name: 'postTypes',
message:
'Which post types should this meta box be enabled for? Enter post type slugs separated by commas (the slugs should match the first argument used in register_post_type).',
initial: 'post',
separator: ',',
},
{
type: 'select',
name: 'context',
message: 'In which context should the box be displayed by default? (It can be moved by admins later)',
choices: [
{
title: 'side (in the sidebar)',
value: 'side',
},
{
title: 'normal (below the post body)',
value: 'normal',
},
{
title: 'advanced (below the post body and "normal" meta boxes)',
value: 'advanced',
},
],
initial: 0,
},
{
type: 'select',
name: 'priority',
message:
'What priority level should be used for placing this box by default? (It can be moved by admins later)',
choices: [
{
title: 'high',
value: 'high',
},
{
title: 'core',
value: 'core',
},
{
title: 'default',
value: 'default',
},
{
title: 'low',
value: 'low',
},
],
initial: 2,
},
];

const response = await prompts(questions);

return response;
};

const generatePageTemplate = async () => {
const { name, label, postTypes, context, priority } = await getDetails();
const abstractClassName = name.replace(/\W/g, '_');
const boxIdentifier = name.toLowerCase().replace(/\W/g, '_');
const templateDetails = { name, label, abstractClassName, boxIdentifier, postTypes, context, priority };

const scriptTemplate = getScriptTemplate(templateDetails);

const fileName = `class-${name.toLowerCase().replace(/\W/g, '-')}`;
const scriptPath = join(__dirname, '../src/php/inc/meta-boxes', `${fileName}.php`);

writeFileSync(scriptPath, scriptTemplate, 'utf-8');
console.log(`Created ${scriptPath}`);
};

generatePageTemplate();
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
"preimport:uploads": "npm run backup:uploads",
"generate:custom-block": "node ./generators/custom-block.js",
"generate:custom-blocks-plugin": "node ./generators/custom-blocks-plugin.js",
"generate:meta-box": "node ./generators/meta-box.js",
"generate:page-template": "node ./generators/page-template.js",
"generate:pattern": "node ./generators/pattern.js",
"generate:post-type": "node ./generators/post-type.js",
Expand Down
7 changes: 7 additions & 0 deletions src/php/functions.php
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,13 @@
require_once $filename;
}

/**
* Custom Meta Boxes
*/
foreach ( glob( get_template_directory() . '/inc/meta-boxes/*.php' ) as $filename ) {
require_once $filename;
}

/**
* Enqueue scripts and styles.
*/
Expand Down
Empty file added src/php/inc/meta-boxes/.gitkeep
Empty file.