Make WordPress Core

Changeset 57545

Timestamp:
02/06/2024 11:44:09 PM (6 months ago)
Author:
costdev
Message:

Upgrade/Install: Introduce Plugin Dependencies.

Introduces a new "Requires Plugins" plugin header so that plugin developers can list the slugs of the plugins theirs depends on.

This will inform users of the requirements, and provide links to the WordPress.org Plugins Repository that they can click to install and activate the dependencies first.

Plugins whose requirements are not met cannot be installed or activated, and they will be deactivated automatically if their requirements become unmet.
Plugins that others rely on cannot be deactivated or deleted until their dependent plugins are deactivated or deleted.

In memory of Alex Mills and Alex King.
WordPress Remembers.

Props ahoereth, afragen, alanfuller, alexkingorg, amykamala, anonymized_10690803, apeatling, ashfame, atimmer, audrasjb, aristath, azaozz, batmoo, beaulebens, blobaugh, bobbingwide, boonebgorges, brianhenryie, chanthaboune, chrisdavidmiles, coolmann, costdev, courane01, danielbachhuber, davidperez, dd32, Denis-de-Bernardy, dingo_d, DJPaul, dougal, DrewAPicture, ethitter, filosofo, georgestephanis, giuseppemazzapica-1, goldenapples, griffinjt, hellofromTonya, husobj, ideag, jarednova, jbobich, jbrinley, jltallon, joedolson, johnciacia, johnjamesjacoby, joppuyo, jsmoriss, karmatosed, kebbet, knutsp, kraftbj, kraftner, kurtpayne, lkraav, logikal16, luisherranz, man4toman, markjaquith, matt, mbijon, megphillips91, mikeschinkel, mordauk, morehawes, mrwweb, mte90, mukesh27, mzaweb, nacin, norcross, nvwd, nwjames, obliviousharmony, ocean90, oglekler, paaljoachim, pauldewouters, pbaylies, pbiron, peterwilsoncc, Philipp15b, poena, pogidude, retlehs, rmccue, ryan, sabreuse, sc0ttkclark, scribu, sereedmedia, SergeyBiryukov, ShaneF, shidouhikari, soean, spacedmonkey, stephenh1988, swissspidy, taylorde, tazotodua, threadi, TimothyBlynJacobs, TJNowell, tollmanz, toscho, tropicalista, Viper007Bond, westi, whiteshadow, williamsba1, wpsmith, ZaneMatthew.
Fixes #22316.

Location:
trunk
Files:
16 added
15 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/js/_enqueues/wp/updates.js

    r56011 r57545  
    415415
    416416    /**
     417
     418
     419
     420
     421
     422
     423
     424
     425
     426
     427
     428
     429
     430
     431
     432
     433
     434
     435
     436
     437
     438
     439
     440
     441
    417442     * Decrements the update counts throughout the various menus.
    418443     *
     
    453478    wp.updates.updatePlugin = function( args ) {
    454479        var $updateRow, $card, $message, message,
    455             $adminBarUpdates = $( '#wp-admin-bar-updates' );
     480            $adminBarUpdates = $( '#wp-admin-bar-updates' ),
     481            buttonText = __( 'Updating...' );
    456482
    457483        args = _.extend( {
     
    469495            );
    470496        } else if ( 'plugin-install' === pagenow || 'plugin-install-network' === pagenow ) {
    471             $card    = $( '.plugin-card-' + args.slug );
     497            $card    = $( '.plugin-card-' + args.slug );
    472498            $message = $card.find( '.update-now' ).addClass( 'updating-message' );
    473499            message    = sprintf(
     
    489515        $message
    490516            .attr( 'aria-label', message )
    491             .text( __( 'Updating...' ) );
     517            .text( );
    492518
    493519        $document.trigger( 'wp-plugin-updating', args );
     520
     521
     522
     523
     524
     525
     526
     527
     528
     529
     530
     531
    494532
    495533        return wp.updates.ajax( 'update-plugin', args );
     
    512550    wp.updates.updatePluginSuccess = function( response ) {
    513551        var $pluginRow, $updateMessage, newText,
    514             $adminBarUpdates = $( '#wp-admin-bar-updates' );
     552            $adminBarUpdates = $( '#wp-admin-bar-updates' ),
     553            buttonText = _x( 'Updated!', 'plugin' ),
     554            ariaLabel = sprintf(
     555                /* translators: %s: Plugin name and version. */
     556                _x( '%s updated!', 'plugin' ),
     557                response.pluginName
     558            );
    515559
    516560        if ( 'plugins' === pagenow || 'plugins-network' === pagenow ) {
     
    529573            $pluginRow.find( '.auto-update-time' ).empty();
    530574        } else if ( 'plugin-install' === pagenow || 'plugin-install-network' === pagenow ) {
    531             $updateMessage = $( '.plugin-card-' + response.slug ).find( '.update-now' )
     575            $updateMessage = $( '.plugin-card-' + response.slug ).find( '.update-now' )
    532576                .removeClass( 'updating-message' )
    533577                .addClass( 'button-disabled updated-message' );
     
    537581
    538582        $updateMessage
    539             .attr(
    540                 'aria-label',
    541                 sprintf(
    542                     /* translators: %s: Plugin name and version. */
    543                     _x( '%s updated!', 'plugin' ),
    544                     response.pluginName
    545                 )
    546             )
    547             .text( _x( 'Updated!', 'plugin' ) );
     583            .attr( 'aria-label', ariaLabel )
     584            .text( buttonText );
    548585
    549586        wp.a11y.speak( __( 'Update completed successfully.' ) );
    550587
    551         wp.updates.decrementCount( 'plugin' );
     588        if ( 'plugin_install_from_iframe' !== $updateMessage.attr( 'id' ) ) {
     589            wp.updates.decrementCount( 'plugin' );
     590        } else {
     591            wp.updates.setCardButtonStatus(
     592                {
     593                    status: 'updated-plugin',
     594                    slug: response.slug,
     595                    removeClasses: 'updating-message',
     596                    addClasses: 'button-disabled updated-message',
     597                    text: buttonText,
     598                    ariaLabel: ariaLabel
     599                }
     600            );
     601        }
    552602
    553603        $document.trigger( 'wp-plugin-update-success', response );
     
    568618     */
    569619    wp.updates.updatePluginError = function( response ) {
    570         var $pluginRow, $card, $message, errorMessage,
     620        var $pluginRow, $card, $message, errorMessage,
    571621            $adminBarUpdates = $( '#wp-admin-bar-updates' );
    572622
     
    609659            }
    610660        } else if ( 'plugin-install' === pagenow || 'plugin-install-network' === pagenow ) {
    611             $card = $( '.plugin-card-' + response.slug )
    612                 .addClass( 'plugin-card-update-failed' )
     661            buttonText = __( 'Update failed.' );
     662
     663            $card = $( '.plugin-card-' + response.slug + ', #plugin-information-footer' )
    613664                .append( wp.updates.adminNotice( {
    614665                    className: 'update-message notice-error notice-alt is-dismissible',
     
    616667                } ) );
    617668
     669
     670
     671
     672
    618673            $card.find( '.update-now' )
    619                 .text(  __( 'Update failed.' ) )
     674                .text( )
    620675                .removeClass( 'updating-message' );
    621676
    622677            if ( response.pluginName ) {
    623                 $card.find( '.update-now' )
    624                     .attr(
    625                         'aria-label',
    626                         sprintf(
    627                             /* translators: %s: Plugin name and version. */
    628                             _x( '%s update failed.', 'plugin' ),
    629                             response.pluginName
    630                         )
    631                     );
     678                ariaLabel = sprintf(
     679                    /* translators: %s: Plugin name and version. */
     680                    _x( '%s update failed.', 'plugin' ),
     681                    response.pluginName
     682                );
     683
     684                $card.find( '.update-now' ).attr( 'aria-label', ariaLabel );
    632685            } else {
     686
    633687                $card.find( '.update-now' ).removeAttr( 'aria-label' );
    634688            }
     
    652706
    653707        wp.a11y.speak( errorMessage, 'assertive' );
     708
     709
     710
     711
     712
     713
     714
     715
     716
     717
     718
     719
    654720
    655721        $document.trigger( 'wp-plugin-update-error', response );
     
    669735     */
    670736    wp.updates.installPlugin = function( args ) {
    671         var $card    = $( '.plugin-card-' + args.slug ),
    672             $message = $card.find( '.install-now' );
     737        var $card    = $( '.plugin-card-' + args.slug + ', #plugin-information-footer' ),
     738            $message = $card.find( '.install-now' ),
     739            buttonText = __( 'Installing...' ),
     740            ariaLabel;
    673741
    674742        args = _.extend( {
     
    685753        }
    686754
     755
     756
     757
     758
     759
     760
    687761        $message
    688762            .addClass( 'updating-message' )
    689             .attr(
    690                 'aria-label',
    691                 sprintf(
    692                     /* translators: %s: Plugin name and version. */
    693                     _x( 'Installing %s...', 'plugin' ),
    694                     $message.data( 'name' )
    695                 )
    696             )
    697             .text( __( 'Installing...' ) );
     763            .attr( 'aria-label', ariaLabel )
     764            .text( buttonText );
    698765
    699766        wp.a11y.speak( __( 'Installing... please wait.' ) );
     
    703770
    704771        $document.trigger( 'wp-plugin-installing', args );
     772
     773
     774
     775
     776
     777
     778
     779
     780
     781
     782
     783
    705784
    706785        return wp.updates.ajax( 'install-plugin', args );
     
    718797     */
    719798    wp.updates.installPluginSuccess = function( response ) {
    720         var $message = $( '.plugin-card-' + response.slug ).find( '.install-now' );
     799        var $message = $( '.plugin-card-' + response.slug + ', #plugin-information-footer' ).find( '.install-now' ),
     800            buttonText = _x( 'Installed!', 'plugin' ),
     801            ariaLabel = sprintf(
     802                /* translators: %s: Plugin name and version. */
     803                _x( '%s installed!', 'plugin' ),
     804                response.pluginName
     805            );
    721806
    722807        $message
    723808            .removeClass( 'updating-message' )
    724809            .addClass( 'updated-message installed button-disabled' )
    725             .attr(
    726                 'aria-label',
    727                 sprintf(
    728                     /* translators: %s: Plugin name and version. */
    729                     _x( '%s installed!', 'plugin' ),
    730                     response.pluginName
    731                 )
    732             )
    733             .text( _x( 'Installed!', 'plugin' ) );
     810            .attr( 'aria-label', ariaLabel )
     811            .text( buttonText );
    734812
    735813        wp.a11y.speak( __( 'Installation completed successfully.' ) );
     
    739817        if ( response.activateUrl ) {
    740818            setTimeout( function() {
    741 
    742                 // Transform the 'Install' button into an 'Activate' button.
    743                 $message.removeClass( 'install-now installed button-disabled updated-message' )
    744                     .addClass( 'activate-now button-primary' )
    745                     .attr( 'href', response.activateUrl );
    746 
    747                 if ( 'plugins-network' === pagenow ) {
    748                     $message
    749                         .attr(
    750                             'aria-label',
    751                             sprintf(
    752                                 /* translators: %s: Plugin name. */
    753                                 _x( 'Network Activate %s', 'plugin' ),
    754                                 response.pluginName
    755                             )
    756                         )
    757                         .text( __( 'Network Activate' ) );
    758                 } else {
    759                     $message
    760                         .attr(
    761                             'aria-label',
    762                             sprintf(
    763                                 /* translators: %s: Plugin name. */
    764                                 _x( 'Activate %s', 'plugin' ),
    765                                 response.pluginName
    766                             )
    767                         )
    768                         .text( __( 'Activate' ) );
    769                 }
     819                wp.updates.checkPluginDependencies( {
     820                    slug: response.slug
     821                } );
    770822            }, 1000 );
     823
     824
     825
     826
     827
     828
     829
     830
     831
     832
     833
     834
     835
    771836        }
    772837    };
     
    784849     */
    785850    wp.updates.installPluginError = function( response ) {
    786         var $card   = $( '.plugin-card-' + response.slug ),
     851        var $card   = $( '.plugin-card-' + response.slug ),
    787852            $button = $card.find( '.install-now' ),
     853
     854
     855
     856
     857
     858
    788859            errorMessage;
    789860
     
    818889        $button
    819890            .removeClass( 'updating-message' ).addClass( 'button-disabled' )
    820             .attr(
    821                 'aria-label',
    822                 sprintf(
    823                     /* translators: %s: Plugin name and version. */
    824                     _x( '%s installation failed', 'plugin' ),
    825                     $button.data( 'name' )
    826                 )
    827             )
    828             .text( __( 'Installation failed.' ) );
     891            .attr( 'aria-label', ariaLabel )
     892            .text( buttonText );
    829893
    830894        wp.a11y.speak( errorMessage, 'assertive' );
    831895
     896
     897
     898
     899
     900
     901
     902
     903
     904
     905
     906
    832907        $document.trigger( 'wp-plugin-install-error', response );
     908
     909
     910
     911
     912
     913
     914
     915
     916
     917
     918
     919
     920
     921
     922
     923
     924
     925
     926
     927
     928
     929
     930
     931
     932
     933
     934
     935
     936
     937
     938
     939
     940
     941
     942
     943
     944
     945
     946
     947
     948
     949
     950
     951
     952
     953
     954
     955
     956
     957
     958
     959
     960
     961
     962
     963
     964
     965
     966
     967
     968
     969
     970
     971
     972
     973
     974
     975
     976
     977
     978
     979
     980
     981
     982
     983
     984
     985
     986
     987
     988
     989
     990
     991
     992
     993
     994
     995
     996
     997
     998
     999
     1000
     1001
     1002
     1003
     1004
     1005
     1006
     1007
     1008
     1009
     1010
     1011
     1012
     1013
     1014
     1015
     1016
     1017
     1018
     1019
     1020
     1021
     1022
     1023
     1024
     1025
     1026
     1027
     1028
     1029
     1030
     1031
     1032
     1033
     1034
     1035
     1036
     1037
     1038
     1039
     1040
     1041
     1042
     1043
     1044
     1045
     1046
     1047
     1048
     1049
     1050
     1051
     1052
     1053
     1054
     1055
     1056
     1057
     1058
     1059
     1060
     1061
     1062
     1063
     1064
     1065
     1066
     1067
     1068
     1069
     1070
     1071
     1072
     1073
     1074
     1075
     1076
     1077
     1078
     1079
     1080
     1081
     1082
     1083
     1084
     1085
     1086
     1087
     1088
     1089
     1090
     1091
     1092
     1093
     1094
     1095
     1096
     1097
     1098
     1099
     1100
     1101
     1102
     1103
     1104
     1105
     1106
     1107
     1108
     1109
     1110
     1111
     1112
     1113
     1114
     1115
     1116
     1117
     1118
     1119
     1120
     1121
     1122
     1123
     1124
     1125
     1126
     1127
     1128
     1129
     1130
     1131
     1132
     1133
     1134
     1135
     1136
     1137
     1138
     1139
     1140
     1141
     1142
     1143
     1144
     1145
     1146
     1147
     1148
     1149
     1150
     1151
     1152
     1153
     1154
     1155
     1156
     1157
     1158
     1159
     1160
     1161
     1162
     1163
     1164
     1165
     1166
     1167
     1168
     1169
     1170
     1171
     1172
     1173
     1174
     1175
     1176
     1177
     1178
     1179
     1180
     1181
     1182
     1183
     1184
     1185
     1186
     1187
     1188
     1189
     1190
     1191
     1192
     1193
     1194
     1195
     1196
     1197
     1198
     1199
     1200
     1201
     1202
     1203
     1204
     1205
     1206
     1207
     1208
     1209
     1210
     1211
     1212
     1213
     1214
     1215
     1216
    8331217    };
    8341218
     
    19712355                break;
    19722356
     2357
     2358
     2359
     2360
     2361
     2362
     2363
     2364
     2365
     2366
    19732367            case 'delete':
    19742368                /* translators: %s: Error string for a failed deletion. */
     
    20262420
    20272421    $( function() {
    2028         var $pluginFilter        = $( '#plugin-filter' ),
     2422        var $pluginFilter        = $( '#plugin-filter' ),
    20292423            $bulkActionForm      = $( '#bulk-action-form' ),
    20302424            $filesystemForm      = $( '#request-filesystem-credentials-form' ),
     
    22432637
    22442638        /**
     2639
     2640
     2641
     2642
     2643
     2644
     2645
     2646
     2647
     2648
     2649
     2650
     2651
     2652
     2653
     2654
     2655
     2656
     2657
     2658
     2659
     2660
     2661
     2662
     2663
     2664
     2665
     2666
     2667
     2668
     2669
     2670
     2671
     2672
     2673
     2674
     2675
     2676
    22452677         * Click handler for importer plugins installs in the Import screen.
    22462678         *
     
    27683200
    27693201        /**
    2770          * Click handler for installing a plugin from the details modal on `plugin-install.php`.
    2771          *
    2772          * @since 4.6.0
    2773          *
    2774          * @param {Event} event Event interface.
    2775          */
    2776         $( '#plugin_install_from_iframe' ).on( 'click', function( event ) {
    2777             var target = window.parent === window ? null : window.parent,
    2778                 install;
    2779 
    2780             $.support.postMessage = !! window.postMessage;
    2781 
    2782             if ( false === $.support.postMessage || null === target || -1 !== window.parent.location.pathname.indexOf( 'index.php' ) ) {
    2783                 return;
    2784             }
    2785 
    2786             event.preventDefault();
    2787 
    2788             install = {
    2789                 action: 'install-plugin',
    2790                 data:   {
    2791                     slug: $( this ).data( 'slug' )
    2792                 }
    2793             };
    2794 
    2795             target.postMessage( JSON.stringify( install ), window.location.origin );
    2796         } );
    2797 
    2798         /**
    27993202         * Handles postMessage events.
    28003203         *
     
    28193222            }
    28203223
    2821             if ( ! message || 'undefined' === typeof message.action ) {
     3224            if ( ! message ) {
     3225                return;
     3226            }
     3227
     3228            if (
     3229                'undefined' !== typeof message.status &&
     3230                'undefined' !== typeof message.slug &&
     3231                'undefined' !== typeof message.text &&
     3232                'undefined' !== typeof message.ariaLabel
     3233            ) {
     3234                var $card = $( '.plugin-card-' + message.slug ),
     3235                    $message = $card.find( '[data-slug="' + message.slug + '"]' );
     3236
     3237                if ( 'undefined' !== typeof message.removeClasses ) {
     3238                    $message.removeClass( message.removeClasses );
     3239                }
     3240
     3241                if ( 'undefined' !== typeof message.addClasses ) {
     3242                    $message.addClass( message.addClasses );
     3243                }
     3244
     3245                if ( '' === message.ariaLabel ) {
     3246                    $message.removeAttr( 'aria-label' );
     3247                } else {
     3248                    $message.attr( 'aria-label', message.ariaLabel );
     3249                }
     3250
     3251                if ( 'dependencies-check-success' === message.status ) {
     3252                    $message
     3253                        .attr( 'data-name', message.pluginName )
     3254                        .attr( 'data-slug', message.slug )
     3255                        .attr( 'data-plugin', message.plugin )
     3256                        .attr( 'href', message.href );
     3257                }
     3258
     3259                $message.text( message.text );
     3260            }
     3261
     3262            if ( 'undefined' === typeof message.action || 'undefined' === typeof message.data.slug ) {
    28223263                return;
    28233264            }
     
    28333274                case 'install-plugin':
    28343275                case 'update-plugin':
    2835                     /* jscs:disable requireCamelCaseOrUpperCaseIdentifiers */
    2836                     window.tb_remove();
    2837                     /* jscs:enable */
    2838 
    28393276                    message.data = wp.updates._addCallbacks( message.data, message.action );
    28403277
  • trunk/src/wp-admin/admin-ajax.php

    r53363 r57545  
    118118    'destroy-sessions',
    119119    'install-plugin',
     120
    120121    'update-plugin',
    121122    'crop-image',
     
    170171add_action( 'wp_ajax_nopriv_heartbeat', 'wp_ajax_nopriv_heartbeat', 1 );
    171172
     173
     174
     175
    172176$action = $_REQUEST['action'];
    173177
  • trunk/src/wp-admin/css/common.css

    r57363 r57545  
    15011501}
    15021502
     1503
     1504
     1505
     1506
     1507
     1508
     1509
     1510
     1511
     1512
     1513
     1514
     1515
     1516
     1517
     1518
    15031519.update-message p:before,
    15041520.updating-message p:before,
     
    15081524.button.updated-message:before,
    15091525.button.installed:before,
    1510 .button.installing:before {
     1526.button.installing:before,
     1527.button.activating-message:before,
     1528.button.activated-message:before {
    15111529    display: inline-block;
    15121530    font: normal 20px/1 'dashicons';
     
    15451563.import-php .updating-message:before,
    15461564.button.updating-message:before,
    1547 .button.installing:before {
     1565.button.installing:before,
     1566.button.activating-message:before {
    15481567    color: #d63638;
    15491568    content: "\f463";
     
    15551574.button.updating-message:before,
    15561575.button.installing:before,
     1576
    15571577.plugins .column-auto-updates .dashicons-update.spin,
    15581578.theme-overlay .theme-autoupdate .dashicons-update.spin {
     
    15651585    .button.updating-message:before,
    15661586    .button.installing:before,
     1587
    15671588    .plugins .column-auto-updates .dashicons-update.spin,
    15681589    .theme-overlay .theme-autoupdate .dashicons-update.spin {
     
    15781599.updated-message p:before,
    15791600.installed p:before,
    1580 .button.updated-message:before {
     1601.button.updated-message:before,
     1602.button.activated-message:before {
    15811603    color: #68de7c;
    15821604    content: "\f147";
     
    16631685.button.updated-message:before,
    16641686.button.installed:before,
    1665 .button.installing:before {
     1687.button.installing:before,
     1688.button.activated-message:before,
     1689.button.activating-message:before {
    16661690    margin: 3px 5px 0 -2px;
    16671691}
    16681692
    1669 .button-primary.updating-message:before {
     1693#plugin-information-footer .button.installed:before,
     1694#plugin-information-footer .button.installing:before,
     1695#plugin-information-footer .button.updating-message:before,
     1696#plugin-information-footer .button.updated-message:before,
     1697#plugin-information-footer .button.activated-message:before,
     1698#plugin-information-footer .button.activating-message:before {
     1699    margin: 9px 5px 0 -2px;
     1700}
     1701
     1702#plugin-information-footer .button.update-now.updating-message:before {
     1703    margin: -3px 5px 0 -2px;
     1704}
     1705
     1706.button-primary.updating-message:before,
     1707.button-primary.activating-message:before {
    16701708    color: #fff;
    16711709}
    16721710
    1673 .button-primary.updated-message:before {
     1711.button-primary.updated-message:before,
     1712.button-primary.activated-message:before {
    16741713    color: #9ec2e6;
    16751714}
    16761715
    1677 .button.updated-message {
     1716.button.updated-message,
     1717.button.activated-message {
    16781718    transition-property: border, background, color;
    16791719    transition-duration: .05s;
  • trunk/src/wp-admin/css/list-tables.css

    r57321 r57545  
    586586}
    587587
    588 .check-column input:where(:not(:disabled)):hover,
    589 .check-column:hover input:where(:not(:disabled)) {
     588.check-column .label-covers-full-cell:hover + input:not(:disabled) {
    590589    box-shadow: 0 0 0 1px #2271b1;
    591590}
     
    15491548}
    15501549
    1551 .plugin-card .name,
    15521550.plugin-card .desc {
    1553     margin-left: 148px; /* icon + margin */
    1554     margin-right: 128px; /* action links + margin */
     1551    margin-inline: 0;
     1552}
     1553
     1554.plugin-card .name, .plugin-card .desc > p {
     1555    margin-left: 148px;
     1556}
     1557
     1558@media (min-width: 1101px) {
     1559    .plugin-card .name, .plugin-card .desc > p {
     1560        margin-right: 128px;
     1561    }
     1562}
     1563
     1564@media (min-width: 481px) and (max-width: 781px) {
     1565    .plugin-card .name, .plugin-card .desc > p {
     1566        margin-right: 128px;
     1567    }
     1568}
     1569
     1570.plugin-card .column-description {
     1571    display: flex;
     1572    flex-direction: column;
     1573    justify-content: flex-start;
     1574}
     1575
     1576.plugin-card .column-description > p {
     1577    margin-top: 0;
     1578}
     1579
     1580.plugin-card .column-description .authors {
     1581    order: 1;
     1582}
     1583
     1584.plugin-card .column-description .plugin-dependencies {
     1585    order: 2;
     1586}
     1587
     1588.plugin-card .column-description p:empty {
     1589    display: none;
     1590}
     1591
     1592.plugin-card .plugin-dependencies {
     1593    background-color: #e5f5fa;
     1594    border-left: 3px solid #72aee6;
     1595    margin-bottom: .5em;
     1596    padding: 15px;
     1597}
     1598
     1599.plugin-card .plugin-dependencies-explainer-text {
     1600    margin-block: 0;
     1601}
     1602
     1603.plugin-card .plugin-dependency {
     1604    align-items: center;
     1605    display: flex;
     1606    flex-wrap: wrap;
     1607    margin-top: .5em;
     1608    column-gap: 1%;
     1609    row-gap: .5em;
     1610}
     1611
     1612.plugin-card .plugin-dependency:nth-child(2),
     1613.plugin-card .plugin-dependency:last-child {
     1614    margin-top: 1em;
     1615}
     1616
     1617.plugin-card .plugin-dependency-name {
     1618    flex-basis: 74%;
     1619}
     1620
     1621.plugin-card .plugin-dependency .more-details-link {
     1622    margin-left: auto;
     1623}
     1624
     1625.rtl .plugin-card .plugin-dependency .more-details-link {
     1626    margin-right: auto;
     1627}
     1628
     1629@media (max-width: 939px) {
     1630    .plugin-card .plugin-dependency-name {
     1631        flex-basis: 69%;
     1632    }
     1633    .plugin-card .plugin-dependency .more-details-link {
     1634    }
     1635}
     1636
     1637.plugins #the-list .required-by,
     1638.plugins #the-list .requires {
     1639    margin-top: 1em;
    15551640}
    15561641
  • trunk/src/wp-admin/includes/ajax-actions.php

    r57136 r57545  
    45804580
    45814581/**
     4582
     4583
     4584
     4585
     4586
     4587
     4588
     4589
     4590
     4591
     4592
     4593
     4594
     4595
     4596
     4597
     4598
     4599
     4600
     4601
     4602
     4603
     4604
     4605
     4606
     4607
     4608
     4609
     4610
     4611
     4612
     4613
     4614
     4615
     4616
     4617
     4618
     4619
     4620
     4621
     4622
     4623
     4624
     4625
     4626
     4627
     4628
     4629
     4630
     4631
    45824632 * Handles updating a plugin via AJAX.
    45834633 *
  • trunk/src/wp-admin/includes/class-plugin-upgrader.php

    r57239 r57545  
    155155        // Force refresh of plugin update information.
    156156        wp_clean_plugins_cache( $parsed_args['clear_update_cache'] );
     157
     158
     159
     160
     161
     162
    157163
    158164        if ( $parsed_args['overwrite_package'] ) {
     
    483489                $info = get_plugin_data( $file, false, false );
    484490                if ( ! empty( $info['Name'] ) ) {
    485                     $this->new_plugin_data = $info;
     491                    $basename = basename( $file );
     492                    $dirname  = basename( dirname( $file ) );
     493
     494                    if ( '.' === $dirname ) {
     495                        $plugin_file = $basename;
     496                    } else {
     497                        $plugin_file = "$dirname/$basename";
     498                    }
     499                    $this->new_plugin_data         = ( $info );
     500                    $this->new_plugin_data['file'] = $plugin_file;
    486501                    break;
    487502                }
  • trunk/src/wp-admin/includes/class-wp-plugin-install-list-table.php

    r56599 r57545  
    526526            $description = strip_tags( $plugin['short_description'] );
    527527
     528
     529
    528530            /**
    529531             * Filters the plugin card description on the Add Plugins screen.
     
    556558            $action_links = array();
    557559
    558             if ( current_user_can( 'install_plugins' ) || current_user_can( 'update_plugins' ) ) {
    559                 $status = install_plugin_install_status( $plugin );
    560 
    561                 switch ( $status['status'] ) {
    562                     case 'install':
    563                         if ( $status['url'] ) {
    564                             if ( $compatible_php && $compatible_wp ) {
    565                                 $action_links[] = sprintf(
    566                                     '<a class="install-now button" data-slug="%s" href="%s" aria-label="%s" data-name="%s">%s</a>',
    567                                     esc_attr( $plugin['slug'] ),
    568                                     esc_url( $status['url'] ),
    569                                     /* translators: %s: Plugin name and version. */
    570                                     esc_attr( sprintf( _x( 'Install %s now', 'plugin' ), $name ) ),
    571                                     esc_attr( $name ),
    572                                     __( 'Install Now' )
    573                                 );
    574                             } else {
    575                                 $action_links[] = sprintf(
    576                                     '<button type="button" class="button button-disabled" disabled="disabled">%s</button>',
    577                                     _x( 'Cannot Install', 'plugin' )
    578                                 );
    579                             }
    580                         }
    581                         break;
    582 
    583                     case 'update_available':
    584                         if ( $status['url'] ) {
    585                             if ( $compatible_php && $compatible_wp ) {
    586                                 $action_links[] = sprintf(
    587                                     '<a class="update-now button aria-button-if-js" data-plugin="%s" data-slug="%s" href="%s" aria-label="%s" data-name="%s">%s</a>',
    588                                     esc_attr( $status['file'] ),
    589                                     esc_attr( $plugin['slug'] ),
    590                                     esc_url( $status['url'] ),
    591                                     /* translators: %s: Plugin name and version. */
    592                                     esc_attr( sprintf( _x( 'Update %s now', 'plugin' ), $name ) ),
    593                                     esc_attr( $name ),
    594                                     __( 'Update Now' )
    595                                 );
    596                             } else {
    597                                 $action_links[] = sprintf(
    598                                     '<button type="button" class="button button-disabled" disabled="disabled">%s</button>',
    599                                     _x( 'Cannot Update', 'plugin' )
    600                                 );
    601                             }
    602                         }
    603                         break;
    604 
    605                     case 'latest_installed':
    606                     case 'newer_installed':
    607                         if ( is_plugin_active( $status['file'] ) ) {
    608                             $action_links[] = sprintf(
    609                                 '<button type="button" class="button button-disabled" disabled="disabled">%s</button>',
    610                                 _x( 'Active', 'plugin' )
    611                             );
    612                         } elseif ( current_user_can( 'activate_plugin', $status['file'] ) ) {
    613                             if ( $compatible_php && $compatible_wp ) {
    614                                 $button_text = __( 'Activate' );
    615                                 /* translators: %s: Plugin name. */
    616                                 $button_label = _x( 'Activate %s', 'plugin' );
    617                                 $activate_url = add_query_arg(
    618                                     array(
    619                                         '_wpnonce' => wp_create_nonce( 'activate-plugin_' . $status['file'] ),
    620                                         'action'   => 'activate',
    621                                         'plugin'   => $status['file'],
    622                                     ),
    623                                     network_admin_url( 'plugins.php' )
    624                                 );
    625 
    626                                 if ( is_network_admin() ) {
    627                                     $button_text = __( 'Network Activate' );
    628                                     /* translators: %s: Plugin name. */
    629                                     $button_label = _x( 'Network Activate %s', 'plugin' );
    630                                     $activate_url = add_query_arg( array( 'networkwide' => 1 ), $activate_url );
    631                                 }
    632 
    633                                 $action_links[] = sprintf(
    634                                     '<a href="%1$s" class="button activate-now" aria-label="%2$s">%3$s</a>',
    635                                     esc_url( $activate_url ),
    636                                     esc_attr( sprintf( $button_label, $plugin['name'] ) ),
    637                                     $button_text
    638                                 );
    639                             } else {
    640                                 $action_links[] = sprintf(
    641                                     '<button type="button" class="button button-disabled" disabled="disabled">%s</button>',
    642                                     _x( 'Cannot Activate', 'plugin' )
    643                                 );
    644                             }
    645                         } else {
    646                             $action_links[] = sprintf(
    647                                 '<button type="button" class="button button-disabled" disabled="disabled">%s</button>',
    648                                 _x( 'Installed', 'plugin' )
    649                             );
    650                         }
    651                         break;
    652                 }
    653             }
     560            $action_links[] = wp_get_plugin_action_button( $name, $plugin, $compatible_php, $compatible_wp );
    654561
    655562            $details_link = self_admin_url(
     
    829736        }
    830737    }
     738
     739
     740
     741
     742
     743
     744
     745
     746
     747
     748
     749
     750
     751
     752
     753
     754
     755
     756
     757
     758
     759
     760
     761
     762
     763
     764
     765
     766
     767
     768
     769
     770
     771
     772
     773
     774
     775
     776
     777
     778
     779
     780
     781
     782
     783
     784
     785
     786
     787
     788
     789
     790
     791
     792
     793
     794
     795
     796
     797
     798
     799
     800
     801
     802
     803
     804
     805
     806
     807
     808
     809
     810
     811
     812
     813
     814
     815
     816
     817
     818
     819
     820
     821
     822
     823
    831824}
  • trunk/src/wp-admin/includes/class-wp-plugins-list-table.php

    r56824 r57545  
    755755        $compatible_wp  = is_wp_version_compatible( $requires_wp );
    756756
     757
     758
     759
     760
     761
    757762        if ( 'mustuse' === $context ) {
    758763            $is_active = true;
     
    797802                if ( $is_active ) {
    798803                    if ( current_user_can( 'manage_network_plugins' ) ) {
    799                         $actions['deactivate'] = sprintf(
    800                             '<a href="%s" id="deactivate-%s" aria-label="%s">%s</a>',
    801                             wp_nonce_url( 'plugins.php?action=deactivate&amp;plugin=' . urlencode( $plugin_file ) . '&amp;plugin_status=' . $context . '&amp;paged=' . $page . '&amp;s=' . $s, 'deactivate-plugin_' . $plugin_file ),
    802                             esc_attr( $plugin_id_attr ),
    803                             /* translators: %s: Plugin name. */
    804                             esc_attr( sprintf( _x( 'Network Deactivate %s', 'plugin' ), $plugin_data['Name'] ) ),
    805                             __( 'Network Deactivate' )
    806                         );
     804                        if ( $has_active_dependents ) {
     805                            $actions['deactivate'] = __( 'Deactivate' ) .
     806                                '<span class="screen-reader-text">' .
     807                                __( 'You cannot deactivate this plugin as other plugins require it.' ) .
     808                                '</span>';
     809
     810                        } else {
     811                            $deactivate_url = 'plugins.php?action=deactivate' .
     812                                '&amp;plugin=' . urlencode( $plugin_file ) .
     813                                '&amp;plugin_status=' . $context .
     814                                '&amp;paged=' . $page .
     815                                '&amp;s=' . $s;
     816
     817                            $actions['deactivate'] = sprintf(
     818                                '<a href="%s" id="deactivate-%s" aria-label="%s">%s</a>',
     819                                wp_nonce_url( $deactivate_url, 'deactivate-plugin_' . $plugin_file ),
     820                                esc_attr( $plugin_id_attr ),
     821                                /* translators: %s: Plugin name. */
     822                                esc_attr( sprintf( _x( 'Network Deactivate %s', 'plugin' ), $plugin_data['Name'] ) ),
     823                                __( 'Network Deactivate' )
     824                            );
     825                        }
    807826                    }
    808827                } else {
    809828                    if ( current_user_can( 'manage_network_plugins' ) ) {
    810829                        if ( $compatible_php && $compatible_wp ) {
    811                             $actions['activate'] = sprintf(
    812                                 '<a href="%s" id="activate-%s" class="edit" aria-label="%s">%s</a>',
    813                                 wp_nonce_url( 'plugins.php?action=activate&amp;plugin=' . urlencode( $plugin_file ) . '&amp;plugin_status=' . $context . '&amp;paged=' . $page . '&amp;s=' . $s, 'activate-plugin_' . $plugin_file ),
    814                                 esc_attr( $plugin_id_attr ),
    815                                 /* translators: %s: Plugin name. */
    816                                 esc_attr( sprintf( _x( 'Network Activate %s', 'plugin' ), $plugin_data['Name'] ) ),
    817                                 __( 'Network Activate' )
    818                             );
     830                            if ( $has_unmet_dependencies ) {
     831                                $actions['activate'] = __( 'Network Activate' ) .
     832                                    '<span class="screen-reader-text">' .
     833                                    __( 'You cannot activate this plugin as it has unmet requirements.' ) .
     834                                    '</span>';
     835                            } else {
     836                                $activate_url = 'plugins.php?action=activate' .
     837                                    '&amp;plugin=' . urlencode( $plugin_file ) .
     838                                    '&amp;plugin_status=' . $context .
     839                                    '&amp;paged=' . $page .
     840                                    '&amp;s=' . $s;
     841
     842                                $actions['activate'] = sprintf(
     843                                    '<a href="%s" id="activate-%s" class="edit" aria-label="%s">%s</a>',
     844                                    wp_nonce_url( $activate_url, 'activate-plugin_' . $plugin_file ),
     845                                    esc_attr( $plugin_id_attr ),
     846                                    /* translators: %s: Plugin name. */
     847                                    esc_attr( sprintf( _x( 'Network Activate %s', 'plugin' ), $plugin_data['Name'] ) ),
     848                                    __( 'Network Activate' )
     849                                );
     850                            }
    819851                        } else {
    820852                            $actions['activate'] = sprintf(
     
    826858
    827859                    if ( current_user_can( 'delete_plugins' ) && ! is_plugin_active( $plugin_file ) ) {
    828                         $actions['delete'] = sprintf(
    829                             '<a href="%s" id="delete-%s" class="delete" aria-label="%s">%s</a>',
    830                             wp_nonce_url( 'plugins.php?action=delete-selected&amp;checked[]=' . urlencode( $plugin_file ) . '&amp;plugin_status=' . $context . '&amp;paged=' . $page . '&amp;s=' . $s, 'bulk-plugins' ),
    831                             esc_attr( $plugin_id_attr ),
    832                             /* translators: %s: Plugin name. */
    833                             esc_attr( sprintf( _x( 'Delete %s', 'plugin' ), $plugin_data['Name'] ) ),
    834                             __( 'Delete' )
    835                         );
     860                        if ( $has_dependents && ! $has_circular_dependency ) {
     861                            $actions['delete'] = __( 'Delete' ) .
     862                                '<span class="screen-reader-text">' .
     863                                __( 'You cannot delete this plugin as other plugins require it.' ) .
     864                                '</span>';
     865                        } else {
     866                            $delete_url = 'plugins.php?action=delete-selected' .
     867                                '&amp;checked[]=' . urlencode( $plugin_file ) .
     868                                '&amp;plugin_status=' . $context .
     869                                '&amp;paged=' . $page .
     870                                '&amp;s=' . $s;
     871
     872                            $actions['delete'] = sprintf(
     873                                '<a href="%s" id="delete-%s" class="delete" aria-label="%s">%s</a>',
     874                                wp_nonce_url( $delete_url, 'bulk-plugins' ),
     875                                esc_attr( $plugin_id_attr ),
     876                                /* translators: %s: Plugin name. */
     877                                esc_attr( sprintf( _x( 'Delete %s', 'plugin' ), $plugin_data['Name'] ) ),
     878                                __( 'Delete' )
     879                            );
     880                        }
    836881                    }
    837882                }
     
    847892                } elseif ( $is_active ) {
    848893                    if ( current_user_can( 'deactivate_plugin', $plugin_file ) ) {
    849                         $actions['deactivate'] = sprintf(
    850                             '<a href="%s" id="deactivate-%s" aria-label="%s">%s</a>',
    851                             wp_nonce_url( 'plugins.php?action=deactivate&amp;plugin=' . urlencode( $plugin_file ) . '&amp;plugin_status=' . $context . '&amp;paged=' . $page . '&amp;s=' . $s, 'deactivate-plugin_' . $plugin_file ),
    852                             esc_attr( $plugin_id_attr ),
    853                             /* translators: %s: Plugin name. */
    854                             esc_attr( sprintf( _x( 'Deactivate %s', 'plugin' ), $plugin_data['Name'] ) ),
    855                             __( 'Deactivate' )
    856                         );
     894                        if ( $has_active_dependents ) {
     895                            $actions['deactivate'] = __( 'Deactivate' ) .
     896                                '<span class="screen-reader-text">' .
     897                                __( 'You cannot deactivate this plugin as other plugins depend on it.' ) .
     898                                '</span>';
     899                        } else {
     900                            $deactivate_url = 'plugins.php?action=deactivate' .
     901                                '&amp;plugin=' . urlencode( $plugin_file ) .
     902                                '&amp;plugin_status=' . $context .
     903                                '&amp;paged=' . $page .
     904                                '&amp;s=' . $s;
     905
     906                            $actions['deactivate'] = sprintf(
     907                                '<a href="%s" id="deactivate-%s" aria-label="%s">%s</a>',
     908                                wp_nonce_url( $deactivate_url, 'deactivate-plugin_' . $plugin_file ),
     909                                esc_attr( $plugin_id_attr ),
     910                                /* translators: %s: Plugin name. */
     911                                esc_attr( sprintf( _x( 'Deactivate %s', 'plugin' ), $plugin_data['Name'] ) ),
     912                                __( 'Deactivate' )
     913                            );
     914                        }
    857915                    }
    858916
    859917                    if ( current_user_can( 'resume_plugin', $plugin_file ) && is_plugin_paused( $plugin_file ) ) {
     918
     919
     920
     921
     922
     923
    860924                        $actions['resume'] = sprintf(
    861925                            '<a href="%s" id="resume-%s" class="resume-link" aria-label="%s">%s</a>',
    862                             wp_nonce_url( 'plugins.php?action=resume&amp;plugin=' . urlencode( $plugin_file ) . '&amp;plugin_status=' . $context . '&amp;paged=' . $page . '&amp;s=' . $s, 'resume-plugin_' . $plugin_file ),
     926                            wp_nonce_url( , 'resume-plugin_' . $plugin_file ),
    863927                            esc_attr( $plugin_id_attr ),
    864928                            /* translators: %s: Plugin name. */
     
    870934                    if ( current_user_can( 'activate_plugin', $plugin_file ) ) {
    871935                        if ( $compatible_php && $compatible_wp ) {
    872                             $actions['activate'] = sprintf(
    873                                 '<a href="%s" id="activate-%s" class="edit" aria-label="%s">%s</a>',
    874                                 wp_nonce_url( 'plugins.php?action=activate&amp;plugin=' . urlencode( $plugin_file ) . '&amp;plugin_status=' . $context . '&amp;paged=' . $page . '&amp;s=' . $s, 'activate-plugin_' . $plugin_file ),
    875                                 esc_attr( $plugin_id_attr ),
    876                                 /* translators: %s: Plugin name. */
    877                                 esc_attr( sprintf( _x( 'Activate %s', 'plugin' ), $plugin_data['Name'] ) ),
    878                                 __( 'Activate' )
    879                             );
     936                            if ( $has_unmet_dependencies ) {
     937                                $actions['activate'] = __( 'Activate' ) .
     938                                    '<span class="screen-reader-text">' .
     939                                    __( 'You cannot activate this plugin as it has unmet requirements.' ) .
     940                                    '</span>';
     941                            } else {
     942                                $activate_url = 'plugins.php?action=activate' .
     943                                    '&amp;plugin=' . urlencode( $plugin_file ) .
     944                                    '&amp;plugin_status=' . $context .
     945                                    '&amp;paged=' . $page .
     946                                    '&amp;s=' . $s;
     947
     948                                $actions['activate'] = sprintf(
     949                                    '<a href="%s" id="activate-%s" class="edit" aria-label="%s">%s</a>',
     950                                    wp_nonce_url( $activate_url, 'activate-plugin_' . $plugin_file ),
     951                                    esc_attr( $plugin_id_attr ),
     952                                    /* translators: %s: Plugin name. */
     953                                    esc_attr( sprintf( _x( 'Activate %s', 'plugin' ), $plugin_data['Name'] ) ),
     954                                    __( 'Activate' )
     955                                );
     956                            }
    880957                        } else {
    881958                            $actions['activate'] = sprintf(
     
    887964
    888965                    if ( ! is_multisite() && current_user_can( 'delete_plugins' ) ) {
    889                         $actions['delete'] = sprintf(
    890                             '<a href="%s" id="delete-%s" class="delete" aria-label="%s">%s</a>',
    891                             wp_nonce_url( 'plugins.php?action=delete-selected&amp;checked[]=' . urlencode( $plugin_file ) . '&amp;plugin_status=' . $context . '&amp;paged=' . $page . '&amp;s=' . $s, 'bulk-plugins' ),
    892                             esc_attr( $plugin_id_attr ),
    893                             /* translators: %s: Plugin name. */
    894                             esc_attr( sprintf( _x( 'Delete %s', 'plugin' ), $plugin_data['Name'] ) ),
    895                             __( 'Delete' )
    896                         );
     966                        if ( $has_dependents && ! $has_circular_dependency ) {
     967                            $actions['delete'] = __( 'Delete' ) .
     968                                '<span class="screen-reader-text">' .
     969                                __( 'You cannot delete this plugin as other plugins require it.' ) .
     970                                '</span>';
     971                        } else {
     972                            $delete_url = 'plugins.php?action=delete-selected' .
     973                                '&amp;checked[]=' . urlencode( $plugin_file ) .
     974                                '&amp;plugin_status=' . $context .
     975                                '&amp;paged=' . $page .
     976                                '&amp;s=' . $s;
     977
     978                            $actions['delete'] = sprintf(
     979                                '<a href="%s" id="delete-%s" class="delete" aria-label="%s">%s</a>',
     980                                wp_nonce_url( $delete_url, 'bulk-plugins' ),
     981                                esc_attr( $plugin_id_attr ),
     982                                /* translators: %s: Plugin name. */
     983                                esc_attr( sprintf( _x( 'Delete %s', 'plugin' ), $plugin_data['Name'] ) ),
     984                                __( 'Delete' )
     985                            );
     986                        }
    897987                    }
    898988                } // End if $is_active.
     
    9891079        $class       = $is_active ? 'active' : 'inactive';
    9901080        $checkbox_id = 'checkbox_' . md5( $plugin_file );
    991 
    992         if ( $restrict_network_active || $restrict_network_only || in_array( $status, array( 'mustuse', 'dropins' ), true ) || ! $compatible_php ) {
     1081        $disabled    = '';
     1082
     1083        if ( $has_active_dependents || $has_unmet_dependencies ) {
     1084            $disabled = 'disabled';
     1085        }
     1086
     1087        if (
     1088            $restrict_network_active ||
     1089            $restrict_network_only ||
     1090            in_array( $status, array( 'mustuse', 'dropins' ), true ) ||
     1091            ! $compatible_php
     1092        ) {
    9931093            $checkbox = '';
    9941094        } else {
    9951095            $checkbox = sprintf(
    996                 '<input type="checkbox" name="checked[]" value="%1$s" id="%2$s" />' .
    997                 '<label for="%2$s"><span class="screen-reader-text">%3$s</span></label>',
    998                 esc_attr( $plugin_file ),
     1096                '<>' .
     1097                '<
     1098                ,
    9991099                $checkbox_id,
    10001100                /* translators: Hidden accessibility text. %s: Plugin name. */
    1001                 sprintf( __( 'Select %s' ), $plugin_data['Name'] )
     1101                sprintf( __( 'Select %s' ), $plugin_data['Name'] ),
     1102                esc_attr( $plugin_file )
    10021103            );
    10031104        }
     
    10081109        }
    10091110
    1010         if ( ! empty( $totals['upgrade'] ) && ! empty( $plugin_data['update'] )
    1011             || ! $compatible_php || ! $compatible_wp
     1111        if (
     1112            ! empty( $totals['upgrade'] ) &&
     1113            ! empty( $plugin_data['update'] ) ||
     1114            ! $compatible_php ||
     1115            ! $compatible_wp
    10121116        ) {
    10131117            $class .= ' update';
     
    10581162
    10591163                    $plugin_meta = array();
     1164
    10601165                    if ( ! empty( $plugin_data['Version'] ) ) {
    10611166                        /* translators: %s: Plugin version number. */
    10621167                        $plugin_meta[] = sprintf( __( 'Version %s' ), $plugin_data['Version'] );
    10631168                    }
     1169
    10641170                    if ( ! empty( $plugin_data['Author'] ) ) {
    10651171                        $author = $plugin_data['Author'];
     1172
    10661173                        if ( ! empty( $plugin_data['AuthorURI'] ) ) {
    10671174                            $author = '<a href="' . $plugin_data['AuthorURI'] . '">' . $plugin_data['Author'] . '</a>';
    10681175                        }
     1176
    10691177                        /* translators: %s: Plugin author name. */
    10701178                        $plugin_meta[] = sprintf( __( 'By %s' ), $author );
     
    11501258                    echo '</div>';
    11511259
     1260
     1261
     1262
     1263
     1264
     1265
     1266
     1267
     1268
     1269
     1270
     1271
     1272
     1273
     1274
     1275
     1276
     1277
    11521278                    if ( $paused ) {
    11531279                        $notice_text = __( 'This plugin failed to load properly and is paused during recovery mode.' );
     
    13921518        return 'name';
    13931519    }
     1520
     1521
     1522
     1523
     1524
     1525
     1526
     1527
     1528
     1529
     1530
     1531
     1532
     1533
     1534
     1535
     1536
     1537
     1538
     1539
     1540
     1541
     1542
     1543
     1544
     1545
     1546
     1547
     1548
     1549
     1550
     1551
     1552
     1553
     1554
     1555
     1556
     1557
     1558
     1559
     1560
     1561
     1562
     1563
     1564
     1565
     1566
     1567
     1568
     1569
     1570
     1571
     1572
     1573
     1574
     1575
     1576
     1577
     1578
     1579
     1580
     1581
     1582
     1583
     1584
     1585
     1586
     1587
     1588
     1589
     1590
     1591
     1592
     1593
     1594
     1595
     1596
     1597
     1598
     1599
     1600
     1601
     1602
     1603
     1604
     1605
     1606
     1607
     1608
     1609
     1610
     1611
     1612
     1613
     1614
     1615
     1616
     1617
     1618
     1619
     1620
     1621
     1622
     1623
     1624
     1625
     1626
    13941627}
  • trunk/src/wp-admin/includes/plugin-install.php

    r56571 r57545  
    885885    echo "<div id='$tab-footer'>\n";
    886886    if ( ! empty( $api->download_link ) && ( current_user_can( 'install_plugins' ) || current_user_can( 'update_plugins' ) ) ) {
    887         $status = install_plugin_install_status( $api );
     887        $button = wp_get_plugin_action_button( $api->name, $api, $compatible_php, $compatible_wp );
     888        $button = str_replace( 'class="', 'class="right ', $button );
     889
     890        if ( ! str_contains( $button, __( 'Activate' ) ) ) {
     891            $button = str_replace( 'class="', 'id="plugin_install_from_iframe" class="', $button );
     892        }
     893
     894        echo wp_kses_post( $button );
     895    }
     896    echo "</div>\n";
     897
     898    wp_print_request_filesystem_credentials_modal();
     899    wp_print_admin_notice_templates();
     900
     901    iframe_footer();
     902    exit;
     903}
     904
     905/**
     906 * Gets the markup for the plugin install action button.
     907 *
     908 * @since 6.5.0
     909 *
     910 * @param string       $name           Plugin name.
     911 * @param array|object $data           {
     912 *     An array or object of plugin data. Can be retrieved from the API.
     913 *
     914 *     @type string   $slug             The plugin slug.
     915 *     @type string[] $requires_plugins An array of plugin dependency slugs.
     916 *     @type string   $version          The plugin's version string. Used when getting the install status.
     917 * }
     918 * @param bool         $compatible_php   The result of a PHP compatibility check.
     919 * @param bool         $compatible_wp    The result of a WP compatibility check.
     920 * @return string $button The markup for the dependency row button.
     921 */
     922function wp_get_plugin_action_button( $name, $data, $compatible_php, $compatible_wp ) {
     923    $button           = '';
     924    $data             = (object) $data;
     925    $status           = install_plugin_install_status( $data );
     926    $requires_plugins = $data->requires_plugins ?? array();
     927
     928    // Determine the status of plugin dependencies.
     929    $installed_plugins                   = get_plugins();
     930    $active_plugins                      = get_option( 'active_plugins' );
     931    $plugin_dependencies_count           = count( $requires_plugins );
     932    $installed_plugin_dependencies_count = 0;
     933    $active_plugin_dependencies_count    = 0;
     934    foreach ( $requires_plugins as $dependency ) {
     935        foreach ( array_keys( $installed_plugins ) as $installed_plugin_file ) {
     936            if ( str_contains( $installed_plugin_file, '/' ) && explode( '/', $installed_plugin_file )[0] === $dependency ) {
     937                ++$installed_plugin_dependencies_count;
     938            }
     939        }
     940
     941        foreach ( $active_plugins as $active_plugin_file ) {
     942            if ( str_contains( $active_plugin_file, '/' ) && explode( '/', $active_plugin_file )[0] === $dependency ) {
     943                ++$active_plugin_dependencies_count;
     944            }
     945        }
     946    }
     947    $all_plugin_dependencies_installed = $installed_plugin_dependencies_count === $plugin_dependencies_count;
     948    $all_plugin_dependencies_active    = $active_plugin_dependencies_count === $plugin_dependencies_count;
     949
     950    sprintf(
     951        '<a class="install-now button" data-slug="%s" href="%s" aria-label="%s" data-name="%s">%s</a>',
     952        esc_attr( $data->slug ),
     953        esc_url( $status['url'] ),
     954        /* translators: %s: Plugin name and version. */
     955        esc_attr( sprintf( _x( 'Install %s now', 'plugin' ), $name ) ),
     956        esc_attr( $name ),
     957        __( 'Install Now' )
     958    );
     959
     960    if ( current_user_can( 'install_plugins' ) || current_user_can( 'update_plugins' ) ) {
    888961        switch ( $status['status'] ) {
    889962            case 'install':
    890963                if ( $status['url'] ) {
    891                     if ( $compatible_php && $compatible_wp ) {
    892                         echo '<a data-slug="' . esc_attr( $api->slug ) . '" id="plugin_install_from_iframe" class="button button-primary right" href="' . $status['url'] . '" target="_parent">' . __( 'Install Now' ) . '</a>';
     964                    if ( $compatible_php && $compatible_wp && $all_plugin_dependencies_installed && ! empty( $data->download_link ) ) {
     965                        $button = sprintf(
     966                            '<a class="install-now button" data-slug="%s" href="%s" aria-label="%s" data-name="%s">%s</a>',
     967                            esc_attr( $data->slug ),
     968                            esc_url( $status['url'] ),
     969                            /* translators: %s: Plugin name and version. */
     970                            esc_attr( sprintf( _x( 'Install %s now', 'plugin' ), $name ) ),
     971                            esc_attr( $name ),
     972                            __( 'Install Now' )
     973                        );
    893974                    } else {
    894                         printf(
    895                             '<button type="button" class="button button-primary button-disabled right" disabled="disabled">%s</button>',
    896                             _x( 'Cannot Install', 'plugin' )
     975                        printf(
     976                            '<button type="button" class="" disabled="disabled">%s</button>',
     977                            _x( '', 'plugin' )
    897978                        );
    898979                    }
    899980                }
    900981                break;
     982
    901983            case 'update_available':
    902984                if ( $status['url'] ) {
    903                     if ( $compatible_php ) {
    904                         echo '<a data-slug="' . esc_attr( $api->slug ) . '" data-plugin="' . esc_attr( $status['file'] ) . '" id="plugin_update_from_iframe" class="button button-primary right" href="' . $status['url'] . '" target="_parent">' . __( 'Install Update Now' ) . '</a>';
     985                    if ( $compatible_php && $compatible_wp ) {
     986                        $button = sprintf(
     987                            '<a class="update-now button aria-button-if-js" data-plugin="%s" data-slug="%s" href="%s" aria-label="%s" data-name="%s">%s</a>',
     988                            esc_attr( $status['file'] ),
     989                            esc_attr( $data->slug ),
     990                            esc_url( $status['url'] ),
     991                            /* translators: %s: Plugin name and version. */
     992                            esc_attr( sprintf( _x( 'Update %s now', 'plugin' ), $name ) ),
     993                            esc_attr( $name ),
     994                            __( 'Update Now' )
     995                        );
    905996                    } else {
    906                         printf(
    907                             '<button type="button" class="button button-primary button-disabled right" disabled="disabled">%s</button>',
    908                             _x( 'Cannot Update', 'plugin' )
     997                        printf(
     998                            '<button type="button" class="button button-" disabled="disabled">%s</button>',
     999                            _x( '', 'plugin' )
    9091000                        );
    9101001                    }
    9111002                }
    9121003                break;
     1004
     1005
    9131006            case 'newer_installed':
    914                 /* translators: %s: Plugin version. */
    915                 echo '<a class="button button-primary right disabled">' . sprintf( __( 'Newer Version (%s) Installed' ), esc_html( $status['version'] ) ) . '</a>';
     1007                if ( is_plugin_active( $status['file'] ) ) {
     1008                    $button = sprintf(
     1009                        '<button type="button" class="button button-disabled" disabled="disabled">%s</button>',
     1010                        _x( 'Active', 'plugin' )
     1011                    );
     1012                } elseif ( current_user_can( 'activate_plugin', $status['file'] ) ) {
     1013                    if ( $compatible_php && $compatible_wp && $all_plugin_dependencies_active ) {
     1014                        $button_text = __( 'Activate' );
     1015                        /* translators: %s: Plugin name. */
     1016                        $button_label = _x( 'Activate %s', 'plugin' );
     1017                        $activate_url = add_query_arg(
     1018                            array(
     1019                                '_wpnonce' => wp_create_nonce( 'activate-plugin_' . $status['file'] ),
     1020                                'action'   => 'activate',
     1021                                'plugin'   => $status['file'],
     1022                            ),
     1023                            network_admin_url( 'plugins.php' )
     1024                        );
     1025
     1026                        if ( is_network_admin() ) {
     1027                            $button_text = __( 'Network Activate' );
     1028                            /* translators: %s: Plugin name. */
     1029                            $button_label = _x( 'Network Activate %s', 'plugin' );
     1030                            $activate_url = add_query_arg( array( 'networkwide' => 1 ), $activate_url );
     1031                        }
     1032
     1033                        $button = sprintf(
     1034                            '<a href="%1$s" data-name="%2$s" data-slug="%3$s" data-plugin="%4$s" class="button button-primary activate-now" aria-label="%5$s">%6$s</a>',
     1035                            esc_url( $activate_url ),
     1036                            esc_attr( $name ),
     1037                            esc_attr( $data->slug ),
     1038                            esc_attr( $status['file'] ),
     1039                            esc_attr( sprintf( $button_label, $name ) ),
     1040                            $button_text
     1041                        );
     1042                    } else {
     1043                        $button = sprintf(
     1044                            '<button type="button" class="button button-disabled" disabled="disabled">%s</button>',
     1045                            is_network_admin() ? _x( 'Network Activate %s', 'plugin' ) : _x( 'Activate', 'plugin' )
     1046                        );
     1047                    }
     1048                } else {
     1049                    $button = sprintf(
     1050                        '<button type="button" class="button button-disabled" disabled="disabled">%s</button>',
     1051                        _x( 'Installed', 'plugin' )
     1052                    );
     1053                }
    9161054                break;
    917             case 'latest_installed':
    918                 echo '<a class="button button-primary right disabled">' . __( 'Latest Version Installed' ) . '</a>';
    919                 break;
    920         }
    921     }
    922     echo "</div>\n";
    923 
    924     iframe_footer();
    925     exit;
     1055        }
     1056
     1057        return $button;
     1058    }
    9261059}
  • trunk/src/wp-admin/includes/plugin.php

    r57337 r57545  
    4646 * @since 5.3.0 Added support for `Requires at least` and `Requires PHP` headers.
    4747 * @since 5.8.0 Added support for `Update URI` header.
     48
    4849 *
    4950 * @param string $plugin_file Absolute path to the main plugin file.
     
    5455 *     Plugin data. Values will be empty if not supplied by the plugin.
    5556 *
    56  *     @type string $Name        Name of the plugin. Should be unique.
    57  *     @type string $PluginURI   Plugin URI.
    58  *     @type string $Version     Plugin version.
    59  *     @type string $Description Plugin description.
    60  *     @type string $Author      Plugin author's name.
    61  *     @type string $AuthorURI   Plugin author's website address (if set).
    62  *     @type string $TextDomain  Plugin textdomain.
    63  *     @type string $DomainPath  Plugin's relative directory path to .mo files.
    64  *     @type bool   $Network     Whether the plugin can only be activated network-wide.
    65  *     @type string $RequiresWP  Minimum required version of WordPress.
    66  *     @type string $RequiresPHP Minimum required version of PHP.
    67  *     @type string $UpdateURI   ID of the plugin for update purposes, should be a URI.
    68  *     @type string $Title       Title of the plugin and link to the plugin's site (if set).
    69  *     @type string $AuthorName  Plugin author's name.
     57 *     @type string $Name            Name of the plugin. Should be unique.
     58 *     @type string $PluginURI       Plugin URI.
     59 *     @type string $Version         Plugin version.
     60 *     @type string $Description     Plugin description.
     61 *     @type string $Author          Plugin author's name.
     62 *     @type string $AuthorURI       Plugin author's website address (if set).
     63 *     @type string $TextDomain      Plugin textdomain.
     64 *     @type string $DomainPath      Plugin's relative directory path to .mo files.
     65 *     @type bool   $Network         Whether the plugin can only be activated network-wide.
     66 *     @type string $RequiresWP      Minimum required version of WordPress.
     67 *     @type string $RequiresPHP     Minimum required version of PHP.
     68 *     @type string $UpdateURI       ID of the plugin for update purposes, should be a URI.
     69 *     @type string $RequiresPlugins Comma separated list of dot org plugin slugs.
     70 *     @type string $Title           Title of the plugin and link to the plugin's site (if set).
     71 *     @type string $AuthorName      Plugin author's name.
    7072 * }
    7173 */
     
    7375
    7476    $default_headers = array(
    75         'Name'        => 'Plugin Name',
    76         'PluginURI'   => 'Plugin URI',
    77         'Version'     => 'Version',
    78         'Description' => 'Description',
    79         'Author'      => 'Author',
    80         'AuthorURI'   => 'Author URI',
    81         'TextDomain'  => 'Text Domain',
    82         'DomainPath'  => 'Domain Path',
    83         'Network'     => 'Network',
    84         'RequiresWP'  => 'Requires at least',
    85         'RequiresPHP' => 'Requires PHP',
    86         'UpdateURI'   => 'Update URI',
     77        'Name'            => 'Plugin Name',
     78        'PluginURI'       => 'Plugin URI',
     79        'Version'         => 'Version',
     80        'Description'     => 'Description',
     81        'Author'          => 'Author',
     82        'AuthorURI'       => 'Author URI',
     83        'TextDomain'      => 'Text Domain',
     84        'DomainPath'      => 'Domain Path',
     85        'Network'         => 'Network',
     86        'RequiresWP'      => 'Requires at least',
     87        'RequiresPHP'     => 'Requires PHP',
     88        'UpdateURI'       => 'Update URI',
     89        'RequiresPlugins' => 'Requires Plugins',
    8790        // Site Wide Only is deprecated in favor of Network.
    88         '_sitewide'   => 'Site Wide Only',
     91        '_sitewide'   => 'Site Wide Only',
    8992    );
    9093
     
    331334    }
    332335
     336
    333337    foreach ( $plugin_files as $plugin_file ) {
    334338        if ( ! is_readable( "$plugin_root/$plugin_file" ) ) {
     
    343347        }
    344348
     349
     350
     351
     352
     353
     354
     355
    345356        $wp_plugins[ plugin_basename( $plugin_file ) ] = $plugin_data;
    346357    }
     
    350361    $cache_plugins[ $plugin_folder ] = $wp_plugins;
    351362    wp_cache_set( 'plugins', $cache_plugins, 'plugins' );
     363
    352364
    353365    return $wp_plugins;
     
    952964
    953965    $plugin_translations = wp_get_installed_translations( 'plugins' );
     966
    954967
    955968    $errors = array();
     
    9961009            continue;
    9971010        }
     1011
    9981012
    9991013        $plugin_slug = dirname( $plugin_file );
     
    10441058        return new WP_Error( 'could_not_remove_plugin', sprintf( $message, implode( ', ', $errors ) ) );
    10451059    }
     1060
    10461061
    10471062    return true;
     
    11151130 * Validates the plugin requirements for WordPress version and PHP version.
    11161131 *
    1117  * Uses the information from `Requires at least` and `Requires PHP` headers
     1132 * Uses the information from `Requires at least`` headers
    11181133 * defined in the plugin's main PHP file.
    11191134 *
     
    11221137 *              main PHP file, with `readme.txt` as a fallback.
    11231138 * @since 5.8.0 Removed support for using `readme.txt` as a fallback.
     1139
    11241140 *
    11251141 * @param string $plugin Path to the plugin file relative to the plugins directory.
     
    11301146
    11311147    $requirements = array(
    1132         'requires'     => ! empty( $plugin_headers['RequiresWP'] ) ? $plugin_headers['RequiresWP'] : '',
    1133         'requires_php' => ! empty( $plugin_headers['RequiresPHP'] ) ? $plugin_headers['RequiresPHP'] : '',
     1148        'requires'         => ! empty( $plugin_headers['RequiresWP'] ) ? $plugin_headers['RequiresWP'] : '',
     1149        'requires_php'     => ! empty( $plugin_headers['RequiresPHP'] ) ? $plugin_headers['RequiresPHP'] : '',
     1150        'requires_plugins' => ! empty( $plugin_headers['RequiresPlugins'] ) ? $plugin_headers['RequiresPlugins'] : '',
    11341151    );
    11351152
     
    11861203    }
    11871204
     1205
     1206
     1207
     1208
     1209
     1210
     1211
     1212
     1213
     1214
     1215
     1216
     1217
     1218
     1219
     1220
     1221
     1222
     1223
     1224
     1225
     1226
     1227
     1228
     1229
    11881230    return true;
    11891231}
  • trunk/src/wp-admin/plugin-install.php

    r55412 r57545  
    135135 */
    136136require_once ABSPATH . 'wp-admin/admin-header.php';
     137
     138
     139
     140
    137141?>
    138142<div class="wrap <?php echo esc_attr( "plugin-install-tab-$tab" ); ?>">
  • trunk/src/wp-admin/plugins.php

    r56695 r57545  
    740740?>
    741741
     742
     743
     744
    742745<div class="wrap">
    743746<h1 class="wp-heading-inline">
  • trunk/src/wp-includes/functions.php

    r57543 r57545  
    33603360         */
    33613361
    3362          // Divide the header string into 4 byte groups.
     3362        // Divide the header string into 4 byte groups.
    33633363        $magic = str_split( $magic, 8 );
    33643364
  • trunk/src/wp-includes/load.php

    r57504 r57545  
    987987    $network_plugins = is_multisite() ? wp_get_active_network_plugins() : false;
    988988
     989
    989990    foreach ( $active_plugins as $plugin ) {
    990991        if ( ! validate_file( $plugin )                     // $plugin must validate as file.
     
    995996        ) {
    996997            $plugins[] = WP_PLUGIN_DIR . '/' . $plugin;
     998
     999
     1000
     1001
     1002
     1003
     1004
     1005
     1006
     1007
     1008
     1009
     1010
     1011
    9971012        }
    9981013    }
     
    11911206        'update-plugin',          // Update an existing plugin.
    11921207        'update-theme',           // Update an existing theme.
     1208
    11931209    );
    11941210
  • trunk/src/wp-settings.php

    r57539 r57545  
    413413$GLOBALS['wp_plugin_paths'] = array();
    414414
     415
     416
     417
     418
     419
     420
    415421// Load must-use plugins.
    416422foreach ( wp_get_mu_plugins() as $mu_plugin ) {
     
    487493
    488494// Load active plugins.
     495
     496
     497
    489498foreach ( wp_get_active_and_valid_plugins() as $plugin ) {
     499
     500
     501
     502
     503
     504
     505
     506
     507
     508
     509
     510
     511
     512
     513
     514
     515
     516
     517
     518
     519
     520
     521
     522
     523
     524
     525
     526
     527
     528
     529
     530
     531
     532
     533
     534
     535
     536
     537
     538
     539
     540
     541
     542
     543
     544
     545
     546
     547
     548
     549
     550
     551
     552
     553
     554
     555
     556
     557
     558
     559
     560
     561
     562
     563
     564
     565
     566
     567
     568
     569
     570
     571
     572
     573
     574
     575
     576
     577
     578
     579
    490580    wp_register_plugin_realpath( $plugin );
    491581
     
    505595unset( $plugin, $_wp_plugin_file );
    506596
     597
     598
     599
     600
     601
     602
     603
     604
     605
     606
     607
     608
     609
     610
     611
     612
     613
     614
    507615// Load pluggable functions.
    508616require ABSPATH . WPINC . '/pluggable.php';
Note: See TracChangeset for help on using the changeset viewer.