diff --git a/config/services/wp-console/generate.yml b/config/services/wp-console/generate.yml index 25217be..5722a1c 100644 --- a/config/services/wp-console/generate.yml +++ b/config/services/wp-console/generate.yml @@ -82,5 +82,10 @@ services: console.generate_cron_single: class: WP\Console\Command\Generate\CronSingleCommand arguments: ['@console.cron_base_generator', '@console.extension_manager', '@console.validator', '@console.string_converter'] + tags: + - { name: wordpress.command } + console.generate_settings_page: + class: WP\Console\Command\Generate\SettingsPageCommand + arguments: ['@console.settings_page_generator', '@console.extension_manager', '@console.validator', '@console.string_converter', '@console.wordpress_api'] tags: - { name: wordpress.command } \ No newline at end of file diff --git a/config/services/wp-console/generator.yml b/config/services/wp-console/generator.yml index e54486f..186e69b 100644 --- a/config/services/wp-console/generator.yml +++ b/config/services/wp-console/generator.yml @@ -70,5 +70,10 @@ services: console.cron_base_generator: class: WP\Console\Generator\CronBaseGenerator arguments: ['@console.extension_manager'] + tags: + - { name: wordpress.generator } + console.settings_page_generator: + class: WP\Console\Generator\SettingsPageGenerator + arguments: ['@console.extension_manager'] tags: - { name: wordpress.generator } \ No newline at end of file diff --git a/config/translations/en/generate.settings.page.yml b/config/translations/en/generate.settings.page.yml new file mode 100644 index 0000000..ae0d46d --- /dev/null +++ b/config/translations/en/generate.settings.page.yml @@ -0,0 +1,49 @@ +description: 'Generate a new custom settings page.' +help: 'The generate:settings:page command helps you generates a new Settings page.' +welcome: 'Welcome to the Wordpress Settings page generator' +options: + plugin: 'The Plugin name.' + class-name: 'The settings page function name' + setting-group: 'Name of the settings group used in register_setting' + setting-name: 'Name of the options saved in the database.' + page-title: 'Setting Page title' + menu-title: 'Admin sidebar menu title.' + capability: 'Access permission.' + slug: 'Unique slug for the admin page' + callback-function: 'The name of the layout function.' + section-field: 'Section to add fields.' + fields: 'Setting Page fields.' + text-domain: 'Translations file.' +questions: + plugin: 'The plugin name' + class-name: 'Enter settings page class name' + setting-group: 'Enter the name of the settings group used in register_setting' + setting-name: 'Enter the name of the options saved in the database' + page-title: 'Enter the setting Page title' + menu-title: 'Enter the admin sidebar menu title' + capability: 'Choice the capability to give access permission' + slug: 'Enter the slug for the admin page' + callback-function: 'Enter the name of the layout function' + section-add: 'Do you want add section to fields' + section-name: 'Enter the name to the new section' + section-add-another: 'Do you want to add another section' + fields: + fields-add: 'Do you want to generate the fields' + type: 'Enter field type' + id: 'Enter field id' + label: 'Enter field label' + description: 'Enter field description' + placeholder: 'Enter field placeholder' + default-value: 'Enter field default value' + src_image: 'Enter the image path' + section-id: 'Choice the section to add the field' + fields-add-another: 'Do you want to add another field' + multiple-label: 'Enter the label for option for ' + multiple-value: 'Enter the value for option for ' + multiple-options-add: 'Do you want to add another option for ' + text-domain: 'Enter the text-domain to translation file' +warnings: + plugin-unavailable: 'Warning The following plugin are not already available in your local environment "%s"' +errors: + directory-exists: 'The target directory "%s" is not empty.' + interval-invalid: 'The interval must be a number' \ No newline at end of file diff --git a/src/Command/Generate/SettingsPageCommand.php b/src/Command/Generate/SettingsPageCommand.php new file mode 100644 index 0000000..86c365e --- /dev/null +++ b/src/Command/Generate/SettingsPageCommand.php @@ -0,0 +1,380 @@ +generator = $generator; + $this->extensionManager = $extensionManager; + $this->validator = $validator; + $this->stringConverter = $stringConverter; + $this->wordpressApi = $wordpressApi; + parent::__construct(); + } + + /** + * {@inheritdoc} + */ + protected function configure() + { + $this + ->setName('generate:settings:page') + ->setDescription($this->trans('commands.generate.settings.page.description')) + ->setHelp($this->trans('commands.generate.settings.page.help')) + ->addOption( + 'plugin', + '', + InputOption::VALUE_REQUIRED, + $this->trans('commands.common.options.plugin') + ) + ->addOption( + 'class-name', + '', + InputOption::VALUE_REQUIRED, + $this->trans('commands.generate.settings.page.options.class-name') + ) + ->addOption( + 'setting-group', + '', + InputOption::VALUE_REQUIRED, + $this->trans('commands.generate.settings.page.options.setting-group') + ) + ->addOption( + 'setting-name', + '', + InputOption::VALUE_REQUIRED, + $this->trans('commands.generate.settings.page.options.setting-name') + ) + ->addOption( + 'menu-title', + '', + InputOption::VALUE_REQUIRED, + $this->trans('commands.generate.settings.page.options.menu-title') + ) + ->addOption( + 'capability', + '', + InputOption::VALUE_REQUIRED, + $this->trans('commands.generate.settings.page.options.user-capability') + ) + ->addOption( + 'slug', + null, + InputOption::VALUE_REQUIRED, + $this->trans('commands.generate.settings.page.options.slug') + ) + ->addOption( + 'callback-function', + null, + InputOption::VALUE_REQUIRED, + $this->trans('commands.generate.settings.page.options.callback-function') + ) + ->addOption( + 'page-title', + '', + InputOption::VALUE_OPTIONAL, + $this->trans('commands.generate.settings.page.options.page-title') + ) + ->addOption( + 'sections', + null, + InputOption::VALUE_OPTIONAL, + $this->trans('commands.generate.settings.page.options.section') + ) + ->addOption( + 'fields', + null, + InputOption::VALUE_OPTIONAL, + $this->trans('commands.generate.settings.page.options.fields') + ) + ->addOption( + 'text-domain', + null, + InputOption::VALUE_OPTIONAL, + $this->trans('commands.generate.settings.page.options.text-domain') + ) + ->setAliases(['gsp']); + } + + /** + * {@inheritdoc} + */ + protected function execute(InputInterface $input, OutputInterface $output) + { + $io = new WPStyle($input, $output); + + // @see use WP\Console\Command\Shared\ConfirmationTrait::confirmGeneration + if (!$this->confirmGeneration($io)) { + return; + } + + $plugin = $plugin = $this->validator->validatePluginName($input->getOption('plugin')); + $class_name = $this->validator->validateClassName($input->getOption('class-name')); + $setting_group = $input->getOption('setting-group'); + $setting_name = $input->getOption('setting-name'); + $page_title = $input->getOption('page-title'); + $menu_title = $input->getOption('menu-title'); + $capability = $input->getOption('capability'); + $slug = $input->getOption('slug'); + $callback_function = $this->validator->validateFunctionName($input->getOption('callback-function')); + $sections= $input->getOption('sections'); + $fields = $input->getOption('fields'); + $text_domain = $input->getOption('text-domain'); + + $this->generator->generate( + $plugin, + $class_name, + $setting_group, + $setting_name, + $page_title, + $menu_title, + $capability, + $slug, + $callback_function, + $sections, + $fields, + $text_domain + ); + } + + /** + * {@inheritdoc} + */ + protected function interact(InputInterface $input, OutputInterface $output) + { + $io = new WPStyle($input, $output); + + // --plugin + $plugin = $input->getOption('plugin'); + if (!$plugin) { + $plugin = $this->pluginQuestion($io); + $input->setOption('plugin', $plugin); + } + + // --class name + $class_name = $input->getOption('class-name'); + if (!$class_name) { + $class_name = $io->ask( + $this->trans('commands.generate.settings.page.questions.class-name'), + 'CustomSettingsPage', + function ($value) { + if (!strlen(trim($value))) { + throw new \Exception('The Class name can not be empty'); + } + return $this->stringConverter->humanToCamelCase($value); + } + ); + $input->setOption('class-name', $class_name); + } + + // --setting group + $setting_group = $input->getOption('setting-group'); + if (!$setting_group) { + $setting_group = $io->ask( + $this->trans('commands.generate.settings.page.questions.setting-group'), + strtolower($class_name).'_group' + ); + } + $input->setOption('setting-group', $setting_group); + + // --setting name + $setting_name = $input->getOption('setting-name'); + if (!$setting_name) { + $setting_name = $io->ask( + $this->trans('commands.generate.settings.page.questions.setting-name'), + strtolower($class_name).'_name' + ); + } + $input->setOption('setting-name', $setting_name); + + // --capability + $capability = $input->getOption('capability'); + if (!$capability) { + $capability = $io->choiceNoList( + $this->trans('commands.generate.settings.page.questions.capability'), + $this->wordpressApi->getCapabilities(), + "manage_options" + ); + } + $input->setOption('capability', $capability); + + // --slug + $slug = $input->getOption('slug'); + if (!$slug) { + $slug = $io->ask( + $this->trans('commands.generate.settings.page.questions.slug'), + $this->stringConverter->createMachineName($menu_title), + function ($value) { + return $this->stringConverter->createMachineName($value); + } + ); + } + $input->setOption('slug', $slug); + + + // --callback function + $callback_function = $input->getOption('callback-function'); + if (!$callback_function) { + $callback_function = $io->ask( + $this->trans('commands.generate.settings.page.questions.callback-function'), + null, + function ($function) { + return $this->validator->validateFunctionName($function); + } + ); + } + $input->setOption('callback-function', $callback_function); + + // --menu title + $menu_title = $input->getOption('menu-title'); + if (!$menu_title) { + $menu_title = $io->ask( + $this->trans('commands.generate.settings.page.questions.menu-title'), + 'Custom Setting Page' + ); + } + $input->setOption('menu-title', $menu_title); + + // --page title + $page_title = $input->getOption('page-title'); + if (!$page_title) { + $page_title = $io->ask( + $this->trans('commands.generate.settings.page.questions.page-title'), + $menu_title + ); + } + $input->setOption('page-title', $page_title); + + // --sections + $sections = $input->getOption('sections'); + if (!$sections) { + $sections = []; + if ($io->confirm( + $this->trans('commands.generate.settings.page.questions.section-add'), + true + ) + ) { + $validate_menu = ''; + while (true) { + $name = $io->ask( + $this->trans('commands.generate.settings.page.questions.section-name'), + 'My custom section settings', + function ($value) use ($validate_menu) { + if ($value == $validate_menu) { + throw new \Exception('The name already exist'); + } + return $value; + } + ); + + if (empty($name)) { + break; + } + + $validate_menu = $name; + + $sections[$this->stringConverter->createMachineName($name)] = $name; + + if (!$io->confirm( + $this->trans('commands.generate.settings.page.questions.section-add-another'), + false + ) + ) { + break; + } + } + } + } + $input->setOption('sections', $sections); + + // --fields + $fields = $input->getOption('fields'); + if (!empty($sections)) { + if (!$fields) { + if ($io->confirm( + $this->trans('commands.generate.settings.page.questions.fields.fields-add'), + true + ) + ) { + // @see \WP\Console\Command\Shared\FieldsTypeTrait::fieldsQuestion + $fields = $this->fieldsQuestion($io, 'settings.page', 'fields', $sections); + $input->setOption('fields', $fields); + } + } + } + + // --text domain + $text_domain = $input->getOption('text-domain'); + if (!$text_domain) { + $text_domain = $io->askEmpty( + $this->trans('commands.generate.settings.page.questions.text-domain') + ); + } + $input->setOption('text-domain', $text_domain); + } +} diff --git a/src/Command/Shared/FieldsTypeTrait.php b/src/Command/Shared/FieldsTypeTrait.php index 972d37f..83b7685 100644 --- a/src/Command/Shared/FieldsTypeTrait.php +++ b/src/Command/Shared/FieldsTypeTrait.php @@ -17,7 +17,7 @@ trait FieldsTypeTrait { - public function fieldsQuestion(WPStyle $io, $command) + public function fieldsQuestion(WPStyle $io, $command, $optionName, $sections = null) { $stringConverter = $this->stringConverter; @@ -27,7 +27,7 @@ public function fieldsQuestion(WPStyle $io, $command) $count = 0; while (true) { $type = $io->choiceNoList( - $this->trans('commands.generate.'.$command.'.questions.'.$command.'-items.type'), + $this->trans('commands.generate.'.$command.'.questions.'.$optionName.'.type'), $fields_options, NULL, TRUE @@ -38,12 +38,12 @@ public function fieldsQuestion(WPStyle $io, $command) } $label = $io->ask( - $this->trans('commands.generate.'.$command.'.questions.'.$command.'-items.label'), + $this->trans('commands.generate.'.$command.'.questions.'.$optionName.'.label'), null ); $id = $io->ask( - $this->trans('commands.generate.'.$command.'.questions.'.$command.'-items.id'), + $this->trans('commands.generate.'.$command.'.questions.'.$optionName.'.id'), $this->stringConverter->createMachineName($label), function ($id) use ($stringConverter) { return $stringConverter->createMachineName($id); @@ -51,7 +51,7 @@ function ($id) use ($stringConverter) { ); $description = $io->askEmpty( - $this->trans('commands.generate.'.$command.'.questions.'.$command.'-items.description') + $this->trans('commands.generate.'.$command.'.questions.'.$optionName.'.description') ); array_push( @@ -66,36 +66,38 @@ function ($id) use ($stringConverter) { if ($type != 'select' && $type != 'radio' && $type != 'checkbox') { $placeholder = $io->askEmpty( - $this->trans('commands.generate.'.$command.'.questions.'.$command.'-items.placeholder') + $this->trans('commands.generate.'.$command.'.questions.'.$optionName.'.placeholder') ); $default_value = $io->askEmpty( - $this->trans('commands.generate.'.$command.'.questions.'.$command.'-items.default-value') + $this->trans('commands.generate.'.$command.'.questions.'.$optionName.'.default-value') ); $fields[$count]['placeholder'] = $placeholder; $fields[$count]['default_value'] = $default_value; } - if ($type == 'select' || $type == 'radio' || $type == 'checkbox') { - if ($io->confirm( - $this->trans('commands.generate.'.$command.'.questions.'.$command.'-items.multiple-options', $type), - false - ) - ) { - $fields[$count]['multi_selection'] = $this->multiSelection($io, $type, $command); - } + if ($type == 'select' || $type == 'radio') { + $fields[$count]['multi_selection'] = $this->multiSelection($io, $type, $command, $optionName); } if ($type == 'image') { $src = $io->ask( - $this->trans('commands.generate.'.$command.'.questions.'.$command.'-items.src') + $this->trans('commands.generate.'.$command.'.questions.'.$optionName.'.src') ); $fields[$count]['src_image'] = $src; } + if ($command == 'settings.page') { + $section_id = $io->choice( + $this->trans('commands.generate.settings.page.questions.fields.section-id'), + array_values($sections) + ); + $fields[$count]['section_id'] = array_search($section_id, $sections); + } + if (!$io->confirm( - $this->trans('commands.generate.'.$command.'.questions.'.$command.'-items.'.$command.'-add-another'), + $this->trans('commands.generate.'.$command.'.questions.'.$optionName.'.'.$optionName.'-add-another'), false ) ) { @@ -107,18 +109,18 @@ function ($id) use ($stringConverter) { return $fields; } - private function multiSelection(WPStyle $io, $type, $command) + private function multiSelection(WPStyle $io, $type, $command, $optionName) { $multiple_options = []; while (true) { $multiple_options_label = $io->ask( - $this->trans('commands.generate.'.$command.'.questions.'.$command.'-items.multiple-label'), + $this->trans('commands.generate.'.$command.'.questions.'.$optionName.'.multiple-label').$type, '' ); $multiple_options_value = $io->ask( - $this->trans('commands.generate.'.$command.'.questions.'.$command.'-items.multiple-value'), + $this->trans('commands.generate.'.$command.'.questions.'.$optionName.'.multiple-value').$type, '' ); @@ -130,7 +132,7 @@ private function multiSelection(WPStyle $io, $type, $command) ] ); if (!$io->confirm( - $this->trans('commands.generate.'.$command.'.questions.'.$command.'-items.multiple-options-add', $type), + $this->trans('commands.generate.'.$command.'.questions.'.$optionName.'.multiple-options-add').$type, false ) ) { diff --git a/src/Generator/SettingsPageGenerator.php b/src/Generator/SettingsPageGenerator.php new file mode 100644 index 0000000..ce4d509 --- /dev/null +++ b/src/Generator/SettingsPageGenerator.php @@ -0,0 +1,128 @@ +extensionManager = $extensionManager; + } + + + /** + * Generator SettingsPage + * + * @param string $plugin, + * @param string $class_name + * @param string $setting_group + * @param string $setting_name + * @param string $page_title + * @param string $menu_title + * @param string $capability + * @param string $slug + * @param string $callback_function + * @param array $sections + * @param array $fields + * @param string $text_domain + */ + public function generate( + $plugin, + $class_name, + $setting_group, + $setting_name, + $page_title, + $menu_title, + $capability, + $slug, + $callback_function, + $sections, + $fields, + $text_domain + ) { + $pluginFile = $this->extensionManager->getPlugin($plugin)->getPathname(); + $dir = $this->extensionManager->getPlugin($plugin)->getPath(); + + $parameters = [ + "plugin" => $plugin, + "class_name" => $class_name, + "setting_group" => $setting_group, + "setting_name" => $setting_name, + "page_title" => $page_title, + "menu_title" => $menu_title, + "capability" => $capability, + "slug" => $slug, + "callback_function" => $callback_function, + "sections" => $sections, + "fields" => $fields, + "text_domain" => $text_domain, + "class_name_path" => 'SettingsPage/' . lcfirst($class_name) . '.php', + "admin_settings_page_path" => 'admin/partials/settings-page-admin.php', + "file_exists" => file_exists($pluginFile), + "command_name" => 'settingspage' + ]; + + $file_path = $dir.'/admin/partials/'.$parameters['class_name_path']; + $file_path_admin = $dir.'/'.$parameters['admin_settings_page_path']; + + if (file_exists($file_path)) { + if (!is_dir($file_path)) { + throw new \RuntimeException( + sprintf( + 'Unable to generate the settings page , it already exist at "%s"', + realpath($file_path) + ) + ); + } + } + + if (!file_exists($file_path_admin)) { + $this->renderFile( + 'plugin/plugin.php.twig', + $pluginFile, + $parameters, + FILE_APPEND + ); + } + + $this->renderFile( + 'plugin/src/SettingsPage/class-settings-page.php.twig', + $file_path, + $parameters + ); + + $parameters['admin_file_exists'] = file_exists($file_path_admin); + + $this->renderFile( + 'plugin/src/class-admin.php.twig', + $file_path_admin, + $parameters, + FILE_APPEND + ); + } +} diff --git a/templates/plugin/plugin.php.twig b/templates/plugin/plugin.php.twig index bac32d0..4043564 100644 --- a/templates/plugin/plugin.php.twig +++ b/templates/plugin/plugin.php.twig @@ -170,4 +170,16 @@ function {{ plugin }}_add_cron_{{ type }}() } {{ plugin }}_add_cron_{{ type }}(); {%- endif -%} +{%- if admin_settings_page_path is defined -%} + +/** + * This function add custom settings page that are in admin/partials/settings-page-admin.php + */ +function {{ plugin }}_add_settings_page() +{ + // Include the files for rendering the display. + include_once plugin_dir_path( __FILE__ ) .'{{ admin_settings_page_path }}'; +} +{{ plugin }}_add_settings_page(); +{%- endif -%} {%- endblock -%} \ No newline at end of file diff --git a/templates/plugin/src/SettingsPage/class-settings-page.php.twig b/templates/plugin/src/SettingsPage/class-settings-page.php.twig new file mode 100644 index 0000000..4831cf3 --- /dev/null +++ b/templates/plugin/src/SettingsPage/class-settings-page.php.twig @@ -0,0 +1,166 @@ +{% extends "base/class.php.twig" %} +{%- block class_declaration -%} +/** + * Create a custom settings page + */ +class {{ class_name }} {% endblock -%} +{% block class_construct %} + /** + * Holds the values to be used in the fields callbacks + */ + private $options; + + /** + * Start up + */ + public function __construct() + { + add_action( 'admin_menu', array( $this, 'add_{{ class_name|lower }}_plugin_page' ) ); + add_action( 'admin_init', array( $this, '{{ class_name|lower}}_page_init' ) ); + } +{% endblock %} + +{% block class_methods %} + + /** + * Add options page + */ + public function add_{{ class_name|lower }}_plugin_page() + { + // This page will be under "Settings" + add_options_page( + 'Settings Submenu', + __( '{{ menu_title }}', '{{ text_domain }}' ), + '{{ capability }}', + '{{ slug }}', + array( $this, '{{ callback_function }}' ) + ); + } + + /** + * Options page callback + */ + public function {{ callback_function }}() + { + // Set class property + $this->options = get_option( '{{ setting_name }}' ); + ?> +
+{% if page_title is not null or page_title is defined %} +

{{ page_title }}

+{% endif %} +
+ +
+
+ +{% for options in field.multi_selection %} + +{% endfor %} + '; +{% elseif field.type == 'radio' %} +{% for options in field.multi_selection %} + echo 'options['{{ field.id }}'], false ).'/> {{ options.label }}
'; +{% endfor %} +{% elseif field.type == 'image' %} + echo '{{ field.description }} +{% elseif field.type == 'checkbox' %} + echo 'options['{{ field.id }}'], false ).'/> {{ options.label }}
'; +{% else %} + printf( + '', + isset( $this->options['{{ field.id }}'] ) ? esc_attr( $this->options['{{ field.id }}']) : '' + ); +{% endif %} + } + +{% endfor %} +{% endif %} +{% endblock %} \ No newline at end of file