Changeset 13335
- Timestamp:
- 03/14/2024 05:40:44 AM (11 months ago)
- Location:
- sites/trunk/wordpress.org/public_html/wp-content
- Files:
-
- 5 edited
Legend:
- Unmodified
- Added
- Removed
-
sites/trunk/wordpress.org/public_html/wp-content/plugins/plugin-directory/api/routes/class-plugin-blueprint.php
r13189 r13335 40 40 $this->reviewer_blueprint( $request, $plugin ); 41 41 } 42 if ( $request->get_param('url_hash') ) { 43 $this->developer_blueprint( $request, $plugin ); 44 } 42 45 43 46 $blueprints = get_post_meta( $plugin->ID, 'assets_blueprints', true ); … … 76 79 if ( $request->get_param('zip_hash') ) { 77 80 foreach ( get_attached_media( 'application/zip', $plugin ) as $zip_file ) { 78 if ( hash_equals( Template::preview_link_hash( $zip_file->ID, 0 ), $request->get_param('zip_hash') ) || 79 hash_equals( Template::preview_link_hash( $zip_file->ID, -1 ), $request->get_param('zip_hash') ) ) { 81 $zip_file_path = get_attached_file( $zip_file->ID ); 82 if ( hash_equals( Template::preview_link_hash( $zip_file_path, 0 ), $request->get_param('zip_hash') ) || 83 hash_equals( Template::preview_link_hash( $zip_file_path, -1 ), $request->get_param('zip_hash') ) ) { 80 84 $zip_url = wp_get_attachment_url( $zip_file->ID ); 81 85 if ( $zip_url ) { 82 83 $landing_page = '/wp-admin/plugins.php'; 84 $activate_plugin = true; 85 $dependencies = $plugin->requires_plugins ?: []; 86 87 if ( stripos( $plugin->post_title, 'woocommerce' ) ) { 88 $dependencies[] = 'woocommerce'; 89 } 90 if ( stripos( $plugin->post_title, 'buddypress' ) ) { 91 $dependencies[] = 'buddypress'; 92 } 93 94 $dependencies = array_diff( $dependencies, [ $plugin->post_name ] ); 95 96 // Plugin deactivated, and land on the Plugin Check page 97 if ( 'pcp' === $request->get_param('type') ) { 98 $landing_page = '/wp-admin/admin.php?page=plugin-check&plugin=' . sanitize_title( $request['plugin_slug'] ); 99 $activate_plugin = false; 100 $dependencies = []; 101 } 102 103 $zip_blueprint = (object)[ 104 'landingPage' => $landing_page, 105 'preferredVersions' => (object)[ 106 'php' => '8.0', 107 'wp' => 'latest', 108 ], 109 'phpExtensionBundles' => [ 110 'kitchen-sink' 111 ], 112 'features' => (object)[ 113 'networking' => true 114 ], 115 'steps' => [ 116 (object)[ 117 'step' => 'installPlugin', 118 'pluginZipFile' => (object)[ 119 'resource' => 'wordpress.org/plugins', 120 'slug' => 'plugin-check', 121 ] 122 ], 123 (object)[ 124 'step' => 'installPlugin', 125 'pluginZipFile' => (object)[ 126 'resource' => 'url', 127 'url' => $zip_url, 128 ], 129 'options' => (object)[ 130 'activate' => (bool)$activate_plugin 131 ] 132 ], 133 (object)[ 134 'step' => 'login', 135 'username' => 'admin', 136 'password' => 'password', 137 ] 138 ] 139 ]; 140 141 if ( $dependencies ) { 142 $dep_step = []; 143 foreach ( $dependencies as $slug ) { 144 $dep_step[] = (object)[ 145 'step' => 'installPlugin', 146 'pluginZipFile' => [ 147 'resource' => 'wordpress.org/plugins', 148 'slug' => sanitize_title( $slug ), 149 ], 150 'options' => (object)[ 151 'activate' => true 152 ] 153 ]; 154 } 155 // Insert dependencies aftter PCP 156 array_splice( $zip_blueprint->steps, 1, 0, $dep_step ); 157 } 158 159 // Include the helper plugin too 160 $helper_zip = self::get_zip_url_by_slug( 'playground-review-helper' ); 161 if ( $helper_zip && 'pcp' !== $request->get_param('type') ) { 162 $helper_step = [ 163 (object)[ 164 'step' => 'installPlugin', 165 'pluginZipFile' => [ 166 'resource' => 'url', 167 'url' => $helper_zip, 168 ], 169 'options' => (object)[ 170 'activate' => (bool)$activate_plugin 171 ] 172 ] 173 ]; 174 array_splice( $zip_blueprint->steps, 1, 0, $helper_step ); 175 } 176 177 $output = json_encode( $zip_blueprint ); 86 $is_pcp = 'pcp' === $request->get_param('type'); 87 $output = $this->generate_blueprint( $request, $plugin, $zip_url, $is_pcp, true ); 178 88 179 89 if ( $output ) { … … 187 97 188 98 return new \WP_Error( 'invalid_blueprint', 'Invalid file', array( 'status' => 500 ) ); 189 99 } 100 101 function developer_blueprint( $request, $plugin ) { 102 // Generated blueprint for developers who haven't yet created a custom blueprint 103 if ( $request->get_param('url_hash') ) { 104 $download_link = Template::download_link( $plugin ); 105 if ( $download_link ) { 106 if ( hash_equals( Template::preview_link_hash( $download_link, 0 ), $request->get_param('url_hash') ) || 107 hash_equals( Template::preview_link_hash( $download_link, -1 ), $request->get_param('url_hash') ) ) { 108 $output = $this->generate_blueprint( $request, $plugin, $download_link, false, false ); 109 110 if ( $output ) { 111 header( 'Access-Control-Allow-Origin: https://playground.wordpress.net' ); 112 die( $output ); 113 } 114 } 115 } 116 } 117 } 118 119 public function generate_blueprint( $request, $plugin, $zip_url, $install_pcp = true, $install_prh = true ) { 120 $landing_page = '/wp-admin/plugins.php'; 121 $activate_plugin = true; 122 $dependencies = $plugin->requires_plugins ?: []; 123 124 if ( stripos( $plugin->post_title, 'woocommerce' ) ) { 125 $dependencies[] = 'woocommerce'; 126 } 127 if ( stripos( $plugin->post_title, 'buddypress' ) ) { 128 $dependencies[] = 'buddypress'; 129 } 130 131 $dependencies = array_diff( $dependencies, [ $plugin->post_name ] ); 132 133 // Plugin deactivated, and land on the Plugin Check page 134 if ( $install_pcp ) { 135 $landing_page = '/wp-admin/admin.php?page=plugin-check&plugin=' . sanitize_title( $request['plugin_slug'] ); 136 $activate_plugin = false; 137 $dependencies = []; 138 } 139 140 $zip_blueprint = (object)[ 141 'landingPage' => $landing_page, 142 'preferredVersions' => (object)[ 143 'php' => '8.0', 144 'wp' => 'latest', 145 ], 146 'phpExtensionBundles' => [ 147 'kitchen-sink' 148 ], 149 'features' => (object)[ 150 'networking' => true 151 ], 152 ]; 153 154 $steps = []; 155 156 // PCP first, if needed. 157 if ( $install_pcp ) { 158 $steps[] = (object)[ 159 'step' => 'installPlugin', 160 'pluginZipFile' => (object)[ 161 'resource' => 'wordpress.org/plugins', 162 'slug' => 'plugin-check', 163 ] 164 ]; 165 } 166 167 // Include the helper plugin too 168 $helper_zip = self::get_zip_url_by_slug( 'playground-review-helper' ); 169 if ( $helper_zip && $install_prh ) { 170 $steps[] = (object)[ 171 'step' => 'installPlugin', 172 'pluginZipFile' => [ 173 'resource' => 'url', 174 'url' => $helper_zip, 175 ], 176 'options' => (object)[ 177 'activate' => (bool)$activate_plugin 178 ] 179 ]; 180 } 181 182 // Dependencies next 183 if ( $dependencies ) { 184 foreach ( $dependencies as $slug ) { 185 $steps[] = (object)[ 186 'step' => 'installPlugin', 187 'pluginZipFile' => [ 188 'resource' => 'wordpress.org/plugins', 189 'slug' => sanitize_title( $slug ), 190 ], 191 'options' => (object)[ 192 'activate' => true 193 ] 194 ]; 195 } 196 } 197 198 // Now the plugin itself 199 $steps[] = (object)[ 200 'step' => 'installPlugin', 201 'pluginZipFile' => (object)[ 202 'resource' => 'url', 203 'url' => $zip_url, 204 ], 205 'options' => (object)[ 206 'activate' => (bool)$activate_plugin 207 ] 208 ]; 209 210 // Finally log in 211 $steps[] = (object)[ 212 'step' => 'login', 213 'username' => 'admin', 214 'password' => 'password', 215 ]; 216 217 $zip_blueprint->steps = $steps; 218 219 $output = json_encode( $zip_blueprint, JSON_PRETTY_PRINT ); 220 221 return $output; 190 222 } 191 223 -
sites/trunk/wordpress.org/public_html/wp-content/plugins/plugin-directory/api/routes/class-plugin-self-toggle-preview.php
r13037 r13335 64 64 header( 'Location: ' . $result['location'] ); 65 65 66 if ( $request->get_param('dismiss') ) { 67 return $this->self_dismiss( $request, $plugin ); 68 } 69 66 70 // Toggle the postmeta value. Note that there is a race condition here. 67 71 $did = ''; … … 83 87 } 84 88 89 /** 90 * Endpoint special case to dismiss the missing blueprint notice. 91 * 92 * @param \WP_REST_Request $request The Rest API Request. 93 * @param object $plugin The plugin post. 94 * @return bool True if the toggle was successful. 95 */ 96 public function self_dismiss( $request, $plugin ) { 97 $result = [ 98 'location' => wp_get_referer() ?: get_permalink( $plugin ), 99 ]; 100 101 // Change the value from 1 to 0. This will persist and prevent it from being added again. 102 update_post_meta( $plugin->ID, '_missing_blueprint_notice', 0, 1 ); 103 104 return $result; 105 } 85 106 } -
sites/trunk/wordpress.org/public_html/wp-content/plugins/plugin-directory/class-template.php
r13310 r13335 774 774 public static function preview_link_zip( $slug, $attachment_id, $type = null ) { 775 775 776 $zip_hash = self::preview_link_hash( $attachment_id ); 776 $file = get_attached_file( $attachment_id ); 777 $zip_hash = self::preview_link_hash( $file ); 777 778 if ( !$zip_hash ) { 778 779 return false; … … 788 789 789 790 /** 791 * Generate a live preview (playground) link for a published plugin that does not yet have a custom blueprint. Needed for developer testing. 792 * 793 * @param string $slug The slug of the plugin post. 794 * @param int $download_link The URL of the zip download for the plugin. 795 * @param bool $blueprint_only False will return a full preview URL. True will return only a blueprint URL. 796 * @return false|string The preview or blueprint URL. 797 */ 798 public static function preview_link_developer( $slug, $download_link, $blueprint_only = false ) { 799 800 $url_hash = self::preview_link_hash( $download_link ); 801 if ( !$url_hash ) { 802 return false; 803 } 804 $dev_blueprint = sprintf( 'https://wordpress.org/plugins/wp-json/plugins/v1/plugin/%s/blueprint.json?url_hash=%s', esc_attr( $slug ), esc_attr( $url_hash ) ); 805 if ( $blueprint_only ) { 806 return $dev_blueprint; 807 } 808 $url_preview = add_query_arg( 'blueprint-url', urlencode($dev_blueprint), 'https://playground.wordpress.net/' ); 809 810 return $url_preview; 811 } 812 813 /** 790 814 * Return a time-dependent variable for zip preview links. 791 815 * … … 800 824 * Return a nonce-style hash for zip preview links. 801 825 * 802 * @param int $attachment_id The ID of the attachment post corresponding to a pluginzip file.826 * @param string $zip_file The filesystem path or URL of the zip file. 803 827 * @param int $tick_offest Number to subtract from the nonce tick. Use both 0 and -1 to verify older nonces. 804 828 * @return false|string The hash as a hex string; or false if the attachment ID is invalid. 805 829 */ 806 public static function preview_link_hash( $attachment_id, $tick_offset = 0 ) { 807 $file = get_attached_file( $attachment_id ); 808 if ( !$file ) { 830 public static function preview_link_hash( $zip_file, $tick_offset = 0 ) { 831 if ( !$zip_file ) { 809 832 return false; 810 833 } 811 834 $tick = self::preview_link_tick() - $tick_offset; 812 return wp_hash( $tick . '|' . $ file, 'nonce' );835 return wp_hash( $tick . '|' . $zip_file, 'nonce' ); 813 836 } 814 837 … … 912 935 return add_query_arg( 913 936 array( '_wpnonce' => wp_create_nonce( 'wp_rest' ) ), 937 home_url( 'wp-json/plugins/v1/plugin/' . $post->post_name . '/self-toggle-preview' ) 938 ); 939 } 940 941 /** 942 * Generates a link to dismiss a missing blueprint notice. 943 * 944 * @param int|\WP_Post|null $post Optional. Post ID or post object. Defaults to global $post. 945 * @return string URL to toggle status. 946 */ 947 public static function get_self_dismiss_blueprint_notice_link( $post = null ) { 948 $post = get_post( $post ); 949 950 return add_query_arg( 951 array( '_wpnonce' => wp_create_nonce( 'wp_rest' ), 'dismiss' => 1 ), 914 952 home_url( 'wp-json/plugins/v1/plugin/' . $post->post_name . '/self-toggle-preview' ) 915 953 ); -
sites/trunk/wordpress.org/public_html/wp-content/plugins/plugin-directory/cli/class-import.php
r13234 r13335 391 391 } else { 392 392 delete_post_meta( $plugin->ID, 'assets_blueprints' ); 393 // TODO: maybe if ( $touches_stable_tag )? 394 add_post_meta( $plugin->ID, '_missing_blueprint_notice', 1, true ); 393 395 } 394 396 -
sites/trunk/wordpress.org/public_html/wp-content/themes/pub/wporg-plugins/inc/template-tags.php
r13238 r13335 728 728 ); 729 729 } 730 } 730 731 // This is less important, so only show if there are no other notices. 732 if ( !$notice && !$import_warnings && get_post_meta( $post->ID, '_missing_blueprint_notice', true ) ) { 733 $blueprint_test_button = sprintf( 734 '<a class="plugin-preview" target="_blank" href="%s">%s</a>', 735 Template::preview_link_developer( $post->post_name, Template::download_link() ), 736 esc_html__( 'Test your plugin in Playground', 'wporg-plugins' ) 737 ); 738 $blueprint_download_button = sprintf( 739 '<a class="plugin-preview" target="_blank" href="%s">%s</a>', 740 Template::preview_link_developer( $post->post_name, Template::download_link(), true ), 741 esc_html__( 'Download blueprint.json', 'wporg-plugins' ) 742 ); 743 $blueprint_dismiss_button = sprintf( 744 '<form method="POST" action="%s"><p><input type="submit" name="dismiss" value="%s" class="plugin-preview button button-secondary alignright" /></p></form>', 745 #'<a class="plugin-preview button button-secondary alignright" href="%s">%s</a>', 746 Template::get_self_dismiss_blueprint_notice_link( $post ), 747 esc_html__( 'Dismiss', 'wporg-plugins' ) 748 ); 749 750 // There is surely a neater way to format this. 751 $blueprint_notice = sprintf( 752 '<ol><li>%s</li><li>%s</li><li>%s</li><li>%s</li></ol>', 753 $blueprint_test_button, 754 esc_html__( 'Fix any bugs in your plugin that prevent it from working in Playground.', 'wporg-plugins' ), 755 $blueprint_download_button, 756 esc_html__( 'Commit your blueprint to svn.', 'wporg-plugins' ) 757 ); 758 $blueprint_more = sprintf( 759 __( 'More info can be found in the <a href="%s">plugin handbook</a>.', 'wporg-plugins' ), 760 'https://developer.wordpress.org/plugins/wordpress-org/previews-and-blueprints/' 761 ); 762 763 printf( 764 '<div class="notice notice-info notice-alt">%s</div>', 765 '<p><strong>' . __( 'Your plugin does not yet have a blueprint file for user previews. If you\'d like to enable previews, please follow these steps to create a blueprint.', 'wporg-plugins' ) . '</strong></p>' . 766 $blueprint_notice . 767 $blueprint_dismiss_button . 768 '<p>' . $blueprint_more . '</p>' 769 ); 770 } 771 }
Note: See TracChangeset
for help on using the changeset viewer.