Backend Frontend Template Pro: the WordPres Plugin Template

Backend Frontend Template Pro: the WordPress Plugin Template

193,60

El WordPress plugin template que necesitas para crear plugins avanzados de forma rápida, sencilla y profesional. Menús, ajustes, listados automatizados, shortcodes, AJAX, y mucho más.

Ahorra tiempo y concéntrate en desarrollar tu idea.

Categorías: ,

Descripción

Backend Frontend Template Pro es una plantilla y librería con la que desarrollar plugins para WordPress de forma fácil y rápida. No tendrás que reinventar la rueda para conseguir crear un plugin en WordPress, sólo desarrollar tu idea.

Empieza ya, no es necesario saber toda la documentación para desarrollos de plugin para WordPress debido a que no será necesario que conozcas funciones de WordPress como add_menu_page, add_submenu_page, add_settings_section, add_settings_field, register_setting entre otras. Tampoco será necesario que reinventes la rueda modificando por ti mismo la clase WP_List_Table para poder tener un listado en WordPress debido a que WP no provee una forma directa de tener un listado en un plugin. Tampoco será necesario investigar cómo poder hacer un formulario AJAX en la parte cliente, como hacer traducciones, como utilizar el sistema de ajustes de WP,… Este WordPress plugin template lo deja fácil y te explica paso a paso estos puntos a diferencia de un simple WordPress boilerplate que sólo te genera dudas y te hará desperdiciar demasiadas horas

Con esta plantilla/librería puedes desarrollar tu plugin ahora mismo sólo siguiendo la instalación, haciendo el plugin tuyo, comprobando el contenido, y viendo los ejemplos sólo de lo que necesites

Condiciones de descarga

  • Podrás descargarte el programa, en su última versión, durante un año desde la compra
  • No hay límite en el número de descargas
  • Desde tu sección de descargar podrás descargar la última versión actual del producto

Valoraciones

No hay valoraciones aún.

Solo los usuarios registrados que hayan comprado este producto pueden hacer una valoración.

Verión gratuita

Si no tienes claro el tiempo que te ahorrará BFT Pro, puedes descargarte ya la versión base desde este enlace, GitHub o desde el repositorio de plugins de WordPress (próximamente) y empezar a acelerar ya el desarrollo de tu plugin, y en el momento en el que necesites más puedes adquirir Backend Frontend Template Pro: the WordPres Plugin Template y actualizar las librerías
BFT BFT Pro
Sistema de menú
Manipulación del log
Manipulación de los errores
Internalización
Sistema de frontend por shortcode
Menú con hijos anidables No
Sistema de ajustes/datos almacenados por WP No
Sistema de ipunts, incluyendo imágenes y archivos tratados por WP No
Base de datos de ejemplo No
Menú de instalación y desistalación de la BBDD del plugin No
Manipulación de datos automatizada de la BBDD del plugin No
Listados y formularios automatizados a través de la BBDD del plugin No
Listado paginado por consulta MySQL/Maria DB No
Listado directo por array No
Formulario manual No
Sistema de descargar para archivos privados No
Sistema de iframes No
PDF por sistema de iframes No
Sistema de frontend por shortcode con AJAX No
Sistema de formulario frontend por shortcode con respuesta AJAX No

Documentación

El plugin contiene toda la documentación con ejemplos, y además se puede acceder mejor gracias a el sistema de menús anidados, pero aquí encontrarás la documentación básica en caso de que necesites consultarla

Instalación

Desactiva Backend Frontend Template (versión no Pro)

Descarga el código y copia la carpeta “backend-frontend-template-pro” en tu WordPress instalation/wp-content/plugins

Haz que el plugin sea tuyo

  1. Desinstala la base de datos de ejemplo en Bases de datos / Explicación de instalación/desinstalación / Menú de instalación/desinstalación. Puedes reinstalar la base de datos de ejemplo después
  2. Cambia la carpeta y los arcrhivos de wp-content/plugins/backend-frontend-template-pro con el id de tu plugin (como ‘your-plugin’)
  3. Elimina los archivos o cambia sus extensiones:
    1. wp-content/plugins/backend-frontend-template-pro/backend-frontend-template-pro.php
    2. wp-content/plugins/backend-frontend-template-pro/includes/class-bft.php
  4. Cambia la extensión de los archivos a PHP:
    1. wp-content/plugins/backend-frontend-template-pro/your-plugin.txt
    2. wp-content/plugins/backend-frontend-template-pro/includes/class-your-plugin.txt
  5. Descomenta: “//$this->admin_pages_main_name = $this->plugin_title; on wp-content/plugins/backend-frontend-template-pro/admin/class-your-plugin-admin.php
  6. Busca y reemplaza los nombres de los archivos con ‘your-plugin’ como ‘class-your-plugin.php’ a tu plugin id, ejemplo: ‘class-a-plugin-name.php’.
  7. En wp-content/plugins/backend-frontend-template-pro/languages reemplaza los nombres de archivo con ‘bft-internationalization’ a ‘your-plugin’, ejemplo: ‘a-plugin-name-es_ES.mo’
  8. Ve a buscar y reemplazar de tu editor, activa ‘coincidir mayúsculas y minúsculas’ y reemplaza estas cadenas:
    1. ‘bft-internationalization’ a your-plugin
    2. ‘$plugin_slug = “bft_pro”‘ a $plugin_slug = “your_plugin”
    3. ‘bft_shortcode’ a your_plugin_shortcode
    4. ‘bft-shortcode’ a your-plugin-shortcode
  9. Ve a buscar y reemplazar de tu editor, activa “coincidir mayúsculas y minúsculas” y reemplaza estas palabas con los nombres e ids de tu plugin:
    1. Description of Your Plugin
    2. https://yourfuturewebsite/your-plugin/
    3. https://yourfuturewebsite
    4. Plugin Author
    5. pluginauthor@email
    6. Your Plugin
    7. your_plugin
    8. Your_Plugin
    9. your-plugin
    10. YOUR_PLUGIN
  10. Reemplaza el icono por el tuyo propio en wp-content/plugins/backend-frontend-template-pro/admin/img/icon-16px.png

Contenido

  1. Carpetas de BFT Pro

    1. /admin -> carpeta de administración
    2. /includes -> carpeta global, para archivos de administración y públicos
    3. /languages -> archivos de traducción, estos archivos binarios se crean con programas como Poedit o EazyPo
    4. /private -> para datos sensibles que sólo un script de descarga pueda enviar el archivo al usuario
    5. /admin -> carpeta pública
  2. Sub carpetas de BFT Pro

    1. /css -> archivos CSS
    2. /img -> imágenes
    3. /js -> archivos JavaScript
    4. /lib -> librería, los archivos internos de BFT se guardan aquí
    5. /partials -> archivos frontend
  3. Principales archivos de BFT Pro (usando los nombres originales de los archivos)

    1. /includes/class-your-plugin.txt -> clase principal del plugin
    2. /includes/class-your-plugin-activator.php -> controla cuando el plugin es activado
    3. /includes/class-your-plugin-deactivator.php -> controla cuando el plugin es desactivado
    4. /includes/class-your-plugin-cronjobs.php -> controla los cronjobs del plugin
    5. /includes/class-your-plugin-install-upgrade-deinstall-database.php -> instala y elimina la base de datos del plugin
    6. /includes/class-your-plugin-functions-admin-public.php -> clase con funciones para las clases de administración y pública, es una extensión de la clase BFT admin-public
    7. /admin/class-your-plugin-admin.php -> clase para la sección de administración, es una extensión de la clase BFT admin-public, tu clase admin-public y la clase BFT admin
    8. /public/class-your-plugin-public.php -> clase para la sección pública, es una extensión de la clase BFT admin-public, tu clase admin-public y la clase BFT public

Menú pro

Edita tu menú en la variable $this->admin_pages del archivo admin/class-your-plugin-admin.php

Diseñar un menú BFT se ve así:

	$this->admin_pages = [
		"hello_world" => [
			"page_title" => $this->__("Hello world page"),
			"menu_title" => $this->__("Hello world"),
			"file" => "your-plugin-admin-display-hello-world.php",
		],
		"blank_page" => [
			"page_title" => $this->__("Blank page"),
			"menu_title" => $this->__("Blank page"),
			"file" => "bft-admin-display-blank-page-with-title.php",
		],	
	];	

El menú BFT puede tener páginas hijas, ejemplo:

	$this->admin_pages = [
		"hello_world" => [
			"page_title" => $this->__("Hello world page"),
			"menu_title" => $this->__("Hello world"),
			"file" => "your-plugin-admin-display-hello-world.php",
			"children" => [
				"blank_page" => [
					"page_title" => $this->__("Blank page"),
					"menu_title" => $this->__("Blank page"),
					"file" => "bft-admin-display-blank-page-with-title.php",
				],	
			]
		],
	];

Nota: los datos del array son expandidos por la función $this->admin_pages_prepare(), si haces un $this->debug_log_write($this->admin_pages) en una página: puedes ver el estado atual del array en el log de WordPress

Eplicación del menú BFT:

  1. Parámetros automáticos añadidos al array

    • id: la clave del array
    • is_child: añadido y true si es hija
    • page_parent: añadido con la clave del padre si es hija
    • ids_required_get_data: los datos GET encontrados dentro de los ids ‘ids_required’
    • ids_optional_get_data: los datos GET encontrados dentro de los ids ‘ids_optional’
    • ids_aux_required_get_data: los datos GET encontrados dentro de los ids ‘ids_aux_required’
    • ids_aux_optional_get_data: los datos GET encontrados dentro de los ids ‘ids_aux_optional’
    • ids_all: ‘ids_required’, ‘ids_optional’, ‘ids_aux_required’, ‘ids_aux_optional’ todos combinados, este orden es la prioridad para mantener los datos
    • ids_all_get_data: los datos GET encontrados dentro de los ids ‘ids_all’, usa la ‘key_final’ como ‘key’
    • ids_all_get_data_excluded_zeros: ids_all_get_data sin los ids con get data == ‘0’
    • ids_all_get_url: ids_all_get_data transformados en una cadena GET URL ‘&key=data’
    • ids_all_get_data_excluded_zeros: ids_all_get_url sin los ids con get data == ‘0’
    • ids_all_inverse: ids_all en orden inverso, ej:
      	$page_data["ids_all"] = [
      		"key_initial" =>"key_final"
      	]
      	->
      	$page_data["ids_all_inverse"] = [
      		"key_final" =>"key_initial"
      	]
      
    • ids_required_all: ‘ids_required’, ‘ids_aux_required’ todos combinados, este orden es la prioridad para mantener los datos
    • ids_required_all_get_data: los datos GET encontrados dentro de los ids ‘ids_required_all’, usa la ‘key_final’ como ‘key’
    • ids_required_all_get_data_excluded_zeros: ids_required_all_get_data sin los ids con get data == ‘0’
    • ids_optional_all: ‘ids_optional’, ‘ids_aux_optional’ todos combinados, este orden es la prioridad para mantener los datos
    • ids_optional_all_get_data: los datos GET encontrados dentro de los ids ‘ids_optional_all’, usa la ‘key_final’ como ‘key’
    • ids_principal_all: ‘ids_required’, ‘ids_optional’ todos combinados, este orden es la prioridad para mantener los datos
    • ids_principal_all_get_data: los datos GET encontrados dentro de los ids ‘ids_principal_all’, usa la ‘key_final’ como ‘key’
    • ids_aux_all: ‘ids_aux_required’, ‘ids_aux_optional’ todos combinados, este orden es la prioridad para mantener los datos
    • ids_aux_all_get_data: los datos GET encontrados dentro de los ids ‘ids_aux_all’, usa la ‘key_final’ como ‘key’
  2. Parámetros con datos por defecto si no están

    • page_title: título de la página, por defecto: $this->admin_pages_page_title_default
    • menu_title: título de la pestaña de la página, por defecto: $this->admin_pages_page_title_default
    • menu_slug: slug de la página, por defecto: clave de la página. El menú slug se cambiará a: $this->admin_pages_slug_name_prefix.”_”.menu_slug porque es necesario un nombre de página único entre los plugins
    • tab_show: si false no muestra la pestaña de la página, incluso si la página está seleccionada, por defecto: true
    • tabs_new_or_edit_on_url: true añade ‘&action=edit’ o ‘&action=new’ en el link de la pestaña. New si hay un id detectado en los datos GET, por defecto false
    • tabs_show_children: si false no muestra la primera línea de pestañas hijas de una página, por defecto true
    • function: la función para cuando una página se muestra, por defecto: $this->admin_pages_function_default
    • function_load: carga la función antes de que la página se muestre,por defecto: $this->admin_pages_function_load_default
    • file: el admin/partials archivo que se mostrará, default: $this->admin_pages_file_default (Si el archivo empieza con ‘bft-‘ el archivo se cargará de la carpeta admin/lib/BFT/partials
    • error_throw_what_do, es usado en error_throw, opciones:
      • show_error: muestra el error (opción por defecto)
      • show_error_and_die: muestra el error y para la ejecución
      • go_to_parent: va a la página padre y anota en los datos GET el error (sólo funciona si $triggered_on_function_load = true, porque en una función normal de WordPress causará el error: ‘Cannot modify header information – headers already sent’)
    • error_throw_file_change: cambia la opción de archivo si error_throw_what_do es activado, por defecto: false
    • capability, por defecto: ‘manage_options’, capacidades de WordPress: https://wordpress.org/support/article/roles-and-capabilities/
    • IDs: son arrays de datos con ‘name on the GET data’ => ‘id internal to use’, array vacío por defecto
      En los datos GET es necesario poner un id único, ejemplo: ‘book_id’, pero en la página/función quizás es necesitado como ‘id’, entonces usa: ‘book_id’ => ‘id’ Opciones:

      • ids_required (lanza un error si no se ha encontrado un GET id)
      • ids_optional
      • ids_aux_required (lanza un error si no se ha encontrado un GET id, para páginas con datos secundarios)
      • ids_aux_optional (para páginas con datos secundarios)
    • Example:
      	"ids_optional" => [
      		"key_initial" => "key_final",
      		"'key_get'" => "'key_needed'",
      		"book_id" => "id",
      	],
      
    • Nota: si es una página hija quizás habrán ids automáticos: if un padre tiene un id o id auxiliar que no se ha encontrado en la página hija, entonces el hijo tiene el id como un id opcional en ids_optional
  3. Functions disponibles listas para usar (puedes crear cualquier función qué necesites)

    • admin_menu_page_display: muestra la página seleccionada en ‘file’
    • admin_menu_page_table_display_first_menu_child: muestra una tabla con los datos del primer hijo y el formulario almacenado en $this->admin_forms[]
    • admin_menu_page_table_display: muestra una tabla con los datos de la página mostrada
    • admin_menu_admin_form_page_display: mostrar un formulario personalizado automático almacenado en $this->admin_forms[]
  4. Functions load disponibles listas para usar (puedes crear cualquier función qué necesites)

    • redirect_to_first_page_child: redirecciona a la primera página hija de la página actual (ejecuta admin_permission_check_and_ids_required_check_function_load first)
    • admin_permission_check_and_ids_required_check_function_load: comprueba los permisos de administración y comprueba los ids requeridos y opcionales especificados en la URL, tipos de ids princpiales y auxilizares seleccionados, preparado para ‘function_load’, ‘go_to_parent’ usaso si es necesario
    • ids_required_check_function_load: comprueba ids requeridos y opcionales de la página especificada en la URL, tipos de ids principales y auxiliares seleccionados, preparado para ‘function_load’, ‘go_to_parent’ usaso si es necesario
    • download_file_private: descargar archivo privado
    • custom_form_set_do_by_post: enviar un formulario para manipulación automatizada de datos
  5. Parámetros opcionales

    • admin_page_settings_id: para seleccionar la clave a usar en $this->admin_settings[], preparado parar usarse con la función $this->settings_section_form($this->admin_pages_data_get(“admin_page_settings_id”)), esa función es usada en “file” => “bft-admin-display-settings.php”,
    • iframe_url: la URL completa de dentro del iframe, para usar con “file” => “bft-admin-display-iframe.php”
    • iframe_admin_page_slug: el slug de dentro del iframe, el slug del iframe se cambiará a: $this->admin_pages_slug_name_prefix.”_”.menu_slug, para usar con “file” => “bft-admin-display-iframe.php”
    • file_aux_folder_includes: para utilizar una segunda ruta completa con la variable $file_aux_url (parametro ‘file’ genera la variable $file_url )
    • new_text: el texto del botón de nueva entrada, puede añadirse en el padre o en el hijo, la prioridad será en los datos del hijo, para usarse con la función admin_menu_page_table_display_first_menu_child() y archivo bft-admin-display-list-table.php
      Crea la variable $button_add y será finalmente usado en $this->html_button_action
      si new_text is boleano y true usará el texto: $this->__(“New”)
    • admin_forms_aux_id: para página con datos automáticos, usado en la función: admin_pages_data_title_from_admin_forms_aux()
      Muestra el nombre automático del formulario (datos column_title_name) antes de los datos como esto: Nombre automático | Título
      Para el nombre automático es usado el ids_required y ids_optional (sólo el primer ID encontardo), pero sólo es usado la key_inicial (la key_get)
    • children: array con las páginas hijas. Una página hija puede tener descendencia, el máximo de niveles es 5 contando la página padre. Hay un límite porque no es recursivo, eso mata el rendimiento del servidor
    • page_copy_of: copia los datos de una página.Sólo los datos no encontrado en la página, tampoco copia id, is_child, page_parent, menu_slug y children”)?>
  6. Tus propios parámetros

    • Puedes crear tu propio parámetros, después puedes acceder a la información desde una función o una página con:
      $variable_name = $this->admin_pages_data_get(“parametter_name”);Y si quieres puedes recuperar los datos de una página en concreto con $page_name, y recuperar todos los datos del array con $key = false
      $variable_name = $this->admin_pages_data_get($key = false, $page_name = NULL)
    • Puedes establecer tus propios parámetros por código con:
      $this->admin_pages_data_set($key, $data, $page_name = NULL)
  7. Cómo empezar

    • Usa los ejemplos del principio, la mayoría de las opciones no se necesitan inicialmente
    • Extepto todo el ‘id_required’/’id_optional’ parte, eso es importante, pero sólo para páginas hijas. Puedes ver ejemplos detallados en otras páginas donde se necesita, porque la idea es tener una página listado con todas las entradas, y entonces ver una simpre entrada en el hijo, ejemplo:
      	$this->admin_pages = [
      		"books" => [
      			"page_title" => $this->__("List with all the books"),
      			"menu_title" => $this->__("Books"),
      			"function" => "admin_menu_page_table_display_first_menu_child",
      			"file" => "bft-admin-display-list-table.php",
      			"children" => [
      				"book" => [
      					"ids_required" => [
      						"book_id" => "id",
      					],
      					"admin_forms_id" => "books",
      					"page_title" => $this->__("Book selected"),
      					"menu_title" => $this->__("Book"),
      					"function" => "admin_menu_admin_form_page_display",
      					"file" => "bft-admin-display-form.php",
      					"function_load" => "custom_form_set_do_by_post",
      				],	
      			]
      		],
      	];
      

      En este ejemplo rápido hay una página que muestra todos los libros: admin.php?page=your_plugin_books , y cada item/libro enlaza a admin.php?page=your_plugin_book&book_id=[id del libro]

      Y porque ‘book’ tiene ‘ids_required’, la página lanza error automáticamente si un dato GET requerido no es encontrado, book_id en este caso

      Un ejemplo complejo de pestañas anidadas:

      Esto es una parte del menú por defecto usado en BFT, más información en base de datos -> Manipulación de datos automatizada

      	$this->admin_pages = [
      		"database" => [
      				"menu_title" => $this->__("Database"),
      				"page_title" => $this->__("Database"),
      				"file" => "bft-admin-display-menu-system.php",
      				"function_load" => "redirect_to_first_page_child",
      				"children" => [
      					"install_deinstall_upgrade_database_explication" => [...],	
      					"automated_data_manipulation_explication" => [
      						"menu_title" => $this->__("Automated data manipulation"),
      						"page_title" => $this->__("Data managed by BFT"),
      						"file" => "bft-admin-display-automated-data-manipulation-system.php",
      						"children" => [
      							"automated_data_manipulation_courses" => [...],
      							"automated_data_manipulation_students" => [...],
      							"automated_data_manipulation_teachers" => [
      								"menu_title" => $this->__("Teachers"),
      								"page_title" => $this->__("List of teachers"),
      								"function" => "admin_menu_page_table_display_first_menu_child",
      								"file" => "bft-admin-display-list-table.php",
      								"children" => [
      									"automated_data_manipulation_teacher" => [
      										"ids_required" => [
      											"teacher_id" => "id",
      										],
      										"admin_forms_id" => "teachers",
      										"tabs_new_or_edit_on_url" => true,
      										"menu_title" => $this->__("Teacher"),
      										"page_title" => $this->__("Teacher form"),
      										"function" => "admin_menu_admin_form_page_display",
      										"file" => "bft-admin-display-form.php",
      										"function_load" => "custom_form_set_do_by_post",
      										"new_text" => $this->__("New teacher"),
      									],
      									"automated_data_manipulation_teacher_notes" => [
      										"ids_required" => [
      											"teacher_id" => "teacher_id",
      										],
      										"ids_aux_required" => [
      											"teacher_id" => "id",
      										],
      										"admin_forms_aux_id" => "teachers",
      										"menu_title" => $this->__("Teacher notes"),
      										"page_title" => $this->__("List of notes"),
      										"function" => "admin_menu_page_table_display_first_menu_child",
      										"file" => "bft-admin-display-list-table.php",
      										"children" => [
      											"automated_data_manipulation_teacher_note" => [
      												"ids_required" => [
      													"note_id" => "id",
      													"teacher_id" => "teacher_id",
      												],
      												"admin_forms_id" => "teachers_notes",
      												"ids_aux_required" => [
      													"teacher_id" => "id",
      												],
      												"admin_forms_aux_id" => "teachers",
      												"tabs_new_or_edit_on_url" => true,
      												"menu_title" => $this->__("Teacher note"),
      												"page_title" => $this->__("Teacher note form"),
      												"function" => "admin_menu_admin_form_page_display",
      												"file" => "bft-admin-display-form.php",
      												"function_load" => "custom_form_set_do_by_post",
      												"new_text" => $this->__("New note"),
      											],
      										],
      									],
      								],
      							],
      						],
      					],
      				],
      			],
      		],
      	];
      

      Eso genera este menú:

      Datos GET: admin.php?page=bft_pro_automated_data_manipulation_explication

      Backend Frontend Template Pro: menú anidado test 1

      Datos GET: admin.php?page=bft_pro_automated_data_manipulation_teachersn

      Backend Frontend Template Pro: menú anidado test 2, listado de profesores

      Datos GET: admin.php?page=bft_pro_automated_data_manipulation_teacher&action=new&teacher_id=0

      Backend Frontend Template Pro: menú anidado test 3, creando profesor

      Datos GET: admin.php?page=bft_pro_automated_data_manipulation_teacher&action=edit&teacher_id=1

      Backend Frontend Template Pro: menú anidado test 4, profesor creado

      Datos GET: admin.php?page=bft_pro_automated_data_manipulation_teacher_notes&teacher_id=1

      Backend Frontend Template Pro: menú anidado test 5, lista de notas del profesor creado

      Datos GET: admin.php?page=bft_pro_automated_data_manipulation_teacher_note&action=edit&note_id=1&teacher_id=1

      Backend Frontend Template Pro: menú anidado test 6, nueva nota del profesor creado

Sistema de ajustes/datos almacenados a través de WP

Wordpress permite almacenar datos con su sistema de ajustes, gracias a BFT Pro puedes crear páginas de ajustes con sus campos de datos:

Edita tus pagínas de ajustes de WordPress en la variable $this->admin_settings del archivo admin/class-your-plugin-admin.php

En cada página describimos los campos, y varias páginas pueden repetir los mismos campos

Diseñar Ajustes BFT se ve así:

	$this->admin_settings = [
		"general" => [
			"title" =>  $this->__("Test settings"),
			"fields" => [
				"text_test" => [
					"title" => $this->__("Text input"),
				],
				"number_test" => [
					"title" => $this->__("Number input"),
					"args" => [
						"type" => "number",
					],
				],
			],
		],
	];

Eplicación del menú BFT:

  1. Páginas de ajustes

    1. Parámetros automáticos añadidos al array

      • id: la clave del array
      • id_wordpress: $this->admin_pages_settings_prefix.”_”.array key
      • page: id_wordpress.$this->admin_pages_settings_page_suffix
    2. Parámetros con datos por defecto si no están

      • id: la clave del array
      • function, por defecto: $this->settings_section_function_default
      • fields, por defecto: array vacío
      • title, por defecto: $this->admin_pages_settings_page_title_default
  2. Campo de la página

    1. Parámetros automáticos añadidos automáticamente en la sección de campos del array

      • id: la clave del array
      • id_wordpress: $this->plugin_slug.”_”.the array key
    2. Parámetros con datos por defecto si no están

      • title, por defecto: clave del array
      • function, por defecto: settings_section_form_field()
      • args, array donde definimos el tipo de datos, si es múltiple, las opciones del select, etc. Por defecto: “type” => “text”
        	"args" => [
        		"type" => "text"
        	],
        
    3. Tipos de entradas

      • text: input text
        	"text_test" => [
        		"title" => $this->__("Text input"),
        	],
        
      • textarea: input textarea, rows y cols son opcionales
        	"textarea_test" => [
        		"title" => $this->__("Textarea input"),
        		"args" => [
        			"type" => "textarea",
        			"rows" => 10,
        			"cols" => 50,
        		],
        	],
        
      • number: input number, args opcionales: min, max y step. Por defeto para step: 1, alternativo: ‘decimal’ o ‘decimals’, esta opción calcula los steps/pasos necesarios
        	"number_test" => [
        		"title" => $this->__("Number input"),
        		"args" => [
        			"type" => "number",
        			"min" => 1,
        			"max" => 99999,
        			"step" => 1,
        		],
        	],
        
      • select: input select, args debe tener ‘options’, guarda cadena con las opciones seleccionadas, ej: ‘en,es’ , args opcionales: search (por defecto false), multiple (por defecto false)
        	"select_test" => [
        		"title" => $this->__("Select input"),
        		"args" => [
        			"type" => "select",
        			"search" => true,
        			"options" => [
        				"zh" => $this->__("Chinesse"),
        				"en" => $this->__("English"),
        				"es" => $this->__("Spanish"),
        			],
        		],
        	],
        	"select_multiple_test" => [
        		"title" => $this->__("Select multiple input"),
        		"args" => [
        			"type" => "select",
        			"multiple" => true,
        			"search" => true,
        			"options" => [
        				"zh" => $this->__("Chinesse"),
        				"en" => $this->__("English"),
        				"es" => $this->__("Spanish"),
        			],
        		],
        	],
        
      • date: input text con un calendario, la fecha será estilo MySQL ‘2023-01-01’
        	"date_test" => [
        		"title" => $this->__("Date input"),
        		"args" => [
        			"type" => "date",
        		],
        	],
        
      • checkbox, single y multiple, en multiple es necesario ‘options’ en args
        	"checkbox_test" => [
        		"title" => $this->__("Checkbox input"),
        		"args" => [
        			"type" => "checkbox",
        			"multiple" => false,
        		],
        	],
        	"checkbox_multiple_test" => [
        		"title" => $this->__("Checkbox multiple input"),
        		"args" => [
        			"type" => "checkbox",
        			"multiple" => true,
        			"options" => [
        				"zh" => $this->__("Chinesse"),
        				"en" => $this->__("English"),
        				"es" => $this->__("Spanish"),
        			],
        		],
        	],
        
      • radio: radio buttons, guarda cadena con las opciones seleeccionadas, ej: ‘en,es’, requiere ‘options’
        	"radio_test" => [
        		"title" => $this->__("Radio input"),
        		"args" => [
        			"type" => "radio",
        			"multiple" => true,
        			"options" => [
        				"zh" => $this->__("Chinesse"),
        				"en" => $this->__("English"),
        				"es" => $this->__("Spanish"),
        			],
        		],
        	],
        
      • image: guarda una imagen en la Biblioteca de Medios de WordPress, el dato al almacenado en los ajustes es el ID de WordPress del archivo. Una vez seleccionado muestra la imagen
        	"image_test" => [
        		"title" => $this->__("Image input"),
        		"args" => [
        			"type" => "image",
        		],
        	],
        
      • file: guarda una archivo en la Biblioteca de Medios de WordPress, el dato al almacenado en los ajustes es el ID de WordPress del archivo. Una vez seleccionado muestraun botón de descarga
        	"file_test" => [
        		"title" => $this->__("File input"),
        		"args" => [
        			"type" => "file",
        		],
        	],
        
      • empty: un input comentado, imprime ”
        	"empty_test" => [
        		"title" => $this->__("Input commented"),
        		"args" => [
        			"type" => "empty",
        		],
        	],
        
  3. Cómo los campos son guardados

    • En el array el campo ID es una fase simple, ej: ‘languages’, ‘currency’, etc., pero BFT lo almacena como: $this->plugin_slug.”_”.”field_id”, entonces será: ‘your_plugin_languages’, ‘your_plugin_currency’, etc.
    • Eso es porque WordPress no aisla los ajustes por plugins, el propio plugin necesita aislar y asegurar los ajustes
    • Sabiendo esto, hay dos estilos de acceso para actualizar y eliminar los datos por código:
      1. Estilo BFT

        • $a_variable = $this->option_field_get(“field_id”)
        • $this->update_option_field(“field_id”, “nuevo valor de la cadena”)
        • $this->delete_option_field(“field_id”)
      2. Estilo WordPress

        • $a_variable = get_option(“plugin_slug”.”_”.”field_id”);
        • update_option(“plugin_slug”.”_”.”field_id”, “nuevo valor de la cadena”)
        • delete_option(“plugin_slug”.”_”.”field_id”);

      Nota: usa ‘update’ para crear una nueva entrada

Un ejemplo con todos los tipos de input:

	$this->admin_settings = [
		"input_types_test" => [
			"title" =>  $this->__("Test settings"),
			"fields" => [
				"text_test" => [
					"title" => $this->__("Text input"),
				],
				"textarea_test" => [
					"title" => $this->__("Textarea input"),
					"args" => [
						"type" => "textarea",
						"rows" => 10,
						"cols" => 50,
					],
				],
				"number_test" => [
					"title" => $this->__("Number input"),
					"args" => [
						"type" => "number",
						"min" => 1,
						"max" => 99999,
						"step" => 1,
					],
				],
				"select_test" => [
					"title" => $this->__("Select input"),
					"args" => [
						"type" => "select",
						"search" => true,
						"options" => [
							"zh" => $this->__("Chinesse"),
							"en" => $this->__("English"),
							"es" => $this->__("Spanish"),
						],
					],
				],
				"select_multiple_test" => [
					"title" => $this->__("Select multiple input"),
					"args" => [
						"type" => "select",
						"multiple" => true,
						"search" => true,
						"options" => [
							"zh" => $this->__("Chinesse"),
							"en" => $this->__("English"),
							"es" => $this->__("Spanish"),
						],
					],
				],
				"date_test" => [
					"title" => $this->__("Date input"),
					"args" => [
						"type" => "date",
					],
				],
				"checkbox_test" => [
					"title" => $this->__("Checkbox input"),
					"args" => [
						"type" => "checkbox",
						"multiple" => false,
					],
				],
				"checkbox_multiple_test" => [
					"title" => $this->__("Checkbox multiple input"),
					"args" => [
						"type" => "checkbox",
						"multiple" => true,
						"options" => [
							"zh" => $this->__("Chinesse"),
							"en" => $this->__("English"),
							"es" => $this->__("Spanish"),
						],
					],
				],
				"radio_test" => [
					"title" => $this->__("Radio input"),
					"args" => [
						"type" => "radio",
						"multiple" => true,
						"options" => [
							"zh" => $this->__("Chinesse"),
							"en" => $this->__("English"),
							"es" => $this->__("Spanish"),
						],
					],
				],
				"image_test" => [
					"title" => $this->__("Image input"),
					"args" => [
						"type" => "image",
					],
				],
				"file_test" => [
					"title" => $this->__("File input"),
					"args" => [
						"type" => "file",
					],
				],
				"empty_test" => [
					"title" => $this->__("Input commented"),
					"args" => [
						"type" => "empty",
					],
				],
			],
		],
	];

Backend Frontend Template Pro: ajustes generales

Backend Frontend Template Pro: Input test 1

Backend Frontend Template Pro: Input test 2

Base de datos de ejemplo

BFT Pro instala esta base de datos para fines de prueba:

Backend Frontend Template Pro: diagrama relacional de la base de datos de ejemplo

Notas sobre la base de datos:

  • Cursos tiene una tabla de internalización
  • Cursos y estudiantes tienen una relación muchos a muchos
  • Cursos tiene una clave foránea suave, teacher_id puede ser NULL, un curso puede existir sin un profesor
  • Notas de los profesores tiene una clave foránea dura, teacher_id no puede ser NULL, una nota no puede existir sin un profesor

Dentro de Backend Frontend Template Pro encontrarás las consultas usadas para instalar la base de datos

 

Backend Frontend Template Pro: desinstalación de la base de datos

Manipulación de datos automatizada de la BBDD del plugin

  1. Campos necesarios en la tabla de la base de datos

    Para mostrar y manipular los datos automáticamente necesitaremos unos pocos campos dedicados en una tabla

    1. Estado, tipo enumerado, nombre del campo decidido en $this->database_status_column_name, para las opciones del enumerado usa los datos almacenados en $this->database_status_option_active_name y $this->database_status_option_bin_name
    2. Tiempo de creación, tipo datetime, nombre del campo decidido en $this->database_datetime_created_name
    3. Tiempo de modificación, tipo datetime, nombre del campo decidido en $this->database_datetime_modified_name
    4. Tiemp ode eliminación (movido a la papelera), tipo datetime, nombre del campo decidido en $this->database_datetime_removed_name

    Además la tabla puede tener una tabla de internalización (i18n), esa tabla tendrá una foreign_key apuntando al id de la tabla principal

    Un ejemplo de una tabla con tabla de internalización:

    			CREATE TABLE `wp_bft_pro_courses`  (
    				`id` int(10) NOT NULL AUTO_INCREMENT,
    				`status` enum('active','bin') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT 'active',
    				`datetime_created` datetime NULL DEFAULT NULL,
    				`datetime_modified` datetime NULL DEFAULT NULL,
    				`datetime_removed` datetime NULL DEFAULT NULL,
    				`hours` int(4) NOT NULL DEFAULT 0,
    				`order` int(10) NOT NULL DEFAULT 0,
    				PRIMARY KEY (`id`) USING BTREE
    			) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
    
    
    			CREATE TABLE `wp_bft_pro_courses_i18n`  (
    				`id` int(10) NOT NULL AUTO_INCREMENT,
    				`course_id` int(10) NOT NULL COMMENT 'Foreign Key',
    				`language` char(2) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
    				`datetime_created` datetime NULL DEFAULT NULL,
    				`datetime_modified` datetime NULL DEFAULT NULL,
    				`name_i18n` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
    				`image` int(10) NOT NULL,
    				PRIMARY KEY (`course_id`, `language`) USING BTREE,
    				UNIQUE INDEX `uk_wp_bft_pro_courses_i18n_id`(`id`) USING BTREE,
    				UNIQUE INDEX `uk_wp_bft_pro_courses_i18n_id_primary_keys`(`course_id`, `language`) USING BTREE,
    				CONSTRAINT `fk_wp_bft_pro_courses_i18n_course_id` FOREIGN KEY (`course_id`) REFERENCES `wp_bft_pro_courses` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
    			) ENGINE = InnoDB AUTO_INCREMENT = 9 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'Internationalization of course names' ROW_FORMAT = Dynamic;
    

    Nota: no usar ‘wp_’, una instalación de WordPress quizás usa otro prefijo, usar en su lugar $wpdb->prefix, ejemplo: CREATE TABLE `”.$wpdb->prefix.”your_plugin_table`

    Aviso: ‘name’ no puede ser usado en una columna de una tabla i18n. WordPress limpia los datos automáticamente de todas las apariciones de ‘name’ y WordPress no espera datos array (es un array porque es el texto en cada idioma)

    En las relaciones muchos a muchos is necesario la fecha de creación y fecha de modificación

    			//Estudiantes no descritos en esta página de ejemplo, la clave foránea no puede funcionar si copias la query			CREATE TABLE `wp_bft_pro_students_courses`  (
    				`id` int(10) NOT NULL AUTO_INCREMENT,
    				`student_id` int(10) NOT NULL COMMENT 'Foreign Key',
    				`course_id` int(10) NOT NULL COMMENT 'Foreign Key',
    				`datetime_created` datetime NULL DEFAULT NULL,
    				`datetime_modified` datetime NULL DEFAULT NULL,
    				PRIMARY KEY (`student_id`, `course_id`) USING BTREE,
    				UNIQUE INDEX `uq_wp_bft_pro_students_courses_id`(`id`) USING BTREE,
    				UNIQUE INDEX `uq_wp_bft_pro_students_courses_student_id_course_id`(`student_id`, `course_id`) USING BTREE,
    				INDEX `fk_wp_bft_pro_students_courses_course_id`(`course_id`) USING BTREE,
    				CONSTRAINT `fk_wp_bft_pro_students_courses_course_id` FOREIGN KEY (`course_id`) REFERENCES `wp_bft_pro_courses` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
    				CONSTRAINT `fk_wp_bft_pro_students_courses_student_id` FOREIGN KEY (`student_id`) REFERENCES `wp_bft_pro_students` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
    			) ENGINE = InnoDB AUTO_INCREMENT = 5 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'Relationship table' ROW_FORMAT = Dynamic;
    
  2. $this->admin_forms

    Los formularios son descritos en $this->admin_forms del archivo admin/class-your-plugin-admin.php, un formulario es la unicón de su tabla y su internalización

    Diseñar un formulario BFT se ve así:

    		$this->admin_forms = [
    			"courses" => [
    				"table" => $wpdb->prefix.$this->plugin_slug."_"."courses",
    				"column_key" => "id",
    				"column_title_name" => "name_i18n",
    				"i18n_foreign_key" => "course_id",
    				"columns" => [
    					$this->database_status_column_name => [
    						"label" => $this->database_status_column_text,
    						"type" => "select",
    						"options" => $this->database_status_options,
    					],
    					"id" => [
    						"label" => $this->__("Nº"),
    						"placeholder" => "",
    						"type" => "text",
    						"display_table" => true,
    						"readonly" => true,
    					],
    					$this->database_datetime_created_name => [
    						"label" => $this->database_datetime_created_text,
    						"placeholder" => "",
    						"type" => "datetime",
    						"display_table" => false,
    						"readonly" => true,
    					],
    					$this->database_datetime_modified_name => [
    						"label" => $this->database_datetime_modified_text,
    						"placeholder" => "",
    						"type" => "datetime",
    						"display_table" => false,
    						"readonly" => true,
    						"only_in_active" => true,
    					],
    					$this->database_datetime_removed_name => [
    						"label" => $this->database_datetime_removed_text,
    						"placeholder" => "",
    						"type" => "datetime",
    						"display_table" => true,
    						"readonly" => true,
    						"only_in_removed" => true,
    					],
    					"hours" => [
    						"label" => $this->__("Total hours of the course"),
    						"placeholder" => $this->__("Hours"),
    						"type" => "number",
    						"i18n" => false,
    						"readonly" => true,
    						"display_table" => true,
    					],
    					"name_i18n" => [
    						"label" => $this->__("Course name"),
    						"placeholder" => $this->__("Name"),
    						"type" => "text",
    						"i18n" => true,
    						"display_table" => true,
    					],
    					"image" => [
    						"label" => $this->__("Course logo"),
    						"placeholder" => $this->__("Image"),
    						"type" => "image",
    						"i18n" => true,
    						"display_table" => true,
    					],
    					"order" => [
    						"label" => $this->__("Order"),
    						"placeholder" => $this->__("Order, lowest number first"),
    						"type" => "text",
    						"i18n" => false,
    						"display_table" => true,
    					],
    					"teacher_id" => [
    						"label" => $this->__("Teacher"),
    						"placeholder" => "",
    						"type" => "select",
    						"foreign_key" => "teachers",
    						"display_table" => true,
    						"value_empty_is_null" => true,
    						"foreign_key_null_text" => $this->__("Teacher not selected"),
    					],
    					"students_courses" => [
    						"label" => $this->__("Enrolled students"),
    						"placeholder" => $this->__("Students"),
    						"type" => "many_to_many_relationship",
    						//Display table doesn't work for now with many_to_many_relationship
    						"display_table" => false,
    						"search" => true,
    					],
    				],
    			],
    		];
    

    Eplicación del menú BFT:

    1. Parámetros del formulario

      1. key: internal id del formulario
      2. table: nombre de la tabla
      3. column_key: nombre de la clave (‘id’ normalmente)
      4. column_title_name: campo donde se guarda el nombre de la fila (el nombre de un usuario, el nombre de un libro, etc.)
      5. i18n_foreign_key: clave foránea de la tabla de internalización
      6. columns: lista de campos
    2. Parámetro opcional de los campos

      1. label: texto a mostrar en la administración. Por defecto: “”
      2. placeholder: placeholder si el tipo de dato puede tener placeholder
      3. display_table: muestra el campo en la tabla-lista. Nota: display_table no funciona por ahora con campos many_to_many_relationship
      4. i18n: si los datos del campo están almacenados en una tabla de internalización
      5. only_in_active: muestra el campo sólo si lso datos están activos
      6. only_in_removed: muestra el campo sólo si los datos están la papelera
      7. readonly: campo de sólo lectura, para la columna clave por ejemplo
      8. value_from_get: coge el dato de los datos GET en la URL si no hay dato guardado de este campo. Para datos dependientes, ejemplo: notas de profesores, una nueva nota necesita saber el id del profesor de la nota
      9. value_empty_is_null: un dato vacío se transformará a NULL (el dato NULL siempre se mostrará como value=”)
      10. foreign_key: guarda una clave foránea
      11. foreign_key_null_text: texto para mostrar cuando NULL es guardado en una clave foránea con NULL opcional
      12. type: las opciones de inputs de BFT y además la opción ‘many_to_many_relationship’, es un select para enlazar la relación. ‘text’ por defecto
        • many_to_many_relationship: usa los datos guardados en $this->admin_forms_many_to_many_relationships
          	"type" => "many_to_many_relationship",
          	"search" => true,
          	//Display table doesn't work for now with many_to_many_relationship
          	"display_table" => false,
          
        • text: input text
          	"type" => "select",
          
        • textarea: input textarea, rows y cols son opcionales
          	"type" => "textarea",
          	"rows" => 10,
          	"cols" => 50,
          
        • number: input number, args opcionales: min, max y step. Por defecto en step: 1, alternativo: ‘decimal’ o ‘decimals’, esta opción calculate los steps necesarios
          	"type" => "number",
          	"min" => 1,
          	"max" => 99999,
          	"step" => 1,
          
        • select: input select, args tiene que tener ‘options’, guarda una cadena con las opciones seleccionadas, ej: ‘en,es’, opcional args: search (false por defecto), multiple (false por defecto)
          	"type" => "select",
          	"search" => true,
          	"options" => [
          		"zh" => $this->__("Chinesse"),
          		"en" => $this->__("English"),
          		"es" => $this->__("Spanish"),
          	],
          
          	"type" => "select",
          	"multiple" => true,
          	"search" => true,
          	"options" => [
          		"zh" => $this->__("Chinesse"),
          		"en" => $this->__("English"),
          		"es" => $this->__("Spanish"),
          	],
          
        • date: input text con un calendario, la fecha será en estilo MySQL ‘2023-01-01’
          	"type" => "date",
          
        • checkbox, single y multiple, en multiple es necesario ‘options’ en args
          	"type" => "checkbox",
          	"multiple" => false,
          
          		"type" => "checkbox",
          		"multiple" => true,
          		"options" => [
          			"zh" => $this->__("Chinesse"),
          			"en" => $this->__("English"),
          			"es" => $this->__("Spanish"),
          		],
          
        • radio: radio buttons, guarda cadena con las opciones seleccionadas, ej: ‘en, es’, requiere ‘options’
          	"type" => "radio",
          	"multiple" => true,
          	"options" => [
          		"zh" => $this->__("Chinesse"),
          		"en" => $this->__("English"),
          		"es" => $this->__("Spanish"),
          	],
          
        • image: guarda si es necesario y selecciona una imagen de la Biblioteca de Medios de WordPress, el dato guardado es el ID del archivo. Una vez seleccionado muestra la imagen
          	"type" => "image",
          
        • file: igual que con la el tipo imagen, pero no intenta mostrar una imagen, sólo muestra un botón de descarga
          	"type" => "file",
          
        • empty: un input comentado, imprime ‘<!– id=”‘.$id_setting.'” empty –>’
          	"type" => "empty",
          
  3. $this->admin_forms_many_to_many_relationships

    Este formulario describe una relación mucho a mucho entre dos tablas

    1. Parámetros del formulario

      1. key: id interno de la relación mucho a mucho
      2. table: nombre de la tabla
      3. forms: array de los dos formulario de la relación
    1. Parámetro de los dos campos relacionados

      1. key: id del formulario
      2. value: clave foránea usado en la tabla

    Ejemplo del array:

    	$this->admin_forms_many_to_many_relationships = [
    		"students_courses" => [
    			"table" => $wpdb->prefix.$this->plugin_slug."_"."students_courses",
    			"forms" => [
    				"courses" => "course_id",
    				"students" => "student_id",
    			],
    		],
    	];
    

    El sistema funcionará con los datos de arriba:

    		$this->admin_forms = [
    			"courses" => [
    				[...]
    				"columns" => [
    					[...]
    					"students_courses" => [
    						"label" => $this->__("Enrolled students"),
    						"placeholder" => $this->__("Students"),
    						"type" => "many_to_many_relationship",
    						//Display table doesn't work for now with many_to_many_relationship
    						"display_table" => false,
    						"search" => true,
    					],
    				],
    			],
    		];
    
  4. $this->admin_pages

    BFT necesita saber qué function y function_load usar en la página. El sistema también necesita saber cómo leer los datos GET de la URL

    Hay páginas de listados y páginas de formularios. Es posible anidar páginas de listas para usar los datos del formulario anterior, por ejemplo: notas del profesor, primero selecciona un profesor (o crea uno nuevo), entonces vas a las notas de ese profesor

    La explicación de $this->admin_pages está en la pestaña ‘Menu’, allí hay un ejemplo completo de uso

      1. Mostrar un listado

    Para mostrar un listado es necesario un hijo con todos los datos, además se necesita:

      • “function” => “admin_menu_page_table_display_first_menu_child”,
      • “file” => “bft-admin-display-list-table.php”,
      1. Mostrar un formulario

    Un formulario norlmamente es una página hija de un listado, el formulario necesita:

      • “ids_required” => [“get_data” => “id_data”],
        	"ids_required" => [
        		"teacher_id" => "id",
        	],
        
      • “admin_forms_id” => “form_key”,
      • “function” => “admin_menu_admin_form_page_display”,
      • “file” => “bft-admin-display-form.php”,
      • “function_load” => “custom_form_set_do_by_post”,
      • “tabs_new_or_edit_on_url” => true,
      • “new_text” => “New entry text”,

    Un ejemplo de un listado y un formulario:

    	$this->admin_pages = [
    		"automated_data_manipulation_courses" => [
    			"menu_title" => $this->__("Courses"),
    			"page_title" => $this->__("List of courses"),
    			"function" => "admin_menu_page_table_display_first_menu_child",
    			"file" => "bft-admin-display-list-table.php",
    			"children" => [
    				"automated_data_manipulation_course" => [
    					"ids_required" => [
    						"courses_id" => "id",
    					],
    					"admin_forms_id" => "courses",
    					"tabs_new_or_edit_on_url" => true,
    					"menu_title" => $this->__("Course"),
    					"page_title" => $this->__("Course form"),
    					"function" => "admin_menu_admin_form_page_display",
    					"file" => "bft-admin-display-form.php",
    					"function_load" => "custom_form_set_do_by_post",
    					"new_text" => $this->__("New course"),
    				],
    			],
    		],
    	];
    
      1. Anidar un formulario

    Para anidar un formulario BFT se necesita especifiar siempre el dato GET ajeno, no pongas ‘id’ en el id ajeno

        1. Mostrar un listado

          • “ids_required” => [“get_data” => “id_data”], es igual que el formulario padre
            	"ids_required" => [
            		"teacher_id" => "teacher_id",
            	],
            
          • “ids_aux_required” => [“get_data” => “id_data”], opcional, funciona con ids_aux_required
          • “admin_forms_aux_id” => “form_key”, opcional
          • “function” => “admin_menu_page_table_display_first_menu_child”,
          • “file” => “bft-admin-display-list-table.php”,
        1. Mostrar un formulario

    La diferencia principal es que tiene dos ids: el id principal y el id foráneo. No poner ‘id’ en el id foráneo. Además puede mostrar column_title_name

        • “ids_required” => [“get_data” => “id_data”],
          	"ids_required" => [
          		"note_id" => "id",
          		"teacher_id" => "teacher_id",
          	],
          
        • “admin_forms_id” => “form_key”,
        • “ids_aux_required” => [“get_data” => “id_data”], opcional, funciona con ids_aux_required
        • “admin_forms_aux_id” => “form_key”, opcional
        • “function” => “admin_menu_admin_form_page_display”,
        • “file” => “bft-admin-display-form.php”,
        • “function_load” => “custom_form_set_do_by_post”,
        • “tabs_new_or_edit_on_url” => true,
        • “new_text” => “New entry text”,

    Un ejemplo de formulario anidado:

    	$this->admin_pages = [
    		"automated_data_manipulation_teachers" => [
    			"menu_title" => $this->__("Teachers"),
    			"page_title" => $this->__("List of teachers"),
    			"function" => "admin_menu_page_table_display_first_menu_child",
    			"file" => "bft-admin-display-list-table.php",
    			"children" => [
    				"automated_data_manipulation_teacher" => [
    					"ids_required" => [
    						"teacher_id" => "id",
    					],
    					"admin_forms_id" => "teachers",
    					"tabs_new_or_edit_on_url" => true,
    					"menu_title" => $this->__("Teacher"),
    					"page_title" => $this->__("Teacher form"),
    					"function" => "admin_menu_admin_form_page_display",
    					"file" => "bft-admin-display-form.php",
    					"function_load" => "custom_form_set_do_by_post",
    					"new_text" => $this->__("New teacher"),
    				],
    				"automated_data_manipulation_teacher_notes" => [
    					"ids_required" => [
    						"teacher_id" => "teacher_id",
    					],
    					"ids_aux_required" => [
    						"teacher_id" => "id",
    					],
    					"admin_forms_aux_id" => "teachers",
    					"menu_title" => $this->__("Teacher notes"),
    					"page_title" => $this->__("List of notes"),
    					"function" => "admin_menu_page_table_display_first_menu_child",
    					"file" => "bft-admin-display-list-table.php",
    					"children" => [
    						"automated_data_manipulation_teacher_note" => [
    							"ids_required" => [
    								"note_id" => "id",
    								"teacher_id" => "teacher_id",
    							],
    							"admin_forms_id" => "teachers_notes",
    							"ids_aux_required" => [
    								"teacher_id" => "id",
    							],
    							"admin_forms_aux_id" => "teachers",
    							"tabs_new_or_edit_on_url" => true,
    							"menu_title" => $this->__("Teacher note"),
    							"page_title" => $this->__("Teacher note form"),
    							"function" => "admin_menu_admin_form_page_display",
    							"file" => "bft-admin-display-form.php",
    							"function_load" => "custom_form_set_do_by_post",
    							"new_text" => $this->__("New note"),
    						],
    					],
    				],
    			],
    		],
    	];
    

Backend Frontend Template Pro: manipulación de datos automática 1

Backend Frontend Template Pro: manipulación de datos automática 2

En la sección “Menu Pro” hay un ejemplo de formularios anidados, si no se ha visto esa sección se recomienda visualizarla

Manipulación manual de datos: dentro de una función

  1. Funciones WordPress

    Para mainpular la base de datos WordPress proporciona la clase $wpdb, llámala dentro de una función con global $wpdb

    Algunas funciones de manipulación de datos de $wpdb son:

    • $wpdb->prefix: el prefijo de la base de datos de WordPress, todas las tablas tendrán este prefijo
    • $wpdb->query($query): hace una consulta directa
    • $wpdb->insert($table_name, $array_data): inserta una nueva entrada (la función sanea los datos)
    • $data = $wpdb->insert_id: último id insertado
    • $wpdb->delete($table_name, $array_search_data): eliminar entradas que coincidan con los datos del array de búsqueda (la función sanea los datos)
    • $wpdb->update($table_name, $array_data, $array_search_data): actualiza los datos en las entradas que coincidan los datos de array (la función sanea los datos)
    • $data = $wpdb->get_results($query, “ARRAY_A” ): devuelve un array bidimensional con todo los datos

    Toda la información de la clase puede encontrarse aquí

  2. Funciones de Backend Frontend Template

    BFT ofrece funciones adicionales para los programadores que prefieran este estilo de acceso a la base de datos

    • $this->wpdb_get_results_array($query): devuelve un array bidimensional con todo los datos
    • $this->wpdb_get_results_with_index($query): devuelve un array bidimensional con todos los datos, el índice de cada fila será el dato de la primera columna
    • $this->wpdb_get_results_one_data_per_row($query): devuelve un array mono dimensional, sólo devuelve la primera columna de cada fila
    • $this->wpdb_get_results_index_and_data_per_row($query): devuelve un array mono dimensional, el dato de la primera columna será el índice, la segunda será el dato
    • $this->wpdb_get_result_one_data($query): devuelve una cadena, sólo devuelve la primera columna de la primera línea
    • $this->wpdb_insert_update_on_duplicate_key($table, $data, $multi_row = false, $modified_value = NULL, $data_for_update = array()): inserta o actualiza varios datos, más explicación debajo (la función sanea los datos)
    • $this->wpdb_insert_update_on_duplicate_key_delete_others($table, $data, $column_where_delete, $value_where_delete): inserta o actualiza varios datos, entonces elimina las filas no actualizadas, más información debajo (la función sanea los datos)

    Explicaciones adicionales

    • wpdb_insert_update_on_duplicate_key

      $this->wpdb_insert_update_on_duplicate_key($table, $data, $multi_row = false, $modified_value = NULL, $data_for_update = array())

      Esta función puede insertar o actualizar una o varias filas, cuando actualizando los datos puede usar datos extras o sólo usar los datos usados en la inserción

      • $table: nombre de la tabla
      • $data: array mono dimensional (un insert) o bidimensional (varias inserciones), los datos pueden tener verdadero NULL o string ‘NULL’
      • $multi_row: true si se necesitan varios inserciones
      • $modified_value: datetime de la modificación, usará la columna $this->database_datetime_modified_name, si NULL usará el tiempo actual
      • $data_for_update: los datos usados para el caso de actualización, si el array está vacio la actualización usará la $data info
    • wpdb_insert_update_on_duplicate_key_delete_others

      $this->wpdb_insert_update_on_duplicate_key_delete_others($table, $data, $column_where_delete, $value_where_delete)

      Esta función usa wpdb_insert_update_on_duplicate_key, entonces hace una eliminación de las filas no actualizadas

      • $table: nombre de la tabla
      • $data: array mono dimensional (un insert) o bidimensional (varias inserciones), los datos pueden tener verdadero NULL o string ‘NULL’
      • $column_where_delete: la columna a comprobar (id, clave foránea, etc.)
      • $value_where_delete: el id a comprobar en column_where_delete

      Esta función es equivalente a eliminar todos losdatos e insertar los nuevos datos, el problema es el abuso de la base de datos, con esto la base de datos actualiza todos los datos (quizás sólo actualiza $this->database_datetime_modified_name), y entonces elimina todos los datos no actualizados. Menos UPDATE/INSERTS, menos DELETES

    NOTA: debido a como WordPress trabbaja las funciones BFT no son accesible desde crear/atualizar/eliminar base de datos en class-your-plugin-install-upgrade-deinstall-database.php sólo usar las funciones oficiales de WordPress

  3. Saneamiento de datos

    Para sanear las entradas WordPress proporciona varias funciones de saneamiento en la clase $wpdb

    Algunas funciones de saneamiento de $wpdb son:

    • $wpdb->sanitize_key: sanea un id
    • $wpdb->sanitize_text_field: sanea una cadena
    • $wpdb->sanitize_textarea_field: sanea multiples cadenas
    • $wpdb->prepare: sanea una consulta completa

    Toda la información de saneamiento puede encontrarse aquí

    Para el uso de $wpdb->prepare($query, $args) comprueba la información

Manipulación manual de datos: listado paginado por consulta

Un listado paginado por consulta es posible gracias a apuntar la página a una función personalizada, y usar dentro de la función $this->display_table_query_custom() y finalmente mostrar la página con $this->admin_menu_page_display()

También es necsario usar el archivo “file” => “bft-admin-display-list-table.php”

$this->display_table_query_custom()

	display_table_query_custom(
		$query_select_inside,
		$query_from_inside,
		$query_where_inside,
		$group_inside,
		$ids,
		$columns_tables_dont_search,
		$search_concat,
		$column_key,
		$columns_tables,
		$columns_labels,
		$column_action_add,
		$status_system = false,
		$write_log_query = false
	)
  1. $query_select_inside

    Parte SELECT de la consulta, sin la etiqueta SELECT

  2. $query_from_inside

    Parte FROM de la consulta, sin la etiqueta FROM

  3. $query_where_inside

    Parte WHERE de la consulta, sin la etiqueta WHERE

  4. $group_inside

    Parte GROUP BY de la consulta, sin la etiqueta FROM

  5. $ids

    Ids a buscar, los índices serán la clave de la columna

    Puede ser un array vacío, un array con datos manuales, o un array automático con el ids_required_get_data gracias a $this->ids_required_and_optional_check_and_get()

    			$ids = [
    				"teacher_id" => "1",
    			];
    
    			$ids = $this->ids_required_and_optional_check_and_get (
    				$ids_principal_aux_type = "principal",
    				$ids_require_optional_type = "both",
    				$read_all_get_data = false
    			);
    
  6. $columns_tables_dont_search

    No buscar la cadena de búsqueda en las columnas. Los índices serán la clave de la columna

    			$columns_tables_dont_search = [
    				"column_1" => "table",
    				"column_2" => "table",
    			];	
    
  7. $search_concat

    Array bidimensional, primera dimensión es la columna final, la segunda dimensión son las columnas del CONCAT, para buscar la cadena en columnas combinadas

    Ej:

    			search_string: "Lorem Ipsum"
    			row_1 column_1: "Lorem"
    			row_1 column_2: "Ipsum"
    
    			$search_concat = [
    				[
    					"column_1" => "table",
    					"column_2" => "table",
    				],
    			];	
    
  8. $column_key

    Columna clave de la consulta

  9. $columns_tables

    Las tablas de las columnas, con índices

    			$columns_tables_dont_search = [
    				"column_1" => "table",
    				"column_2" => "table",
    			];	
    
  10. $columns_labels

    Las etiquetas de las columnas, con índices de las columnas

    			$columns_labels = [
    				"id" => $this->__("Nº"),
    				"column_2" => $this->__("Label of the column"),
    				"column_3" => "Label without internalization",
    			];
    
  11. $column_action_add

    Añadir o no añadir un enlace

    • column_action_key: la columna clave para el enlace, false si no es necesario un link
    • column_action_edit_slug: el slug de la página
    			$column_action_add = [
    				"column_action_key" => "course_id",
    				"column_action_edit_slug" => $this->admin_pages_slug_name_prefix."_"."slug_of_the_page",
    			];
    
    			$column_action_add = [
    				"column_action_key" => false,
    				"column_action_edit_slug" => "",
    			];
    
  12. $status_system

    La table usa la columna $this->database_status_column_name

  13. $write_log_query

    Escribe en el log la consulta base

Un ejemplo completo de $this->display_table_query_custom() usado en una función

	public function manual_data_manipulation_listing_by_query_example() {
		global $wpdb;

		$this->admin_permission_check();

		$language_admin = $this->language_admin_get();
		$ids = array();

		
		//Add or not add a "to go element", inside the array: "column_action_key"  with the future get data with the id, "column_action_edit_slug" the target slug for the edit action
		$column_action_add = [
			"column_action_key" => "course_id", //The future get data name with the id
			"column_action_edit_slug" => $this->admin_pages_slug_name_prefix."_automated_data_manipulation_course", //Target slug for the edit action
		];

		/*
		SELECT
			wp_bft_pro_courses.id,
			wp_bft_pro_courses_i18n.name_i18n AS course
		FROM
			wp_bft_pro_courses
			LEFT JOIN	wp_bft_pro_courses_i18n
				ON	wp_bft_pro_courses.id = wp_bft_pro_courses_i18n.course_id
				AND wp_bft_pro_courses_i18n.language = 'en';
		WHERE
			teacher_id is not null
		*/

		//SELECT part of the query, whitout the SELECT tag
		$query_select_inside = "
			".$wpdb->prefix.$this->plugin_slug."_"."courses.id,
			".$wpdb->prefix.$this->plugin_slug."_"."courses_i18n.name_i18n AS name";
			
		//FROM part of the query, whitout the FROM tag
		$query_from_inside = "
			".$wpdb->prefix.$this->plugin_slug."_"."courses
			LEFT JOIN	".$wpdb->prefix.$this->plugin_slug."_"."courses_i18n
				ON	".$wpdb->prefix.$this->plugin_slug."_"."courses.id = ".$wpdb->prefix.$this->plugin_slug."_"."courses_i18n.course_id
				AND ".$wpdb->prefix.$this->plugin_slug."_"."courses_i18n.`".$this->database_i18n_column_language."` = '$language_admin'";

		//WHERE part of the query, whitout the WHERE tag
		$query_where_inside = "
			teacher_id IS NOT NULL";

		//GROUP BY part of the query, whitout the FROM tag
		$group_inside = "";

		//Column key of the query
		$column_key = "id";

		//The tables of the columns, with indexes of the tables
		$columns_tables = [
			"id" => $wpdb->prefix.$this->plugin_slug."_"."courses",
			"name" => $wpdb->prefix.$this->plugin_slug."_"."courses_i18n",
		];

		//Don't search the search string on this columns. The indexes will be the column key
		$columns_tables_dont_search = array();

		//Two dimensional array, first dimension is the final colum, the second dimension are the colums of the CONCAT ("column" => "table"), for search  the string on the final CONCAT data
		$search_concat = [];

		//The labels of the columns, with indexes of the columns
		$columns_labels = [
			"id" => $this->__("Nº"),
			"name" => $this->__("Course"),
		];

		$status_system = false;
		$write_log_query = false;
		$args = $this->display_table_query_custom($query_select_inside, $query_from_inside, $query_where_inside, $group_inside, $ids, $columns_tables_dont_search, $search_concat, $column_key, $columns_tables, $columns_labels, $column_action_add, $status_system, $write_log_query);

		$args["ids"] = $ids;
		$this->admin_menu_page_display($args);
	}

Backend Frontend Template Pro: listado por consulta

Manipulación manual de datos: listado por array

Un listado directo por array es posible enviando todos los datos necsearios a $this->admin_menu_page_display()

También es necesario usar “file” => “bft-admin-display-list-table.php”

  1. Datos array

    1. Datos requeridos

      1. data

        Array con cada fila de datos, sin id. Dentro de cada fila, cada columna de datos tiene la clave de la columna

      2. columns

        Array con las claves y nombres de las columnas

      	$display_table_data = [
      			"data" => [
      				[
      					"id" => "1",
      					"name" => "Lorem Ipsum Name",
      				],
      				[
      					"id" => "2",
      					"name" => "Dolor Sit Name",
      				],
      			],
      			"columns" => [
      				"id" => "Nº",
      				"name" => "Name",
      			],
      		];	
      
    2. Datos opcionales

      1. $column_action_add

        Añadir o no añadir un enlace

        • column_action_key: la columna clave para el enlace, false si no es necesario un link
        • column_action_edit_slug: el slug de la página
        					$column_action_add = [
        						"column_action_key" => "course_id",
        						"column_action_edit_slug" => $this->admin_pages_slug_name_prefix."_"."slug_of_the_page",
        					];
        
        					$column_action_add = [
        						"column_action_key" => false,
        						"column_action_edit_slug" => "",
        					];
        
      2. get_extra_all_rows

        Array con data a añadir en los datos GET de los links

        					"get_extra_all_rows" => [
        						"example_get_data" => "Lorem_Ipsum",
        					],
        
        					GET resultant: [...]?page=[...]&example_get_data=Lorem_Ipsum
        
      3. items_per_page

        Los items para una página, para datos no paginados no es necesario este dato

      4. items_column_key

        La columna clave

      5. items_count

        Recuento total de elementos, para datos no paginados no es necesario este dato

      6. items_count_with_search

        Recuento total de elementos con la búsqueda, para datos sin búsqueda no es necesario este dato

      7. search_text

        El label de búsqueda, para datos sin búsqueda no es necesario este dato

      8. page_slug

        El slug de la página actual

      9. ids

        Ids usados en esta página

  2. Enviando los datos

    Para mostrar una tabla la función admin_menu_page_display() necesita “display_table” => true” y “display_table_data” con los datos del listado

    			$args = [
    				"ids" => $ids,
    				"display_table" => true,
    				"display_table_data" => $display_table_data,
    			];
    
    			$this->admin_menu_page_display($args);
    

Un ejemplo completo de listado personalizado por datos array usado en una función

 

	public function manual_data_manipulation_listing_by_array_example() {
		$this->admin_permission_check();

		$ids = $this->ids_required_and_optional_check_and_get($ids_principal_aux_type = "principal", $ids_require_optional_type = "both", $read_all_get_data = false);
		//$ids = array();

		/*
		$display_table_data = [
			"data" => [
				[
					"id" => "1",
					"name" => "Lorem Ipsum Name",
				],
			],
			"columns" => [
				"id" => "Nº",
                "name" => "Name",
			],
			"column_action_add" => [
				"column_action_key" => false,
                "column_action_edit_slug" => "",
			],
			"get_extra_all_rows" => false,
			"items_per_page" => 999999,
			"items_column_key" => "id",
			"items_count" => "1",
			"items_count_with_search" => "1",
			"search_text" => false,
			"page_slug" => $this->plugin_slug."_manual_data_manipulation_listing_by_array_example",
			"ids" => [],
		];
		
		$display_table_data = [
			"data" => [
				[
					"id" => "1",
					"name" => "Lorem Ipsum Name",
				],
			],
			"columns" => [
				"id" => "Nº",
                "name" => "Name",
			],
			"column_action_add" => [
				"column_action_key" => "course_id",
                "column_action_edit_slug" => $this->admin_pages_slug_name_prefix."_automated_data_manipulation_course",
			],
			"get_extra_all_rows" => [
				"example_get_data" => "Lorem Ipsum",
			],
			"items_per_page" => 999999,
			"items_column_key" => "id",
			"items_count" => "1",
			"items_count_with_search" => "1",
			"search_text" => false,
			"page_slug" => $this->plugin_slug."_manual_data_manipulation_listing_by_array_example",
			"ids" => [],
		];
		*/

		$display_table_data = [
			"data" => [
				[
					"id" => "1",
					"name" => "Lorem Ipsum Name",
				],
			],
			"columns" => [
				"id" => "Nº",
				"name" => "Name",
			],
		];

		$args = [
			"ids" => $ids,
			"display_table" => true,
			"display_table_data" => $display_table_data,
		];

		$this->admin_menu_page_display($args);
	}

Backend Frontend Template Pro: listado por array

Manipulación manual de datos: formularios

Un formulario manual es posible gracias a apuntar la página a una function personalizada para mostrar el formulario y a una function_load personalizada para guardar los cambios del formulario

Puedes usar la página bft-admin-display-form.php para mostrar el formulario o crear tu propia página

  1. function personalizada

    Recupera los datos como quieras y envíalos a la función $this->admin_menu_page_display(), por ejemplo:

    	$args = [
    		"title" => $this->admin_pages_data_get("page_title"),
    		"id" => $id,
    		"ids" => $ids,
    		"form_data" => [
    			"page_name" => $this->page_name,
    			"data" => $data,
    			"column_key" => $column_key,
    		],
    	];
    
    	$this->admin_menu_page_display($args);
    

    Si la página usa bft-admin-display-form.php los datos se formarán de esta manera:

    	$data = [
    		"column_name_1" => [
    			"label" => "",
    			"placeholder" => "",
    			"type" => text,
    			"id" => column_name_1,
    			"value" => "",
    		],
    		"column_name_2" => [
    			"label" => "",
    			"placeholder" => "",
    			"type" => text,
    			"id" => column_name_2,
    			"value" => "",
    		],
    		"column_group_name_1" => [
    			"label" => "",
    			"values" => [
    				"column_name_3" => [
    					"label" => "",
    					"placeholder" => "",
    					"type" => text,
    					"id" => column_name_3,
    					"value" => "",
    				],
    				"column_name_4" => [
    					"label" => "",
    					"placeholder" => "",
    					"type" => text,
    					"id" => column_name_4,
    					"value" => "",
    				],
    			],
    		],
    	];
    
  2. function_load personalizada

    Esta función se ejecuta primero, se envíen datos POST por el navegador o no, parar la función si no se han enviado datos POST o se encuentra algún error, ejemplo:

    	if ("POST" !== $_SERVER['REQUEST_METHOD']) {
    		return false;
    	}
    

    Al final de la función usa redirección si es necsario. Para redireccionar puede usarse wp_redirect() o $this->custom_form_redirect()

    1. wp_redirect($url)

      Esta función de WordPress necesita la URL completa, por eso BFT ofrece mejores alternativas:

      • $this->admin_page_url_get()

        Devuelve la página mostrada actualmente sin datos GET adicionales, sólo el dato GET de la página

        			https://yourfuturewebsite/wp-admin/admin.php?page=bft_pro_manual_data_manipulation_form_explanation
        
      • $this->gets_for_admin_page($id)

        Devuelve los datos GET necesarios para el formulario de la página. Ej: si una página usa el formulario ‘courses’, envíale el id ‘1’ y devolverá:

        			&course_id=1
        
    2. $this->custom_form_redirect($id = false)

      Esta función BFT hace una redirección a la URL compelta con el ID necesario para el formulario y añade &action=new o &action=edit dependiendo en si se le ha pasado ID

  3. Ejemplo completo

    	$this->admin_pages = [
    		"manual_data_manipulation_form_simple_example_teacher" => [
    				/*"ids_required" => [
    					"teacher_id" => "id",
    				],*/
    				"admin_forms_id" => "teachers",
    				"columns" => [
    					"id",
    					"name",
    					"surname",
    					"id_card",
    				],
    				"menu_title" => $this->__("Example 1"),
    				"page_title" => $this->__("Teacher")." 1,
    				"function" => "manual_data_manipulation_form_example_for_two_pages_get",
    				"file" => "bft-admin-display-form.php",
    				"function_load" => "manual_data_manipulation_form_example_for_two_pages_set",
    			],
    		];
    
    	public function manual_data_manipulation_form_example_for_two_pages_get() {
    		$this->admin_permission_check();
    
    		global $wpdb;
    
    		$ids = $this->ids_required_and_optional_check_and_get($ids_principal_aux_type = "principal", $ids_require_optional_type = "both", $read_all_get_data = false);
    		//$ids will be empty on the example, adding the id
    		$ids["id"] = "1";
    
    		//teachers or students
    		$admin_forms_id = $this->admin_pages_data_get_admin_forms_id();
    
    		/*
    		Remember: on $this->admin_pages you can store all the data you want and retrieve it with $this->admin_pages_data_get();
    
    		Teachers:
    		"columns" => [
    			"id",
    			"name",
    			"surname",
    			"id_card",
    		],
    
    		Students:
    		"columns" => [
    			"id",
    			"name",
    			"surname",
    		],
    		*/
    		$columns_array = $this->admin_pages_data_get( "columns");
    
    		//$language_admin = $this->language_admin_get();
    
    		if (0 == count($ids)
    			||	false == $admin_forms_id
    			||	!isset($this->admin_forms[$admin_forms_id])
    			||	false == $columns_array) {
    			$error_message = $this->__("Error message");
    			$this->error_throw ($error_message, $error_throw_what_do_use_this = "show_error_and_die");
    		}
    		$id = sanitize_key(array_values($ids)[0]);
    
    
    		$query = "
    			SELECT
    				".implode(", ", $columns_array)."
    			FROM
    				".$this->admin_forms[$admin_forms_id]["table"]."
    			WHERE
    				id = '$id'";
    
    
    		$data_database = $this->wpdb_get_result_one_row($query);
    
    		if (0 == count($data_database)) {
    			$error_message = $this->__("Error message");
    			$this->error_throw ($error_message, $error_throw_what_do_use_this = "show_error_and_die");
    		}
     
    
    		
    		$data = array();
    		foreach ($data_database AS $data_database_key => $data_database_value) {
    			if (isset($this->admin_forms[$admin_forms_id]["columns"][$data_database_key])) {
    				$data[$data_database_key] = $this->admin_forms[$admin_forms_id]["columns"][$data_database_key];
    				$data[$data_database_key]["value"] = $data_database_value;
    			}
    		}
    
    		
    		$args = [
    			"title" => $this->admin_pages_data_get("page_title"),
    			"id" => $id,
    			"ids" => $ids,
    			"form_data" => [
    				"page_name" => $this->page_name,
    				"data" => $data,
    				"column_key" => $this->admin_forms[$admin_forms_id]["column_key"],
    			],
    		];
    
    		$this->admin_menu_page_display($args);
    	}
    
    	public function manual_data_manipulation_form_example_for_two_pages_set() {
    		$this->admin_permission_check();
    
    		$redirect_page = false;
    		$request_method = "POST";
    
    		if ($request_method !== $_SERVER['REQUEST_METHOD']) {
    			//Post data not found
    			return false;
    		}
    		
    
    		$data_raw = $_POST;
    
    		if (	!isset($data_raw["_wpnonce"])
    			||	!wp_verify_nonce($data_raw["_wpnonce"], $this->plugin_slug."_form")) {
    			//Nonce not verified
    			return false;
    		}
    
    		//For security check
    		$this->ids_required_and_optional_check_and_get($ids_principal_aux_type = "principal", $ids_require_optional_type = "both", $read_all_get_data = false);
    
    
    		//teachers or students
    		$admin_forms_id = $this->admin_pages_data_get_admin_forms_id();
    
    		/*
    		Remember: on $this->admin_pages you can store all the data you want and retrieve it with $this->admin_pages_data_get();
    
    		Teachers:
    		"columns" => [
    			"id",
    			"name",
    			"surname",
    			"id_card",
    		],
    
    		Students:
    		"columns" => [
    			"id",
    			"name",
    			"surname",
    		],
    		*/
    		$columns_array = $this->admin_pages_data_get( "columns");
    
    		if (	false == $admin_forms_id
    			||	!isset($this->admin_forms[$admin_forms_id])
    			||	false == $columns_array) {
    			return false;
    		}
    
    
    
    		$data_row = array();
    
    		foreach ($columns_array AS $column) {
    			if (!isset($data_raw[$column])) {
    				return false;
    			}
    
    			$data_row[$column] = $data_raw[$column];
    		}
    
    
    		$this->wpdb_insert_update_on_duplicate_key($this->admin_forms[$admin_forms_id]["table"], $data_row, $multi_row = false);
    
    		/*
    		Query executed:
    
    		INSERT INTO
    			wp_bft_pro_teachers
    			(
    				datetime_modified,
    				id,
    				name,
    				surname,
    				id_card,
    				datetime_created
    			)
    		VALUES
    			(
    				'2023-01-01 00:00:01',
    				'1',
    				'Teacher 1 edited',
    				'surname 1',
    				'1111',
    				'2023-01-01 00:00:01'
    			)
    		ON DUPLICATE KEY UPDATE
    			datetime_modified = '2023-01-01 00:00:01',
    			id = '1',
    			name = 'Teacher 1 edited',
    			surname = 'surname 1',
    			id_card = '1111'
    
    		Obviously the duplicate key will be executed on this case for the "id" column
    
    		Note the automated columns:
    		$this->database_datetime_created_name (datetime_created)
    		$this->database_datetime_modified_name (datetime_modified)
    		*/
    
    		if (true === $redirect_page) {
    			//ids not specified in the example page, this is for a complete case
    			$this->custom_form_redirect($data_row["id"]);
    		}
    		else {
    			return true;
    		}
    	}
    

Backend Frontend Template Pro: ejemplo de formulario manual

Internacionalización

Prepara el plugin para futuras traducciones

  1. Preparando el texto

    Para especificar un texto que quizás necesita traducción, WordPress proporciona las funciones:

    • __(‘string’, ‘dominio de traducción/plugin id’): para traducción directa
    • _e(‘string’, ‘dominio de traducción/plugin id’): para traducción directa y mostrar el texto traducido
    • esc_html_(‘string’, ‘dominio de traducción/plugin id’) para traducción y escapar los caracteres HTML
    • esc_html_e(‘string’, ‘dominio de traducción/plugin id’) para traducción, escapar los carácteres HTML y mostrar el texto resultante

    Para más funciones buscar en la documentación de WordPress: enlace aquí

    Con eso, WordPress usará el archivo de traducción si existe y tiene la frase, o un plugin externo será capaz de traducir tu plugin al idioma del visitante

    BFT además ofrece la opción de use sus funciones intermediarias para evitar tener que poner el dominio en cada cadena preparada para una futura traducción . Con TODAS las función de traducción de WordPress

    Para eso, llama la función a través de ‘$this’ y no pontas el dominio de traducción

    • $this->__(‘string’): para traducción directa
    • $this->_e(‘string’): para traducción directa y mostrar el texto traducido
    • $this->esc_html_(‘string’) para traducción y escapar los caracteres HTML
    • $this->esc_html_e(‘string’) para traducción, escapar los carácteres HTML y mostrar el texto resultante

    NOTA: las funciones admiten el campo dominio, si pones un dominio se usará ese dominio

  2. Preparando los archivos de traducción

    Los archivos de traducción se alojan en plugin_folder/languages, BFT automáticamente configurará WordPress para buscar las traducciones en esa carpeta

    Los archivos de idiomas son:

    • .pot: Portable Object Template, el archivo maestro con todas las cadenas de texto
    • .po: Portable Object, el archivo con las cadenas traducidas a un idioma
    • .mo: Portable Object, Machine Object, los datos compilados del archivo .po, WordPress usará este archivo

    Parar para traducir el plugin:

    1. Crea un nuevo archivo .pot de tu plugin
    2. Actualiza/combina el .pot original con el nuevo archivo .pot
    3. Borra los archivos .pot antiguos y renombra el archivo combinado si es necesario
    4. Prepara el archivo de idioma .po
      1. Si es una nueva traducción de idioma: duplica el archivo .pot y cambia el nombre y la extensión al idioma seleccionado, como bft-pro – copy.pot a bft-pro-es.po o bft-pro-es_ES.po
      2. Si es una traducción de idioma existente: actualiza/combina el archivo con el nuevo archivo .pot
    5. Traduce las frases del archivo .po
    6. Crea el archivo .mo desde el archivo .po

    Para crear y combinar los archivos y traducir las oraciones se pueden usar programas como Poedit o EazyPo

El registro de WordPress con BFT

El log en WordPress se activa en wp-config.php, cambia:

  • define( ‘WP_DEBUG’, true );
  • define( ‘WP_DEBUG_LOG’, true );

Ahora puedes comprobar el log en wp-content/debug.log

Para imprimir en el log puedes usar la función de WordPress error_log($string_or_number), pero con Backend Frontend Template puedes usar: $this->debug_log_write($whatever)

$this->debug_log_write() es mejor opción porque muestra:

  • ‘NULL’ si es una variable NULL
  • ‘TRUE’ y ‘FALSE’ si es un booleano
  • print_r() si es un array o un objeto

Ahora puedes imprimir en el log la variable que quieras

Además BFT ofrece un nombre alternativo para debug_log_write: $this->write_log()

Visibilidad de las funciones

Un resumen rápido sobre qué visibilidad usar en las funciones de tu plugin:

  • Private

    No uses funciones privadas, BFT usa herencia en las clases y una función privada no puede heredarse

  • Protected

    Ideal para las funciones internas por razones de seguridad, sólo tus clases pueden usar estas funciones

  • Public

    Algunas funciones necesitan ser públicas debido a cómo funciona WordPress:

    • Funciones invocadas via $this->admin_pages -> an_admin_page -> ‘function_load’ data
    • Funciones invocadas via $this->admin_pages -> an_admin_page -> ‘function’ data
    • Funciones invocadas via instalación, actualización o desistalación
    • Funciones invocadas via shortcodes
    • Funciones invocadas via respuestas AJAX

Asegura las funciones

  1. Function load

    La opción ‘function_load’ del menú es la función que la página ejecuta antes de enviar las cabeceras HTML

    Por defecto todas las las páginas ejecutan admin_permission_check_and_ids_required_check_function_load(), la función ejecutada puede cambiarse en
    class-your-plugin-admin -> $this->admin_pages_function_load_default = “admin_permission_check_and_ids_required_check_function_load”

    La función admin_permission_check_and_ids_required_check_function_load() comprueba si las capacidades administrativas son correctas y si el id requerido está. En esta función funciona el ‘go_to_parent’ opción del menú

    Esta función puede llamarse al principio de una function_load personalizada para comprobar todo antes de guardar los cambios

  2. Function

    La opción ‘function’ del menú is la función principal que la página ejecuta

    Por defecto todas las las páginas ejecutan admin_permission_check_and_ids_required_and_optional_check_page_display(), la función ejecutada puede cambiarse en
    class-your-plugin-admin -> $this->admin_pages_function_default = “admin_permission_check_and_ids_required_and_optional_check_page_display”

    La función admin_permission_check_and_ids_required_and_optional_check_page_display() comprueba si las capacidades administrativas son correctas y si faltan los datos id requeridos

    En una función personalizada hay funciones para comprobar el acceso y recuperar los ids:

    • $this->admin_permission_check(): comprueba los permisos de administración y lanza un error si es necesario. Se recomienda usar al principio de la función
    • $this->ids_required_check(): comprueba los permisos de los ids requeridos y lanza error si es necesario
    • $this->ids_required_and_optional_check_and_get ($ids_principal_aux_type = “principal”, $ids_require_optional_type = “both”, $read_all_get_data = true, $return_type = “array”, $error_message = NULL, $die_always_if_required_missing = true, $triggered_on_function_load = false): comprueba los ids y devuelve los datos

    Explicaciones adicionales

    • ids_required_and_optional_check_and_get

      $this->ids_required_and_optional_check_and_get ($ids_principal_aux_type = “principal”, $ids_require_optional_type = “both”, $read_all_get_data = true, $return_type = “array”, $error_message = NULL, $die_always_if_required_missing = true, $triggered_on_function_load = false)

      Esto es un método alternativo para recuperar manualmente los datos con admin_pages_data_get()

      	$data = $this->admin_pages_data_get("ids_required_get_data");
      	$data = $this->admin_pages_data_get("ids_principal_all_get_data");
      	$data = $this->admin_pages_data_get("ids_aux_required_get_data");
      	$data = $this->admin_pages_data_get("ids_aux_all_get_data");
      	$data = $this->admin_pages_data_get("ids_required_all_get_data");
      	$data = $this->admin_pages_data_get("ids_all_get_data");
      

      Pero este método comprueba si hay ids requeridos no encontrados, también añade datos GET no definidos en los ids

      Variables de la función:

      • $ids_principal_aux_type: Qué ids recibir. Opciones: ‘principal’, ‘aux’ y ‘both’, por defecto ‘principal’. Principal -> “ids_required’, aux -> ‘ids_aux_required’, both -> ‘ids_required_all’ (ids_required y ids_aux_required)
      • $ids_require_optional_type: Selecciona si sólo ids principales o añadir los opcionales. Opciones: ‘require’ y ‘both’, por defecto ‘require’. Si ambos: Principal -> ‘ids_principal_all_get_data’ (ids_required y ids_optional), aux -> ‘ids_aux_all_get_data’ (ids_aux_required y ids_aux_optional), both -> ‘ids_all_get_data’ (ids_required, ids_optional, ids_aux_required y ids_aux_optional)
      • $read_all_get_data: Leer todos los datos GET de la URL y añadir las opciones adicionales, por defecto true. ‘page’ datos GET no se añadirá, la clave del dato GET necesita tener más de 2 caracteres
      • $return_type: ‘array’ (opción por defecto), ‘array_always’ (no devuelve false, en su lugar devuelve un array vacío si se ha encontrado un error), ‘data’ (primer dato si hay múltiples ids)
      • $error_message: texto por defecto: ‘ID requerido no encontrado’
      • $die_always_if_required_missing: Si true añade ‘show_error_and_die’ en un error lanza. Por defecto true
      • $triggered_on_function_load: Si es ejecutado en un function_load, selecciona false en una función principal. Por defecto false

      Ejemplo de uso:

      	$ids = $this->ids_required_and_optional_check_and_get ($ids_principal_aux_type = 'principal', $ids_require_optional_type = 'required', $read_all_get_data = false);
      	$ids_aux = $this->ids_required_and_optional_check_and_get ($ids_principal_aux_type = 'aux', $ids_require_optional_type = 'required', $read_all_get_data = false);

Controla y muestra errores

  1. Muestra un error

    Backend Frontend Template puede mostrar errores fácilmente, y no repite el mismo error en la misma carga. Además: el título del plugin ser añadirá al mensaje

    • $this->error_show ($error_message = “”) muestra un mensaje de error. Si $error_message = “” muestra “Error detectado”
    • Añadiendo error_message en el GET URL, el mensaje de error se puede activar con las funciones $this->admin_permission_check() o $this->error_throw()
  2. Lanza un error

    BFT puede lanzar errores con
    $this->error_throw ($error_message = “”, $error_throw_what_do_use_this = NULL, $error_throw_file_change_use_this = NULL, $triggered_on_function_load = false, $page_id = NULL)

    • $error_message: error para enviar a $this->error_show(), pero primero mostrará el ‘error_message’ guardado en la URL
    • $error_throw_what_do_use_this: para usar estos datos en vez de $this->admin_pages_data_get(“error_throw_what_do”), opciones: show_error, show_error_and_die, go_to_parent
    • $error_throw_file_change_use_this: NULL por defecto, usa estos datos en vez de $this->admin_pages_data_get(“error_throw_file_change”), para cambiar el archivo mostrado si se lanza un error
    • $triggered_on_function_load: false por defecto, ‘go_to_parent’ sólo funciona si true == $triggered_on_function_load porque es necesario hacer la redirección antes de enviar las cabeceras
    • $page_id: la clave/nombre de la página, si NULL será la página visualizada
  3. Ejemplos

    • Esta página muestra un error con:
      		$error_message = $this->__("This is an error test");
      		$this->error_show ($error_message);
      
    • La página hija lanza un error y vuelve a esta página con:
      		$this->admin_pages = [
      			"errors_manage" => [
      				"menu_title" => $this->__("Errors"),
      				"page_title" => $this->__("Manage and display errors"),
      				"file" => "bft-admin-display-errors-manage-show-pro.php",
      				"children" => [
      					"throw_error_and_return_to_parent" => [
      						"menu_title" => $this->__("Throw error and return to parent"),
      						"page_title" => $this->__("Throw error and return to parent"),
      						"ids_required" => [
      							"nonexistent_id" => "nonexistent_id",
      						],
      						"error_throw_what_do" => "go_to_parent",
      					],
      				]
      			],	
      		];
      

      Resultado que da el probar entrar a una página hija que da error:

      Backend Frontend Template Pro: mostrando error de página hija que redirige a la página padre

Descarga archivos privados

La carpeta private es una carpeta privada gracias a su .htaccess

	Deny from all

Por lo tanto un simple link no funcionará, pero una descarga BFT funciona (Ejemplos disponibles dentro de Backend Frontend Pro: el WordPress Plugin Template)

Para la descarga es necesario una página donde enviar los datos, esta página usa la “function_load” => “download_file_private”

Además nota que download_file_private() busca el dato get ‘file’ en la URL, por eso es necesario filtrar las llamadas URLs sin dato ‘file’: “ids_required” => [“file” => “file”]

Recuerda:

  • El menú no muestra una pestaña con datos GET no encontrados
  • El menú administarción de WordPress no puede filtrar una página existente, no usarlo en una página padre:Backend Frontend Template Pro: problema con la página de descargas si es alojada como página padre

 

Para este ejemplo se utiliza esta página de descarga:

	"download_explanation" => [
		[...]
		"children" => [
			"download_file_private" => [
				"menu_title" => $this->__("Download private file"),
				"page_title" => $this->__("Download private file"),
				"menu_slug" => "download",
				"function_load" => "download_file_private",
				"file" => "bft-admin-display-blank-page.php",
				"ids_required" => [
					"file" => "file",
				],
				"error_throw_what_do" => "go_to_parent",
			],
		]
	],	

Iframe en una página de administración

Hay dos tipos de iframes, ambos usan la página bft-admin-display-iframe.php, pero puedes hacer tu propia página:

	<?php
	if (isset($iframe_admin_page_slug) && false != $iframe_admin_page_slug)  {
	?>
		<iframe src="" width="100%" height="700">
		</iframe>
	<?php
	}

	if (isset($iframe_url) && false != $iframe_url)  {
	?>
		<iframe src="" width="100%" height="700">
		</iframe>
	<?php
	}
	?>

Hay dos tipos de iframes:

  1. Iframe por slug

    Este método necesita dos páginas: una es la página principal con el iframe, the other is the iframe itself

    1. Página principal

      La página principal especifica el slug de la página iframe con “iframe_admin_page_slug” => “iframe page” y la página que muestra el iframe con “file” => “bft-admin-display-iframe.php”

      	"iframe_admin_page_slug_test" => [
      		"menu_title" => $this->__("Iframe by slug"),
      		"page_title" => $this->__("Iframe by slug").': "iframe_admin_page_slug" => "iframe_test"',
      		"file" => "bft-admin-display-iframe.php",
      		"iframe_admin_page_slug" => "iframe_test",
      	],
      
    2. Página iframe

      La página iframe llamará a una function_load con un die, una function_load se ejecuta antes de mostrar el Menú de Administración de WordPress. Con “tab_show” => false ignoramos la página on el menú de pestaña de BFT

      	"iframe_test" => [
      		"tab_show" => false,
      		"file" => "bft-admin-display-iframe-test.php",
      		"function_load" => "function_load_page_display",
      	],
      
  2. Iframe por URL

    Este método sólo necesita el URL del iframe: “iframe_url” => admin_url() y la página que muestra el iframe “file” => “bft-admin-display-iframe.php”

    	"iframe_url_test" => [
    		"menu_title" => $this->__("URL iframe"),
    		"page_title" => $this->__("URL iframe").": ".admin_url(),
    		"file" => "bft-admin-display-iframe.php",
    		"iframe_url" => admin_url()."admin.php?page=".$this->plugin_slug."_iframe_test",
    	],
    

    Nota: admin_url() apunta al Menú de Administración de WordPress, es usado en este ejemplo porque normalmente un iframe externo no funcionará

  3. Mostrar PDF en un iframe

    Con todo esto podemos mostrar un PDF privado a través de un iframe por slug con “private_file_dir” => “file on private folder” y “function_load” => “show_pdf_private”

    	"iframe_admin_page_slug_test_pdf" => [
    		"menu_title" => $this->__("PDF example"),
    		"page_title" => $this->__("Iframe by slug - PDF example").': "private_file_dir" => "hello_world.pdf" | "function_load" => "show_pdf_private"',
    		"file" => "bft-admin-display-iframe.php",
    		"iframe_admin_page_slug" => "iframe_test_pdf",
    		"private_file_dir" => "hello_world.pdf",
    	],
    	"iframe_test_pdf" => [
    		"tab_show" => false,
    		"function_load" => "show_pdf_private",
    	],
    

Backend Frontend Template Pro: iframe en una página de administración

Backend Frontend Template Pro: mostrando PDF por iframe en una página de administración

Funciones de idiomas

Backend Frontend Template ofrece varias funciones sobre los idiomas:

  1. $this->languages_codes_names_get()

    Devuelve una lista de idiomas

    	$languages_codes_names = [
    		'ab' => $this->__('Abkhazian'),
    		'aa' => $this->__('Afar'),
    		'af' => $this->__('Afrikaans'),
    		'ak' => $this->__('Akan'),
    		'sq' => $this->__('Albanian'),
    		'am' => $this->__('Amharic'),
    		[...]
    
  2. $this->languages_get($country_code)

    Devuelve los datos guardados en el ajuste $this->option_field_get(“languages”)

  3. $this->language_admin_get($country_code)

    Devuelve los datos guardados en el ajuste $this->option_field_get(“language_admin”) si existe en $this->option_field_get(“languages”)

    • Si idiomas está vacío configurará los idiomas ‘en’ y ‘es’
    • Si language_admin está vacío o no es encontrado en los idiomas, se configurará el primer idioma guardado en languages

Funciones de países

Backend Frontend Template ofrece varias funciones sobre los países:

  1. $this->countries_codes_names_get()

    Devuelve la lista de países

    	$countries_codes_names = [
    		'AF'=> $this->__('Afghanistan'),
    		'AX'=> $this->__('Aland Islands'),
    		'AL'=> $this->__('Albania'),
    		'DZ'=> $this->__('Algeria'),
    		'AS'=> $this->__('American Samoa'),
    		'AD'=> $this->__('Andorra'),	
    		[...]
    
  2. $this->country_code_name_get($country_code)

    Devuelve el nombre del país a través del código del país

Funciones de divisas

Backend Frontend Template ofrece varias funciones sobre las monedas:

  1. $this->currencies_array_get()

    Devuelve a una lista de divisas con todos los datos, incluyendo el número de divisa según el estándard ISO 4217

    	$currencies_name_and_symbol = [
    		'ARS' => [
    			'id'   => 'ARS',
    			'name'   => 'Argentina Peso',
    			'symbol' => '$',
    			'code' => '032',
    		],
    		'AWG' => [
    			'id'   => 'AWG',
    			'name'   => 'Aruba Guilder',
    			'symbol' => 'ƒ',
    			'code' => '533',
    		],
    		[...]
    
  2. $this->currencies_selector_get()

    Devuelve una lista de divisas

    	$currencies_name_and_symbol = [
    		'ALL' => 'L - Albania Lek',
    		'AFN' => '؋ Afghanistan Afghani',
    		'ARS' => '$ Argentina Peso',
    		'AWG' => 'ƒ Aruba Guilder',
    		[...]
    
  3. $this->currency_symbol_get($currency_id)

    Devuelve el símbolo de una divisa a través del código de divisa

  4. $this->currency_code_get($currency_id)

    Devuelve el número ISO 4217 a través de la ID de la divisa

Sistema de shortcodes

Es fácil crear y administrar shortcodes con BFT:

  1. Definiendo un shortcode

    Los shortcores en BFT son definidos en public -> class-your-plugin-admin -> shortcodes_init_plugin()

    La estructura de un shortcode es:

    	add_shortcode("shortcode-name", array($this, "shortcode_function_name"));
    
  2. Definiendo una función

    La estructura de una función del shortcode es:

    	public function shortcode_function_name ( $atts = [], $content = null, $tag = '' ) {
    	}
    

    Las variables de la función son:

    • $atts: array con todos los datos especificados en el shortcode
    • $content: el contenido dentro de las dos etiquetas, si el shortcode usa una etiqueta de cierre
    • $tag: la etiqueta del shortcode
  3. Ejemplos de usos de shortcodes

    Un shortcode sin data en $atts y $content

    	[bft-shortcode-test]
    

    Shortcode con datos on $atts y $content

    	[bft-shortcode-test atts_data_1="Lorem ipsum" atts_data_2="Dolor sit amet"]Datos del contenido[/bft-shortcode-test]
    
  4. Ejemplo completo

    	public function shortcodes_init_plugin() {
    		add_shortcode("bft-shortcode-test", array($this, "bft_shortcode_test"));
    	}
    
    	public function bft_shortcode_test( $atts = [], $content = null, $tag = '' ) {
    
    		$html_aux = "";
    
    		if (isset($atts["aditional_text"])) {
    			$html_aux .= "<h4>".esc_html($atts["aditional_text"])."</h4>";
    		}
    
    		if (!is_null($content)) {
    			$html_aux .= "<p>".esc_html($content)."<p>";
    		}
    
    		ob_start();
    		require plugin_dir_path( dirname( __FILE__ ) ) . "public/partials/your-plugin-shortcode-test.php";
    		$html = ob_get_clean(); 
    
    		return $html;
    	}
    
  5. Pruébalo tu mismo

    Crea una page, inserta un bloque de shortcode y pon:

    		[bft-shortcode-test]
    

    O:

    		[bft-shortcode-test aditional_text="Esto es un texto adicional"]El texto dentro de las etiquetas[/bft-shortcode-test]
    

Backend Frontend Template Pro: ejemplo de shortcode simple, editando en la administración de WordPress

Backend Frontend Template Pro: ejemplo de shortcode simple, mostrando los resultado en el frontend de WordPress

Sistema de shortcodes con AJAX

Es fácil añadir AJAX en tus shortcodes:

  1. Shortcode inicial

    1. Explicación

      El shortcode no cambiará,el único cambio está en la página parcial, esa página tendrá los datos JavaScript AJAX

      Puedes usar tu propio método, pero BFT usa jQuery, las funciones proporcionadas por $this->bft_ajax_functions() están preparadas para ser impresas dentro de un script jQuery

      $this->bft_ajax_functions() provee funcioens JavaScript para mostrar error en el contenedor seleccionado y borrar los datos HTML en el contenedor principal:

      • bft_pro_error_wordpress_show(response_array, id_container_error, id_container_success = “”)
      • bft_pro_error_conection_show(jqXHR, textStatus, errorThrown, id_container_error, id_container_success = “”)

      Para la parte WordPress, es necesario:

      • AJAX URL, lo proporciona Backend Frontend Template con la variable bft_pro_ajax_url
      • Action data, from a form or created by code:
        	var form_data = [];
        	var data = {};
        	data["name"] = 'action';
        	data["value"] = "bft_shortcode_ajax_test_response";
        	form_data.push(data);
        
    2. Ejemplo completo
      	<div id="bft_shortcode_ajax_test_response_container"></div>
      	<div id="bft_shortcode_ajax_test_response_error_container"></div>
      
      	<!--
      	<form method="post" action="#" name="bft_shortcode_ajax_test_response" class="bft_shortcode_ajax_test_response" id="bft_shortcode_ajax_test_response">
      		<input type="hidden" name="action" value="bft_shortcode_ajax_test_response">   
      	</form>
      	-->
      
      	<script>
      		(function( $ ) {
      		"use strict";
      
      		function bft_shortcode_ajax_test_function () {
      			var form_data = [];
      			var data = {};
      			data["name"] = "action";
      			data["value"] = "bft_shortcode_ajax_test_response";
      			form_data.push(data);
      
      			//var form_data = jQuery("#bft_shortcode_ajax_test_response").serializeArray();
      
      			jQuery.ajax({
      				url : your_plugin_ajax_url,
      				type : "post",
      				data : form_data,
      				success : function( response ) {
      					console.log("<?=$this->__("AJAX successful")?>")
      					console.log(response);
      					if (typeof response.success !== "undefined" && false === false) {
      						console.log("<?=$this->__("AJAX failed")?>");
      						<?=$this->plugin_slug?>_error_wordpress_show(response, "bft_shortcode_ajax_test_response_error_container", "bft_shortcode_ajax_test_response_container");
      					}
      					else {
      						$("#bft_shortcode_ajax_test_response_container").html(response.data.html);
      					}
      				},
      				fail : function( jqXHR, textStatus, errorThrown) {
      					console.log("<?=$this->__("AJAX failed")?>");
      					<?=$this->plugin_slug?>_error_conection_show(jqXHR, textStatus, errorThrown, "bft_shortcode_ajax_test_response_error_container", "bft_shortcode_ajax_test_response_container");
      				}
      			});
      		}
      
      		bft_shortcode_ajax_test_function();
      
      		<?=$this->bft_ajax_functions()?>
      
      		})( jQuery );
      
      	</script>
      
  2. respuesta AJAX

    1. Definiendo una Acción AJAX de WordPress

      Las respuestas AJAX son definidas en includes -> class-your-plugin -> define_public_hooks()

      La estructura de una respuesta AJAX es doble, WordPress separa los usuarios logeados de los usuarios no logeados:

      	//AJAX response for logged users
      	$this->loader->add_action( 'wp_ajax_ajax_response_function_name', $plugin_public, 'ajax_response_function_name' );
      	
      	//AJAX response for non logged users
      	$this->loader->add_action( 'wp_ajax_nopriv_ajax_response_function_name', $plugin_public, 'ajax_response_function_name' );
      
    2. Definiendo a función

      Esta función no tiene variables, todos los datos pasados serán datos POST

      Para preparar los datos de vuelva, BFT usa esta estructura:

      	$data = array();
      	$data["html"] = $html;
      
      	$return = [
      		"error" => [],
      		"data" => $data,
      	];
      

      Para senviar los datos, la función usará las funciones de WordPress wp_send_json() y wp_die()

      	wp_send_json($return);
      	wp_die();
      
    3. Devolviendo un error

      Backend Frontend Template provee la función $this->error_send_json(“Error text”)

      $this->error_send_json() devolverá el JSON y parará la ejecución del código

    4. Ejemplo completo
      	private function define_public_hooks() {
      		//bft_shortcode_ajax_test_response
      		$this->loader->add_action( 'wp_ajax_bft_shortcode_ajax_test_response', $plugin_public, 'bft_shortcode_ajax_test_response' );
      		$this->loader->add_action( 'wp_ajax_nopriv_bft_shortcode_ajax_test_response', $plugin_public, 'bft_shortcode_ajax_test_response' );
      	}
      
      	public function bft_shortcode_ajax_test_response( ) {
      
      		ob_start();
      		require plugin_dir_path( dirname( __FILE__ ) ) . "public/partials/your-plugin-shortcode-ajax-test-response.php";
      		$html = ob_get_clean();
      
      		$data = array();
      		$data["html"] = $html;
      
      		$return = [
      			"error" => [],
      			"data" => $data,
      		];
      
      		wp_send_json($return);
      		wp_die();
      
      		return $html;
      	}
      
  3. Pruébalo tu mismo

    Crea una page, inserta un bloque de shortcode y pon

    		[bft-shortcode-ajax-test]
    

Backend Frontend Template Pro: ejemplo de shortcode con AJAX, editando en la administración de WordPress

Backend Frontend Template Pro: ejemplo de shortcode con AJAX, mostrando los resultado en el frontend de WordPress

Sistema de shortcodes con un formulario con respuesta AJAX

De una respuesta AJAX a un formulario sólo hay algunos pasos a considerar:

  1. Shortcode inicial

    1. Explicación

      En los datos HTML estará el formulario con el dato ‘action’, los datos se leerán con jQuery(“”).serializeArray()

      	var form_data = jQuery("#bft_shortcode_form_test_response").serializeArray();
      

      Además, los datos del formulario tendrán un nonce si el usuario está logueado, para seguridad adicional

      	$script_push_nonce = "";
      	if(is_user_logged_in()) {
      		$script_push_nonce = 'form_data.push( { "name" : "'.$this->plugin_slug.'_security", "value" : '.$this->plugin_slug.'_ajax_nonce } );';
      	}
      
    2. Ejemplo completo
      	public function bft_shortcode_form_test( $atts = [], $content = null, $tag = '' ) {
      
      		$script_push_nonce = "";
      		if(is_user_logged_in()) {
      			$script_push_nonce = 'form_data.push( { "name" : "'.$this->plugin_slug.'_security", "value" : '.$this->plugin_slug.'_ajax_nonce } );';
      		}
      
      		ob_start();
      		require plugin_dir_path( dirname( __FILE__ ) ) . "public/partials/bft-shortcode-form-test-static.php";
      		$html = ob_get_clean(); 
      
      		return $html;
      	}
      

      HTML

      	<form method="post" action="#" name="bft_shortcode_form_test_response" class="bft_shortcode_form_test_response" id="bft_shortcode_form_test_response">
      		<input type="hidden" name="action" value="bft_shortcode_form_test_response">
      		<div>
      			<label><?=$this->__("Name")?></label> <input type="text" name="bft_shortcode_form_test_response_name" id="bft_shortcode_form_test_response_name" value="">   
      		</div>
      		<div>
      			<label><?=$this->__("Surname")?></label> <input type="text" name="bft_shortcode_form_test_response_surname" id="bft_shortcode_form_test_response_surname" value="">   
      		</div>
      		<div>
      			<input type="submit" value="<?=$this->__("Test form")?>" id="bft_shortcode_form_test_response_submit">
      		</div>
      	</form>
      
      	<div id="bft_shortcode_form_test_response_container"></div>
      	<div id="bft_shortcode_form_test_response_error_container"></div>
      
      	<script>
      		(function( $ ) {
      		"use strict";
      
      		$(document).on("submit", ".bft_shortcode_form_test_response", function(e) {
      			e.preventDefault();
      
      			var form_data = jQuery("#bft_shortcode_form_test_response").serializeArray();
      			<?=$script_push_nonce?>
      
      			$("#bft_shortcode_form_test_response_container").html("");
      			$("#bft_shortcode_form_test_response_error_container").text("");
      
      			jQuery.ajax({
      				url : your_plugin_ajax_url,
      				type : "post",
      				data : form_data,
      				success : function( response ) {
      					console.log("<?=$this->__("AJAX successful")?>")
      					if (typeof response.success !== "undefined" && false === false) {
      						console.log("<?=$this->__("AJAX failed")?>");
      						<?=$this->plugin_slug?>_error_wordpress_show(response, "bft_shortcode_form_test_response_error_container", "bft_shortcode_form_test_response_container");
      					}
      					else {
      						$("#bft_shortcode_form_test_response_container").html(response.data.html);
      					}
      				},
      				fail : function( jqXHR, textStatus, errorThrown) {
      					console.log("<?=$this->__("AJAX failed")?>");
      					<?=$this->plugin_slug?>_error_conection_show(jqXHR, textStatus, errorThrown, "bft_shortcode_form_test_response_error_container", "bft_shortcode_form_test_response_container");
      				}
      			});
      		});
      
      		<?=$this->bft_ajax_functions()?>
      
      		})( jQuery );   
      
      	</script>
      
  2. respuesta AJAX

    1. Explicación

      Un formulario AJAX comprobará el nonce para usuario logeados antes de usar los datos con check_ajax_referer(), si el nonce falla la ejecución parará

      		if(is_user_logged_in()) {
      			check_ajax_referer($this->plugin_slug."_form_public_nonce", $this->plugin_slug."_security" );
      		}
      		unset($_POST["action"]);
      		unset($_POST[$this->plugin_slug."_security"]);
      
    2. Ejemplo completo
      		private function define_public_hooks() {
      			//bft_shortcode_form_test_response
      			$this->loader->add_action( 'wp_ajax_bft_shortcode_form_test_response', $plugin_public, 'bft_shortcode_form_test_response' );
      			$this->loader->add_action( 'wp_ajax_nopriv_bft_shortcode_form_test_response', $plugin_public, 'bft_shortcode_form_test_response' );
      		}
      
      		public function bft_shortcode_form_test_response( ) {
      
      			if(is_user_logged_in()) {
      				check_ajax_referer($this->plugin_slug."_form_public_nonce", $this->plugin_slug."_security" );
      			}
      			unset($_POST["action"]);
      			unset($_POST[$this->plugin_slug."_security"]);
      
      			if (	!isset($_POST["bft_shortcode_form_test_response_name"])
      				||	!isset($_POST["bft_shortcode_form_test_response_surname"])) {
      				$this->error_send_json($this->__("An error of validation ocurred, contact the admin of the site"));
      			}
      
      
      			ob_start();
      			require plugin_dir_path( dirname( __FILE__ ) ) . "public/partials/bft-shortcode-form-test-response.php";
      			$html = ob_get_clean();
      
      			$data = array();
      			$data["html"] = $html;
      
      			$return = [
      				"error" => [],
      				"data" => $data,
      			];
      
      			wp_send_json($return);
      			wp_die();
      
      			return $html;
      		}
      
  3. Pruébalo tu mismo

    Crea una page, inserta un bloque de shortcode y pon

    		[bft-shortcode-form-test]
    

Backend Frontend Template Pro: ejemplo de shortcode que genera un formulario con respuesta AJAX, editando en la administración de WordPress

Backend Frontend Template Pro: ejemplo de shortcode que genera un formulario con respuesta AJAX, mostrando los resultado en el frontend de WordPress

Tu primera página editada

Intenta modificar admin/partials/your-plugin-admin-display-hello-world.php y transforma su Lorem Ipsum en tu propio Hello World

Changelog

1.1.0 | 2023-10-02

Cambiado

  • Las imágenes de ejemplo ahora se cargan desde moisesbarrachina.online para hacer más liviano el plugin
  • Mejorada la explicación y legibilidad del los textos

Corregido

  • Corregidos errores tipográficos

1.0.0 | 2023-09-14

Añadido

  • Sistema de menú con hijos
  • Sistema de ajustes
  • Sistema de ipunts:text, textarea, number, select, select multiple, fecha, checkbox, checkbox múltiple, radio, imagen, archivo e input comentado
  • Ejemplo de la base de datos
  • Instalar y desinstalar la base de datos del plugin
  • Manipulación de datos automatizada
  • Manipulación manual de datos
  • Listado paginado por consulta
  • Listado directo por array
  • Formulario manual
  • Manipulación del log
  • Manipulación errores
  • Internalización
  • Sistema de descargar para archivos privados
  • Sistema de iframes
  • PDF por sistema de iframes
  • Sistema de frontend por shortcode
  • Sistema AJAX por frontend
  • Interiorización al español

Blog sobre Backend Frontend Template Pro

Utilizamos Cookies propias y de terceros para mejorar nuestros servicios y para ofrecerte una mejor experiencia (por ejemplo, mostrando publicidad personalizada) mediante el análisis de tus hábitos de navegación (por ejemplo, páginas visitadas). Puedes aceptar todas las cookies pulsando el botón “Aceptar”. Para configurarlas, obtener más información o rechazar su uso, haz click AQUÍ

Los ajustes de cookies en esta web están configurados para «permitir las cookies» y ofrecerte la mejor experiencia de navegación posible. Si sigues usando esta web sin cambiar tus ajustes de cookies o haces clic en «Aceptar», estarás dando tu consentimiento a esto.

Cerrar