Wordpress Documentation

advertise, Anuncio

Plugins

📁 Carpeta: /mi-plugin/

				
					/mi-plugin/
├── mi-plugin.php
├── includes/
│   ├── custom-post-types.php
│   └── functions.php
└── assets/
    ├── style.css
    └── script.js

				
			

📄 mi-plugin.php (archivo principal)

				
					<?php
/*
Plugin Name: Mi Plugin Pro
Plugin URI: https://tusitio.com
Description: Plugin estructurado con CPTs y funciones auxiliares.
Version: 1.0
Author: Erick Sánchez
Author URI: https://tusitio.com
*/

if (!defined('ABSPATH')) exit;

// Incluir archivos
require_once plugin_dir_path(__FILE__) . 'includes/custom-post-types.php';
require_once plugin_dir_path(__FILE__) . 'includes/functions.php';

// Cargar estilos y scripts
add_action('admin_enqueue_scripts', function () {
  wp_enqueue_style('mi-plugin-style', plugin_dir_url(__FILE__) . 'assets/style.css');
  wp_enqueue_script('mi-plugin-script', plugin_dir_url(__FILE__) . 'assets/script.js', ['jquery'], false, true);
});

				
			

📄 includes/custom-post-types.php

				
					<?php
// Registrar un CPT de ejemplo
add_action('init', function () {
  register_post_type('proyecto', [
    'labels' => [
      'name' => 'Proyectos',
      'singular_name' => 'Proyecto',
    ],
    'public' => true,
    'has_archive' => true,
    'supports' => ['title', 'editor', 'thumbnail'],
    'menu_icon' => 'dashicons-portfolio',
  ]);
});

				
			

📄 includes/functions.php

				
					<?php
// Funciones reutilizables del plugin
function mi_plugin_utilidad($texto) {
  return strtoupper($texto);
}

				
			

 Plugin Completo (Modular y Escalable)

  • Uso de register_post_type

  • add_meta_box o tabla personalizada para relación CPT <-> user

  • API con register_rest_route

  • Organización del código en carpetas (/includes, /admin, /api)

  • Seguridad con nonces, sanitize, current_user_can

  • Autoload con PSR-4 (ideal, si sabes Composer)

				
					<?php
/*
Plugin Name: Cursos Pro API
Description: Plugin modular para gestionar cursos, instructores y exponer REST API personalizada.
Version: 1.0
Author: Erick S.
*/

if (!defined('ABSPATH')) exit;

// 1. Registrar CPT 'curso'
add_action('init', function () {
  register_post_type('curso', [
    'label' => 'Cursos',
    'public' => true,
    'has_archive' => true,
    'rewrite' => ['slug' => 'cursos'],
    'supports' => ['title', 'editor', 'thumbnail'],
    'show_in_rest' => true,
  ]);
});

// 2. Metabox para asignar instructor (usuario)
add_action('add_meta_boxes', function () {
  add_meta_box('instructor_curso', 'Instructor asignado', function ($post) {
    wp_nonce_field('guardar_instructor', 'instructor_nonce');
    $user_id = get_post_meta($post->ID, '_instructor_id', true);
    $usuarios = get_users(['role__in' => ['author', 'editor', 'administrator']]);
    echo '<select name="instructor_id">';
    foreach ($usuarios as $usuario) {
      $selected = ($usuario->ID == $user_id) ? 'selected' : '';
      echo "<option value='{$usuario->ID}' $selected>{$usuario->display_name}</option>";
    }
    echo '</select>';
  }, 'curso', 'side');
});

add_action('save_post_curso', function ($post_id) {
  if (!isset($_POST['instructor_nonce']) || !wp_verify_nonce($_POST['instructor_nonce'], 'guardar_instructor')) return;
  update_post_meta($post_id, '_instructor_id', intval($_POST['instructor_id']));
});

// 3. Shortcode con filtro por instructor
add_shortcode('cursos_filtrados', function () {
  $instructor = isset($_GET['instructor']) ? intval($_GET['instructor']) : 0;

  $args = ['post_type' => 'curso', 'posts_per_page' => -1];
  if ($instructor) {
    $args['meta_query'] = [[
      'key' => '_instructor_id',
      'value' => $instructor,
      'compare' => '='
    ]];
  }
  $query = new WP_Query($args);
  ob_start();
  echo '<form method="get"><select name="instructor"><option value="">Todos</option>';
  foreach (get_users() as $u) {
    $selected = ($u->ID == $instructor) ? 'selected' : '';
    echo "<option value='{$u->ID}' $selected>{$u->display_name}</option>";
  }
  echo '</select><button>Filtrar</button></form>';
  while ($query->have_posts()) {
    $query->the_post();
    echo '<div><h3>' . get_the_title() . '</h3><p>' . get_the_excerpt() . '</p></div>';
  }
  wp_reset_postdata();
  return ob_get_clean();
});

// 4. REST API: obtener cursos por instructor (GET)
add_action('rest_api_init', function () {
  register_rest_route('cursospro/v1', '/instructor/(?P<id>\d+)', [
    'methods' => 'GET',
    'callback' => 'api_get_cursos_by_instructor',
    'permission_callback' => '__return_true',
  ]);

  register_rest_route('cursospro/v1', '/curso', [
    'methods' => 'POST',
    'callback' => 'api_crear_curso',
    'permission_callback' => function () {
      return current_user_can('edit_posts');
    }
  ]);
});

function api_get_cursos_by_instructor($req) {
  $id = intval($req['id']);
  $q = new WP_Query([
    'post_type' => 'curso',
    'meta_key' => '_instructor_id',
    'meta_value' => $id
  ]);
  $result = [];
  foreach ($q->posts as $post) {
    $result[] = [
      'id' => $post->ID,
      'titulo' => get_the_title($post),
      'link' => get_permalink($post)
    ];
  }
  return rest_ensure_response($result);
}

function api_crear_curso($req) {
  $titulo = sanitize_text_field($req['titulo']);
  $contenido = wp_kses_post($req['contenido']);
  $instructor = intval($req['instructor_id']);

  $post_id = wp_insert_post([
    'post_type' => 'curso',
    'post_title' => $titulo,
    'post_content' => $contenido,
    'post_status' => 'publish'
  ]);

  if ($post_id && $instructor) {
    update_post_meta($post_id, '_instructor_id', $instructor);
  }

  return rest_ensure_response(['id' => $post_id]);
}

// 5. Hook complejo: campo adicional en perfil de usuario
add_action('show_user_profile', 'campo_especialidad_usuario');
add_action('edit_user_profile', 'campo_especialidad_usuario');
function campo_especialidad_usuario($user) {
  ?>
  <h3>Especialidad del instructor</h3>
  <input type="text" name="especialidad" value="<?php echo esc_attr(get_user_meta($user->ID, 'especialidad', true)); ?>">
  <?php
}
add_action('personal_options_update', 'guardar_especialidad_usuario');
add_action('edit_user_profile_update', 'guardar_especialidad_usuario');
function guardar_especialidad_usuario($user_id) {
  update_user_meta($user_id, 'especialidad', sanitize_text_field($_POST['especialidad']));
}