Making WordPress.org

Changeset 13729


Ignore:
Timestamp:
05/17/2024 06:14:37 AM (11 months ago)
Author:
dd32
Message:

Plugin Directory: Allow plugin slugs to be renamed during the approval stage.

This allows plugin reviewers to change the slug immediately after the plugin is approved, but before the author commits any code.

Fixes #6878.

Location:
sites/trunk/wordpress.org/public_html/wp-content/plugins/plugin-directory
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • sites/trunk/wordpress.org/public_html/wp-content/plugins/plugin-directory/admin/class-customizations.php

    r13522 r13729  
    44use \WordPressdotorg\Plugin_Directory;
    55use \WordPressdotorg\Plugin_Directory\Tools;
     6use \WordPressdotorg\Plugin_Directory\Tools\SVN;
    67use \WordPressdotorg\Plugin_Directory\Template;
    78use \WordPressdotorg\Plugin_Directory\Readme\Validator;
     
    562563     */
    563564    function check_existing_plugin_slug_on_post_update( $data, $postarr ) {
     565        global $wpdb;
     566
    564567        if ( 'plugin' !== $data['post_type'] || ! isset( $postarr['ID'] ) ) {
    565568            return $data;
    566569        }
    567570
    568         $existing_plugin = Plugin_Directory\Plugin_Directory::get_plugin_post( $data['post_name'] );
     571        // If we can't locate the existing plugin, we can't check for a conflict.
     572        $plugin = get_post( $postarr['ID'] );
     573        if ( ! $plugin ) {
     574            return $data;
     575        }
     576
     577        $old_slug        = $plugin->post_name;
     578        $new_slug        = $data['post_name'];
     579        $existing_plugin = Plugin_Directory\Plugin_Directory::get_plugin_post( $new_slug );
    569580
    570581        // Is there already a plugin with the same slug?
    571         if ( $existing_plugin && $existing_plugin->ID != $postarr['ID'] ) {
     582        if ( $existing_plugin && $existing_plugin->ID != $plugin->ID ) {
    572583            wp_die( sprintf(
    573584                /* translators: %s: plugin slug */
    574585                __( 'Error: The plugin %s already exists.', 'wporg-plugins' ),
    575                 $data['post_name']
     586                $new_slug
    576587            ) );
    577588        }
    578589
     590        // If the plugin is approved, we'll need to perform a folder rename, and re-grant SVN access.
     591        if ( 'approved' === $plugin->post_status ) {
     592            // SVN Rename $old_slug to $new_slug
     593            $result = SVN::rename(
     594                "http://plugins.svn.wordpress.org/{$old_slug}/",
     595                "http://plugins.svn.wordpress.org/{$new_slug}/",
     596                array(
     597                    'message' => sprintf( 'Renaming %1$s to %2$s.', $old_slug, $new_slug ),
     598                )
     599            );
     600            if ( $result['errors'] ) {
     601                $error = 'Error renaming SVN repository: ' . var_export( $result['errors'], true );
     602                Tools::audit_log( $error, $plugin->ID );
     603                wp_die( $error ); // Abort before the post is altered.
     604            } else {
     605                Tools::audit_log(
     606                    sprintf(
     607                        'Renamed SVN repository in %s.',
     608                        'https://plugins.svn.wordpress.org/changeset/' . $result['revision']
     609                    ),
     610                    $plugin->ID
     611                );
     612
     613                /*
     614                 * Migrate Committers to new path.
     615                 * As no committers have changed as part of this operation, just update the database.
     616                 */
     617                $wpdb->update(
     618                    PLUGINS_TABLE_PREFIX . 'svn_access',
     619                    [ 'path' => '/' . $new_slug ],
     620                    [ 'path' => '/' . $old_slug ]
     621                );
     622            }
     623        }
     624
    579625        // Record the slug change.
    580         $plugin = get_post( $postarr['ID'] );
    581         if ( $plugin && $plugin->post_name !== $data['post_name'] ) {
     626        if ( $old_slug !== $new_slug ) {
    582627            // Only log if the slugs don't appear to be rejection-related.
    583628            if (
    584                 ! preg_match( '!^rejected-.+-rejected$!', $post->post_name ) &&
    585                 ! preg_match( '!^rejected-.+-rejected$!', $data['post_name'] )
     629                ! preg_match( '!^rejected-.+-rejected$!', $old_slug ) &&
     630                ! preg_match( '!^rejected-.+-rejected$!', $new_slug )
    586631            ) {
    587632                Tools::audit_log( sprintf(
    588633                    "Slug changed from '%s' to '%s'.",
    589                     $plugin->post_name,
    590                     $data['post_name']
     634                    $old_slug,
     635                    $new_slug
    591636                ), $plugin->ID );
    592637            }
     
    736781        remove_meta_box( 'commentstatusdiv', 'plugin', 'normal' );
    737782
    738         // Remove slug metabox unless the slug is editable for the current user.
    739         if ( ! in_array( $post->post_status, array( 'new', 'pending' ) ) || ! current_user_can( 'plugin_approve', $post ) ) {
     783        // Remove slug metabox unless the slug is editable by the current user.
     784        if ( ! in_array( $post->post_status, array( 'new', 'pending', 'approved' ) ) || ! current_user_can( 'plugin_approve', $post ) ) {
    740785            remove_meta_box( 'slugdiv', 'plugin', 'normal' );
    741786        }
  • sites/trunk/wordpress.org/public_html/wp-content/plugins/plugin-directory/tools/class-svn.php

    r13709 r13729  
    430430
    431431    /**
     432     * Rename a SVN path (or url).
     433     *
     434     * @static
     435     *
     436     * @param string $from    The path of the SVN folder to rename. May be a URL.
     437     * @param string $to      The new path of the SVN folder. May be a URL.
     438     * @param array  $options  Optional. A list of options to pass to SVN. Default: empty array.
     439     * @return array {
     440     *     @type bool        $result   The result of the operation.
     441     *     @type int         $revision The revision.
     442     *     @type false|array $errors   Whether any errors or warnings were encountered.
     443     * }
     444     */
     445    public static function rename( $from, $to, $options = array() ) {
     446        $options[] = 'non-interactive';
     447        $is_url    = ( preg_match( '#https?://#i', $from ) && preg_match( '#https?://#i', $to ) );
     448
     449        if ( $is_url ) {
     450            // Set the message if not provided.
     451            if ( ! isset( $options['message'] ) && ! isset( $options['m'] ) ) {
     452                $options['message'] = sprintf( "Rename %s to %s.", basename( $from ), basename( $to ) );
     453            }
     454
     455            if ( empty( $options['username'] ) ) {
     456                $options['username'] = PLUGIN_SVN_MANAGEMENT_USER;
     457                $options['password'] = PLUGIN_SVN_MANAGEMENT_PASS;
     458            }
     459        }
     460
     461        $esc_options = self::parse_esc_parameters( $options );
     462
     463        $esc_from = escapeshellarg( $from );
     464        $esc_to   = escapeshellarg( $to );
     465
     466        $output = self::shell_exec( "svn mv $esc_from $esc_to $esc_options 2>&1" );
     467        if ( $is_url && preg_match( '/Committed revision (?P<revision>\d+)[.]/i', $output, $m ) ) {
     468            $revision = (int) $m['revision'];
     469            $result   = true;
     470            $errors   = false;
     471        } else {
     472            $errors   = self::parse_svn_errors( $output );
     473            $revision = false;
     474
     475            if ( $is_url || $errors ) {
     476                $result = false;
     477            } else {
     478                $result = true;
     479            }
     480        }
     481
     482        return compact( 'result', 'revision', 'errors' );
     483    }
     484
     485    /**
    432486     * Parse and escape the provided SVN arguements for usage on the CLI.
    433487     *
Note: See TracChangeset for help on using the changeset viewer.