Ξεκινάμε με τα αρχιτεκτονικά project. Όπως ξέρουμε στο WordPress μπορούμε να κάνουμε άρθρα (posts) και σελίδες (pages). Στο WordPress αυτά είναι και τα δύο ξεχωριστοί τύποι άρθρων (post types) και εδώ και αρκετά χρόνια το WordPress μας δίνει τη δυνατότητα να ορίσουμε νέους δικούς μας τύπους άρθρων (custom post types). Μεσά στο φάκελο src δημιουργούμε ένα νέο αρχείο με το όνομα ArchitectureProject.php και με το προσθέτουμε τα παρακάτω (τα παρουσιάζω αποσπασματικά για να γίνει και μια μικρή εξήγηση, όλα τα παρακάτω είναι στο ίδιο αρχείο, μέχρι το σημείο που αναφέρεται ότι περνάμε σε άλλο αρχείο):
<?php namespace DasodaHae\Architect; if ( ! defined( 'ABSPATH' ) ) { exit(); } class ArchitectureProject { public static function UpdatePostMessages( $messages) { global $post, $post_id; $messages['dh_at_archproj'] = array( 0 => '', /* translators: Pass project URI as string parameter. */ 1 => sprintf( __('Architecture project updated. <a href="%s">View project</a>', 'dh-architect-plugin' ), esc_url( get_permalink($post_id) ) ), 2 => __('Custom field updated.', 'dh-architect-plugin' ), 3 => __('Custom field deleted.', 'dh-architect-plugin' ), 4 => __('Architecture project updated.', 'dh-architect-plugin' ), /* translators: Passed parameter is the custom post's date timestamp of revision . */ 5 => isset($_GET['revision']) ? sprintf( __('Architecture project restored to revision from %s', 'dh-architect-plugin' ), wp_post_revision_title( (int) $_GET['revision'], false ) ) : false, /* translators: Pass project URI as string parameter. */ 6 => sprintf( __('Architecture project published. <a href="%s">View project</a>', 'dh-architect-plugin' ), esc_url( get_permalink($post_id) ) ), 7 => __('Architecture project saved.', 'dh-architect-plugin' ), /* translators: Pass project's preview URI as string parameter. */ 8 => sprintf( __('Architecture project submitted. <a target="_blank" href="%s">Preview project</a>', 'dh-architect-plugin' ), esc_url( add_query_arg( 'preview', 'true', get_permalink($post_id) ) ) ), /* translators: Pass project's scheduled date and URI as string parameter. */ 9 => sprintf( __('Architecture project scheduled for: <strong>%1$s</strong>. <a target="_blank" href="%2$s">Preview project</a>', 'dh-architect-plugin' ), date_i18n( __( 'M j, Y @ G:i' ), strtotime( $post->post_date ) ), esc_url( get_permalink($post_id) ) ), /* translators: Pass project's preview URI as string parameter. */ 10 => sprintf( __('Architecture project draft updated. <a target="_blank" href="%s">Preview project</a>', 'dh-architect-plugin' ), esc_url( add_query_arg( 'preview', 'true', get_permalink($post_id) ) ) ), ); return $messages; }
Στο πρώτο αυτό κομμάτι, ορίζουμε την κλάση (class) και την πρώτη συνάρτηση που θα καλέσουμε αργότερα μέσω ενός φίλτρου (WordPress filter), του post_updated_messages ώστε να ορίζουμε τα μηνύματα που επιστρέφει το WordPress, κατά το update του συγκεκριμένου post type.
public static function RegisterCPT() { /* Remember to keep the following in sync with the ones set for the custom post type admin notices, using the 'post_updated_messages' filter */ $labels = array( 'name' => __( 'Architecture projects', 'dh-architect-plugin' ), 'singular_name' => __( 'Architecture project', 'dh-architect-plugin' ), 'add_new' => __( 'Add new', 'dh-architect-plugin' ), 'add_new_item' => __( 'Add new architecture project', 'dh-architect-plugin' ), 'edit_item' => __( 'Edit architecture project', 'dh-architect-plugin' ), 'new_item' => __( 'New architecture project', 'dh-architect-plugin' ), 'view_item' => __( 'View architecture project', 'dh-architect-plugin' ), 'view_items' => __( 'View architecture projects', 'dh-architect-plugin' ), 'search_items' => __( 'Search architecture projects', 'dh-architect-plugin' ), 'not_found' => __( 'No architecture projects found', 'dh-architect-plugin' ), 'not_found_in_trash' => __( 'No architecure projects found in Trash', 'dh-architect-plugin' ), 'all_items' => __( 'All architecture projects', 'dh-architect-plugin' ), 'archives' => __( 'Architecture project archives', 'dh-architect-plugin' ), 'attributes' => __( 'Architecture projects attributes', 'dh-architect-plugin' ), 'insert_into_item' => __( 'Insert into architecture project', 'dh-architect-plugin' ), 'uploaded_to_this_item' => __( 'Uploaded to this architecture project', 'dh-architect-plugin' ), 'featured_image' => __( 'Featured image', 'dh-architect-plugin' ), 'set_featured_image' => __( 'Set featured image', 'dh-architect-plugin' ), 'remove_featured_image' => __( 'Remove featured image', 'dh-architect-plugin' ), 'use_featured_image' => __( 'Use as featured image', 'dh-architect-plugin' ), 'menu_name' => __( 'Architecture projects', 'dh-architect-plugin' ), 'filter_items_list' => __( 'Filter architecture projects list', 'dh-architect-plugin' ), 'items_list_navigation' => __( 'Architecture projects list navigation', 'dh-architect-plugin' ), 'items_list' => __( 'Architecture projects list', 'dh-architect-plugin' ), 'item_published' => __( 'Architecture project published', 'dh-architect-plugin' ), 'item_published_privately' => __( 'Architecture project published privately', 'dh-architect-plugin' ), 'item_reverted_to_draft' => __( 'Architecture project reverted to draft', 'dh-architect-plugin' ), 'item_scheduled' => __( 'Architecture project scheduled', 'dh-architect-plugin' ), 'item_updated' => __( 'Architecture project updated', 'dh-architect-plugin' ), ); $args = array( 'labels' => $labels, 'description' => 'Architecture projects', 'public' => true, 'exclude_from_search' => false, 'publicly_queryable' => true, 'show_in_rest' => true, 'rest_base' => 'architecture-projects', 'menu_icon' => 'dashicons-admin-page', 'menu_position' => 22, 'capability_type' => 'architecture_project', 'map_meta_cap' => true, 'supports' => array( 'title', 'editor', 'thumbnail', 'author', 'custom-fields', ), 'has_archive' => 'architecture-projects', 'rewrite' => array( 'slug' => 'architecture-projects', 'with_front' => false, 'feeds' => false, 'pages' => true, ), 'query_var' => 'architecture-projects', 'can_export' => true, ); return register_post_type( 'dh_at_archproj', $args ); }
Εδώ αφού ορίζουμε κάποια μηνύματα που θα επιστρέφει το περιβάλλον του WordPress, και κάποιες παραμέτρους μέσω του πίνακα $args, σχετικές με τη συμπεριφορά και τη λειτουργία του custom post type, καλούμε την συνάρτηση register_post_type για να το καταχωρίσουμε. Επίσης, δεν ξεχνάμε και με βάση την τεκμηρίωση σχετικά με την υποστήριξη των metadata στο custom post type, να συμπεριλάβουμε στα supports τις τιμές editor και custom-fields, όπως και το πεδίο show_in_rest να έχει την τιμή true.
Και τελευταίο κομμάτι το παρακάτω, οι δύο συναρτήσεις που θέτουν και αφαιρούν τα δικαιώματα πάνω σε αυτό το CPT στους ρόλους που υπάρχουν σε μια εγκατάσταση WordPress, σύμφωνα πάντα με τον έλεγχο που βασίζεται σε ρόλους και ικανότητες:
public static function AddCapabilities() { // Add caps for Administrator role. $role = get_role( 'administrator' ); $role->add_cap( 'edit_architecture_projects' ); $role->add_cap( 'edit_others_architecture_projects' ); $role->add_cap( 'edit_published_architecture_projects' ); $role->add_cap( 'publish_architecture_projects' ); $role->add_cap( 'delete_architecture_projects' ); $role->add_cap( 'delete_others_architecture_projects' ); $role->add_cap( 'delete_published_architecture_projects' ); $role->add_cap( 'delete_private_architecture_projects' ); $role->add_cap( 'edit_private_architecture_projects' ); $role->add_cap( 'read_private_architecture_projects' ); // Add caps for Editor role. $role = get_role( 'editor' ); $role->add_cap( 'edit_architecture_projects' ); $role->add_cap( 'edit_others_architecture_projects' ); $role->add_cap( 'edit_published_architecture_projects' ); $role->add_cap( 'publish_architecture_projects' ); $role->add_cap( 'delete_architecture_projects' ); $role->add_cap( 'delete_others_architecture_projects' ); $role->add_cap( 'delete_published_architecture_projects' ); $role->add_cap( 'delete_private_architecture_projects' ); $role->add_cap( 'edit_private_architecture_projects' ); $role->add_cap( 'read_private_architecture_projects' ); // Add caps for Author role. $role = get_role( 'author' ); $role->add_cap( 'edit_architecture_projects' ); $role->add_cap( 'edit_published_architecture_projects' ); $role->add_cap( 'publish_architecture_projects' ); $role->add_cap( 'delete_architecture_projects' ); $role->add_cap( 'delete_published_architecture_projects' ); // Add caps for Contributor role. $role = get_role( 'contributor' ); $role->add_cap( 'edit_architecture_projects' ); $role->add_cap( 'delete_architecture_projects' ); } public static function RemoveCapabilities() { // Remove caps for Administrator role. $role = get_role( 'administrator' ); $role->remove_cap( 'edit_architecture_projects' ); $role->remove_cap( 'edit_others_architecture_projects' ); $role->remove_cap( 'edit_published_architecture_projects' ); $role->remove_cap( 'publish_architecture_projects' ); $role->remove_cap( 'delete_architecture_projects' ); $role->remove_cap( 'delete_others_architecture_projects' ); $role->remove_cap( 'delete_published_architecture_projects' ); $role->remove_cap( 'delete_private_architecture_projects' ); $role->remove_cap( 'edit_private_architecture_projects' ); $role->remove_cap( 'read_private_architecture_projects' ); // Remove caps for Editor role. $role = get_role( 'editor' ); $role->remove_cap( 'edit_architecture_projects' ); $role->remove_cap( 'edit_others_architecture_projects' ); $role->remove_cap( 'edit_published_architecture_projects' ); $role->remove_cap( 'publish_architecture_projects' ); $role->remove_cap( 'delete_architecture_projects' ); $role->remove_cap( 'delete_others_architecture_projects' ); $role->remove_cap( 'delete_published_architecture_projects' ); $role->remove_cap( 'delete_private_architecture_projects' ); $role->remove_cap( 'edit_private_architecture_projects' ); $role->remove_cap( 'read_private_architecture_projects' ); // Remove caps for Author role. $role = get_role( 'author' ); $role->remove_cap( 'edit_architecture_projects' ); $role->remove_cap( 'edit_published_architecture_projects' ); $role->remove_cap( 'publish_architecture_projects' ); $role->remove_cap( 'delete_architecture_projects' ); $role->remove_cap( 'delete_published_architecture_projects' ); // Remove caps for Contributor role. $role = get_role( 'contributor' ); $role->remove_cap( 'edit_architecture_projects' ); $role->remove_cap( 'delete_architecture_projects' ); } }
Now that we have put these functions in place we can use them in our plugin’s activation – deactivation hooks. To do so we add the following public functions in our Plugin class in our src/Plugin.php file:
public static function Activate() { // Register Architecture Project CPT $result = ArchitectureProject::RegisterCPT(); if ( ! is_wp_error( $result ) ) { // Add capabilities to the Roles for the CPT ArchitectureProject::AddCapabilities(); // Clear and recreate the permalinks after the post type has been registered flush_rewrite_rules(); } } public static function Deactivate() { // Unregister Architecture Project CPT $result = unregister_post_type( 'dh_at_archproj' ); if ( ! is_wp_error( $result ) ) { // Remove capabilities from the Roles for the CPT ArchitectureProject::RemoveCapabilities(); // Clear the permalinks to remove our CPT rules from the database flush_rewrite_rules(); } }
And then we enter the following in our dh-architect-plugin.php file:
register_activation_hook( __FILE__ , ['DasodaHae\Architect\Plugin', 'Activate'] ); register_deactivation_hook( __FILE__ , ['DasodaHae\Architect\Plugin', 'Deactivate'] ); register_uninstall_hook( __FILE__ , ['DasodaHae\Architect\Plugin', 'Uninstall'] );
During activation, we register the CPT, to be able to update our permalink structure, and we add the capabilities to our database. The opposite during deactivation. Updating the capabilities and the permalinks are both expensive operations and should happen during activation/deactivation. But we should “remind” WordPress about the existence of our CPT in every page load. So we add in our dh-architect-plugin.php file the following, to be able to do just that, and to update the messages when needed (that’s why we use the corresponding hooks):
/* Register the "Architecture Project" CPT */ add_action( 'init', ['DasodaHae\Architect\ArchitectureProject', 'RegisterCPT'] ); /* Filter the post updated messages for the Architecture Project CPT */ add_filter( 'post_updated_messages', ['DasodaHae\Architect\ArchitectureProject', 'UpdatePostMessages'] );