diff --git a/.gitignore b/.gitignore index d98e886..4da4d64 100644 --- a/.gitignore +++ b/.gitignore @@ -50,4 +50,5 @@ phpunit.xml phpcs-report-*.txt # Allowed vendor files -!vendor/freemius \ No newline at end of file +!vendor/freemius +.vscode/launch.json diff --git a/assets/js/explanations.js b/assets/js/explanations.js new file mode 100644 index 0000000..3e32eb8 --- /dev/null +++ b/assets/js/explanations.js @@ -0,0 +1,105 @@ +/** + * Explanations JS. + */ + +( function( $ ) { + + // + // Explanations AJAX handlers. + // + + var statusLabel = $( '#status-label' ), + createLink = $( '#create-expl' ), + unPublishLink = $( '#unpublish-expl' ), + rowActions = $( '#expl-row-actions' ); + + var rowCreateLink = $( '.create-expl' ); + + /** + * AJAX handler for creating and associating a new explanation post. + * + * @param {object} event Event object. + */ + function createExplanation( event ) { + event.preventDefault(); + + wp.ajax.send( 'new_explanation', { + success: createExplSuccess, + error: createExplError, + data: { + nonce: $( this ).data( 'nonce' ), + post_id: $( this ).data( 'id' ), + context: event.data.context + } + } ); + } + + /** + * Success callback for creating a new explanation via AJAX. + * + * @param {object} data Data response object. + */ + function createExplSuccess( data ) { + var editLink = '' + wporg.editContentLabel + ''; + + if ( 'edit' == data.context ) { + // Action in the parsed post type edit screen. + createLink.hide(); + rowActions.html( editLink ); + statusLabel.text( wporg.statusLabel.draft ); + } else { + // Row link in the list table. + $( '#post-' + data.parent_id + ' .add-expl' ).html( editLink + ' | ' ); + } + } + + /** + * Error callback for creating a new explanation via AJAX. + * + * @param {object} data Data response object. + */ + function createExplError( data ) {} + + /** + * Handler for un-publishing an existing Explanation. + * + * @param {object} event Event object. + */ + function unPublishExplantaion( event ) { + event.preventDefault(); + + wp.ajax.send( 'un_publish', { + success: unPublishSuccess, + error: unPublishError, + data: { + nonce: $( this ).data( 'nonce' ), + post_id: $( this ).data( 'id' ) + } + } ); + } + + /** + * Success callback for un-publishing an explanation via AJAX. + * + * @param {object} data Data response object. + */ + function unPublishSuccess( data ) { + if ( statusLabel.hasClass( 'pending' ) || statusLabel.hasClass( 'publish' ) ) { + statusLabel.removeClass( 'pending publish' ).text( wporg.statusLabel.draft ); + } + unPublishLink.hide(); + } + + /** + * Error callback for un-publishing an explanation via AJAX. + * + * @param {object} data Data response object. + */ + function unPublishError( data ) {} + + // Events. + createLink.on( 'click', { context: 'edit' }, createExplanation ); + rowCreateLink.on( 'click', { context: 'list' }, createExplanation ); + unPublishLink.on( 'click', unPublishExplantaion ); + +} )( jQuery ); diff --git a/class-phpdoc-plugin.php b/class-phpdoc-plugin.php index fa4e8af..53ab706 100644 --- a/class-phpdoc-plugin.php +++ b/class-phpdoc-plugin.php @@ -32,11 +32,18 @@ class Bootstrap { public function plugins_loaded() { $plugin = new Plugin(); + // Run any actions for theme init. + add_action( 'after_setup_theme', array( $plugin, 'after_setup_theme' ) ); + // Init the plugin. add_action( 'init', array( $plugin, 'init' ) ); + + // Plugins loaded actions. + $plugin->plugins_loaded(); } } $phpdoc_plugin = new Bootstrap(); +register_activation_hook( __FILE__, array( '\Pods\phpDoc_Plugin\Plugin', 'register_activation_hook' ) ); add_action( 'plugins_loaded', array( $phpdoc_plugin, 'plugins_loaded' ) ); diff --git a/php/Explanations.php b/php/Explanations.php new file mode 100644 index 0000000..d0c780b --- /dev/null +++ b/php/Explanations.php @@ -0,0 +1,670 @@ +post_types = PostTypes::get_parsed_post_types(); + + $this->screen_ids = array( $this->exp_post_type, "edit-{$this->exp_post_type}" ); + + // Setup. + add_action( 'init', array( $this, 'register_post_type' ), 0 ); + add_action( 'init', array( $this, 'remove_editor_support' ), 100 ); + + // Admin. + add_action( 'edit_form_after_title', array( $this, 'post_to_expl_controls' ) ); + add_action( 'edit_form_top', array( $this, 'expl_to_post_controls' ) ); + add_action( 'admin_bar_menu', array( $this, 'toolbar_edit_link' ), 100 ); + add_action( 'admin_menu', array( $this, 'admin_menu' ) ); + add_action( 'load-post-new.php', array( $this, 'prevent_direct_creation' ) ); + // Add admin post listing column for explanations indicator. + add_filter( 'manage_posts_columns', array( $this, 'add_post_column' ) ); + // Output checkmark in explanations column if post has an explanation. + add_action( 'manage_posts_custom_column', array( $this, 'handle_column_data' ), 10, 2 ); + + add_filter( 'preview_post_link', array( $this, 'preview_post_link' ), 10, 2 ); + + // Permissions. + add_action( 'after_switch_theme', array( $this, 'add_roles' ) ); + add_filter( 'user_has_cap', array( $this, 'grant_caps' ) ); + add_filter( 'post_row_actions', array( $this, 'expl_row_action' ), 10, 2 ); + + // Script and styles. + add_filter( 'devhub-admin_enqueue_scripts', array( $this, 'admin_enqueue_base_scripts' ) ); + add_action( 'admin_enqueue_scripts', array( $this, 'admin_enqueue_scripts' ) ); + + // AJAX. + add_action( 'wp_ajax_new_explanation', array( $this, 'new_explanation' ) ); + add_action( 'wp_ajax_un_publish', array( $this, 'un_publish_explanation' ) ); + } + + /** + * Register the Explanations post type. + * + * @access public + */ + public function register_post_type() { + register_post_type( + $this->exp_post_type, + array( + 'labels' => array( + 'name' => __( 'Explanations', 'phpdoc-plugin' ), + 'singular_name' => __( 'Explanation', 'phpdoc-plugin' ), + 'all_items' => __( 'Explanations', 'phpdoc-plugin' ), + 'edit_item' => __( 'Edit Explanation', 'phpdoc-plugin' ), + 'view_item' => __( 'View Explanation', 'phpdoc-plugin' ), + 'search_items' => __( 'Search Explanations', 'phpdoc-plugin' ), + 'not_found' => __( 'No Explanations found', 'phpdoc-plugin' ), + 'not_found_in_trash' => __( 'No Explanations found in trash', 'phpdoc-plugin' ), + ), + 'public' => false, + 'publicly_queryable' => true, + 'hierarchical' => false, + 'show_ui' => true, + 'show_in_menu' => true, + 'menu_icon' => 'dashicons-info', + 'show_in_admin_bar' => false, + 'show_in_nav_menus' => false, + 'capability_type' => 'explanation', + 'map_meta_cap' => true, + 'supports' => array( 'editor', 'revisions' ), + 'rewrite' => false, + 'query_var' => false, + ) + ); + } + + /** + * Remove 'editor' support for the function, hook, class, and method post types. + * + * @access public + */ + public function remove_editor_support() { + foreach ( $this->post_types as $type ) { + remove_post_type_support( $type, 'editor' ); + } + } + + /** + * Override preview post links for explanations to preview the explanation + * within the context of its associated function/hook/method/class. + * + * The associated post's preview link is amended with query parameters used + * by `get_explanation_content()` to use the explanation being previewed + * instead of the published explanation currently associated with the post. + * + * @access public + * @see 'preview_post_link' filter + * + * @param string $preview_link URL used for the post preview. + * @param WP_Post $post Post object. + * @return string + **/ + public function preview_post_link( $preview_link, $post ) { + if ( $this->exp_post_type !== $post->post_type ) { + return $preview_link; + } + + if ( false !== strpos( $preview_link, 'preview_nonce=' ) ) { + $url = wp_parse_url( $preview_link ); + $url_query = array(); + parse_str( $url['query'], $url_query ); + + $preview_link = get_preview_post_link( + $post->post_parent, + array( + 'wporg_explanations_preview_id' => $url_query['preview_id'], + 'wporg_explanations_preview_nonce' => $url_query['preview_nonce'], + ) + ); + } + + return $preview_link; + } + + /** + * Customizes admin menu. + * + * - Removes "Add new". + * - Adds count of pending explanations. + * + * @access public + */ + public function admin_menu() { + global $menu; + + $menu_slug = 'edit.php?post_type=' . $this->exp_post_type; + + // Remove 'Add New' from submenu. + remove_submenu_page( $menu_slug, 'post-new.php?post_type=' . $this->exp_post_type ); + + // Add pending posts count. + $counts = wp_count_posts( $this->exp_post_type ); + $count = $counts->pending; + if ( $count ) { + // Find the explanations menu item. + foreach ( $menu as $i => $item ) { + if ( $menu_slug === $item[2] ) { + // Modify it to include the pending count. + $menu[ $i ][0] = sprintf( // phpcs:ignore + /* Translators: %s is the count. */ + __( 'Explanations %s', 'phpdoc-plugin' ), + "" . number_format_i18n( $count ) . '' + ); + break; + } + } + } + } + + /** + * Prevents direct access to the admin page for creating a new explanation. + * + * Only prevents admin UI access to directly create a new explanation. It does + * not attempt to prevent direct programmatic creation of a new explanation. + * + * @access public + */ + public function prevent_direct_creation() { + $post_type = filter_input( INPUT_GET, 'post_type', FILTER_SANITIZE_STRING ); + if ( $post_type && $post_type === $this->exp_post_type ) { + wp_safe_redirect( admin_url() ); + exit; + } + } + + /** + * Output the Post-to-Explanation controls in the post editor for functions, + * hooks, classes, and methods. + * + * @access public + * + * @param WP_Post $post Current post object. + */ + public function post_to_expl_controls( $post ) { + if ( ! in_array( $post->post_type, $this->post_types, true ) ) { + return; + } + + $explanation = get_explanation( $post ); + $date_format = get_option( 'date_format' ) . ', ' . get_option( 'time_format' ); + ?> +
| + + | +
+
+ status_controls( $post ); ?>
+
+ |
+
|---|---|
| + + | +
+ ID ) ); ?> + |
+
' . $label . '
'; + } + + /** + * Enables enqueuing of admin.css for explanation pages. + * + * @access public + * + * @param bool $do_enqueue Should admin.css be enqueued?. + * + * @return bool True if admin.css should be enqueued, false otherwise. + */ + public function admin_enqueue_base_scripts( $do_enqueue ) { + return $do_enqueue || in_array( get_current_screen()->id, $this->screen_ids, true ); + } + + /** + * Enqueue JS and CSS for all parsed post types and explanation pages. + * + * @access public + */ + public function admin_enqueue_scripts() { + + $parsed_post_types_screen_ids = Functions::get_parsed_post_types_screen_ids(); + + if ( in_array( + get_current_screen()->id, + array_merge( + $parsed_post_types_screen_ids, + $this->screen_ids + ), + true + ) ) { + wp_enqueue_script( 'wporg-explanations', Plugin::get_plugin_dir( '/assets/js/explanations.js' ), array( 'jquery', 'wp-util' ), '20160630', true ); + + wp_localize_script( + 'wporg-explanations', + 'phpdoc-plugin', + array( + 'editContentLabel' => __( 'Edit Explanation', 'phpdoc-plugin' ), + 'statusLabel' => array( + 'draft' => __( 'Draft', 'phpdoc-plugin' ), + 'pending' => __( 'Pending Review', 'phpdoc-plugin' ), + 'publish' => __( 'Published', 'phpdoc-plugin' ), + ), + ) + ); + } + } + + /** + * AJAX handler for creating and associating a new explanation. + * + * @access public + */ + public function new_explanation() { + check_ajax_referer( 'create-expl', 'nonce' ); + + $post_id = empty( $_REQUEST['post_id'] ) ? 0 : absint( $_REQUEST['post_id'] ); + $context = empty( $_REQUEST['context'] ) ? '' : sanitize_text_field( wp_unslash( $_REQUEST['context'] ) ); + + if ( DevHub\get_explanation( $post_id ) ) { + wp_send_json_error( new WP_Error( 'post_exists', __( 'Explanation already exists.', 'phpdoc-plugin' ) ) ); + } else { + $title = get_post_field( 'post_title', $post_id ); + + $explanation = wp_insert_post( + array( + 'post_type' => 'wporg_explanations', + 'post_title' => "Explanation: $title", + 'ping_status' => false, + 'post_parent' => $post_id, + ) + ); + + if ( ! is_wp_error( $explanation ) && 0 !== $explanation ) { + wp_send_json_success( + array( + 'post_id' => $explanation, + 'parent_id' => $post_id, + 'context' => $context, + ) + ); + } else { + wp_send_json_error( + new WP_Error( 'post_error', __( 'Explanation could not be created.', 'phpdoc-plugin' ) ) + ); + } + } + } + + /** + * AJAX handler for un-publishing an explanation. + * + * @access public + */ + public function un_publish_explanation() { + check_ajax_referer( 'unpublish-expl', 'nonce' ); + + $post_id = empty( $_REQUEST['post_id'] ) ? 0 : absint( $_REQUEST['post_id'] ); + + if ( $explanation = get_explanation( $post_id ) ) { // phpcs:ignore + $update = wp_update_post( + array( + 'ID' => $explanation->ID, + 'post_status' => 'draft', + ) + ); + + if ( ! is_wp_error( $update ) && 0 !== $update ) { + wp_send_json_success( array( 'post_id' => $update ) ); + } else { + wp_send_json_error( + new WP_Error( 'unpublish_error', __( 'Explanation could not be un-published.', 'phpdoc-plugin' ) ) + ); + } + } + } + + /** + * Adds a column in the admin listing of posts for parsed post types to + * indicate if they have an explanation. + * + * Inserted as first column after title column. + * + * @access public + * + * @param array $columns Associative array of post column ids and labels. + * @return array + */ + public function add_post_column( $columns ) { + if ( ! empty( $_GET['post_type'] ) && Functions::is_parsed_post_type( $_GET['post_type'] ) ) { // phpcs:ignore + $index = array_search( 'title', array_keys( $columns ), true ); + $pos = false === $index ? count( $columns ) : $index + 1; + + $col_data = array( + 'has_explanation' => sprintf( + '%s', + esc_attr__( 'Has explanation?', 'phpdoc-plugin' ), + esc_html__( 'Explanation?', 'phpdoc-plugin' ) + ), + ); + $columns = array_merge( array_slice( $columns, 0, $pos ), $col_data, array_slice( $columns, $pos ) ); + } + + return $columns; + } + + /** + * Outputs an indicator for the explanations column if post has an explanation. + * + * @access public + * + * @param string $column_name The name of the column. + * @param int $post_id The ID of the post. + */ + public function handle_column_data( $column_name, $post_id ) { + if ( 'has_explanation' === $column_name ) { + if ( $explanation = get_explanation( $post_id ) ) { // phpcs:ignore + printf( + '%s%s', + esc_url( get_edit_post_link( $explanation ) ), + '', + '' . esc_html__( 'Post has an explanation.', 'phpdoc-plugin' ) . '' + ); + } + } + } +} diff --git a/php/Functions.php b/php/Functions.php new file mode 100644 index 0000000..989266f --- /dev/null +++ b/php/Functions.php @@ -0,0 +1,82 @@ + 'wporg_explanations', + 'post_parent' => $post->ID, + 'no_found_rows' => true, + 'posts_per_page' => 1, + ); + + if ( true === $published ) { + $args['post_status'] = 'publish'; + } + + $explanation = get_children( $args, OBJECT ); + + if ( empty( $explanation ) ) { + return null; + } + + $explanation = reset( $explanation ); + + if ( ! $explanation ) { + return null; + } + return $explanation; +} diff --git a/php/Plugin.php b/php/Plugin.php index 7858f53..f6e9105 100644 --- a/php/Plugin.php +++ b/php/Plugin.php @@ -40,7 +40,43 @@ public function __construct() { * @see WP init action. */ public function init() { - // todo - init actions here. + // Create post types. + PostTypes::create(); + + // Add taxonomies. + Taxonomies::create(); + + // Init Posts to Posts. + PostsToPosts::register_post_relationships(); + } + + /** + * Actions to run when all plugins have been loaded. + * + * @see WP plugins_loaded action. + */ + public function plugins_loaded() { + new Explanations(); + } + + /** + * After a theme's functions.php file has been run. + * + * @see WP after_setup_theme action. + */ + public function after_setup_theme() { + // Remove post types registered by theme. + global $explanations; + remove_action( 'init', array( 'DevHub_CLI', 'action_init_register_post_types' ) ); + remove_action( 'init', array( 'DevHub_Registrations', 'do_init' ), 10 ); + remove_action( 'init', array( $explanations, 'register_post_type' ), 0 ); + } + + /** + * Run when the plugin is activated. + */ + public static function register_activation_hook() { + RewriteRules::flush(); } /** diff --git a/php/PostTypes.php b/php/PostTypes.php new file mode 100644 index 0000000..1f10473 --- /dev/null +++ b/php/PostTypes.php @@ -0,0 +1,184 @@ + 'reference/functions', + 'label' => __( 'Functions', 'phpdoc-plugin' ), + 'labels' => array( + 'name' => __( 'Functions', 'phpdoc-plugin' ), + 'singular_name' => __( 'Function', 'phpdoc-plugin' ), + 'all_items' => __( 'Functions', 'phpdoc-plugin' ), + 'new_item' => __( 'New Function', 'phpdoc-plugin' ), + 'add_new' => __( 'Add New', 'phpdoc-plugin' ), + 'add_new_item' => __( 'Add New Function', 'phpdoc-plugin' ), + 'edit_item' => __( 'Edit Function', 'phpdoc-plugin' ), + 'view_item' => __( 'View Function', 'phpdoc-plugin' ), + 'search_items' => __( 'Search Functions', 'phpdoc-plugin' ), + 'not_found' => __( 'No Functions found', 'phpdoc-plugin' ), + 'not_found_in_trash' => __( 'No Functions found in trash', 'phpdoc-plugin' ), + 'parent_item_colon' => __( 'Parent Function', 'phpdoc-plugin' ), + 'menu_name' => __( 'Functions', 'phpdoc-plugin' ), + ), + 'menu_icon' => 'dashicons-editor-code', + 'public' => true, + 'rewrite' => array( + 'feeds' => false, + 'slug' => 'reference/functions', + 'with_front' => false, + ), + 'supports' => $supports, + 'show_in_rest' => true, + ) + ); + } + + if ( ! post_type_exists( 'wp-parser-class' ) ) { + register_post_type( + 'wp-parser-class', + array( + 'has_archive' => 'reference/classes', + 'label' => __( 'Classes', 'phpdoc-plugin' ), + 'labels' => array( + 'name' => __( 'Classes', 'phpdoc-plugin' ), + 'singular_name' => __( 'Class', 'phpdoc-plugin' ), + 'all_items' => __( 'Classes', 'phpdoc-plugin' ), + 'new_item' => __( 'New Class', 'phpdoc-plugin' ), + 'add_new' => __( 'Add New', 'phpdoc-plugin' ), + 'add_new_item' => __( 'Add New Class', 'phpdoc-plugin' ), + 'edit_item' => __( 'Edit Class', 'phpdoc-plugin' ), + 'view_item' => __( 'View Class', 'phpdoc-plugin' ), + 'search_items' => __( 'Search Classes', 'phpdoc-plugin' ), + 'not_found' => __( 'No Classes found', 'phpdoc-plugin' ), + 'not_found_in_trash' => __( 'No Classes found in trash', 'phpdoc-plugin' ), + 'parent_item_colon' => __( 'Parent Class', 'phpdoc-plugin' ), + 'menu_name' => __( 'Classes', 'phpdoc-plugin' ), + ), + 'menu_icon' => 'dashicons-editor-code', + 'public' => true, + 'rewrite' => array( + 'feeds' => false, + 'slug' => 'reference/classes', + 'with_front' => false, + ), + 'supports' => $supports, + 'show_in_rest' => true, + ) + ); + } + + if ( ! post_type_exists( 'wp-parser-hook' ) ) { + register_post_type( + 'wp-parser-hook', + array( + 'has_archive' => 'reference/hooks', + 'label' => __( 'Hooks', 'phpdoc-plugin' ), + 'labels' => array( + 'name' => __( 'Hooks', 'phpdoc-plugin' ), + 'singular_name' => __( 'Hook', 'phpdoc-plugin' ), + 'all_items' => __( 'Hooks', 'phpdoc-plugin' ), + 'new_item' => __( 'New Hook', 'phpdoc-plugin' ), + 'add_new' => __( 'Add New', 'phpdoc-plugin' ), + 'add_new_item' => __( 'Add New Hook', 'phpdoc-plugin' ), + 'edit_item' => __( 'Edit Hook', 'phpdoc-plugin' ), + 'view_item' => __( 'View Hook', 'phpdoc-plugin' ), + 'search_items' => __( 'Search Hooks', 'phpdoc-plugin' ), + 'not_found' => __( 'No Hooks found', 'phpdoc-plugin' ), + 'not_found_in_trash' => __( 'No Hooks found in trash', 'phpdoc-plugin' ), + 'parent_item_colon' => __( 'Parent Hook', 'phpdoc-plugin' ), + 'menu_name' => __( 'Hooks', 'phpdoc-plugin' ), + ), + 'menu_icon' => 'dashicons-editor-code', + 'public' => true, + 'rewrite' => array( + 'feeds' => false, + 'slug' => 'reference/hooks', + 'with_front' => false, + ), + 'supports' => $supports, + 'show_in_rest' => true, + ) + ); + } + + if ( ! post_type_exists( 'wp-parser-method' ) ) { + register_post_type( + 'wp-parser-method', + array( + 'has_archive' => 'reference/methods', + 'label' => __( 'Methods', 'phpdoc-plugin' ), + 'labels' => array( + 'name' => __( 'Methods', 'phpdoc-plugin' ), + 'singular_name' => __( 'Method', 'phpdoc-plugin' ), + 'all_items' => __( 'Methods', 'phpdoc-plugin' ), + 'new_item' => __( 'New Method', 'phpdoc-plugin' ), + 'add_new' => __( 'Add New', 'phpdoc-plugin' ), + 'add_new_item' => __( 'Add New Method', 'phpdoc-plugin' ), + 'edit_item' => __( 'Edit Method', 'phpdoc-plugin' ), + 'view_item' => __( 'View Method', 'phpdoc-plugin' ), + 'search_items' => __( 'Search Methods', 'phpdoc-plugin' ), + 'not_found' => __( 'No Methods found', 'phpdoc-plugin' ), + 'not_found_in_trash' => __( 'No Methods found in trash', 'phpdoc-plugin' ), + 'parent_item_colon' => __( 'Parent Method', 'phpdoc-plugin' ), + 'menu_name' => __( 'Methods', 'phpdoc-plugin' ), + ), + 'menu_icon' => 'dashicons-editor-code', + 'public' => true, + 'rewrite' => array( + 'feeds' => false, + 'slug' => 'classes', + 'with_front' => false, + ), + 'supports' => $supports, + 'show_in_rest' => true, + ) + ); + } + } + + /** + * Return registered post types for plugin. + * + * @param bool $labels Whether to return just post type keys or also labels. + */ + public static function get_parsed_post_types( bool $labels = true ) { + $post_types = array( + 'wp-parser-class' => __( 'Classes', 'phpdoc-plugin' ), + 'wp-parser-function' => __( 'Functions', 'phpdoc-plugin' ), + 'wp-parser-hook' => __( 'Hooks', 'phpdoc-plugin' ), + 'wp-parser-method' => __( 'Methods', 'phpdoc-plugin' ), + ); + + if ( ! $labels ) { + return array_keys( $post_types ); + } + + return $post_types; + } +} diff --git a/php/PostsToPosts.php b/php/PostsToPosts.php new file mode 100644 index 0000000..7467ebd --- /dev/null +++ b/php/PostsToPosts.php @@ -0,0 +1,168 @@ + 'functions_to_functions', + 'from' => 'wp-parser-function', + 'to' => 'wp-parser-function', + 'can_create_post' => false, + 'self_connections' => true, + 'from_query_vars' => array( + 'orderby' => 'post_title', + 'order' => 'ASC', + ), + 'to_query_vars' => array( + 'orderby' => 'post_title', + 'order' => 'ASC', + ), + 'title' => array( + 'from' => __( 'Uses Functions', 'phpdoc-plugin' ), + 'to' => __( 'Used by Functions', 'phpdoc-plugin' ), + ), + ) + ); + + p2p_register_connection_type( + array( + 'name' => 'functions_to_methods', + 'from' => 'wp-parser-function', + 'to' => 'wp-parser-method', + 'can_create_post' => false, + 'from_query_vars' => array( + 'orderby' => 'post_title', + 'order' => 'ASC', + ), + 'to_query_vars' => array( + 'orderby' => 'post_title', + 'order' => 'ASC', + ), + 'title' => array( + 'from' => __( 'Uses Methods', 'phpdoc-plugin' ), + 'to' => __( 'Used by Functions', 'phpdoc-plugin' ), + ), + ) + ); + + p2p_register_connection_type( + array( + 'name' => 'functions_to_hooks', + 'from' => 'wp-parser-function', + 'to' => 'wp-parser-hook', + 'can_create_post' => false, + 'from_query_vars' => array( + 'orderby' => 'post_title', + 'order' => 'ASC', + ), + 'to_query_vars' => array( + 'orderby' => 'post_title', + 'order' => 'ASC', + ), + 'title' => array( + 'from' => __( 'Uses Hooks', 'phpdoc-plugin' ), + 'to' => __( 'Used by Functions', 'phpdoc-plugin' ), + ), + ) + ); + + /* + * Methods to functions, methods and hooks + */ + p2p_register_connection_type( + array( + 'name' => 'methods_to_functions', + 'from' => 'wp-parser-method', + 'to' => 'wp-parser-function', + 'can_create_post' => false, + 'from_query_vars' => array( + 'orderby' => 'post_title', + 'order' => 'ASC', + ), + 'to_query_vars' => array( + 'orderby' => 'post_title', + 'order' => 'ASC', + ), + 'title' => array( + 'from' => __( 'Uses Functions', 'phpdoc-plugin' ), + 'to' => __( 'Used by Methods', 'phpdoc-plugin' ), + ), + ) + ); + + p2p_register_connection_type( + array( + 'name' => 'methods_to_methods', + 'from' => 'wp-parser-method', + 'to' => 'wp-parser-method', + 'can_create_post' => false, + 'self_connections' => true, + 'from_query_vars' => array( + 'orderby' => 'post_title', + 'order' => 'ASC', + ), + 'to_query_vars' => array( + 'orderby' => 'post_title', + 'order' => 'ASC', + ), + 'title' => array( + 'from' => __( 'Uses Methods', 'phpdoc-plugin' ), + 'to' => __( 'Used by Methods', 'phpdoc-plugin' ), + ), + ) + ); + + p2p_register_connection_type( + array( + 'name' => 'methods_to_hooks', + 'from' => 'wp-parser-method', + 'to' => 'wp-parser-hook', + 'can_create_post' => false, + 'from_query_vars' => array( + 'orderby' => 'post_title', + 'order' => 'ASC', + ), + 'to_query_vars' => array( + 'orderby' => 'post_title', + 'order' => 'ASC', + ), + 'title' => array( + 'from' => __( 'Used by Methods', 'phpdoc-plugin' ), + 'to' => __( 'Uses Hooks', 'phpdoc-plugin' ), + ), + ) + ); + } +} diff --git a/php/RewriteRules.php b/php/RewriteRules.php new file mode 100644 index 0000000..5c11ace --- /dev/null +++ b/php/RewriteRules.php @@ -0,0 +1,29 @@ + __( 'Files', 'phpdoc-plugin' ), + 'labels' => array( + 'name' => __( 'Files', 'phpdoc-plugin' ), + 'singular_name' => _x( 'File', 'taxonomy general name', 'phpdoc-plugin' ), + 'search_items' => __( 'Search Files', 'phpdoc-plugin' ), + 'popular_items' => null, + 'all_items' => __( 'All Files', 'phpdoc-plugin' ), + 'parent_item' => __( 'Parent File', 'phpdoc-plugin' ), + 'parent_item_colon' => __( 'Parent File:', 'phpdoc-plugin' ), + 'edit_item' => __( 'Edit File', 'phpdoc-plugin' ), + 'update_item' => __( 'Update File', 'phpdoc-plugin' ), + 'add_new_item' => __( 'New File', 'phpdoc-plugin' ), + 'new_item_name' => __( 'New File', 'phpdoc-plugin' ), + 'separate_items_with_commas' => __( 'Files separated by comma', 'phpdoc-plugin' ), + 'add_or_remove_items' => __( 'Add or remove Files', 'phpdoc-plugin' ), + 'choose_from_most_used' => __( 'Choose from the most used Files', 'phpdoc-plugin' ), + 'menu_name' => __( 'Files', 'phpdoc-plugin' ), + ), + 'public' => true, + // Hierarchical x 2 to enable (.+) rather than ([^/]+) for rewrites. + 'hierarchical' => true, + 'rewrite' => array( + 'with_front' => false, + 'slug' => 'reference/files', + 'hierarchical' => true, + ), + 'sort' => false, + 'update_count_callback' => '_update_post_term_count', + 'show_in_rest' => true, + ) + ); + + register_taxonomy( + 'wp-parser-package', + PostTypes::get_parsed_post_types( false ), + array( + 'hierarchical' => true, + 'label' => '@package', + 'public' => true, + 'rewrite' => array( + 'with_front' => false, + 'slug' => 'reference/package', + ), + 'sort' => false, + 'update_count_callback' => '_update_post_term_count', + 'show_in_rest' => true, + ) + ); + + // @since + register_taxonomy( + 'wp-parser-since', + PostTypes::get_parsed_post_types( false ), + array( + 'hierarchical' => true, + 'label' => __( '@since', 'phpdoc-plugin' ), + 'public' => true, + 'rewrite' => array( + 'with_front' => false, + 'slug' => 'reference/since', + ), + 'sort' => false, + 'update_count_callback' => '_update_post_term_count', + 'show_in_rest' => true, + ) + ); + + } +}