script-loader.php 133 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705
  1. <?php
  2. /**
  3. * WordPress scripts and styles default loader.
  4. *
  5. * Several constants are used to manage the loading, concatenating and compression of scripts and CSS:
  6. * define('SCRIPT_DEBUG', true); loads the development (non-minified) versions of all scripts and CSS, and disables compression and concatenation,
  7. * define('CONCATENATE_SCRIPTS', false); disables compression and concatenation of scripts and CSS,
  8. * define('COMPRESS_SCRIPTS', false); disables compression of scripts,
  9. * define('COMPRESS_CSS', false); disables compression of CSS,
  10. * define('ENFORCE_GZIP', true); forces gzip for compression (default is deflate).
  11. *
  12. * The globals $concatenate_scripts, $compress_scripts and $compress_css can be set by plugins
  13. * to temporarily override the above settings. Also a compression test is run once and the result is saved
  14. * as option 'can_compress_scripts' (0/1). The test will run again if that option is deleted.
  15. *
  16. * @package WordPress
  17. */
  18. /** WordPress Dependency Class */
  19. require ABSPATH . WPINC . '/class-wp-dependency.php';
  20. /** WordPress Dependencies Class */
  21. require ABSPATH . WPINC . '/class-wp-dependencies.php';
  22. /** WordPress Scripts Class */
  23. require ABSPATH . WPINC . '/class-wp-scripts.php';
  24. /** WordPress Scripts Functions */
  25. require ABSPATH . WPINC . '/functions.wp-scripts.php';
  26. /** WordPress Styles Class */
  27. require ABSPATH . WPINC . '/class-wp-styles.php';
  28. /** WordPress Styles Functions */
  29. require ABSPATH . WPINC . '/functions.wp-styles.php';
  30. /**
  31. * Registers TinyMCE scripts.
  32. *
  33. * @since 5.0.0
  34. *
  35. * @global string $tinymce_version
  36. * @global bool $concatenate_scripts
  37. * @global bool $compress_scripts
  38. *
  39. * @param WP_Scripts $scripts WP_Scripts object.
  40. * @param bool $force_uncompressed Whether to forcibly prevent gzip compression. Default false.
  41. */
  42. function wp_register_tinymce_scripts( $scripts, $force_uncompressed = false ) {
  43. global $tinymce_version, $concatenate_scripts, $compress_scripts;
  44. $suffix = wp_scripts_get_suffix();
  45. $dev_suffix = wp_scripts_get_suffix( 'dev' );
  46. script_concat_settings();
  47. $compressed = $compress_scripts && $concatenate_scripts && isset( $_SERVER['HTTP_ACCEPT_ENCODING'] )
  48. && false !== stripos( $_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip' ) && ! $force_uncompressed;
  49. // Load tinymce.js when running from /src, otherwise load wp-tinymce.js.gz (in production)
  50. // or tinymce.min.js (when SCRIPT_DEBUG is true).
  51. if ( $compressed ) {
  52. $scripts->add( 'wp-tinymce', includes_url( 'js/tinymce/' ) . 'wp-tinymce.js', array(), $tinymce_version );
  53. } else {
  54. $scripts->add( 'wp-tinymce-root', includes_url( 'js/tinymce/' ) . "tinymce$dev_suffix.js", array(), $tinymce_version );
  55. $scripts->add( 'wp-tinymce', includes_url( 'js/tinymce/' ) . "plugins/compat3x/plugin$dev_suffix.js", array( 'wp-tinymce-root' ), $tinymce_version );
  56. }
  57. $scripts->add( 'wp-tinymce-lists', includes_url( "js/tinymce/plugins/lists/plugin$suffix.js" ), array( 'wp-tinymce' ), $tinymce_version );
  58. }
  59. /**
  60. * Registers all the WordPress vendor scripts that are in the standardized
  61. * `js/dist/vendor/` location.
  62. *
  63. * For the order of `$scripts->add` see `wp_default_scripts`.
  64. *
  65. * @since 5.0.0
  66. *
  67. * @global WP_Locale $wp_locale WordPress date and time locale object.
  68. *
  69. * @param WP_Scripts $scripts WP_Scripts object.
  70. */
  71. function wp_default_packages_vendor( $scripts ) {
  72. global $wp_locale;
  73. $suffix = wp_scripts_get_suffix();
  74. $vendor_scripts = array(
  75. 'react' => array( 'wp-polyfill' ),
  76. 'react-dom' => array( 'react' ),
  77. 'regenerator-runtime',
  78. 'moment',
  79. 'lodash',
  80. 'wp-polyfill-fetch',
  81. 'wp-polyfill-formdata',
  82. 'wp-polyfill-node-contains',
  83. 'wp-polyfill-url',
  84. 'wp-polyfill-dom-rect',
  85. 'wp-polyfill-element-closest',
  86. 'wp-polyfill-object-fit',
  87. 'wp-polyfill' => array( 'regenerator-runtime' ),
  88. );
  89. $vendor_scripts_versions = array(
  90. 'react' => '17.0.1',
  91. 'react-dom' => '17.0.1',
  92. 'regenerator-runtime' => '0.13.9',
  93. 'moment' => '2.29.4',
  94. 'lodash' => '4.17.19',
  95. 'wp-polyfill-fetch' => '3.6.2',
  96. 'wp-polyfill-formdata' => '4.0.10',
  97. 'wp-polyfill-node-contains' => '4.4.0',
  98. 'wp-polyfill-url' => '3.6.4',
  99. 'wp-polyfill-dom-rect' => '4.4.0',
  100. 'wp-polyfill-element-closest' => '2.0.2',
  101. 'wp-polyfill-object-fit' => '2.3.5',
  102. 'wp-polyfill' => '3.15.0',
  103. );
  104. foreach ( $vendor_scripts as $handle => $dependencies ) {
  105. if ( is_string( $dependencies ) ) {
  106. $handle = $dependencies;
  107. $dependencies = array();
  108. }
  109. $path = "/wp-includes/js/dist/vendor/$handle$suffix.js";
  110. $version = $vendor_scripts_versions[ $handle ];
  111. $scripts->add( $handle, $path, $dependencies, $version, 1 );
  112. }
  113. did_action( 'init' ) && $scripts->add_inline_script( 'lodash', 'window.lodash = _.noConflict();' );
  114. did_action( 'init' ) && $scripts->add_inline_script(
  115. 'moment',
  116. sprintf(
  117. "moment.updateLocale( '%s', %s );",
  118. get_user_locale(),
  119. wp_json_encode(
  120. array(
  121. 'months' => array_values( $wp_locale->month ),
  122. 'monthsShort' => array_values( $wp_locale->month_abbrev ),
  123. 'weekdays' => array_values( $wp_locale->weekday ),
  124. 'weekdaysShort' => array_values( $wp_locale->weekday_abbrev ),
  125. 'week' => array(
  126. 'dow' => (int) get_option( 'start_of_week', 0 ),
  127. ),
  128. 'longDateFormat' => array(
  129. 'LT' => get_option( 'time_format', __( 'g:i a' ) ),
  130. 'LTS' => null,
  131. 'L' => null,
  132. 'LL' => get_option( 'date_format', __( 'F j, Y' ) ),
  133. 'LLL' => __( 'F j, Y g:i a' ),
  134. 'LLLL' => null,
  135. ),
  136. )
  137. )
  138. ),
  139. 'after'
  140. );
  141. }
  142. /**
  143. * Returns contents of an inline script used in appending polyfill scripts for
  144. * browsers which fail the provided tests. The provided array is a mapping from
  145. * a condition to verify feature support to its polyfill script handle.
  146. *
  147. * @since 5.0.0
  148. *
  149. * @param WP_Scripts $scripts WP_Scripts object.
  150. * @param string[] $tests Features to detect.
  151. * @return string Conditional polyfill inline script.
  152. */
  153. function wp_get_script_polyfill( $scripts, $tests ) {
  154. $polyfill = '';
  155. foreach ( $tests as $test => $handle ) {
  156. if ( ! array_key_exists( $handle, $scripts->registered ) ) {
  157. continue;
  158. }
  159. $src = $scripts->registered[ $handle ]->src;
  160. $ver = $scripts->registered[ $handle ]->ver;
  161. if ( ! preg_match( '|^(https?:)?//|', $src ) && ! ( $scripts->content_url && 0 === strpos( $src, $scripts->content_url ) ) ) {
  162. $src = $scripts->base_url . $src;
  163. }
  164. if ( ! empty( $ver ) ) {
  165. $src = add_query_arg( 'ver', $ver, $src );
  166. }
  167. /** This filter is documented in wp-includes/class-wp-scripts.php */
  168. $src = esc_url( apply_filters( 'script_loader_src', $src, $handle ) );
  169. if ( ! $src ) {
  170. continue;
  171. }
  172. $polyfill .= (
  173. // Test presence of feature...
  174. '( ' . $test . ' ) || ' .
  175. /*
  176. * ...appending polyfill on any failures. Cautious viewers may balk
  177. * at the `document.write`. Its caveat of synchronous mid-stream
  178. * blocking write is exactly the behavior we need though.
  179. */
  180. 'document.write( \'<script src="' .
  181. $src .
  182. '"></scr\' + \'ipt>\' );'
  183. );
  184. }
  185. return $polyfill;
  186. }
  187. /**
  188. * Registers development scripts that integrate with `@wordpress/scripts`.
  189. *
  190. * @see https://github.com/WordPress/gutenberg/tree/trunk/packages/scripts#start
  191. *
  192. * @since 6.0.0
  193. *
  194. * @param WP_Scripts $scripts WP_Scripts object.
  195. */
  196. function wp_register_development_scripts( $scripts ) {
  197. if (
  198. ! defined( 'SCRIPT_DEBUG' ) || ! SCRIPT_DEBUG
  199. || empty( $scripts->registered['react'] )
  200. || defined( 'WP_RUN_CORE_TESTS' )
  201. ) {
  202. return;
  203. }
  204. $development_scripts = array(
  205. 'react-refresh-entry',
  206. 'react-refresh-runtime',
  207. );
  208. foreach ( $development_scripts as $script_name ) {
  209. $assets = include ABSPATH . WPINC . '/assets/script-loader-' . $script_name . '.php';
  210. if ( ! is_array( $assets ) ) {
  211. return;
  212. }
  213. $scripts->add(
  214. 'wp-' . $script_name,
  215. '/wp-includes/js/dist/development/' . $script_name . '.js',
  216. $assets['dependencies'],
  217. $assets['version']
  218. );
  219. }
  220. // See https://github.com/pmmmwh/react-refresh-webpack-plugin/blob/main/docs/TROUBLESHOOTING.md#externalising-react.
  221. $scripts->registered['react']->deps[] = 'wp-react-refresh-entry';
  222. }
  223. /**
  224. * Registers all the WordPress packages scripts that are in the standardized
  225. * `js/dist/` location.
  226. *
  227. * For the order of `$scripts->add` see `wp_default_scripts`.
  228. *
  229. * @since 5.0.0
  230. *
  231. * @param WP_Scripts $scripts WP_Scripts object.
  232. */
  233. function wp_default_packages_scripts( $scripts ) {
  234. $suffix = defined( 'WP_RUN_CORE_TESTS' ) ? '.min' : wp_scripts_get_suffix();
  235. /*
  236. * Expects multidimensional array like:
  237. *
  238. * 'a11y.js' => array('dependencies' => array(...), 'version' => '...'),
  239. * 'annotations.js' => array('dependencies' => array(...), 'version' => '...'),
  240. * 'api-fetch.js' => array(...
  241. */
  242. $assets = include ABSPATH . WPINC . "/assets/script-loader-packages{$suffix}.php";
  243. foreach ( $assets as $file_name => $package_data ) {
  244. $basename = str_replace( $suffix . '.js', '', basename( $file_name ) );
  245. $handle = 'wp-' . $basename;
  246. $path = "/wp-includes/js/dist/{$basename}{$suffix}.js";
  247. if ( ! empty( $package_data['dependencies'] ) ) {
  248. $dependencies = $package_data['dependencies'];
  249. } else {
  250. $dependencies = array();
  251. }
  252. // Add dependencies that cannot be detected and generated by build tools.
  253. switch ( $handle ) {
  254. case 'wp-block-library':
  255. array_push( $dependencies, 'editor' );
  256. break;
  257. case 'wp-edit-post':
  258. array_push( $dependencies, 'media-models', 'media-views', 'postbox', 'wp-dom-ready' );
  259. break;
  260. case 'wp-preferences':
  261. array_push( $dependencies, 'wp-preferences-persistence' );
  262. break;
  263. }
  264. $scripts->add( $handle, $path, $dependencies, $package_data['version'], 1 );
  265. if ( in_array( 'wp-i18n', $dependencies, true ) ) {
  266. $scripts->set_translations( $handle );
  267. }
  268. /*
  269. * Manually set the text direction localization after wp-i18n is printed.
  270. * This ensures that wp.i18n.isRTL() returns true in RTL languages.
  271. * We cannot use $scripts->set_translations( 'wp-i18n' ) to do this
  272. * because WordPress prints a script's translations *before* the script,
  273. * which means, in the case of wp-i18n, that wp.i18n.setLocaleData()
  274. * is called before wp.i18n is defined.
  275. */
  276. if ( 'wp-i18n' === $handle ) {
  277. $ltr = _x( 'ltr', 'text direction' );
  278. $script = sprintf( "wp.i18n.setLocaleData( { 'text direction\u0004ltr': [ '%s' ] } );", $ltr );
  279. $scripts->add_inline_script( $handle, $script, 'after' );
  280. }
  281. }
  282. }
  283. /**
  284. * Adds inline scripts required for the WordPress JavaScript packages.
  285. *
  286. * @since 5.0.0
  287. *
  288. * @global WP_Locale $wp_locale WordPress date and time locale object.
  289. * @global wpdb $wpdb WordPress database abstraction object.
  290. *
  291. * @param WP_Scripts $scripts WP_Scripts object.
  292. */
  293. function wp_default_packages_inline_scripts( $scripts ) {
  294. global $wp_locale, $wpdb;
  295. if ( isset( $scripts->registered['wp-api-fetch'] ) ) {
  296. $scripts->registered['wp-api-fetch']->deps[] = 'wp-hooks';
  297. }
  298. $scripts->add_inline_script(
  299. 'wp-api-fetch',
  300. sprintf(
  301. 'wp.apiFetch.use( wp.apiFetch.createRootURLMiddleware( "%s" ) );',
  302. sanitize_url( get_rest_url() )
  303. ),
  304. 'after'
  305. );
  306. $scripts->add_inline_script(
  307. 'wp-api-fetch',
  308. implode(
  309. "\n",
  310. array(
  311. sprintf(
  312. 'wp.apiFetch.nonceMiddleware = wp.apiFetch.createNonceMiddleware( "%s" );',
  313. wp_installing() ? '' : wp_create_nonce( 'wp_rest' )
  314. ),
  315. 'wp.apiFetch.use( wp.apiFetch.nonceMiddleware );',
  316. 'wp.apiFetch.use( wp.apiFetch.mediaUploadMiddleware );',
  317. sprintf(
  318. 'wp.apiFetch.nonceEndpoint = "%s";',
  319. admin_url( 'admin-ajax.php?action=rest-nonce' )
  320. ),
  321. )
  322. ),
  323. 'after'
  324. );
  325. $meta_key = $wpdb->get_blog_prefix() . 'persisted_preferences';
  326. $user_id = get_current_user_id();
  327. $preload_data = get_user_meta( $user_id, $meta_key, true );
  328. $scripts->add_inline_script(
  329. 'wp-preferences',
  330. sprintf(
  331. '( function() {
  332. var serverData = %s;
  333. var userId = "%d";
  334. var persistenceLayer = wp.preferencesPersistence.__unstableCreatePersistenceLayer( serverData, userId );
  335. var preferencesStore = wp.preferences.store;
  336. wp.data.dispatch( preferencesStore ).setPersistenceLayer( persistenceLayer );
  337. } ) ();',
  338. wp_json_encode( $preload_data ),
  339. $user_id
  340. )
  341. );
  342. // Backwards compatibility - configure the old wp-data persistence system.
  343. $scripts->add_inline_script(
  344. 'wp-data',
  345. implode(
  346. "\n",
  347. array(
  348. '( function() {',
  349. ' var userId = ' . get_current_user_ID() . ';',
  350. ' var storageKey = "WP_DATA_USER_" + userId;',
  351. ' wp.data',
  352. ' .use( wp.data.plugins.persistence, { storageKey: storageKey } );',
  353. '} )();',
  354. )
  355. )
  356. );
  357. // Calculate the timezone abbr (EDT, PST) if possible.
  358. $timezone_string = get_option( 'timezone_string', 'UTC' );
  359. $timezone_abbr = '';
  360. if ( ! empty( $timezone_string ) ) {
  361. $timezone_date = new DateTime( 'now', new DateTimeZone( $timezone_string ) );
  362. $timezone_abbr = $timezone_date->format( 'T' );
  363. }
  364. $scripts->add_inline_script(
  365. 'wp-date',
  366. sprintf(
  367. 'wp.date.setSettings( %s );',
  368. wp_json_encode(
  369. array(
  370. 'l10n' => array(
  371. 'locale' => get_user_locale(),
  372. 'months' => array_values( $wp_locale->month ),
  373. 'monthsShort' => array_values( $wp_locale->month_abbrev ),
  374. 'weekdays' => array_values( $wp_locale->weekday ),
  375. 'weekdaysShort' => array_values( $wp_locale->weekday_abbrev ),
  376. 'meridiem' => (object) $wp_locale->meridiem,
  377. 'relative' => array(
  378. /* translators: %s: Duration. */
  379. 'future' => __( '%s from now' ),
  380. /* translators: %s: Duration. */
  381. 'past' => __( '%s ago' ),
  382. ),
  383. 'startOfWeek' => (int) get_option( 'start_of_week', 0 ),
  384. ),
  385. 'formats' => array(
  386. /* translators: Time format, see https://www.php.net/manual/datetime.format.php */
  387. 'time' => get_option( 'time_format', __( 'g:i a' ) ),
  388. /* translators: Date format, see https://www.php.net/manual/datetime.format.php */
  389. 'date' => get_option( 'date_format', __( 'F j, Y' ) ),
  390. /* translators: Date/Time format, see https://www.php.net/manual/datetime.format.php */
  391. 'datetime' => __( 'F j, Y g:i a' ),
  392. /* translators: Abbreviated date/time format, see https://www.php.net/manual/datetime.format.php */
  393. 'datetimeAbbreviated' => __( 'M j, Y g:i a' ),
  394. ),
  395. 'timezone' => array(
  396. 'offset' => (float) get_option( 'gmt_offset', 0 ),
  397. 'string' => $timezone_string,
  398. 'abbr' => $timezone_abbr,
  399. ),
  400. )
  401. )
  402. ),
  403. 'after'
  404. );
  405. // Loading the old editor and its config to ensure the classic block works as expected.
  406. $scripts->add_inline_script(
  407. 'editor',
  408. 'window.wp.oldEditor = window.wp.editor;',
  409. 'after'
  410. );
  411. /*
  412. * wp-editor module is exposed as window.wp.editor.
  413. * Problem: there is quite some code expecting window.wp.oldEditor object available under window.wp.editor.
  414. * Solution: fuse the two objects together to maintain backward compatibility.
  415. * For more context, see https://github.com/WordPress/gutenberg/issues/33203.
  416. */
  417. $scripts->add_inline_script(
  418. 'wp-editor',
  419. 'Object.assign( window.wp.editor, window.wp.oldEditor );',
  420. 'after'
  421. );
  422. }
  423. /**
  424. * Adds inline scripts required for the TinyMCE in the block editor.
  425. *
  426. * These TinyMCE init settings are used to extend and override the default settings
  427. * from `_WP_Editors::default_settings()` for the Classic block.
  428. *
  429. * @since 5.0.0
  430. *
  431. * @global WP_Scripts $wp_scripts
  432. */
  433. function wp_tinymce_inline_scripts() {
  434. global $wp_scripts;
  435. /** This filter is documented in wp-includes/class-wp-editor.php */
  436. $editor_settings = apply_filters( 'wp_editor_settings', array( 'tinymce' => true ), 'classic-block' );
  437. $tinymce_plugins = array(
  438. 'charmap',
  439. 'colorpicker',
  440. 'hr',
  441. 'lists',
  442. 'media',
  443. 'paste',
  444. 'tabfocus',
  445. 'textcolor',
  446. 'fullscreen',
  447. 'wordpress',
  448. 'wpautoresize',
  449. 'wpeditimage',
  450. 'wpemoji',
  451. 'wpgallery',
  452. 'wplink',
  453. 'wpdialogs',
  454. 'wptextpattern',
  455. 'wpview',
  456. );
  457. /** This filter is documented in wp-includes/class-wp-editor.php */
  458. $tinymce_plugins = apply_filters( 'tiny_mce_plugins', $tinymce_plugins, 'classic-block' );
  459. $tinymce_plugins = array_unique( $tinymce_plugins );
  460. $disable_captions = false;
  461. // Runs after `tiny_mce_plugins` but before `mce_buttons`.
  462. /** This filter is documented in wp-admin/includes/media.php */
  463. if ( apply_filters( 'disable_captions', '' ) ) {
  464. $disable_captions = true;
  465. }
  466. $toolbar1 = array(
  467. 'formatselect',
  468. 'bold',
  469. 'italic',
  470. 'bullist',
  471. 'numlist',
  472. 'blockquote',
  473. 'alignleft',
  474. 'aligncenter',
  475. 'alignright',
  476. 'link',
  477. 'unlink',
  478. 'wp_more',
  479. 'spellchecker',
  480. 'wp_add_media',
  481. 'wp_adv',
  482. );
  483. /** This filter is documented in wp-includes/class-wp-editor.php */
  484. $toolbar1 = apply_filters( 'mce_buttons', $toolbar1, 'classic-block' );
  485. $toolbar2 = array(
  486. 'strikethrough',
  487. 'hr',
  488. 'forecolor',
  489. 'pastetext',
  490. 'removeformat',
  491. 'charmap',
  492. 'outdent',
  493. 'indent',
  494. 'undo',
  495. 'redo',
  496. 'wp_help',
  497. );
  498. /** This filter is documented in wp-includes/class-wp-editor.php */
  499. $toolbar2 = apply_filters( 'mce_buttons_2', $toolbar2, 'classic-block' );
  500. /** This filter is documented in wp-includes/class-wp-editor.php */
  501. $toolbar3 = apply_filters( 'mce_buttons_3', array(), 'classic-block' );
  502. /** This filter is documented in wp-includes/class-wp-editor.php */
  503. $toolbar4 = apply_filters( 'mce_buttons_4', array(), 'classic-block' );
  504. /** This filter is documented in wp-includes/class-wp-editor.php */
  505. $external_plugins = apply_filters( 'mce_external_plugins', array(), 'classic-block' );
  506. $tinymce_settings = array(
  507. 'plugins' => implode( ',', $tinymce_plugins ),
  508. 'toolbar1' => implode( ',', $toolbar1 ),
  509. 'toolbar2' => implode( ',', $toolbar2 ),
  510. 'toolbar3' => implode( ',', $toolbar3 ),
  511. 'toolbar4' => implode( ',', $toolbar4 ),
  512. 'external_plugins' => wp_json_encode( $external_plugins ),
  513. 'classic_block_editor' => true,
  514. );
  515. if ( $disable_captions ) {
  516. $tinymce_settings['wpeditimage_disable_captions'] = true;
  517. }
  518. if ( ! empty( $editor_settings['tinymce'] ) && is_array( $editor_settings['tinymce'] ) ) {
  519. array_merge( $tinymce_settings, $editor_settings['tinymce'] );
  520. }
  521. /** This filter is documented in wp-includes/class-wp-editor.php */
  522. $tinymce_settings = apply_filters( 'tiny_mce_before_init', $tinymce_settings, 'classic-block' );
  523. // Do "by hand" translation from PHP array to js object.
  524. // Prevents breakage in some custom settings.
  525. $init_obj = '';
  526. foreach ( $tinymce_settings as $key => $value ) {
  527. if ( is_bool( $value ) ) {
  528. $val = $value ? 'true' : 'false';
  529. $init_obj .= $key . ':' . $val . ',';
  530. continue;
  531. } elseif ( ! empty( $value ) && is_string( $value ) && (
  532. ( '{' === $value[0] && '}' === $value[ strlen( $value ) - 1 ] ) ||
  533. ( '[' === $value[0] && ']' === $value[ strlen( $value ) - 1 ] ) ||
  534. preg_match( '/^\(?function ?\(/', $value ) ) ) {
  535. $init_obj .= $key . ':' . $value . ',';
  536. continue;
  537. }
  538. $init_obj .= $key . ':"' . $value . '",';
  539. }
  540. $init_obj = '{' . trim( $init_obj, ' ,' ) . '}';
  541. $script = 'window.wpEditorL10n = {
  542. tinymce: {
  543. baseURL: ' . wp_json_encode( includes_url( 'js/tinymce' ) ) . ',
  544. suffix: ' . ( SCRIPT_DEBUG ? '""' : '".min"' ) . ',
  545. settings: ' . $init_obj . ',
  546. }
  547. }';
  548. $wp_scripts->add_inline_script( 'wp-block-library', $script, 'before' );
  549. }
  550. /**
  551. * Registers all the WordPress packages scripts.
  552. *
  553. * @since 5.0.0
  554. *
  555. * @param WP_Scripts $scripts WP_Scripts object.
  556. */
  557. function wp_default_packages( $scripts ) {
  558. wp_default_packages_vendor( $scripts );
  559. wp_register_development_scripts( $scripts );
  560. wp_register_tinymce_scripts( $scripts );
  561. wp_default_packages_scripts( $scripts );
  562. if ( did_action( 'init' ) ) {
  563. wp_default_packages_inline_scripts( $scripts );
  564. }
  565. }
  566. /**
  567. * Returns the suffix that can be used for the scripts.
  568. *
  569. * There are two suffix types, the normal one and the dev suffix.
  570. *
  571. * @since 5.0.0
  572. *
  573. * @param string $type The type of suffix to retrieve.
  574. * @return string The script suffix.
  575. */
  576. function wp_scripts_get_suffix( $type = '' ) {
  577. static $suffixes;
  578. if ( null === $suffixes ) {
  579. // Include an unmodified $wp_version.
  580. require ABSPATH . WPINC . '/version.php';
  581. $develop_src = false !== strpos( $wp_version, '-src' );
  582. if ( ! defined( 'SCRIPT_DEBUG' ) ) {
  583. define( 'SCRIPT_DEBUG', $develop_src );
  584. }
  585. $suffix = SCRIPT_DEBUG ? '' : '.min';
  586. $dev_suffix = $develop_src ? '' : '.min';
  587. $suffixes = array(
  588. 'suffix' => $suffix,
  589. 'dev_suffix' => $dev_suffix,
  590. );
  591. }
  592. if ( 'dev' === $type ) {
  593. return $suffixes['dev_suffix'];
  594. }
  595. return $suffixes['suffix'];
  596. }
  597. /**
  598. * Registers all WordPress scripts.
  599. *
  600. * Localizes some of them.
  601. * args order: `$scripts->add( 'handle', 'url', 'dependencies', 'query-string', 1 );`
  602. * when last arg === 1 queues the script for the footer
  603. *
  604. * @since 2.6.0
  605. *
  606. * @param WP_Scripts $scripts WP_Scripts object.
  607. */
  608. function wp_default_scripts( $scripts ) {
  609. $suffix = wp_scripts_get_suffix();
  610. $dev_suffix = wp_scripts_get_suffix( 'dev' );
  611. $guessurl = site_url();
  612. if ( ! $guessurl ) {
  613. $guessed_url = true;
  614. $guessurl = wp_guess_url();
  615. }
  616. $scripts->base_url = $guessurl;
  617. $scripts->content_url = defined( 'WP_CONTENT_URL' ) ? WP_CONTENT_URL : '';
  618. $scripts->default_version = get_bloginfo( 'version' );
  619. $scripts->default_dirs = array( '/wp-admin/js/', '/wp-includes/js/' );
  620. $scripts->add( 'utils', "/wp-includes/js/utils$suffix.js" );
  621. did_action( 'init' ) && $scripts->localize(
  622. 'utils',
  623. 'userSettings',
  624. array(
  625. 'url' => (string) SITECOOKIEPATH,
  626. 'uid' => (string) get_current_user_id(),
  627. 'time' => (string) time(),
  628. 'secure' => (string) ( 'https' === parse_url( site_url(), PHP_URL_SCHEME ) ),
  629. )
  630. );
  631. $scripts->add( 'common', "/wp-admin/js/common$suffix.js", array( 'jquery', 'hoverIntent', 'utils' ), false, 1 );
  632. $scripts->set_translations( 'common' );
  633. $scripts->add( 'wp-sanitize', "/wp-includes/js/wp-sanitize$suffix.js", array(), false, 1 );
  634. $scripts->add( 'sack', "/wp-includes/js/tw-sack$suffix.js", array(), '1.6.1', 1 );
  635. $scripts->add( 'quicktags', "/wp-includes/js/quicktags$suffix.js", array(), false, 1 );
  636. did_action( 'init' ) && $scripts->localize(
  637. 'quicktags',
  638. 'quicktagsL10n',
  639. array(
  640. 'closeAllOpenTags' => __( 'Close all open tags' ),
  641. 'closeTags' => __( 'close tags' ),
  642. 'enterURL' => __( 'Enter the URL' ),
  643. 'enterImageURL' => __( 'Enter the URL of the image' ),
  644. 'enterImageDescription' => __( 'Enter a description of the image' ),
  645. 'textdirection' => __( 'text direction' ),
  646. 'toggleTextdirection' => __( 'Toggle Editor Text Direction' ),
  647. 'dfw' => __( 'Distraction-free writing mode' ),
  648. 'strong' => __( 'Bold' ),
  649. 'strongClose' => __( 'Close bold tag' ),
  650. 'em' => __( 'Italic' ),
  651. 'emClose' => __( 'Close italic tag' ),
  652. 'link' => __( 'Insert link' ),
  653. 'blockquote' => __( 'Blockquote' ),
  654. 'blockquoteClose' => __( 'Close blockquote tag' ),
  655. 'del' => __( 'Deleted text (strikethrough)' ),
  656. 'delClose' => __( 'Close deleted text tag' ),
  657. 'ins' => __( 'Inserted text' ),
  658. 'insClose' => __( 'Close inserted text tag' ),
  659. 'image' => __( 'Insert image' ),
  660. 'ul' => __( 'Bulleted list' ),
  661. 'ulClose' => __( 'Close bulleted list tag' ),
  662. 'ol' => __( 'Numbered list' ),
  663. 'olClose' => __( 'Close numbered list tag' ),
  664. 'li' => __( 'List item' ),
  665. 'liClose' => __( 'Close list item tag' ),
  666. 'code' => __( 'Code' ),
  667. 'codeClose' => __( 'Close code tag' ),
  668. 'more' => __( 'Insert Read More tag' ),
  669. )
  670. );
  671. $scripts->add( 'colorpicker', "/wp-includes/js/colorpicker$suffix.js", array( 'prototype' ), '3517m' );
  672. $scripts->add( 'editor', "/wp-admin/js/editor$suffix.js", array( 'utils', 'jquery' ), false, 1 );
  673. $scripts->add( 'clipboard', "/wp-includes/js/clipboard$suffix.js", array(), '2.0.11', 1 );
  674. $scripts->add( 'wp-ajax-response', "/wp-includes/js/wp-ajax-response$suffix.js", array( 'jquery', 'wp-a11y' ), false, 1 );
  675. did_action( 'init' ) && $scripts->localize(
  676. 'wp-ajax-response',
  677. 'wpAjax',
  678. array(
  679. 'noPerm' => __( 'Sorry, you are not allowed to do that.' ),
  680. 'broken' => __( 'Something went wrong.' ),
  681. )
  682. );
  683. $scripts->add( 'wp-api-request', "/wp-includes/js/api-request$suffix.js", array( 'jquery' ), false, 1 );
  684. // `wpApiSettings` is also used by `wp-api`, which depends on this script.
  685. did_action( 'init' ) && $scripts->localize(
  686. 'wp-api-request',
  687. 'wpApiSettings',
  688. array(
  689. 'root' => sanitize_url( get_rest_url() ),
  690. 'nonce' => wp_installing() ? '' : wp_create_nonce( 'wp_rest' ),
  691. 'versionString' => 'wp/v2/',
  692. )
  693. );
  694. $scripts->add( 'wp-pointer', "/wp-includes/js/wp-pointer$suffix.js", array( 'jquery-ui-core' ), false, 1 );
  695. $scripts->set_translations( 'wp-pointer' );
  696. $scripts->add( 'autosave', "/wp-includes/js/autosave$suffix.js", array( 'heartbeat' ), false, 1 );
  697. $scripts->add( 'heartbeat', "/wp-includes/js/heartbeat$suffix.js", array( 'jquery', 'wp-hooks' ), false, 1 );
  698. did_action( 'init' ) && $scripts->localize(
  699. 'heartbeat',
  700. 'heartbeatSettings',
  701. /**
  702. * Filters the Heartbeat settings.
  703. *
  704. * @since 3.6.0
  705. *
  706. * @param array $settings Heartbeat settings array.
  707. */
  708. apply_filters( 'heartbeat_settings', array() )
  709. );
  710. $scripts->add( 'wp-auth-check', "/wp-includes/js/wp-auth-check$suffix.js", array( 'heartbeat' ), false, 1 );
  711. $scripts->set_translations( 'wp-auth-check' );
  712. $scripts->add( 'wp-lists', "/wp-includes/js/wp-lists$suffix.js", array( 'wp-ajax-response', 'jquery-color' ), false, 1 );
  713. // WordPress no longer uses or bundles Prototype or script.aculo.us. These are now pulled from an external source.
  714. $scripts->add( 'prototype', 'https://ajax.googleapis.com/ajax/libs/prototype/1.7.1.0/prototype.js', array(), '1.7.1' );
  715. $scripts->add( 'scriptaculous-root', 'https://ajax.googleapis.com/ajax/libs/scriptaculous/1.9.0/scriptaculous.js', array( 'prototype' ), '1.9.0' );
  716. $scripts->add( 'scriptaculous-builder', 'https://ajax.googleapis.com/ajax/libs/scriptaculous/1.9.0/builder.js', array( 'scriptaculous-root' ), '1.9.0' );
  717. $scripts->add( 'scriptaculous-dragdrop', 'https://ajax.googleapis.com/ajax/libs/scriptaculous/1.9.0/dragdrop.js', array( 'scriptaculous-builder', 'scriptaculous-effects' ), '1.9.0' );
  718. $scripts->add( 'scriptaculous-effects', 'https://ajax.googleapis.com/ajax/libs/scriptaculous/1.9.0/effects.js', array( 'scriptaculous-root' ), '1.9.0' );
  719. $scripts->add( 'scriptaculous-slider', 'https://ajax.googleapis.com/ajax/libs/scriptaculous/1.9.0/slider.js', array( 'scriptaculous-effects' ), '1.9.0' );
  720. $scripts->add( 'scriptaculous-sound', 'https://ajax.googleapis.com/ajax/libs/scriptaculous/1.9.0/sound.js', array( 'scriptaculous-root' ), '1.9.0' );
  721. $scripts->add( 'scriptaculous-controls', 'https://ajax.googleapis.com/ajax/libs/scriptaculous/1.9.0/controls.js', array( 'scriptaculous-root' ), '1.9.0' );
  722. $scripts->add( 'scriptaculous', false, array( 'scriptaculous-dragdrop', 'scriptaculous-slider', 'scriptaculous-controls' ) );
  723. // Not used in core, replaced by Jcrop.js.
  724. $scripts->add( 'cropper', '/wp-includes/js/crop/cropper.js', array( 'scriptaculous-dragdrop' ) );
  725. // jQuery.
  726. // The unminified jquery.js and jquery-migrate.js are included to facilitate debugging.
  727. $scripts->add( 'jquery', false, array( 'jquery-core', 'jquery-migrate' ), '3.6.1' );
  728. $scripts->add( 'jquery-core', "/wp-includes/js/jquery/jquery$suffix.js", array(), '3.6.1' );
  729. $scripts->add( 'jquery-migrate', "/wp-includes/js/jquery/jquery-migrate$suffix.js", array(), '3.3.2' );
  730. // Full jQuery UI.
  731. // The build process in 1.12.1 has changed significantly.
  732. // In order to keep backwards compatibility, and to keep the optimized loading,
  733. // the source files were flattened and included with some modifications for AMD loading.
  734. // A notable change is that 'jquery-ui-core' now contains 'jquery-ui-position' and 'jquery-ui-widget'.
  735. $scripts->add( 'jquery-ui-core', "/wp-includes/js/jquery/ui/core$suffix.js", array( 'jquery' ), '1.13.2', 1 );
  736. $scripts->add( 'jquery-effects-core', "/wp-includes/js/jquery/ui/effect$suffix.js", array( 'jquery' ), '1.13.2', 1 );
  737. $scripts->add( 'jquery-effects-blind', "/wp-includes/js/jquery/ui/effect-blind$suffix.js", array( 'jquery-effects-core' ), '1.13.2', 1 );
  738. $scripts->add( 'jquery-effects-bounce', "/wp-includes/js/jquery/ui/effect-bounce$suffix.js", array( 'jquery-effects-core' ), '1.13.2', 1 );
  739. $scripts->add( 'jquery-effects-clip', "/wp-includes/js/jquery/ui/effect-clip$suffix.js", array( 'jquery-effects-core' ), '1.13.2', 1 );
  740. $scripts->add( 'jquery-effects-drop', "/wp-includes/js/jquery/ui/effect-drop$suffix.js", array( 'jquery-effects-core' ), '1.13.2', 1 );
  741. $scripts->add( 'jquery-effects-explode', "/wp-includes/js/jquery/ui/effect-explode$suffix.js", array( 'jquery-effects-core' ), '1.13.2', 1 );
  742. $scripts->add( 'jquery-effects-fade', "/wp-includes/js/jquery/ui/effect-fade$suffix.js", array( 'jquery-effects-core' ), '1.13.2', 1 );
  743. $scripts->add( 'jquery-effects-fold', "/wp-includes/js/jquery/ui/effect-fold$suffix.js", array( 'jquery-effects-core' ), '1.13.2', 1 );
  744. $scripts->add( 'jquery-effects-highlight', "/wp-includes/js/jquery/ui/effect-highlight$suffix.js", array( 'jquery-effects-core' ), '1.13.2', 1 );
  745. $scripts->add( 'jquery-effects-puff', "/wp-includes/js/jquery/ui/effect-puff$suffix.js", array( 'jquery-effects-core', 'jquery-effects-scale' ), '1.13.2', 1 );
  746. $scripts->add( 'jquery-effects-pulsate', "/wp-includes/js/jquery/ui/effect-pulsate$suffix.js", array( 'jquery-effects-core' ), '1.13.2', 1 );
  747. $scripts->add( 'jquery-effects-scale', "/wp-includes/js/jquery/ui/effect-scale$suffix.js", array( 'jquery-effects-core', 'jquery-effects-size' ), '1.13.2', 1 );
  748. $scripts->add( 'jquery-effects-shake', "/wp-includes/js/jquery/ui/effect-shake$suffix.js", array( 'jquery-effects-core' ), '1.13.2', 1 );
  749. $scripts->add( 'jquery-effects-size', "/wp-includes/js/jquery/ui/effect-size$suffix.js", array( 'jquery-effects-core' ), '1.13.2', 1 );
  750. $scripts->add( 'jquery-effects-slide', "/wp-includes/js/jquery/ui/effect-slide$suffix.js", array( 'jquery-effects-core' ), '1.13.2', 1 );
  751. $scripts->add( 'jquery-effects-transfer', "/wp-includes/js/jquery/ui/effect-transfer$suffix.js", array( 'jquery-effects-core' ), '1.13.2', 1 );
  752. // Widgets
  753. $scripts->add( 'jquery-ui-accordion', "/wp-includes/js/jquery/ui/accordion$suffix.js", array( 'jquery-ui-core' ), '1.13.2', 1 );
  754. $scripts->add( 'jquery-ui-autocomplete', "/wp-includes/js/jquery/ui/autocomplete$suffix.js", array( 'jquery-ui-menu', 'wp-a11y' ), '1.13.2', 1 );
  755. $scripts->add( 'jquery-ui-button', "/wp-includes/js/jquery/ui/button$suffix.js", array( 'jquery-ui-core', 'jquery-ui-controlgroup', 'jquery-ui-checkboxradio' ), '1.13.2', 1 );
  756. $scripts->add( 'jquery-ui-datepicker', "/wp-includes/js/jquery/ui/datepicker$suffix.js", array( 'jquery-ui-core' ), '1.13.2', 1 );
  757. $scripts->add( 'jquery-ui-dialog', "/wp-includes/js/jquery/ui/dialog$suffix.js", array( 'jquery-ui-resizable', 'jquery-ui-draggable', 'jquery-ui-button' ), '1.13.2', 1 );
  758. $scripts->add( 'jquery-ui-menu', "/wp-includes/js/jquery/ui/menu$suffix.js", array( 'jquery-ui-core' ), '1.13.2', 1 );
  759. $scripts->add( 'jquery-ui-mouse', "/wp-includes/js/jquery/ui/mouse$suffix.js", array( 'jquery-ui-core' ), '1.13.2', 1 );
  760. $scripts->add( 'jquery-ui-progressbar', "/wp-includes/js/jquery/ui/progressbar$suffix.js", array( 'jquery-ui-core' ), '1.13.2', 1 );
  761. $scripts->add( 'jquery-ui-selectmenu', "/wp-includes/js/jquery/ui/selectmenu$suffix.js", array( 'jquery-ui-menu' ), '1.13.2', 1 );
  762. $scripts->add( 'jquery-ui-slider', "/wp-includes/js/jquery/ui/slider$suffix.js", array( 'jquery-ui-mouse' ), '1.13.2', 1 );
  763. $scripts->add( 'jquery-ui-spinner', "/wp-includes/js/jquery/ui/spinner$suffix.js", array( 'jquery-ui-button' ), '1.13.2', 1 );
  764. $scripts->add( 'jquery-ui-tabs', "/wp-includes/js/jquery/ui/tabs$suffix.js", array( 'jquery-ui-core' ), '1.13.2', 1 );
  765. $scripts->add( 'jquery-ui-tooltip', "/wp-includes/js/jquery/ui/tooltip$suffix.js", array( 'jquery-ui-core' ), '1.13.2', 1 );
  766. // New in 1.12.1
  767. $scripts->add( 'jquery-ui-checkboxradio', "/wp-includes/js/jquery/ui/checkboxradio$suffix.js", array( 'jquery-ui-core' ), '1.13.2', 1 );
  768. $scripts->add( 'jquery-ui-controlgroup', "/wp-includes/js/jquery/ui/controlgroup$suffix.js", array( 'jquery-ui-core' ), '1.13.2', 1 );
  769. // Interactions
  770. $scripts->add( 'jquery-ui-draggable', "/wp-includes/js/jquery/ui/draggable$suffix.js", array( 'jquery-ui-mouse' ), '1.13.2', 1 );
  771. $scripts->add( 'jquery-ui-droppable', "/wp-includes/js/jquery/ui/droppable$suffix.js", array( 'jquery-ui-draggable' ), '1.13.2', 1 );
  772. $scripts->add( 'jquery-ui-resizable', "/wp-includes/js/jquery/ui/resizable$suffix.js", array( 'jquery-ui-mouse' ), '1.13.2', 1 );
  773. $scripts->add( 'jquery-ui-selectable', "/wp-includes/js/jquery/ui/selectable$suffix.js", array( 'jquery-ui-mouse' ), '1.13.2', 1 );
  774. $scripts->add( 'jquery-ui-sortable', "/wp-includes/js/jquery/ui/sortable$suffix.js", array( 'jquery-ui-mouse' ), '1.13.2', 1 );
  775. // As of 1.12.1 `jquery-ui-position` and `jquery-ui-widget` are part of `jquery-ui-core`.
  776. // Listed here for back-compat.
  777. $scripts->add( 'jquery-ui-position', false, array( 'jquery-ui-core' ), '1.13.2', 1 );
  778. $scripts->add( 'jquery-ui-widget', false, array( 'jquery-ui-core' ), '1.13.2', 1 );
  779. // Strings for 'jquery-ui-autocomplete' live region messages.
  780. did_action( 'init' ) && $scripts->localize(
  781. 'jquery-ui-autocomplete',
  782. 'uiAutocompleteL10n',
  783. array(
  784. 'noResults' => __( 'No results found.' ),
  785. /* translators: Number of results found when using jQuery UI Autocomplete. */
  786. 'oneResult' => __( '1 result found. Use up and down arrow keys to navigate.' ),
  787. /* translators: %d: Number of results found when using jQuery UI Autocomplete. */
  788. 'manyResults' => __( '%d results found. Use up and down arrow keys to navigate.' ),
  789. 'itemSelected' => __( 'Item selected.' ),
  790. )
  791. );
  792. // Deprecated, not used in core, most functionality is included in jQuery 1.3.
  793. $scripts->add( 'jquery-form', "/wp-includes/js/jquery/jquery.form$suffix.js", array( 'jquery' ), '4.3.0', 1 );
  794. // jQuery plugins.
  795. $scripts->add( 'jquery-color', '/wp-includes/js/jquery/jquery.color.min.js', array( 'jquery' ), '2.2.0', 1 );
  796. $scripts->add( 'schedule', '/wp-includes/js/jquery/jquery.schedule.js', array( 'jquery' ), '20m', 1 );
  797. $scripts->add( 'jquery-query', '/wp-includes/js/jquery/jquery.query.js', array( 'jquery' ), '2.2.3', 1 );
  798. $scripts->add( 'jquery-serialize-object', '/wp-includes/js/jquery/jquery.serialize-object.js', array( 'jquery' ), '0.2-wp', 1 );
  799. $scripts->add( 'jquery-hotkeys', "/wp-includes/js/jquery/jquery.hotkeys$suffix.js", array( 'jquery' ), '0.0.2m', 1 );
  800. $scripts->add( 'jquery-table-hotkeys', "/wp-includes/js/jquery/jquery.table-hotkeys$suffix.js", array( 'jquery', 'jquery-hotkeys' ), false, 1 );
  801. $scripts->add( 'jquery-touch-punch', '/wp-includes/js/jquery/jquery.ui.touch-punch.js', array( 'jquery-ui-core', 'jquery-ui-mouse' ), '0.2.2', 1 );
  802. // Not used any more, registered for backward compatibility.
  803. $scripts->add( 'suggest', "/wp-includes/js/jquery/suggest$suffix.js", array( 'jquery' ), '1.1-20110113', 1 );
  804. // Masonry v2 depended on jQuery. v3 does not. The older jquery-masonry handle is a shiv.
  805. // It sets jQuery as a dependency, as the theme may have been implicitly loading it this way.
  806. $scripts->add( 'imagesloaded', '/wp-includes/js/imagesloaded.min.js', array(), '4.1.4', 1 );
  807. $scripts->add( 'masonry', '/wp-includes/js/masonry.min.js', array( 'imagesloaded' ), '4.2.2', 1 );
  808. $scripts->add( 'jquery-masonry', '/wp-includes/js/jquery/jquery.masonry.min.js', array( 'jquery', 'masonry' ), '3.1.2b', 1 );
  809. $scripts->add( 'thickbox', '/wp-includes/js/thickbox/thickbox.js', array( 'jquery' ), '3.1-20121105', 1 );
  810. did_action( 'init' ) && $scripts->localize(
  811. 'thickbox',
  812. 'thickboxL10n',
  813. array(
  814. 'next' => __( 'Next &gt;' ),
  815. 'prev' => __( '&lt; Prev' ),
  816. 'image' => __( 'Image' ),
  817. 'of' => __( 'of' ),
  818. 'close' => __( 'Close' ),
  819. 'noiframes' => __( 'This feature requires inline frames. You have iframes disabled or your browser does not support them.' ),
  820. 'loadingAnimation' => includes_url( 'js/thickbox/loadingAnimation.gif' ),
  821. )
  822. );
  823. // Not used in core, replaced by imgAreaSelect.
  824. $scripts->add( 'jcrop', '/wp-includes/js/jcrop/jquery.Jcrop.min.js', array( 'jquery' ), '0.9.15' );
  825. $scripts->add( 'swfobject', '/wp-includes/js/swfobject.js', array(), '2.2-20120417' );
  826. // Error messages for Plupload.
  827. $uploader_l10n = array(
  828. 'queue_limit_exceeded' => __( 'You have attempted to queue too many files.' ),
  829. /* translators: %s: File name. */
  830. 'file_exceeds_size_limit' => __( '%s exceeds the maximum upload size for this site.' ),
  831. 'zero_byte_file' => __( 'This file is empty. Please try another.' ),
  832. 'invalid_filetype' => __( 'Sorry, you are not allowed to upload this file type.' ),
  833. 'not_an_image' => __( 'This file is not an image. Please try another.' ),
  834. 'image_memory_exceeded' => __( 'Memory exceeded. Please try another smaller file.' ),
  835. 'image_dimensions_exceeded' => __( 'This is larger than the maximum size. Please try another.' ),
  836. 'default_error' => __( 'An error occurred in the upload. Please try again later.' ),
  837. 'missing_upload_url' => __( 'There was a configuration error. Please contact the server administrator.' ),
  838. 'upload_limit_exceeded' => __( 'You may only upload 1 file.' ),
  839. 'http_error' => __( 'Unexpected response from the server. The file may have been uploaded successfully. Check in the Media Library or reload the page.' ),
  840. 'http_error_image' => __( 'The server cannot process the image. This can happen if the server is busy or does not have enough resources to complete the task. Uploading a smaller image may help. Suggested maximum size is 2560 pixels.' ),
  841. 'upload_failed' => __( 'Upload failed.' ),
  842. /* translators: 1: Opening link tag, 2: Closing link tag. */
  843. 'big_upload_failed' => __( 'Please try uploading this file with the %1$sbrowser uploader%2$s.' ),
  844. /* translators: %s: File name. */
  845. 'big_upload_queued' => __( '%s exceeds the maximum upload size for the multi-file uploader when used in your browser.' ),
  846. 'io_error' => __( 'IO error.' ),
  847. 'security_error' => __( 'Security error.' ),
  848. 'file_cancelled' => __( 'File canceled.' ),
  849. 'upload_stopped' => __( 'Upload stopped.' ),
  850. 'dismiss' => __( 'Dismiss' ),
  851. 'crunching' => __( 'Crunching&hellip;' ),
  852. 'deleted' => __( 'moved to the Trash.' ),
  853. /* translators: %s: File name. */
  854. 'error_uploading' => __( '&#8220;%s&#8221; has failed to upload.' ),
  855. 'unsupported_image' => __( 'This image cannot be displayed in a web browser. For best results convert it to JPEG before uploading.' ),
  856. 'noneditable_image' => __( 'This image cannot be processed by the web server. Convert it to JPEG or PNG before uploading.' ),
  857. 'file_url_copied' => __( 'The file URL has been copied to your clipboard' ),
  858. );
  859. $scripts->add( 'moxiejs', "/wp-includes/js/plupload/moxie$suffix.js", array(), '1.3.5' );
  860. $scripts->add( 'plupload', "/wp-includes/js/plupload/plupload$suffix.js", array( 'moxiejs' ), '2.1.9' );
  861. // Back compat handles:
  862. foreach ( array( 'all', 'html5', 'flash', 'silverlight', 'html4' ) as $handle ) {
  863. $scripts->add( "plupload-$handle", false, array( 'plupload' ), '2.1.1' );
  864. }
  865. $scripts->add( 'plupload-handlers', "/wp-includes/js/plupload/handlers$suffix.js", array( 'clipboard', 'jquery', 'plupload', 'underscore', 'wp-a11y', 'wp-i18n' ) );
  866. did_action( 'init' ) && $scripts->localize( 'plupload-handlers', 'pluploadL10n', $uploader_l10n );
  867. $scripts->add( 'wp-plupload', "/wp-includes/js/plupload/wp-plupload$suffix.js", array( 'plupload', 'jquery', 'json2', 'media-models' ), false, 1 );
  868. did_action( 'init' ) && $scripts->localize( 'wp-plupload', 'pluploadL10n', $uploader_l10n );
  869. // Keep 'swfupload' for back-compat.
  870. $scripts->add( 'swfupload', '/wp-includes/js/swfupload/swfupload.js', array(), '2201-20110113' );
  871. $scripts->add( 'swfupload-all', false, array( 'swfupload' ), '2201' );
  872. $scripts->add( 'swfupload-handlers', "/wp-includes/js/swfupload/handlers$suffix.js", array( 'swfupload-all', 'jquery' ), '2201-20110524' );
  873. did_action( 'init' ) && $scripts->localize( 'swfupload-handlers', 'swfuploadL10n', $uploader_l10n );
  874. $scripts->add( 'comment-reply', "/wp-includes/js/comment-reply$suffix.js", array(), false, 1 );
  875. $scripts->add( 'json2', "/wp-includes/js/json2$suffix.js", array(), '2015-05-03' );
  876. did_action( 'init' ) && $scripts->add_data( 'json2', 'conditional', 'lt IE 8' );
  877. $scripts->add( 'underscore', "/wp-includes/js/underscore$dev_suffix.js", array(), '1.13.4', 1 );
  878. $scripts->add( 'backbone', "/wp-includes/js/backbone$dev_suffix.js", array( 'underscore', 'jquery' ), '1.4.1', 1 );
  879. $scripts->add( 'wp-util', "/wp-includes/js/wp-util$suffix.js", array( 'underscore', 'jquery' ), false, 1 );
  880. did_action( 'init' ) && $scripts->localize(
  881. 'wp-util',
  882. '_wpUtilSettings',
  883. array(
  884. 'ajax' => array(
  885. 'url' => admin_url( 'admin-ajax.php', 'relative' ),
  886. ),
  887. )
  888. );
  889. $scripts->add( 'wp-backbone', "/wp-includes/js/wp-backbone$suffix.js", array( 'backbone', 'wp-util' ), false, 1 );
  890. $scripts->add( 'revisions', "/wp-admin/js/revisions$suffix.js", array( 'wp-backbone', 'jquery-ui-slider', 'hoverIntent' ), false, 1 );
  891. $scripts->add( 'imgareaselect', "/wp-includes/js/imgareaselect/jquery.imgareaselect$suffix.js", array( 'jquery' ), false, 1 );
  892. $scripts->add( 'mediaelement', false, array( 'jquery', 'mediaelement-core', 'mediaelement-migrate' ), '4.2.17', 1 );
  893. $scripts->add( 'mediaelement-core', "/wp-includes/js/mediaelement/mediaelement-and-player$suffix.js", array(), '4.2.17', 1 );
  894. $scripts->add( 'mediaelement-migrate', "/wp-includes/js/mediaelement/mediaelement-migrate$suffix.js", array(), false, 1 );
  895. did_action( 'init' ) && $scripts->add_inline_script(
  896. 'mediaelement-core',
  897. sprintf(
  898. 'var mejsL10n = %s;',
  899. wp_json_encode(
  900. array(
  901. 'language' => strtolower( strtok( determine_locale(), '_-' ) ),
  902. 'strings' => array(
  903. 'mejs.download-file' => __( 'Download File' ),
  904. 'mejs.install-flash' => __( 'You are using a browser that does not have Flash player enabled or installed. Please turn on your Flash player plugin or download the latest version from https://get.adobe.com/flashplayer/' ),
  905. 'mejs.fullscreen' => __( 'Fullscreen' ),
  906. 'mejs.play' => __( 'Play' ),
  907. 'mejs.pause' => __( 'Pause' ),
  908. 'mejs.time-slider' => __( 'Time Slider' ),
  909. 'mejs.time-help-text' => __( 'Use Left/Right Arrow keys to advance one second, Up/Down arrows to advance ten seconds.' ),
  910. 'mejs.live-broadcast' => __( 'Live Broadcast' ),
  911. 'mejs.volume-help-text' => __( 'Use Up/Down Arrow keys to increase or decrease volume.' ),
  912. 'mejs.unmute' => __( 'Unmute' ),
  913. 'mejs.mute' => __( 'Mute' ),
  914. 'mejs.volume-slider' => __( 'Volume Slider' ),
  915. 'mejs.video-player' => __( 'Video Player' ),
  916. 'mejs.audio-player' => __( 'Audio Player' ),
  917. 'mejs.captions-subtitles' => __( 'Captions/Subtitles' ),
  918. 'mejs.captions-chapters' => __( 'Chapters' ),
  919. 'mejs.none' => __( 'None' ),
  920. 'mejs.afrikaans' => __( 'Afrikaans' ),
  921. 'mejs.albanian' => __( 'Albanian' ),
  922. 'mejs.arabic' => __( 'Arabic' ),
  923. 'mejs.belarusian' => __( 'Belarusian' ),
  924. 'mejs.bulgarian' => __( 'Bulgarian' ),
  925. 'mejs.catalan' => __( 'Catalan' ),
  926. 'mejs.chinese' => __( 'Chinese' ),
  927. 'mejs.chinese-simplified' => __( 'Chinese (Simplified)' ),
  928. 'mejs.chinese-traditional' => __( 'Chinese (Traditional)' ),
  929. 'mejs.croatian' => __( 'Croatian' ),
  930. 'mejs.czech' => __( 'Czech' ),
  931. 'mejs.danish' => __( 'Danish' ),
  932. 'mejs.dutch' => __( 'Dutch' ),
  933. 'mejs.english' => __( 'English' ),
  934. 'mejs.estonian' => __( 'Estonian' ),
  935. 'mejs.filipino' => __( 'Filipino' ),
  936. 'mejs.finnish' => __( 'Finnish' ),
  937. 'mejs.french' => __( 'French' ),
  938. 'mejs.galician' => __( 'Galician' ),
  939. 'mejs.german' => __( 'German' ),
  940. 'mejs.greek' => __( 'Greek' ),
  941. 'mejs.haitian-creole' => __( 'Haitian Creole' ),
  942. 'mejs.hebrew' => __( 'Hebrew' ),
  943. 'mejs.hindi' => __( 'Hindi' ),
  944. 'mejs.hungarian' => __( 'Hungarian' ),
  945. 'mejs.icelandic' => __( 'Icelandic' ),
  946. 'mejs.indonesian' => __( 'Indonesian' ),
  947. 'mejs.irish' => __( 'Irish' ),
  948. 'mejs.italian' => __( 'Italian' ),
  949. 'mejs.japanese' => __( 'Japanese' ),
  950. 'mejs.korean' => __( 'Korean' ),
  951. 'mejs.latvian' => __( 'Latvian' ),
  952. 'mejs.lithuanian' => __( 'Lithuanian' ),
  953. 'mejs.macedonian' => __( 'Macedonian' ),
  954. 'mejs.malay' => __( 'Malay' ),
  955. 'mejs.maltese' => __( 'Maltese' ),
  956. 'mejs.norwegian' => __( 'Norwegian' ),
  957. 'mejs.persian' => __( 'Persian' ),
  958. 'mejs.polish' => __( 'Polish' ),
  959. 'mejs.portuguese' => __( 'Portuguese' ),
  960. 'mejs.romanian' => __( 'Romanian' ),
  961. 'mejs.russian' => __( 'Russian' ),
  962. 'mejs.serbian' => __( 'Serbian' ),
  963. 'mejs.slovak' => __( 'Slovak' ),
  964. 'mejs.slovenian' => __( 'Slovenian' ),
  965. 'mejs.spanish' => __( 'Spanish' ),
  966. 'mejs.swahili' => __( 'Swahili' ),
  967. 'mejs.swedish' => __( 'Swedish' ),
  968. 'mejs.tagalog' => __( 'Tagalog' ),
  969. 'mejs.thai' => __( 'Thai' ),
  970. 'mejs.turkish' => __( 'Turkish' ),
  971. 'mejs.ukrainian' => __( 'Ukrainian' ),
  972. 'mejs.vietnamese' => __( 'Vietnamese' ),
  973. 'mejs.welsh' => __( 'Welsh' ),
  974. 'mejs.yiddish' => __( 'Yiddish' ),
  975. ),
  976. )
  977. )
  978. ),
  979. 'before'
  980. );
  981. $scripts->add( 'mediaelement-vimeo', '/wp-includes/js/mediaelement/renderers/vimeo.min.js', array( 'mediaelement' ), '4.2.17', 1 );
  982. $scripts->add( 'wp-mediaelement', "/wp-includes/js/mediaelement/wp-mediaelement$suffix.js", array( 'mediaelement' ), false, 1 );
  983. $mejs_settings = array(
  984. 'pluginPath' => includes_url( 'js/mediaelement/', 'relative' ),
  985. 'classPrefix' => 'mejs-',
  986. 'stretching' => 'responsive',
  987. );
  988. did_action( 'init' ) && $scripts->localize(
  989. 'mediaelement',
  990. '_wpmejsSettings',
  991. /**
  992. * Filters the MediaElement configuration settings.
  993. *
  994. * @since 4.4.0
  995. *
  996. * @param array $mejs_settings MediaElement settings array.
  997. */
  998. apply_filters( 'mejs_settings', $mejs_settings )
  999. );
  1000. $scripts->add( 'wp-codemirror', '/wp-includes/js/codemirror/codemirror.min.js', array(), '5.29.1-alpha-ee20357' );
  1001. $scripts->add( 'csslint', '/wp-includes/js/codemirror/csslint.js', array(), '1.0.5' );
  1002. $scripts->add( 'esprima', '/wp-includes/js/codemirror/esprima.js', array(), '4.0.0' );
  1003. $scripts->add( 'jshint', '/wp-includes/js/codemirror/fakejshint.js', array( 'esprima' ), '2.9.5' );
  1004. $scripts->add( 'jsonlint', '/wp-includes/js/codemirror/jsonlint.js', array(), '1.6.2' );
  1005. $scripts->add( 'htmlhint', '/wp-includes/js/codemirror/htmlhint.js', array(), '0.9.14-xwp' );
  1006. $scripts->add( 'htmlhint-kses', '/wp-includes/js/codemirror/htmlhint-kses.js', array( 'htmlhint' ) );
  1007. $scripts->add( 'code-editor', "/wp-admin/js/code-editor$suffix.js", array( 'jquery', 'wp-codemirror', 'underscore' ) );
  1008. $scripts->add( 'wp-theme-plugin-editor', "/wp-admin/js/theme-plugin-editor$suffix.js", array( 'common', 'wp-util', 'wp-sanitize', 'jquery', 'jquery-ui-core', 'wp-a11y', 'underscore' ) );
  1009. $scripts->set_translations( 'wp-theme-plugin-editor' );
  1010. $scripts->add( 'wp-playlist', "/wp-includes/js/mediaelement/wp-playlist$suffix.js", array( 'wp-util', 'backbone', 'mediaelement' ), false, 1 );
  1011. $scripts->add( 'zxcvbn-async', "/wp-includes/js/zxcvbn-async$suffix.js", array(), '1.0' );
  1012. did_action( 'init' ) && $scripts->localize(
  1013. 'zxcvbn-async',
  1014. '_zxcvbnSettings',
  1015. array(
  1016. 'src' => empty( $guessed_url ) ? includes_url( '/js/zxcvbn.min.js' ) : $scripts->base_url . '/wp-includes/js/zxcvbn.min.js',
  1017. )
  1018. );
  1019. $scripts->add( 'password-strength-meter', "/wp-admin/js/password-strength-meter$suffix.js", array( 'jquery', 'zxcvbn-async' ), false, 1 );
  1020. did_action( 'init' ) && $scripts->localize(
  1021. 'password-strength-meter',
  1022. 'pwsL10n',
  1023. array(
  1024. 'unknown' => _x( 'Password strength unknown', 'password strength' ),
  1025. 'short' => _x( 'Very weak', 'password strength' ),
  1026. 'bad' => _x( 'Weak', 'password strength' ),
  1027. 'good' => _x( 'Medium', 'password strength' ),
  1028. 'strong' => _x( 'Strong', 'password strength' ),
  1029. 'mismatch' => _x( 'Mismatch', 'password mismatch' ),
  1030. )
  1031. );
  1032. $scripts->set_translations( 'password-strength-meter' );
  1033. $scripts->add( 'application-passwords', "/wp-admin/js/application-passwords$suffix.js", array( 'jquery', 'wp-util', 'wp-api-request', 'wp-date', 'wp-i18n', 'wp-hooks' ), false, 1 );
  1034. $scripts->set_translations( 'application-passwords' );
  1035. $scripts->add( 'auth-app', "/wp-admin/js/auth-app$suffix.js", array( 'jquery', 'wp-api-request', 'wp-i18n', 'wp-hooks' ), false, 1 );
  1036. $scripts->set_translations( 'auth-app' );
  1037. $scripts->add( 'user-profile', "/wp-admin/js/user-profile$suffix.js", array( 'jquery', 'password-strength-meter', 'wp-util' ), false, 1 );
  1038. $scripts->set_translations( 'user-profile' );
  1039. $user_id = isset( $_GET['user_id'] ) ? (int) $_GET['user_id'] : 0;
  1040. did_action( 'init' ) && $scripts->localize(
  1041. 'user-profile',
  1042. 'userProfileL10n',
  1043. array(
  1044. 'user_id' => $user_id,
  1045. 'nonce' => wp_installing() ? '' : wp_create_nonce( 'reset-password-for-' . $user_id ),
  1046. )
  1047. );
  1048. $scripts->add( 'language-chooser', "/wp-admin/js/language-chooser$suffix.js", array( 'jquery' ), false, 1 );
  1049. $scripts->add( 'user-suggest', "/wp-admin/js/user-suggest$suffix.js", array( 'jquery-ui-autocomplete' ), false, 1 );
  1050. $scripts->add( 'admin-bar', "/wp-includes/js/admin-bar$suffix.js", array( 'hoverintent-js' ), false, 1 );
  1051. $scripts->add( 'wplink', "/wp-includes/js/wplink$suffix.js", array( 'jquery', 'wp-a11y' ), false, 1 );
  1052. did_action( 'init' ) && $scripts->localize(
  1053. 'wplink',
  1054. 'wpLinkL10n',
  1055. array(
  1056. 'title' => __( 'Insert/edit link' ),
  1057. 'update' => __( 'Update' ),
  1058. 'save' => __( 'Add Link' ),
  1059. 'noTitle' => __( '(no title)' ),
  1060. 'noMatchesFound' => __( 'No results found.' ),
  1061. 'linkSelected' => __( 'Link selected.' ),
  1062. 'linkInserted' => __( 'Link inserted.' ),
  1063. /* translators: Minimum input length in characters to start searching posts in the "Insert/edit link" modal. */
  1064. 'minInputLength' => (int) _x( '3', 'minimum input length for searching post links' ),
  1065. )
  1066. );
  1067. $scripts->add( 'wpdialogs', "/wp-includes/js/wpdialog$suffix.js", array( 'jquery-ui-dialog' ), false, 1 );
  1068. $scripts->add( 'word-count', "/wp-admin/js/word-count$suffix.js", array(), false, 1 );
  1069. $scripts->add( 'media-upload', "/wp-admin/js/media-upload$suffix.js", array( 'thickbox', 'shortcode' ), false, 1 );
  1070. $scripts->add( 'hoverIntent', "/wp-includes/js/hoverIntent$suffix.js", array( 'jquery' ), '1.10.2', 1 );
  1071. // JS-only version of hoverintent (no dependencies).
  1072. $scripts->add( 'hoverintent-js', '/wp-includes/js/hoverintent-js.min.js', array(), '2.2.1', 1 );
  1073. $scripts->add( 'customize-base', "/wp-includes/js/customize-base$suffix.js", array( 'jquery', 'json2', 'underscore' ), false, 1 );
  1074. $scripts->add( 'customize-loader', "/wp-includes/js/customize-loader$suffix.js", array( 'customize-base' ), false, 1 );
  1075. $scripts->add( 'customize-preview', "/wp-includes/js/customize-preview$suffix.js", array( 'wp-a11y', 'customize-base' ), false, 1 );
  1076. $scripts->add( 'customize-models', '/wp-includes/js/customize-models.js', array( 'underscore', 'backbone' ), false, 1 );
  1077. $scripts->add( 'customize-views', '/wp-includes/js/customize-views.js', array( 'jquery', 'underscore', 'imgareaselect', 'customize-models', 'media-editor', 'media-views' ), false, 1 );
  1078. $scripts->add( 'customize-controls', "/wp-admin/js/customize-controls$suffix.js", array( 'customize-base', 'wp-a11y', 'wp-util', 'jquery-ui-core' ), false, 1 );
  1079. did_action( 'init' ) && $scripts->localize(
  1080. 'customize-controls',
  1081. '_wpCustomizeControlsL10n',
  1082. array(
  1083. 'activate' => __( 'Activate &amp; Publish' ),
  1084. 'save' => __( 'Save &amp; Publish' ), // @todo Remove as not required.
  1085. 'publish' => __( 'Publish' ),
  1086. 'published' => __( 'Published' ),
  1087. 'saveDraft' => __( 'Save Draft' ),
  1088. 'draftSaved' => __( 'Draft Saved' ),
  1089. 'updating' => __( 'Updating' ),
  1090. 'schedule' => _x( 'Schedule', 'customizer changeset action/button label' ),
  1091. 'scheduled' => _x( 'Scheduled', 'customizer changeset status' ),
  1092. 'invalid' => __( 'Invalid' ),
  1093. 'saveBeforeShare' => __( 'Please save your changes in order to share the preview.' ),
  1094. 'futureDateError' => __( 'You must supply a future date to schedule.' ),
  1095. 'saveAlert' => __( 'The changes you made will be lost if you navigate away from this page.' ),
  1096. 'saved' => __( 'Saved' ),
  1097. 'cancel' => __( 'Cancel' ),
  1098. 'close' => __( 'Close' ),
  1099. 'action' => __( 'Action' ),
  1100. 'discardChanges' => __( 'Discard changes' ),
  1101. 'cheatin' => __( 'Something went wrong.' ),
  1102. 'notAllowedHeading' => __( 'You need a higher level of permission.' ),
  1103. 'notAllowed' => __( 'Sorry, you are not allowed to customize this site.' ),
  1104. 'previewIframeTitle' => __( 'Site Preview' ),
  1105. 'loginIframeTitle' => __( 'Session expired' ),
  1106. 'collapseSidebar' => _x( 'Hide Controls', 'label for hide controls button without length constraints' ),
  1107. 'expandSidebar' => _x( 'Show Controls', 'label for hide controls button without length constraints' ),
  1108. 'untitledBlogName' => __( '(Untitled)' ),
  1109. 'unknownRequestFail' => __( 'Looks like something&#8217;s gone wrong. Wait a couple seconds, and then try again.' ),
  1110. 'themeDownloading' => __( 'Downloading your new theme&hellip;' ),
  1111. 'themePreviewWait' => __( 'Setting up your live preview. This may take a bit.' ),
  1112. 'revertingChanges' => __( 'Reverting unpublished changes&hellip;' ),
  1113. 'trashConfirm' => __( 'Are you sure you want to discard your unpublished changes?' ),
  1114. /* translators: %s: Display name of the user who has taken over the changeset in customizer. */
  1115. 'takenOverMessage' => __( '%s has taken over and is currently customizing.' ),
  1116. /* translators: %s: URL to the Customizer to load the autosaved version. */
  1117. 'autosaveNotice' => __( 'There is a more recent autosave of your changes than the one you are previewing. <a href="%s">Restore the autosave</a>' ),
  1118. 'videoHeaderNotice' => __( 'This theme does not support video headers on this page. Navigate to the front page or another page that supports video headers.' ),
  1119. // Used for overriding the file types allowed in Plupload.
  1120. 'allowedFiles' => __( 'Allowed Files' ),
  1121. 'customCssError' => array(
  1122. /* translators: %d: Error count. */
  1123. 'singular' => _n( 'There is %d error which must be fixed before you can save.', 'There are %d errors which must be fixed before you can save.', 1 ),
  1124. /* translators: %d: Error count. */
  1125. 'plural' => _n( 'There is %d error which must be fixed before you can save.', 'There are %d errors which must be fixed before you can save.', 2 ),
  1126. // @todo This is lacking, as some languages have a dedicated dual form. For proper handling of plurals in JS, see #20491.
  1127. ),
  1128. 'pageOnFrontError' => __( 'Homepage and posts page must be different.' ),
  1129. 'saveBlockedError' => array(
  1130. /* translators: %s: Number of invalid settings. */
  1131. 'singular' => _n( 'Unable to save due to %s invalid setting.', 'Unable to save due to %s invalid settings.', 1 ),
  1132. /* translators: %s: Number of invalid settings. */
  1133. 'plural' => _n( 'Unable to save due to %s invalid setting.', 'Unable to save due to %s invalid settings.', 2 ),
  1134. // @todo This is lacking, as some languages have a dedicated dual form. For proper handling of plurals in JS, see #20491.
  1135. ),
  1136. 'scheduleDescription' => __( 'Schedule your customization changes to publish ("go live") at a future date.' ),
  1137. 'themePreviewUnavailable' => __( 'Sorry, you cannot preview new themes when you have changes scheduled or saved as a draft. Please publish your changes, or wait until they publish to preview new themes.' ),
  1138. 'themeInstallUnavailable' => sprintf(
  1139. /* translators: %s: URL to Add Themes admin screen. */
  1140. __( 'You will not be able to install new themes from here yet since your install requires SFTP credentials. For now, please <a href="%s">add themes in the admin</a>.' ),
  1141. esc_url( admin_url( 'theme-install.php' ) )
  1142. ),
  1143. 'publishSettings' => __( 'Publish Settings' ),
  1144. 'invalidDate' => __( 'Invalid date.' ),
  1145. 'invalidValue' => __( 'Invalid value.' ),
  1146. 'blockThemeNotification' => sprintf(
  1147. /* translators: 1: Link to Site Editor documentation on HelpHub, 2: HTML button. */
  1148. __( 'Hurray! Your theme supports site editing with blocks. <a href="%1$s">Tell me more</a>. %2$s' ),
  1149. __( 'https://wordpress.org/support/article/site-editor/' ),
  1150. sprintf(
  1151. '<button type="button" data-action="%1$s" class="button switch-to-editor">%2$s</button>',
  1152. esc_url( admin_url( 'site-editor.php' ) ),
  1153. __( 'Use Site Editor' )
  1154. )
  1155. ),
  1156. )
  1157. );
  1158. $scripts->add( 'customize-selective-refresh', "/wp-includes/js/customize-selective-refresh$suffix.js", array( 'jquery', 'wp-util', 'customize-preview' ), false, 1 );
  1159. $scripts->add( 'customize-widgets', "/wp-admin/js/customize-widgets$suffix.js", array( 'jquery', 'jquery-ui-sortable', 'jquery-ui-droppable', 'wp-backbone', 'customize-controls' ), false, 1 );
  1160. $scripts->add( 'customize-preview-widgets', "/wp-includes/js/customize-preview-widgets$suffix.js", array( 'jquery', 'wp-util', 'customize-preview', 'customize-selective-refresh' ), false, 1 );
  1161. $scripts->add( 'customize-nav-menus', "/wp-admin/js/customize-nav-menus$suffix.js", array( 'jquery', 'wp-backbone', 'customize-controls', 'accordion', 'nav-menu', 'wp-sanitize' ), false, 1 );
  1162. $scripts->add( 'customize-preview-nav-menus', "/wp-includes/js/customize-preview-nav-menus$suffix.js", array( 'jquery', 'wp-util', 'customize-preview', 'customize-selective-refresh' ), false, 1 );
  1163. $scripts->add( 'wp-custom-header', "/wp-includes/js/wp-custom-header$suffix.js", array( 'wp-a11y' ), false, 1 );
  1164. $scripts->add( 'accordion', "/wp-admin/js/accordion$suffix.js", array( 'jquery' ), false, 1 );
  1165. $scripts->add( 'shortcode', "/wp-includes/js/shortcode$suffix.js", array( 'underscore' ), false, 1 );
  1166. $scripts->add( 'media-models', "/wp-includes/js/media-models$suffix.js", array( 'wp-backbone' ), false, 1 );
  1167. did_action( 'init' ) && $scripts->localize(
  1168. 'media-models',
  1169. '_wpMediaModelsL10n',
  1170. array(
  1171. 'settings' => array(
  1172. 'ajaxurl' => admin_url( 'admin-ajax.php', 'relative' ),
  1173. 'post' => array( 'id' => 0 ),
  1174. ),
  1175. )
  1176. );
  1177. $scripts->add( 'wp-embed', "/wp-includes/js/wp-embed$suffix.js", array(), false, 1 );
  1178. // To enqueue media-views or media-editor, call wp_enqueue_media().
  1179. // Both rely on numerous settings, styles, and templates to operate correctly.
  1180. $scripts->add( 'media-views', "/wp-includes/js/media-views$suffix.js", array( 'utils', 'media-models', 'wp-plupload', 'jquery-ui-sortable', 'wp-mediaelement', 'wp-api-request', 'wp-a11y', 'clipboard' ), false, 1 );
  1181. $scripts->set_translations( 'media-views' );
  1182. $scripts->add( 'media-editor', "/wp-includes/js/media-editor$suffix.js", array( 'shortcode', 'media-views' ), false, 1 );
  1183. $scripts->set_translations( 'media-editor' );
  1184. $scripts->add( 'media-audiovideo', "/wp-includes/js/media-audiovideo$suffix.js", array( 'media-editor' ), false, 1 );
  1185. $scripts->add( 'mce-view', "/wp-includes/js/mce-view$suffix.js", array( 'shortcode', 'jquery', 'media-views', 'media-audiovideo' ), false, 1 );
  1186. $scripts->add( 'wp-api', "/wp-includes/js/wp-api$suffix.js", array( 'jquery', 'backbone', 'underscore', 'wp-api-request' ), false, 1 );
  1187. if ( is_admin() ) {
  1188. $scripts->add( 'admin-tags', "/wp-admin/js/tags$suffix.js", array( 'jquery', 'wp-ajax-response' ), false, 1 );
  1189. $scripts->set_translations( 'admin-tags' );
  1190. $scripts->add( 'admin-comments', "/wp-admin/js/edit-comments$suffix.js", array( 'wp-lists', 'quicktags', 'jquery-query' ), false, 1 );
  1191. $scripts->set_translations( 'admin-comments' );
  1192. did_action( 'init' ) && $scripts->localize(
  1193. 'admin-comments',
  1194. 'adminCommentsSettings',
  1195. array(
  1196. 'hotkeys_highlight_first' => isset( $_GET['hotkeys_highlight_first'] ),
  1197. 'hotkeys_highlight_last' => isset( $_GET['hotkeys_highlight_last'] ),
  1198. )
  1199. );
  1200. $scripts->add( 'xfn', "/wp-admin/js/xfn$suffix.js", array( 'jquery' ), false, 1 );
  1201. $scripts->add( 'postbox', "/wp-admin/js/postbox$suffix.js", array( 'jquery-ui-sortable', 'wp-a11y' ), false, 1 );
  1202. $scripts->set_translations( 'postbox' );
  1203. $scripts->add( 'tags-box', "/wp-admin/js/tags-box$suffix.js", array( 'jquery', 'tags-suggest' ), false, 1 );
  1204. $scripts->set_translations( 'tags-box' );
  1205. $scripts->add( 'tags-suggest', "/wp-admin/js/tags-suggest$suffix.js", array( 'jquery-ui-autocomplete', 'wp-a11y' ), false, 1 );
  1206. $scripts->set_translations( 'tags-suggest' );
  1207. $scripts->add( 'post', "/wp-admin/js/post$suffix.js", array( 'suggest', 'wp-lists', 'postbox', 'tags-box', 'underscore', 'word-count', 'wp-a11y', 'wp-sanitize', 'clipboard' ), false, 1 );
  1208. $scripts->set_translations( 'post' );
  1209. $scripts->add( 'editor-expand', "/wp-admin/js/editor-expand$suffix.js", array( 'jquery', 'underscore' ), false, 1 );
  1210. $scripts->add( 'link', "/wp-admin/js/link$suffix.js", array( 'wp-lists', 'postbox' ), false, 1 );
  1211. $scripts->add( 'comment', "/wp-admin/js/comment$suffix.js", array( 'jquery', 'postbox' ), false, 1 );
  1212. $scripts->set_translations( 'comment' );
  1213. $scripts->add( 'admin-gallery', "/wp-admin/js/gallery$suffix.js", array( 'jquery-ui-sortable' ) );
  1214. $scripts->add( 'admin-widgets', "/wp-admin/js/widgets$suffix.js", array( 'jquery-ui-sortable', 'jquery-ui-draggable', 'jquery-ui-droppable', 'wp-a11y' ), false, 1 );
  1215. $scripts->set_translations( 'admin-widgets' );
  1216. $scripts->add( 'media-widgets', "/wp-admin/js/widgets/media-widgets$suffix.js", array( 'jquery', 'media-models', 'media-views', 'wp-api-request' ) );
  1217. $scripts->add_inline_script( 'media-widgets', 'wp.mediaWidgets.init();', 'after' );
  1218. $scripts->add( 'media-audio-widget', "/wp-admin/js/widgets/media-audio-widget$suffix.js", array( 'media-widgets', 'media-audiovideo' ) );
  1219. $scripts->add( 'media-image-widget', "/wp-admin/js/widgets/media-image-widget$suffix.js", array( 'media-widgets' ) );
  1220. $scripts->add( 'media-gallery-widget', "/wp-admin/js/widgets/media-gallery-widget$suffix.js", array( 'media-widgets' ) );
  1221. $scripts->add( 'media-video-widget', "/wp-admin/js/widgets/media-video-widget$suffix.js", array( 'media-widgets', 'media-audiovideo', 'wp-api-request' ) );
  1222. $scripts->add( 'text-widgets', "/wp-admin/js/widgets/text-widgets$suffix.js", array( 'jquery', 'backbone', 'editor', 'wp-util', 'wp-a11y' ) );
  1223. $scripts->add( 'custom-html-widgets', "/wp-admin/js/widgets/custom-html-widgets$suffix.js", array( 'jquery', 'backbone', 'wp-util', 'jquery-ui-core', 'wp-a11y' ) );
  1224. $scripts->add( 'theme', "/wp-admin/js/theme$suffix.js", array( 'wp-backbone', 'wp-a11y', 'customize-base' ), false, 1 );
  1225. $scripts->add( 'inline-edit-post', "/wp-admin/js/inline-edit-post$suffix.js", array( 'jquery', 'tags-suggest', 'wp-a11y' ), false, 1 );
  1226. $scripts->set_translations( 'inline-edit-post' );
  1227. $scripts->add( 'inline-edit-tax', "/wp-admin/js/inline-edit-tax$suffix.js", array( 'jquery', 'wp-a11y' ), false, 1 );
  1228. $scripts->set_translations( 'inline-edit-tax' );
  1229. $scripts->add( 'plugin-install', "/wp-admin/js/plugin-install$suffix.js", array( 'jquery', 'jquery-ui-core', 'thickbox' ), false, 1 );
  1230. $scripts->set_translations( 'plugin-install' );
  1231. $scripts->add( 'site-health', "/wp-admin/js/site-health$suffix.js", array( 'clipboard', 'jquery', 'wp-util', 'wp-a11y', 'wp-api-request', 'wp-url', 'wp-i18n', 'wp-hooks' ), false, 1 );
  1232. $scripts->set_translations( 'site-health' );
  1233. $scripts->add( 'privacy-tools', "/wp-admin/js/privacy-tools$suffix.js", array( 'jquery', 'wp-a11y' ), false, 1 );
  1234. $scripts->set_translations( 'privacy-tools' );
  1235. $scripts->add( 'updates', "/wp-admin/js/updates$suffix.js", array( 'common', 'jquery', 'wp-util', 'wp-a11y', 'wp-sanitize', 'wp-i18n' ), false, 1 );
  1236. $scripts->set_translations( 'updates' );
  1237. did_action( 'init' ) && $scripts->localize(
  1238. 'updates',
  1239. '_wpUpdatesSettings',
  1240. array(
  1241. 'ajax_nonce' => wp_installing() ? '' : wp_create_nonce( 'updates' ),
  1242. )
  1243. );
  1244. $scripts->add( 'farbtastic', '/wp-admin/js/farbtastic.js', array( 'jquery' ), '1.2' );
  1245. $scripts->add( 'iris', '/wp-admin/js/iris.min.js', array( 'jquery-ui-draggable', 'jquery-ui-slider', 'jquery-touch-punch' ), '1.1.1', 1 );
  1246. $scripts->add( 'wp-color-picker', "/wp-admin/js/color-picker$suffix.js", array( 'iris' ), false, 1 );
  1247. $scripts->set_translations( 'wp-color-picker' );
  1248. $scripts->add( 'dashboard', "/wp-admin/js/dashboard$suffix.js", array( 'jquery', 'admin-comments', 'postbox', 'wp-util', 'wp-a11y', 'wp-date' ), false, 1 );
  1249. $scripts->set_translations( 'dashboard' );
  1250. $scripts->add( 'list-revisions', "/wp-includes/js/wp-list-revisions$suffix.js" );
  1251. $scripts->add( 'media-grid', "/wp-includes/js/media-grid$suffix.js", array( 'media-editor' ), false, 1 );
  1252. $scripts->add( 'media', "/wp-admin/js/media$suffix.js", array( 'jquery', 'clipboard', 'wp-i18n', 'wp-a11y' ), false, 1 );
  1253. $scripts->set_translations( 'media' );
  1254. $scripts->add( 'image-edit', "/wp-admin/js/image-edit$suffix.js", array( 'jquery', 'jquery-ui-core', 'json2', 'imgareaselect', 'wp-a11y' ), false, 1 );
  1255. $scripts->set_translations( 'image-edit' );
  1256. $scripts->add( 'set-post-thumbnail', "/wp-admin/js/set-post-thumbnail$suffix.js", array( 'jquery' ), false, 1 );
  1257. $scripts->set_translations( 'set-post-thumbnail' );
  1258. /*
  1259. * Navigation Menus: Adding underscore as a dependency to utilize _.debounce
  1260. * see https://core.trac.wordpress.org/ticket/42321
  1261. */
  1262. $scripts->add( 'nav-menu', "/wp-admin/js/nav-menu$suffix.js", array( 'jquery-ui-sortable', 'jquery-ui-draggable', 'jquery-ui-droppable', 'wp-lists', 'postbox', 'json2', 'underscore' ) );
  1263. $scripts->set_translations( 'nav-menu' );
  1264. $scripts->add( 'custom-header', '/wp-admin/js/custom-header.js', array( 'jquery-masonry' ), false, 1 );
  1265. $scripts->add( 'custom-background', "/wp-admin/js/custom-background$suffix.js", array( 'wp-color-picker', 'media-views' ), false, 1 );
  1266. $scripts->add( 'media-gallery', "/wp-admin/js/media-gallery$suffix.js", array( 'jquery' ), false, 1 );
  1267. $scripts->add( 'svg-painter', '/wp-admin/js/svg-painter.js', array( 'jquery' ), false, 1 );
  1268. }
  1269. }
  1270. /**
  1271. * Assigns default styles to $styles object.
  1272. *
  1273. * Nothing is returned, because the $styles parameter is passed by reference.
  1274. * Meaning that whatever object is passed will be updated without having to
  1275. * reassign the variable that was passed back to the same value. This saves
  1276. * memory.
  1277. *
  1278. * Adding default styles is not the only task, it also assigns the base_url
  1279. * property, the default version, and text direction for the object.
  1280. *
  1281. * @since 2.6.0
  1282. *
  1283. * @global array $editor_styles
  1284. *
  1285. * @param WP_Styles $styles
  1286. */
  1287. function wp_default_styles( $styles ) {
  1288. global $editor_styles;
  1289. // Include an unmodified $wp_version.
  1290. require ABSPATH . WPINC . '/version.php';
  1291. if ( ! defined( 'SCRIPT_DEBUG' ) ) {
  1292. define( 'SCRIPT_DEBUG', false !== strpos( $wp_version, '-src' ) );
  1293. }
  1294. $guessurl = site_url();
  1295. if ( ! $guessurl ) {
  1296. $guessurl = wp_guess_url();
  1297. }
  1298. $styles->base_url = $guessurl;
  1299. $styles->content_url = defined( 'WP_CONTENT_URL' ) ? WP_CONTENT_URL : '';
  1300. $styles->default_version = get_bloginfo( 'version' );
  1301. $styles->text_direction = function_exists( 'is_rtl' ) && is_rtl() ? 'rtl' : 'ltr';
  1302. $styles->default_dirs = array( '/wp-admin/', '/wp-includes/css/' );
  1303. // Open Sans is no longer used by core, but may be relied upon by themes and plugins.
  1304. $open_sans_font_url = '';
  1305. /*
  1306. * translators: If there are characters in your language that are not supported
  1307. * by Open Sans, translate this to 'off'. Do not translate into your own language.
  1308. */
  1309. if ( 'off' !== _x( 'on', 'Open Sans font: on or off' ) ) {
  1310. $subsets = 'latin,latin-ext';
  1311. /*
  1312. * translators: To add an additional Open Sans character subset specific to your language,
  1313. * translate this to 'greek', 'cyrillic' or 'vietnamese'. Do not translate into your own language.
  1314. */
  1315. $subset = _x( 'no-subset', 'Open Sans font: add new subset (greek, cyrillic, vietnamese)' );
  1316. if ( 'cyrillic' === $subset ) {
  1317. $subsets .= ',cyrillic,cyrillic-ext';
  1318. } elseif ( 'greek' === $subset ) {
  1319. $subsets .= ',greek,greek-ext';
  1320. } elseif ( 'vietnamese' === $subset ) {
  1321. $subsets .= ',vietnamese';
  1322. }
  1323. // Hotlink Open Sans, for now.
  1324. $open_sans_font_url = "https://fonts.googleapis.com/css?family=Open+Sans:300italic,400italic,600italic,300,400,600&subset=$subsets&display=fallback";
  1325. }
  1326. // Register a stylesheet for the selected admin color scheme.
  1327. $styles->add( 'colors', true, array( 'wp-admin', 'buttons' ) );
  1328. $suffix = SCRIPT_DEBUG ? '' : '.min';
  1329. // Admin CSS.
  1330. $styles->add( 'common', "/wp-admin/css/common$suffix.css" );
  1331. $styles->add( 'forms', "/wp-admin/css/forms$suffix.css" );
  1332. $styles->add( 'admin-menu', "/wp-admin/css/admin-menu$suffix.css" );
  1333. $styles->add( 'dashboard', "/wp-admin/css/dashboard$suffix.css" );
  1334. $styles->add( 'list-tables', "/wp-admin/css/list-tables$suffix.css" );
  1335. $styles->add( 'edit', "/wp-admin/css/edit$suffix.css" );
  1336. $styles->add( 'revisions', "/wp-admin/css/revisions$suffix.css" );
  1337. $styles->add( 'media', "/wp-admin/css/media$suffix.css" );
  1338. $styles->add( 'themes', "/wp-admin/css/themes$suffix.css" );
  1339. $styles->add( 'about', "/wp-admin/css/about$suffix.css" );
  1340. $styles->add( 'nav-menus', "/wp-admin/css/nav-menus$suffix.css" );
  1341. $styles->add( 'widgets', "/wp-admin/css/widgets$suffix.css", array( 'wp-pointer' ) );
  1342. $styles->add( 'site-icon', "/wp-admin/css/site-icon$suffix.css" );
  1343. $styles->add( 'l10n', "/wp-admin/css/l10n$suffix.css" );
  1344. $styles->add( 'code-editor', "/wp-admin/css/code-editor$suffix.css", array( 'wp-codemirror' ) );
  1345. $styles->add( 'site-health', "/wp-admin/css/site-health$suffix.css" );
  1346. $styles->add( 'wp-admin', false, array( 'dashicons', 'common', 'forms', 'admin-menu', 'dashboard', 'list-tables', 'edit', 'revisions', 'media', 'themes', 'about', 'nav-menus', 'widgets', 'site-icon', 'l10n' ) );
  1347. $styles->add( 'login', "/wp-admin/css/login$suffix.css", array( 'dashicons', 'buttons', 'forms', 'l10n' ) );
  1348. $styles->add( 'install', "/wp-admin/css/install$suffix.css", array( 'dashicons', 'buttons', 'forms', 'l10n' ) );
  1349. $styles->add( 'wp-color-picker', "/wp-admin/css/color-picker$suffix.css" );
  1350. $styles->add( 'customize-controls', "/wp-admin/css/customize-controls$suffix.css", array( 'wp-admin', 'colors', 'imgareaselect' ) );
  1351. $styles->add( 'customize-widgets', "/wp-admin/css/customize-widgets$suffix.css", array( 'wp-admin', 'colors' ) );
  1352. $styles->add( 'customize-nav-menus', "/wp-admin/css/customize-nav-menus$suffix.css", array( 'wp-admin', 'colors' ) );
  1353. // Common dependencies.
  1354. $styles->add( 'buttons', "/wp-includes/css/buttons$suffix.css" );
  1355. $styles->add( 'dashicons', "/wp-includes/css/dashicons$suffix.css" );
  1356. // Includes CSS.
  1357. $styles->add( 'admin-bar', "/wp-includes/css/admin-bar$suffix.css", array( 'dashicons' ) );
  1358. $styles->add( 'wp-auth-check', "/wp-includes/css/wp-auth-check$suffix.css", array( 'dashicons' ) );
  1359. $styles->add( 'editor-buttons', "/wp-includes/css/editor$suffix.css", array( 'dashicons' ) );
  1360. $styles->add( 'media-views', "/wp-includes/css/media-views$suffix.css", array( 'buttons', 'dashicons', 'wp-mediaelement' ) );
  1361. $styles->add( 'wp-pointer', "/wp-includes/css/wp-pointer$suffix.css", array( 'dashicons' ) );
  1362. $styles->add( 'customize-preview', "/wp-includes/css/customize-preview$suffix.css", array( 'dashicons' ) );
  1363. $styles->add( 'wp-embed-template-ie', "/wp-includes/css/wp-embed-template-ie$suffix.css" );
  1364. $styles->add_data( 'wp-embed-template-ie', 'conditional', 'lte IE 8' );
  1365. // External libraries and friends.
  1366. $styles->add( 'imgareaselect', '/wp-includes/js/imgareaselect/imgareaselect.css', array(), '0.9.8' );
  1367. $styles->add( 'wp-jquery-ui-dialog', "/wp-includes/css/jquery-ui-dialog$suffix.css", array( 'dashicons' ) );
  1368. $styles->add( 'mediaelement', '/wp-includes/js/mediaelement/mediaelementplayer-legacy.min.css', array(), '4.2.17' );
  1369. $styles->add( 'wp-mediaelement', "/wp-includes/js/mediaelement/wp-mediaelement$suffix.css", array( 'mediaelement' ) );
  1370. $styles->add( 'thickbox', '/wp-includes/js/thickbox/thickbox.css', array( 'dashicons' ) );
  1371. $styles->add( 'wp-codemirror', '/wp-includes/js/codemirror/codemirror.min.css', array(), '5.29.1-alpha-ee20357' );
  1372. // Deprecated CSS.
  1373. $styles->add( 'deprecated-media', "/wp-admin/css/deprecated-media$suffix.css" );
  1374. $styles->add( 'farbtastic', "/wp-admin/css/farbtastic$suffix.css", array(), '1.3u1' );
  1375. $styles->add( 'jcrop', '/wp-includes/js/jcrop/jquery.Jcrop.min.css', array(), '0.9.15' );
  1376. $styles->add( 'colors-fresh', false, array( 'wp-admin', 'buttons' ) ); // Old handle.
  1377. $styles->add( 'open-sans', $open_sans_font_url ); // No longer used in core as of 4.6.
  1378. // Noto Serif is no longer used by core, but may be relied upon by themes and plugins.
  1379. $fonts_url = '';
  1380. /*
  1381. * translators: Use this to specify the proper Google Font name and variants
  1382. * to load that is supported by your language. Do not translate.
  1383. * Set to 'off' to disable loading.
  1384. */
  1385. $font_family = _x( 'Noto Serif:400,400i,700,700i', 'Google Font Name and Variants' );
  1386. if ( 'off' !== $font_family ) {
  1387. $fonts_url = 'https://fonts.googleapis.com/css?family=' . urlencode( $font_family );
  1388. }
  1389. $styles->add( 'wp-editor-font', $fonts_url ); // No longer used in core as of 5.7.
  1390. $block_library_theme_path = WPINC . "/css/dist/block-library/theme$suffix.css";
  1391. $styles->add( 'wp-block-library-theme', "/$block_library_theme_path" );
  1392. $styles->add_data( 'wp-block-library-theme', 'path', ABSPATH . $block_library_theme_path );
  1393. $styles->add(
  1394. 'wp-reset-editor-styles',
  1395. "/wp-includes/css/dist/block-library/reset$suffix.css",
  1396. array( 'common', 'forms' ) // Make sure the reset is loaded after the default WP Admin styles.
  1397. );
  1398. $styles->add(
  1399. 'wp-editor-classic-layout-styles',
  1400. "/wp-includes/css/dist/edit-post/classic$suffix.css",
  1401. array()
  1402. );
  1403. $wp_edit_blocks_dependencies = array(
  1404. 'wp-components',
  1405. 'wp-editor',
  1406. // This need to be added before the block library styles,
  1407. // The block library styles override the "reset" styles.
  1408. 'wp-reset-editor-styles',
  1409. 'wp-block-library',
  1410. 'wp-reusable-blocks',
  1411. );
  1412. // Only load the default layout and margin styles for themes without theme.json file.
  1413. if ( ! WP_Theme_JSON_Resolver::theme_has_support() ) {
  1414. $wp_edit_blocks_dependencies[] = 'wp-editor-classic-layout-styles';
  1415. }
  1416. if ( ! is_array( $editor_styles ) || count( $editor_styles ) === 0 ) {
  1417. // Include opinionated block styles if no $editor_styles are declared, so the editor never appears broken.
  1418. $wp_edit_blocks_dependencies[] = 'wp-block-library-theme';
  1419. }
  1420. $styles->add(
  1421. 'wp-edit-blocks',
  1422. "/wp-includes/css/dist/block-library/editor$suffix.css",
  1423. $wp_edit_blocks_dependencies
  1424. );
  1425. $package_styles = array(
  1426. 'block-editor' => array( 'wp-components' ),
  1427. 'block-library' => array(),
  1428. 'block-directory' => array(),
  1429. 'components' => array(),
  1430. 'edit-post' => array(
  1431. 'wp-components',
  1432. 'wp-block-editor',
  1433. 'wp-editor',
  1434. 'wp-edit-blocks',
  1435. 'wp-block-library',
  1436. 'wp-nux',
  1437. ),
  1438. 'editor' => array(
  1439. 'wp-components',
  1440. 'wp-block-editor',
  1441. 'wp-nux',
  1442. 'wp-reusable-blocks',
  1443. ),
  1444. 'format-library' => array(),
  1445. 'list-reusable-blocks' => array( 'wp-components' ),
  1446. 'reusable-blocks' => array( 'wp-components' ),
  1447. 'nux' => array( 'wp-components' ),
  1448. 'widgets' => array(
  1449. 'wp-components',
  1450. ),
  1451. 'edit-widgets' => array(
  1452. 'wp-widgets',
  1453. 'wp-block-editor',
  1454. 'wp-edit-blocks',
  1455. 'wp-block-library',
  1456. 'wp-reusable-blocks',
  1457. ),
  1458. 'customize-widgets' => array(
  1459. 'wp-widgets',
  1460. 'wp-block-editor',
  1461. 'wp-edit-blocks',
  1462. 'wp-block-library',
  1463. 'wp-reusable-blocks',
  1464. ),
  1465. 'edit-site' => array(
  1466. 'wp-components',
  1467. 'wp-block-editor',
  1468. 'wp-edit-blocks',
  1469. ),
  1470. );
  1471. foreach ( $package_styles as $package => $dependencies ) {
  1472. $handle = 'wp-' . $package;
  1473. $path = "/wp-includes/css/dist/$package/style$suffix.css";
  1474. if ( 'block-library' === $package && wp_should_load_separate_core_block_assets() ) {
  1475. $path = "/wp-includes/css/dist/$package/common$suffix.css";
  1476. }
  1477. $styles->add( $handle, $path, $dependencies );
  1478. $styles->add_data( $handle, 'path', ABSPATH . $path );
  1479. }
  1480. // RTL CSS.
  1481. $rtl_styles = array(
  1482. // Admin CSS.
  1483. 'common',
  1484. 'forms',
  1485. 'admin-menu',
  1486. 'dashboard',
  1487. 'list-tables',
  1488. 'edit',
  1489. 'revisions',
  1490. 'media',
  1491. 'themes',
  1492. 'about',
  1493. 'nav-menus',
  1494. 'widgets',
  1495. 'site-icon',
  1496. 'l10n',
  1497. 'install',
  1498. 'wp-color-picker',
  1499. 'customize-controls',
  1500. 'customize-widgets',
  1501. 'customize-nav-menus',
  1502. 'customize-preview',
  1503. 'login',
  1504. 'site-health',
  1505. // Includes CSS.
  1506. 'buttons',
  1507. 'admin-bar',
  1508. 'wp-auth-check',
  1509. 'editor-buttons',
  1510. 'media-views',
  1511. 'wp-pointer',
  1512. 'wp-jquery-ui-dialog',
  1513. // Package styles.
  1514. 'wp-reset-editor-styles',
  1515. 'wp-editor-classic-layout-styles',
  1516. 'wp-block-library-theme',
  1517. 'wp-edit-blocks',
  1518. 'wp-block-editor',
  1519. 'wp-block-library',
  1520. 'wp-block-directory',
  1521. 'wp-components',
  1522. 'wp-customize-widgets',
  1523. 'wp-edit-post',
  1524. 'wp-edit-site',
  1525. 'wp-edit-widgets',
  1526. 'wp-editor',
  1527. 'wp-format-library',
  1528. 'wp-list-reusable-blocks',
  1529. 'wp-reusable-blocks',
  1530. 'wp-nux',
  1531. 'wp-widgets',
  1532. // Deprecated CSS.
  1533. 'deprecated-media',
  1534. 'farbtastic',
  1535. );
  1536. foreach ( $rtl_styles as $rtl_style ) {
  1537. $styles->add_data( $rtl_style, 'rtl', 'replace' );
  1538. if ( $suffix ) {
  1539. $styles->add_data( $rtl_style, 'suffix', $suffix );
  1540. }
  1541. }
  1542. }
  1543. /**
  1544. * Reorders JavaScript scripts array to place prototype before jQuery.
  1545. *
  1546. * @since 2.3.1
  1547. *
  1548. * @param string[] $js_array JavaScript scripts array
  1549. * @return string[] Reordered array, if needed.
  1550. */
  1551. function wp_prototype_before_jquery( $js_array ) {
  1552. $prototype = array_search( 'prototype', $js_array, true );
  1553. if ( false === $prototype ) {
  1554. return $js_array;
  1555. }
  1556. $jquery = array_search( 'jquery', $js_array, true );
  1557. if ( false === $jquery ) {
  1558. return $js_array;
  1559. }
  1560. if ( $prototype < $jquery ) {
  1561. return $js_array;
  1562. }
  1563. unset( $js_array[ $prototype ] );
  1564. array_splice( $js_array, $jquery, 0, 'prototype' );
  1565. return $js_array;
  1566. }
  1567. /**
  1568. * Loads localized data on print rather than initialization.
  1569. *
  1570. * These localizations require information that may not be loaded even by init.
  1571. *
  1572. * @since 2.5.0
  1573. */
  1574. function wp_just_in_time_script_localization() {
  1575. wp_localize_script(
  1576. 'autosave',
  1577. 'autosaveL10n',
  1578. array(
  1579. 'autosaveInterval' => AUTOSAVE_INTERVAL,
  1580. 'blog_id' => get_current_blog_id(),
  1581. )
  1582. );
  1583. wp_localize_script(
  1584. 'mce-view',
  1585. 'mceViewL10n',
  1586. array(
  1587. 'shortcodes' => ! empty( $GLOBALS['shortcode_tags'] ) ? array_keys( $GLOBALS['shortcode_tags'] ) : array(),
  1588. )
  1589. );
  1590. wp_localize_script(
  1591. 'word-count',
  1592. 'wordCountL10n',
  1593. array(
  1594. /*
  1595. * translators: If your word count is based on single characters (e.g. East Asian characters),
  1596. * enter 'characters_excluding_spaces' or 'characters_including_spaces'. Otherwise, enter 'words'.
  1597. * Do not translate into your own language.
  1598. */
  1599. 'type' => _x( 'words', 'Word count type. Do not translate!' ),
  1600. 'shortcodes' => ! empty( $GLOBALS['shortcode_tags'] ) ? array_keys( $GLOBALS['shortcode_tags'] ) : array(),
  1601. )
  1602. );
  1603. }
  1604. /**
  1605. * Localizes the jQuery UI datepicker.
  1606. *
  1607. * @since 4.6.0
  1608. *
  1609. * @link https://api.jqueryui.com/datepicker/#options
  1610. *
  1611. * @global WP_Locale $wp_locale WordPress date and time locale object.
  1612. */
  1613. function wp_localize_jquery_ui_datepicker() {
  1614. global $wp_locale;
  1615. if ( ! wp_script_is( 'jquery-ui-datepicker', 'enqueued' ) ) {
  1616. return;
  1617. }
  1618. // Convert the PHP date format into jQuery UI's format.
  1619. $datepicker_date_format = str_replace(
  1620. array(
  1621. 'd',
  1622. 'j',
  1623. 'l',
  1624. 'z', // Day.
  1625. 'F',
  1626. 'M',
  1627. 'n',
  1628. 'm', // Month.
  1629. 'Y',
  1630. 'y', // Year.
  1631. ),
  1632. array(
  1633. 'dd',
  1634. 'd',
  1635. 'DD',
  1636. 'o',
  1637. 'MM',
  1638. 'M',
  1639. 'm',
  1640. 'mm',
  1641. 'yy',
  1642. 'y',
  1643. ),
  1644. get_option( 'date_format' )
  1645. );
  1646. $datepicker_defaults = wp_json_encode(
  1647. array(
  1648. 'closeText' => __( 'Close' ),
  1649. 'currentText' => __( 'Today' ),
  1650. 'monthNames' => array_values( $wp_locale->month ),
  1651. 'monthNamesShort' => array_values( $wp_locale->month_abbrev ),
  1652. 'nextText' => __( 'Next' ),
  1653. 'prevText' => __( 'Previous' ),
  1654. 'dayNames' => array_values( $wp_locale->weekday ),
  1655. 'dayNamesShort' => array_values( $wp_locale->weekday_abbrev ),
  1656. 'dayNamesMin' => array_values( $wp_locale->weekday_initial ),
  1657. 'dateFormat' => $datepicker_date_format,
  1658. 'firstDay' => absint( get_option( 'start_of_week' ) ),
  1659. 'isRTL' => $wp_locale->is_rtl(),
  1660. )
  1661. );
  1662. wp_add_inline_script( 'jquery-ui-datepicker', "jQuery(function(jQuery){jQuery.datepicker.setDefaults({$datepicker_defaults});});" );
  1663. }
  1664. /**
  1665. * Localizes community events data that needs to be passed to dashboard.js.
  1666. *
  1667. * @since 4.8.0
  1668. */
  1669. function wp_localize_community_events() {
  1670. if ( ! wp_script_is( 'dashboard' ) ) {
  1671. return;
  1672. }
  1673. require_once ABSPATH . 'wp-admin/includes/class-wp-community-events.php';
  1674. $user_id = get_current_user_id();
  1675. $saved_location = get_user_option( 'community-events-location', $user_id );
  1676. $saved_ip_address = isset( $saved_location['ip'] ) ? $saved_location['ip'] : false;
  1677. $current_ip_address = WP_Community_Events::get_unsafe_client_ip();
  1678. /*
  1679. * If the user's location is based on their IP address, then update their
  1680. * location when their IP address changes. This allows them to see events
  1681. * in their current city when travelling. Otherwise, they would always be
  1682. * shown events in the city where they were when they first loaded the
  1683. * Dashboard, which could have been months or years ago.
  1684. */
  1685. if ( $saved_ip_address && $current_ip_address && $current_ip_address !== $saved_ip_address ) {
  1686. $saved_location['ip'] = $current_ip_address;
  1687. update_user_meta( $user_id, 'community-events-location', $saved_location );
  1688. }
  1689. $events_client = new WP_Community_Events( $user_id, $saved_location );
  1690. wp_localize_script(
  1691. 'dashboard',
  1692. 'communityEventsData',
  1693. array(
  1694. 'nonce' => wp_create_nonce( 'community_events' ),
  1695. 'cache' => $events_client->get_cached_events(),
  1696. 'time_format' => get_option( 'time_format' ),
  1697. )
  1698. );
  1699. }
  1700. /**
  1701. * Administration Screen CSS for changing the styles.
  1702. *
  1703. * If installing the 'wp-admin/' directory will be replaced with './'.
  1704. *
  1705. * The $_wp_admin_css_colors global manages the Administration Screens CSS
  1706. * stylesheet that is loaded. The option that is set is 'admin_color' and is the
  1707. * color and key for the array. The value for the color key is an object with
  1708. * a 'url' parameter that has the URL path to the CSS file.
  1709. *
  1710. * The query from $src parameter will be appended to the URL that is given from
  1711. * the $_wp_admin_css_colors array value URL.
  1712. *
  1713. * @since 2.6.0
  1714. *
  1715. * @global array $_wp_admin_css_colors
  1716. *
  1717. * @param string $src Source URL.
  1718. * @param string $handle Either 'colors' or 'colors-rtl'.
  1719. * @return string|false URL path to CSS stylesheet for Administration Screens.
  1720. */
  1721. function wp_style_loader_src( $src, $handle ) {
  1722. global $_wp_admin_css_colors;
  1723. if ( wp_installing() ) {
  1724. return preg_replace( '#^wp-admin/#', './', $src );
  1725. }
  1726. if ( 'colors' === $handle ) {
  1727. $color = get_user_option( 'admin_color' );
  1728. if ( empty( $color ) || ! isset( $_wp_admin_css_colors[ $color ] ) ) {
  1729. $color = 'fresh';
  1730. }
  1731. $color = $_wp_admin_css_colors[ $color ];
  1732. $url = $color->url;
  1733. if ( ! $url ) {
  1734. return false;
  1735. }
  1736. $parsed = parse_url( $src );
  1737. if ( isset( $parsed['query'] ) && $parsed['query'] ) {
  1738. wp_parse_str( $parsed['query'], $qv );
  1739. $url = add_query_arg( $qv, $url );
  1740. }
  1741. return $url;
  1742. }
  1743. return $src;
  1744. }
  1745. /**
  1746. * Prints the script queue in the HTML head on admin pages.
  1747. *
  1748. * Postpones the scripts that were queued for the footer.
  1749. * print_footer_scripts() is called in the footer to print these scripts.
  1750. *
  1751. * @since 2.8.0
  1752. *
  1753. * @see wp_print_scripts()
  1754. *
  1755. * @global bool $concatenate_scripts
  1756. *
  1757. * @return array
  1758. */
  1759. function print_head_scripts() {
  1760. global $concatenate_scripts;
  1761. if ( ! did_action( 'wp_print_scripts' ) ) {
  1762. /** This action is documented in wp-includes/functions.wp-scripts.php */
  1763. do_action( 'wp_print_scripts' );
  1764. }
  1765. $wp_scripts = wp_scripts();
  1766. script_concat_settings();
  1767. $wp_scripts->do_concat = $concatenate_scripts;
  1768. $wp_scripts->do_head_items();
  1769. /**
  1770. * Filters whether to print the head scripts.
  1771. *
  1772. * @since 2.8.0
  1773. *
  1774. * @param bool $print Whether to print the head scripts. Default true.
  1775. */
  1776. if ( apply_filters( 'print_head_scripts', true ) ) {
  1777. _print_scripts();
  1778. }
  1779. $wp_scripts->reset();
  1780. return $wp_scripts->done;
  1781. }
  1782. /**
  1783. * Prints the scripts that were queued for the footer or too late for the HTML head.
  1784. *
  1785. * @since 2.8.0
  1786. *
  1787. * @global WP_Scripts $wp_scripts
  1788. * @global bool $concatenate_scripts
  1789. *
  1790. * @return array
  1791. */
  1792. function print_footer_scripts() {
  1793. global $wp_scripts, $concatenate_scripts;
  1794. if ( ! ( $wp_scripts instanceof WP_Scripts ) ) {
  1795. return array(); // No need to run if not instantiated.
  1796. }
  1797. script_concat_settings();
  1798. $wp_scripts->do_concat = $concatenate_scripts;
  1799. $wp_scripts->do_footer_items();
  1800. /**
  1801. * Filters whether to print the footer scripts.
  1802. *
  1803. * @since 2.8.0
  1804. *
  1805. * @param bool $print Whether to print the footer scripts. Default true.
  1806. */
  1807. if ( apply_filters( 'print_footer_scripts', true ) ) {
  1808. _print_scripts();
  1809. }
  1810. $wp_scripts->reset();
  1811. return $wp_scripts->done;
  1812. }
  1813. /**
  1814. * Prints scripts (internal use only)
  1815. *
  1816. * @ignore
  1817. *
  1818. * @global WP_Scripts $wp_scripts
  1819. * @global bool $compress_scripts
  1820. */
  1821. function _print_scripts() {
  1822. global $wp_scripts, $compress_scripts;
  1823. $zip = $compress_scripts ? 1 : 0;
  1824. if ( $zip && defined( 'ENFORCE_GZIP' ) && ENFORCE_GZIP ) {
  1825. $zip = 'gzip';
  1826. }
  1827. $concat = trim( $wp_scripts->concat, ', ' );
  1828. $type_attr = current_theme_supports( 'html5', 'script' ) ? '' : " type='text/javascript'";
  1829. if ( $concat ) {
  1830. if ( ! empty( $wp_scripts->print_code ) ) {
  1831. echo "\n<script{$type_attr}>\n";
  1832. echo "/* <![CDATA[ */\n"; // Not needed in HTML 5.
  1833. echo $wp_scripts->print_code;
  1834. echo "/* ]]> */\n";
  1835. echo "</script>\n";
  1836. }
  1837. $concat = str_split( $concat, 128 );
  1838. $concatenated = '';
  1839. foreach ( $concat as $key => $chunk ) {
  1840. $concatenated .= "&load%5Bchunk_{$key}%5D={$chunk}";
  1841. }
  1842. $src = $wp_scripts->base_url . "/wp-admin/load-scripts.php?c={$zip}" . $concatenated . '&ver=' . $wp_scripts->default_version;
  1843. echo "<script{$type_attr} src='" . esc_attr( $src ) . "'></script>\n";
  1844. }
  1845. if ( ! empty( $wp_scripts->print_html ) ) {
  1846. echo $wp_scripts->print_html;
  1847. }
  1848. }
  1849. /**
  1850. * Prints the script queue in the HTML head on the front end.
  1851. *
  1852. * Postpones the scripts that were queued for the footer.
  1853. * wp_print_footer_scripts() is called in the footer to print these scripts.
  1854. *
  1855. * @since 2.8.0
  1856. *
  1857. * @global WP_Scripts $wp_scripts
  1858. *
  1859. * @return array
  1860. */
  1861. function wp_print_head_scripts() {
  1862. global $wp_scripts;
  1863. if ( ! did_action( 'wp_print_scripts' ) ) {
  1864. /** This action is documented in wp-includes/functions.wp-scripts.php */
  1865. do_action( 'wp_print_scripts' );
  1866. }
  1867. if ( ! ( $wp_scripts instanceof WP_Scripts ) ) {
  1868. return array(); // No need to run if nothing is queued.
  1869. }
  1870. return print_head_scripts();
  1871. }
  1872. /**
  1873. * Private, for use in *_footer_scripts hooks
  1874. *
  1875. * @since 3.3.0
  1876. */
  1877. function _wp_footer_scripts() {
  1878. print_late_styles();
  1879. print_footer_scripts();
  1880. }
  1881. /**
  1882. * Hooks to print the scripts and styles in the footer.
  1883. *
  1884. * @since 2.8.0
  1885. */
  1886. function wp_print_footer_scripts() {
  1887. /**
  1888. * Fires when footer scripts are printed.
  1889. *
  1890. * @since 2.8.0
  1891. */
  1892. do_action( 'wp_print_footer_scripts' );
  1893. }
  1894. /**
  1895. * Wrapper for do_action( 'wp_enqueue_scripts' ).
  1896. *
  1897. * Allows plugins to queue scripts for the front end using wp_enqueue_script().
  1898. * Runs first in wp_head() where all is_home(), is_page(), etc. functions are available.
  1899. *
  1900. * @since 2.8.0
  1901. */
  1902. function wp_enqueue_scripts() {
  1903. /**
  1904. * Fires when scripts and styles are enqueued.
  1905. *
  1906. * @since 2.8.0
  1907. */
  1908. do_action( 'wp_enqueue_scripts' );
  1909. }
  1910. /**
  1911. * Prints the styles queue in the HTML head on admin pages.
  1912. *
  1913. * @since 2.8.0
  1914. *
  1915. * @global bool $concatenate_scripts
  1916. *
  1917. * @return array
  1918. */
  1919. function print_admin_styles() {
  1920. global $concatenate_scripts;
  1921. $wp_styles = wp_styles();
  1922. script_concat_settings();
  1923. $wp_styles->do_concat = $concatenate_scripts;
  1924. $wp_styles->do_items( false );
  1925. /**
  1926. * Filters whether to print the admin styles.
  1927. *
  1928. * @since 2.8.0
  1929. *
  1930. * @param bool $print Whether to print the admin styles. Default true.
  1931. */
  1932. if ( apply_filters( 'print_admin_styles', true ) ) {
  1933. _print_styles();
  1934. }
  1935. $wp_styles->reset();
  1936. return $wp_styles->done;
  1937. }
  1938. /**
  1939. * Prints the styles that were queued too late for the HTML head.
  1940. *
  1941. * @since 3.3.0
  1942. *
  1943. * @global WP_Styles $wp_styles
  1944. * @global bool $concatenate_scripts
  1945. *
  1946. * @return array|void
  1947. */
  1948. function print_late_styles() {
  1949. global $wp_styles, $concatenate_scripts;
  1950. if ( ! ( $wp_styles instanceof WP_Styles ) ) {
  1951. return;
  1952. }
  1953. script_concat_settings();
  1954. $wp_styles->do_concat = $concatenate_scripts;
  1955. $wp_styles->do_footer_items();
  1956. /**
  1957. * Filters whether to print the styles queued too late for the HTML head.
  1958. *
  1959. * @since 3.3.0
  1960. *
  1961. * @param bool $print Whether to print the 'late' styles. Default true.
  1962. */
  1963. if ( apply_filters( 'print_late_styles', true ) ) {
  1964. _print_styles();
  1965. }
  1966. $wp_styles->reset();
  1967. return $wp_styles->done;
  1968. }
  1969. /**
  1970. * Prints styles (internal use only).
  1971. *
  1972. * @ignore
  1973. * @since 3.3.0
  1974. *
  1975. * @global bool $compress_css
  1976. */
  1977. function _print_styles() {
  1978. global $compress_css;
  1979. $wp_styles = wp_styles();
  1980. $zip = $compress_css ? 1 : 0;
  1981. if ( $zip && defined( 'ENFORCE_GZIP' ) && ENFORCE_GZIP ) {
  1982. $zip = 'gzip';
  1983. }
  1984. $concat = trim( $wp_styles->concat, ', ' );
  1985. $type_attr = current_theme_supports( 'html5', 'style' ) ? '' : ' type="text/css"';
  1986. if ( $concat ) {
  1987. $dir = $wp_styles->text_direction;
  1988. $ver = $wp_styles->default_version;
  1989. $concat = str_split( $concat, 128 );
  1990. $concatenated = '';
  1991. foreach ( $concat as $key => $chunk ) {
  1992. $concatenated .= "&load%5Bchunk_{$key}%5D={$chunk}";
  1993. }
  1994. $href = $wp_styles->base_url . "/wp-admin/load-styles.php?c={$zip}&dir={$dir}" . $concatenated . '&ver=' . $ver;
  1995. echo "<link rel='stylesheet' href='" . esc_attr( $href ) . "'{$type_attr} media='all' />\n";
  1996. if ( ! empty( $wp_styles->print_code ) ) {
  1997. echo "<style{$type_attr}>\n";
  1998. echo $wp_styles->print_code;
  1999. echo "\n</style>\n";
  2000. }
  2001. }
  2002. if ( ! empty( $wp_styles->print_html ) ) {
  2003. echo $wp_styles->print_html;
  2004. }
  2005. }
  2006. /**
  2007. * Determines the concatenation and compression settings for scripts and styles.
  2008. *
  2009. * @since 2.8.0
  2010. *
  2011. * @global bool $concatenate_scripts
  2012. * @global bool $compress_scripts
  2013. * @global bool $compress_css
  2014. */
  2015. function script_concat_settings() {
  2016. global $concatenate_scripts, $compress_scripts, $compress_css;
  2017. $compressed_output = ( ini_get( 'zlib.output_compression' ) || 'ob_gzhandler' === ini_get( 'output_handler' ) );
  2018. $can_compress_scripts = ! wp_installing() && get_site_option( 'can_compress_scripts' );
  2019. if ( ! isset( $concatenate_scripts ) ) {
  2020. $concatenate_scripts = defined( 'CONCATENATE_SCRIPTS' ) ? CONCATENATE_SCRIPTS : true;
  2021. if ( ( ! is_admin() && ! did_action( 'login_init' ) ) || ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ) ) {
  2022. $concatenate_scripts = false;
  2023. }
  2024. }
  2025. if ( ! isset( $compress_scripts ) ) {
  2026. $compress_scripts = defined( 'COMPRESS_SCRIPTS' ) ? COMPRESS_SCRIPTS : true;
  2027. if ( $compress_scripts && ( ! $can_compress_scripts || $compressed_output ) ) {
  2028. $compress_scripts = false;
  2029. }
  2030. }
  2031. if ( ! isset( $compress_css ) ) {
  2032. $compress_css = defined( 'COMPRESS_CSS' ) ? COMPRESS_CSS : true;
  2033. if ( $compress_css && ( ! $can_compress_scripts || $compressed_output ) ) {
  2034. $compress_css = false;
  2035. }
  2036. }
  2037. }
  2038. /**
  2039. * Handles the enqueueing of block scripts and styles that are common to both
  2040. * the editor and the front-end.
  2041. *
  2042. * @since 5.0.0
  2043. */
  2044. function wp_common_block_scripts_and_styles() {
  2045. if ( is_admin() && ! wp_should_load_block_editor_scripts_and_styles() ) {
  2046. return;
  2047. }
  2048. wp_enqueue_style( 'wp-block-library' );
  2049. if ( current_theme_supports( 'wp-block-styles' ) ) {
  2050. if ( wp_should_load_separate_core_block_assets() ) {
  2051. $suffix = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? 'css' : 'min.css';
  2052. $files = glob( __DIR__ . "/blocks/**/theme.$suffix" );
  2053. foreach ( $files as $path ) {
  2054. $block_name = basename( dirname( $path ) );
  2055. if ( is_rtl() && file_exists( __DIR__ . "/blocks/$block_name/theme-rtl.$suffix" ) ) {
  2056. $path = __DIR__ . "/blocks/$block_name/theme-rtl.$suffix";
  2057. }
  2058. wp_add_inline_style( "wp-block-{$block_name}", file_get_contents( $path ) );
  2059. }
  2060. } else {
  2061. wp_enqueue_style( 'wp-block-library-theme' );
  2062. }
  2063. }
  2064. /**
  2065. * Fires after enqueuing block assets for both editor and front-end.
  2066. *
  2067. * Call `add_action` on any hook before 'wp_enqueue_scripts'.
  2068. *
  2069. * In the function call you supply, simply use `wp_enqueue_script` and
  2070. * `wp_enqueue_style` to add your functionality to the Gutenberg editor.
  2071. *
  2072. * @since 5.0.0
  2073. */
  2074. do_action( 'enqueue_block_assets' );
  2075. }
  2076. /**
  2077. * Applies a filter to the list of style nodes that comes from WP_Theme_JSON::get_style_nodes().
  2078. *
  2079. * This particular filter removes all of the blocks from the array.
  2080. *
  2081. * We want WP_Theme_JSON to be ignorant of the implementation details of how the CSS is being used.
  2082. * This filter allows us to modify the output of WP_Theme_JSON depending on whether or not we are
  2083. * loading separate assets, without making the class aware of that detail.
  2084. *
  2085. * @since 6.1.0
  2086. *
  2087. * @param array $nodes The nodes to filter.
  2088. * @return array A filtered array of style nodes.
  2089. */
  2090. function wp_filter_out_block_nodes( $nodes ) {
  2091. return array_filter(
  2092. $nodes,
  2093. function( $node ) {
  2094. return ! in_array( 'blocks', $node['path'], true );
  2095. },
  2096. ARRAY_FILTER_USE_BOTH
  2097. );
  2098. }
  2099. /**
  2100. * Enqueues the global styles defined via theme.json.
  2101. *
  2102. * @since 5.8.0
  2103. */
  2104. function wp_enqueue_global_styles() {
  2105. $separate_assets = wp_should_load_separate_core_block_assets();
  2106. $is_block_theme = wp_is_block_theme();
  2107. $is_classic_theme = ! $is_block_theme;
  2108. /*
  2109. * Global styles should be printed in the head when loading all styles combined.
  2110. * The footer should only be used to print global styles for classic themes with separate core assets enabled.
  2111. *
  2112. * See https://core.trac.wordpress.org/ticket/53494.
  2113. */
  2114. if (
  2115. ( $is_block_theme && doing_action( 'wp_footer' ) ) ||
  2116. ( $is_classic_theme && doing_action( 'wp_footer' ) && ! $separate_assets ) ||
  2117. ( $is_classic_theme && doing_action( 'wp_enqueue_scripts' ) && $separate_assets )
  2118. ) {
  2119. return;
  2120. }
  2121. /*
  2122. * If loading the CSS for each block separately, then load the theme.json CSS conditionally.
  2123. * This removes the CSS from the global-styles stylesheet and adds it to the inline CSS for each block.
  2124. * This filter must be registered before calling wp_get_global_stylesheet();
  2125. */
  2126. add_filter( 'wp_theme_json_get_style_nodes', 'wp_filter_out_block_nodes' );
  2127. $stylesheet = wp_get_global_stylesheet();
  2128. if ( empty( $stylesheet ) ) {
  2129. return;
  2130. }
  2131. wp_register_style( 'global-styles', false, array(), true, true );
  2132. wp_add_inline_style( 'global-styles', $stylesheet );
  2133. wp_enqueue_style( 'global-styles' );
  2134. // Add each block as an inline css.
  2135. wp_add_global_styles_for_blocks();
  2136. }
  2137. /**
  2138. * Renders the SVG filters supplied by theme.json.
  2139. *
  2140. * Note that this doesn't render the per-block user-defined
  2141. * filters which are handled by wp_render_duotone_support,
  2142. * but it should be rendered before the filtered content
  2143. * in the body to satisfy Safari's rendering quirks.
  2144. *
  2145. * @since 5.9.1
  2146. */
  2147. function wp_global_styles_render_svg_filters() {
  2148. /*
  2149. * When calling via the in_admin_header action, we only want to render the
  2150. * SVGs on block editor pages.
  2151. */
  2152. if (
  2153. is_admin() &&
  2154. ! get_current_screen()->is_block_editor()
  2155. ) {
  2156. return;
  2157. }
  2158. $filters = wp_get_global_styles_svg_filters();
  2159. if ( ! empty( $filters ) ) {
  2160. echo $filters;
  2161. }
  2162. }
  2163. /**
  2164. * Checks if the editor scripts and styles for all registered block types
  2165. * should be enqueued on the current screen.
  2166. *
  2167. * @since 5.6.0
  2168. *
  2169. * @global WP_Screen $current_screen WordPress current screen object.
  2170. *
  2171. * @return bool Whether scripts and styles should be enqueued.
  2172. */
  2173. function wp_should_load_block_editor_scripts_and_styles() {
  2174. global $current_screen;
  2175. $is_block_editor_screen = ( $current_screen instanceof WP_Screen ) && $current_screen->is_block_editor();
  2176. /**
  2177. * Filters the flag that decides whether or not block editor scripts and styles
  2178. * are going to be enqueued on the current screen.
  2179. *
  2180. * @since 5.6.0
  2181. *
  2182. * @param bool $is_block_editor_screen Current value of the flag.
  2183. */
  2184. return apply_filters( 'should_load_block_editor_scripts_and_styles', $is_block_editor_screen );
  2185. }
  2186. /**
  2187. * Checks whether separate styles should be loaded for core blocks on-render.
  2188. *
  2189. * When this function returns true, other functions ensure that core blocks
  2190. * only load their assets on-render, and each block loads its own, individual
  2191. * assets. Third-party blocks only load their assets when rendered.
  2192. *
  2193. * When this function returns false, all core block assets are loaded regardless
  2194. * of whether they are rendered in a page or not, because they are all part of
  2195. * the `block-library/style.css` file. Assets for third-party blocks are always
  2196. * enqueued regardless of whether they are rendered or not.
  2197. *
  2198. * This only affects front end and not the block editor screens.
  2199. *
  2200. * @see wp_enqueue_registered_block_scripts_and_styles()
  2201. * @see register_block_style_handle()
  2202. *
  2203. * @since 5.8.0
  2204. *
  2205. * @return bool Whether separate assets will be loaded.
  2206. */
  2207. function wp_should_load_separate_core_block_assets() {
  2208. if ( is_admin() || is_feed() || ( defined( 'REST_REQUEST' ) && REST_REQUEST ) ) {
  2209. return false;
  2210. }
  2211. /**
  2212. * Filters whether block styles should be loaded separately.
  2213. *
  2214. * Returning false loads all core block assets, regardless of whether they are rendered
  2215. * in a page or not. Returning true loads core block assets only when they are rendered.
  2216. *
  2217. * @since 5.8.0
  2218. *
  2219. * @param bool $load_separate_assets Whether separate assets will be loaded.
  2220. * Default false (all block assets are loaded, even when not used).
  2221. */
  2222. return apply_filters( 'should_load_separate_core_block_assets', false );
  2223. }
  2224. /**
  2225. * Enqueues registered block scripts and styles, depending on current rendered
  2226. * context (only enqueuing editor scripts while in context of the editor).
  2227. *
  2228. * @since 5.0.0
  2229. *
  2230. * @global WP_Screen $current_screen WordPress current screen object.
  2231. */
  2232. function wp_enqueue_registered_block_scripts_and_styles() {
  2233. global $current_screen;
  2234. if ( wp_should_load_separate_core_block_assets() ) {
  2235. return;
  2236. }
  2237. $load_editor_scripts_and_styles = is_admin() && wp_should_load_block_editor_scripts_and_styles();
  2238. $block_registry = WP_Block_Type_Registry::get_instance();
  2239. foreach ( $block_registry->get_all_registered() as $block_name => $block_type ) {
  2240. // Front-end and editor styles.
  2241. foreach ( $block_type->style_handles as $style_handle ) {
  2242. wp_enqueue_style( $style_handle );
  2243. }
  2244. // Front-end and editor scripts.
  2245. foreach ( $block_type->script_handles as $script_handle ) {
  2246. wp_enqueue_script( $script_handle );
  2247. }
  2248. if ( $load_editor_scripts_and_styles ) {
  2249. // Editor styles.
  2250. foreach ( $block_type->editor_style_handles as $editor_style_handle ) {
  2251. wp_enqueue_style( $editor_style_handle );
  2252. }
  2253. // Editor scripts.
  2254. foreach ( $block_type->editor_script_handles as $editor_script_handle ) {
  2255. wp_enqueue_script( $editor_script_handle );
  2256. }
  2257. }
  2258. }
  2259. }
  2260. /**
  2261. * Function responsible for enqueuing the styles required for block styles functionality on the editor and on the frontend.
  2262. *
  2263. * @since 5.3.0
  2264. *
  2265. * @global WP_Styles $wp_styles
  2266. */
  2267. function enqueue_block_styles_assets() {
  2268. global $wp_styles;
  2269. $block_styles = WP_Block_Styles_Registry::get_instance()->get_all_registered();
  2270. foreach ( $block_styles as $block_name => $styles ) {
  2271. foreach ( $styles as $style_properties ) {
  2272. if ( isset( $style_properties['style_handle'] ) ) {
  2273. // If the site loads separate styles per-block, enqueue the stylesheet on render.
  2274. if ( wp_should_load_separate_core_block_assets() ) {
  2275. add_filter(
  2276. 'render_block',
  2277. function( $html, $block ) use ( $block_name, $style_properties ) {
  2278. if ( $block['blockName'] === $block_name ) {
  2279. wp_enqueue_style( $style_properties['style_handle'] );
  2280. }
  2281. return $html;
  2282. },
  2283. 10,
  2284. 2
  2285. );
  2286. } else {
  2287. wp_enqueue_style( $style_properties['style_handle'] );
  2288. }
  2289. }
  2290. if ( isset( $style_properties['inline_style'] ) ) {
  2291. // Default to "wp-block-library".
  2292. $handle = 'wp-block-library';
  2293. // If the site loads separate styles per-block, check if the block has a stylesheet registered.
  2294. if ( wp_should_load_separate_core_block_assets() ) {
  2295. $block_stylesheet_handle = generate_block_asset_handle( $block_name, 'style' );
  2296. if ( isset( $wp_styles->registered[ $block_stylesheet_handle ] ) ) {
  2297. $handle = $block_stylesheet_handle;
  2298. }
  2299. }
  2300. // Add inline styles to the calculated handle.
  2301. wp_add_inline_style( $handle, $style_properties['inline_style'] );
  2302. }
  2303. }
  2304. }
  2305. }
  2306. /**
  2307. * Function responsible for enqueuing the assets required for block styles functionality on the editor.
  2308. *
  2309. * @since 5.3.0
  2310. */
  2311. function enqueue_editor_block_styles_assets() {
  2312. $block_styles = WP_Block_Styles_Registry::get_instance()->get_all_registered();
  2313. $register_script_lines = array( '( function() {' );
  2314. foreach ( $block_styles as $block_name => $styles ) {
  2315. foreach ( $styles as $style_properties ) {
  2316. $block_style = array(
  2317. 'name' => $style_properties['name'],
  2318. 'label' => $style_properties['label'],
  2319. );
  2320. if ( isset( $style_properties['is_default'] ) ) {
  2321. $block_style['isDefault'] = $style_properties['is_default'];
  2322. }
  2323. $register_script_lines[] = sprintf(
  2324. ' wp.blocks.registerBlockStyle( \'%s\', %s );',
  2325. $block_name,
  2326. wp_json_encode( $block_style )
  2327. );
  2328. }
  2329. }
  2330. $register_script_lines[] = '} )();';
  2331. $inline_script = implode( "\n", $register_script_lines );
  2332. wp_register_script( 'wp-block-styles', false, array( 'wp-blocks' ), true, true );
  2333. wp_add_inline_script( 'wp-block-styles', $inline_script );
  2334. wp_enqueue_script( 'wp-block-styles' );
  2335. }
  2336. /**
  2337. * Enqueues the assets required for the block directory within the block editor.
  2338. *
  2339. * @since 5.5.0
  2340. */
  2341. function wp_enqueue_editor_block_directory_assets() {
  2342. wp_enqueue_script( 'wp-block-directory' );
  2343. wp_enqueue_style( 'wp-block-directory' );
  2344. }
  2345. /**
  2346. * Enqueues the assets required for the format library within the block editor.
  2347. *
  2348. * @since 5.8.0
  2349. */
  2350. function wp_enqueue_editor_format_library_assets() {
  2351. wp_enqueue_script( 'wp-format-library' );
  2352. wp_enqueue_style( 'wp-format-library' );
  2353. }
  2354. /**
  2355. * Sanitizes an attributes array into an attributes string to be placed inside a `<script>` tag.
  2356. *
  2357. * Automatically injects type attribute if needed.
  2358. * Used by {@see wp_get_script_tag()} and {@see wp_get_inline_script_tag()}.
  2359. *
  2360. * @since 5.7.0
  2361. *
  2362. * @param array $attributes Key-value pairs representing `<script>` tag attributes.
  2363. * @return string String made of sanitized `<script>` tag attributes.
  2364. */
  2365. function wp_sanitize_script_attributes( $attributes ) {
  2366. $html5_script_support = ! is_admin() && ! current_theme_supports( 'html5', 'script' );
  2367. $attributes_string = '';
  2368. // If HTML5 script tag is supported, only the attribute name is added
  2369. // to $attributes_string for entries with a boolean value, and that are true.
  2370. foreach ( $attributes as $attribute_name => $attribute_value ) {
  2371. if ( is_bool( $attribute_value ) ) {
  2372. if ( $attribute_value ) {
  2373. $attributes_string .= $html5_script_support ? sprintf( ' %1$s="%2$s"', esc_attr( $attribute_name ), esc_attr( $attribute_name ) ) : ' ' . esc_attr( $attribute_name );
  2374. }
  2375. } else {
  2376. $attributes_string .= sprintf( ' %1$s="%2$s"', esc_attr( $attribute_name ), esc_attr( $attribute_value ) );
  2377. }
  2378. }
  2379. return $attributes_string;
  2380. }
  2381. /**
  2382. * Formats `<script>` loader tags.
  2383. *
  2384. * It is possible to inject attributes in the `<script>` tag via the {@see 'wp_script_attributes'} filter.
  2385. * Automatically injects type attribute if needed.
  2386. *
  2387. * @since 5.7.0
  2388. *
  2389. * @param array $attributes Key-value pairs representing `<script>` tag attributes.
  2390. * @return string String containing `<script>` opening and closing tags.
  2391. */
  2392. function wp_get_script_tag( $attributes ) {
  2393. if ( ! isset( $attributes['type'] ) && ! is_admin() && ! current_theme_supports( 'html5', 'script' ) ) {
  2394. $attributes['type'] = 'text/javascript';
  2395. }
  2396. /**
  2397. * Filters attributes to be added to a script tag.
  2398. *
  2399. * @since 5.7.0
  2400. *
  2401. * @param array $attributes Key-value pairs representing `<script>` tag attributes.
  2402. * Only the attribute name is added to the `<script>` tag for
  2403. * entries with a boolean value, and that are true.
  2404. */
  2405. $attributes = apply_filters( 'wp_script_attributes', $attributes );
  2406. return sprintf( "<script%s></script>\n", wp_sanitize_script_attributes( $attributes ) );
  2407. }
  2408. /**
  2409. * Prints formatted `<script>` loader tag.
  2410. *
  2411. * It is possible to inject attributes in the `<script>` tag via the {@see 'wp_script_attributes'} filter.
  2412. * Automatically injects type attribute if needed.
  2413. *
  2414. * @since 5.7.0
  2415. *
  2416. * @param array $attributes Key-value pairs representing `<script>` tag attributes.
  2417. */
  2418. function wp_print_script_tag( $attributes ) {
  2419. echo wp_get_script_tag( $attributes );
  2420. }
  2421. /**
  2422. * Wraps inline JavaScript in `<script>` tag.
  2423. *
  2424. * It is possible to inject attributes in the `<script>` tag via the {@see 'wp_script_attributes'} filter.
  2425. * Automatically injects type attribute if needed.
  2426. *
  2427. * @since 5.7.0
  2428. *
  2429. * @param string $javascript Inline JavaScript code.
  2430. * @param array $attributes Optional. Key-value pairs representing `<script>` tag attributes.
  2431. * @return string String containing inline JavaScript code wrapped around `<script>` tag.
  2432. */
  2433. function wp_get_inline_script_tag( $javascript, $attributes = array() ) {
  2434. if ( ! isset( $attributes['type'] ) && ! is_admin() && ! current_theme_supports( 'html5', 'script' ) ) {
  2435. $attributes['type'] = 'text/javascript';
  2436. }
  2437. /**
  2438. * Filters attributes to be added to a script tag.
  2439. *
  2440. * @since 5.7.0
  2441. *
  2442. * @param array $attributes Key-value pairs representing `<script>` tag attributes.
  2443. * Only the attribute name is added to the `<script>` tag for
  2444. * entries with a boolean value, and that are true.
  2445. * @param string $javascript Inline JavaScript code.
  2446. */
  2447. $attributes = apply_filters( 'wp_inline_script_attributes', $attributes, $javascript );
  2448. $javascript = "\n" . trim( $javascript, "\n\r " ) . "\n";
  2449. return sprintf( "<script%s>%s</script>\n", wp_sanitize_script_attributes( $attributes ), $javascript );
  2450. }
  2451. /**
  2452. * Prints inline JavaScript wrapped in `<script>` tag.
  2453. *
  2454. * It is possible to inject attributes in the `<script>` tag via the {@see 'wp_script_attributes'} filter.
  2455. * Automatically injects type attribute if needed.
  2456. *
  2457. * @since 5.7.0
  2458. *
  2459. * @param string $javascript Inline JavaScript code.
  2460. * @param array $attributes Optional. Key-value pairs representing `<script>` tag attributes.
  2461. */
  2462. function wp_print_inline_script_tag( $javascript, $attributes = array() ) {
  2463. echo wp_get_inline_script_tag( $javascript, $attributes );
  2464. }
  2465. /**
  2466. * Allows small styles to be inlined.
  2467. *
  2468. * This improves performance and sustainability, and is opt-in. Stylesheets can opt in
  2469. * by adding `path` data using `wp_style_add_data`, and defining the file's absolute path:
  2470. *
  2471. * wp_style_add_data( $style_handle, 'path', $file_path );
  2472. *
  2473. * @since 5.8.0
  2474. *
  2475. * @global WP_Styles $wp_styles
  2476. */
  2477. function wp_maybe_inline_styles() {
  2478. global $wp_styles;
  2479. $total_inline_limit = 20000;
  2480. /**
  2481. * The maximum size of inlined styles in bytes.
  2482. *
  2483. * @since 5.8.0
  2484. *
  2485. * @param int $total_inline_limit The file-size threshold, in bytes. Default 20000.
  2486. */
  2487. $total_inline_limit = apply_filters( 'styles_inline_size_limit', $total_inline_limit );
  2488. $styles = array();
  2489. // Build an array of styles that have a path defined.
  2490. foreach ( $wp_styles->queue as $handle ) {
  2491. if ( wp_styles()->get_data( $handle, 'path' ) && file_exists( $wp_styles->registered[ $handle ]->extra['path'] ) ) {
  2492. $styles[] = array(
  2493. 'handle' => $handle,
  2494. 'src' => $wp_styles->registered[ $handle ]->src,
  2495. 'path' => $wp_styles->registered[ $handle ]->extra['path'],
  2496. 'size' => filesize( $wp_styles->registered[ $handle ]->extra['path'] ),
  2497. );
  2498. }
  2499. }
  2500. if ( ! empty( $styles ) ) {
  2501. // Reorder styles array based on size.
  2502. usort(
  2503. $styles,
  2504. static function( $a, $b ) {
  2505. return ( $a['size'] <= $b['size'] ) ? -1 : 1;
  2506. }
  2507. );
  2508. /*
  2509. * The total inlined size.
  2510. *
  2511. * On each iteration of the loop, if a style gets added inline the value of this var increases
  2512. * to reflect the total size of inlined styles.
  2513. */
  2514. $total_inline_size = 0;
  2515. // Loop styles.
  2516. foreach ( $styles as $style ) {
  2517. // Size check. Since styles are ordered by size, we can break the loop.
  2518. if ( $total_inline_size + $style['size'] > $total_inline_limit ) {
  2519. break;
  2520. }
  2521. // Get the styles if we don't already have them.
  2522. $style['css'] = file_get_contents( $style['path'] );
  2523. // Check if the style contains relative URLs that need to be modified.
  2524. // URLs relative to the stylesheet's path should be converted to relative to the site's root.
  2525. $style['css'] = _wp_normalize_relative_css_links( $style['css'], $style['src'] );
  2526. // Set `src` to `false` and add styles inline.
  2527. $wp_styles->registered[ $style['handle'] ]->src = false;
  2528. if ( empty( $wp_styles->registered[ $style['handle'] ]->extra['after'] ) ) {
  2529. $wp_styles->registered[ $style['handle'] ]->extra['after'] = array();
  2530. }
  2531. array_unshift( $wp_styles->registered[ $style['handle'] ]->extra['after'], $style['css'] );
  2532. // Add the styles size to the $total_inline_size var.
  2533. $total_inline_size += (int) $style['size'];
  2534. }
  2535. }
  2536. }
  2537. /**
  2538. * Makes URLs relative to the WordPress installation.
  2539. *
  2540. * @since 5.9.0
  2541. * @access private
  2542. *
  2543. * @param string $css The CSS to make URLs relative to the WordPress installation.
  2544. * @param string $stylesheet_url The URL to the stylesheet.
  2545. *
  2546. * @return string The CSS with URLs made relative to the WordPress installation.
  2547. */
  2548. function _wp_normalize_relative_css_links( $css, $stylesheet_url ) {
  2549. $has_src_results = preg_match_all( '#url\s*\(\s*[\'"]?\s*([^\'"\)]+)#', $css, $src_results );
  2550. if ( $has_src_results ) {
  2551. // Loop through the URLs to find relative ones.
  2552. foreach ( $src_results[1] as $src_index => $src_result ) {
  2553. // Skip if this is an absolute URL.
  2554. if ( 0 === strpos( $src_result, 'http' ) || 0 === strpos( $src_result, '//' ) ) {
  2555. continue;
  2556. }
  2557. // Skip if the URL is an HTML ID.
  2558. if ( str_starts_with( $src_result, '#' ) ) {
  2559. continue;
  2560. }
  2561. // Skip if the URL is a data URI.
  2562. if ( str_starts_with( $src_result, 'data:' ) ) {
  2563. continue;
  2564. }
  2565. // Build the absolute URL.
  2566. $absolute_url = dirname( $stylesheet_url ) . '/' . $src_result;
  2567. $absolute_url = str_replace( '/./', '/', $absolute_url );
  2568. // Convert to URL related to the site root.
  2569. $relative_url = wp_make_link_relative( $absolute_url );
  2570. // Replace the URL in the CSS.
  2571. $css = str_replace(
  2572. $src_results[0][ $src_index ],
  2573. str_replace( $src_result, $relative_url, $src_results[0][ $src_index ] ),
  2574. $css
  2575. );
  2576. }
  2577. }
  2578. return $css;
  2579. }
  2580. /**
  2581. * Function that enqueues the CSS Custom Properties coming from theme.json.
  2582. *
  2583. * @since 5.9.0
  2584. */
  2585. function wp_enqueue_global_styles_css_custom_properties() {
  2586. wp_register_style( 'global-styles-css-custom-properties', false, array(), true, true );
  2587. wp_add_inline_style( 'global-styles-css-custom-properties', wp_get_global_stylesheet( array( 'variables' ) ) );
  2588. wp_enqueue_style( 'global-styles-css-custom-properties' );
  2589. }
  2590. /**
  2591. * Hooks inline styles in the proper place, depending on the active theme.
  2592. *
  2593. * @since 5.9.1
  2594. * @since 6.1.0 Added the `$priority` parameter.
  2595. *
  2596. * For block themes, styles are loaded in the head.
  2597. * For classic ones, styles are loaded in the body because the wp_head action happens before render_block.
  2598. *
  2599. * @link https://core.trac.wordpress.org/ticket/53494.
  2600. *
  2601. * @param string $style String containing the CSS styles to be added.
  2602. * @param int $priority To set the priority for the add_action.
  2603. */
  2604. function wp_enqueue_block_support_styles( $style, $priority = 10 ) {
  2605. $action_hook_name = 'wp_footer';
  2606. if ( wp_is_block_theme() ) {
  2607. $action_hook_name = 'wp_head';
  2608. }
  2609. add_action(
  2610. $action_hook_name,
  2611. static function () use ( $style ) {
  2612. echo "<style>$style</style>\n";
  2613. },
  2614. $priority
  2615. );
  2616. }
  2617. /**
  2618. * Fetches, processes and compiles stored core styles, then combines and renders them to the page.
  2619. * Styles are stored via the style engine API.
  2620. *
  2621. * @link https://developer.wordpress.org/block-editor/reference-guides/packages/packages-style-engine/
  2622. *
  2623. * @since 6.1.0
  2624. *
  2625. * @param array $options {
  2626. * Optional. An array of options to pass to wp_style_engine_get_stylesheet_from_context(). Default empty array.
  2627. *
  2628. * @type bool $optimize Whether to optimize the CSS output, e.g., combine rules. Default is `false`.
  2629. * @type bool $prettify Whether to add new lines and indents to output. Default is the test of whether the global constant `SCRIPT_DEBUG` is defined.
  2630. * }
  2631. *
  2632. * @return void
  2633. */
  2634. function wp_enqueue_stored_styles( $options = array() ) {
  2635. $is_block_theme = wp_is_block_theme();
  2636. $is_classic_theme = ! $is_block_theme;
  2637. /*
  2638. * For block themes, this function prints stored styles in the header.
  2639. * For classic themes, in the footer.
  2640. */
  2641. if (
  2642. ( $is_block_theme && doing_action( 'wp_footer' ) ) ||
  2643. ( $is_classic_theme && doing_action( 'wp_enqueue_scripts' ) )
  2644. ) {
  2645. return;
  2646. }
  2647. $core_styles_keys = array( 'block-supports' );
  2648. $compiled_core_stylesheet = '';
  2649. $style_tag_id = 'core';
  2650. // Adds comment if code is prettified to identify core styles sections in debugging.
  2651. $should_prettify = isset( $options['prettify'] ) ? true === $options['prettify'] : defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG;
  2652. foreach ( $core_styles_keys as $style_key ) {
  2653. if ( $should_prettify ) {
  2654. $compiled_core_stylesheet .= "/**\n * Core styles: $style_key\n */\n";
  2655. }
  2656. // Chains core store ids to signify what the styles contain.
  2657. $style_tag_id .= '-' . $style_key;
  2658. $compiled_core_stylesheet .= wp_style_engine_get_stylesheet_from_context( $style_key, $options );
  2659. }
  2660. // Combines Core styles.
  2661. if ( ! empty( $compiled_core_stylesheet ) ) {
  2662. wp_register_style( $style_tag_id, false, array(), true, true );
  2663. wp_add_inline_style( $style_tag_id, $compiled_core_stylesheet );
  2664. wp_enqueue_style( $style_tag_id );
  2665. }
  2666. // Prints out any other stores registered by themes or otherwise.
  2667. $additional_stores = WP_Style_Engine_CSS_Rules_Store::get_stores();
  2668. foreach ( array_keys( $additional_stores ) as $store_name ) {
  2669. if ( in_array( $store_name, $core_styles_keys, true ) ) {
  2670. continue;
  2671. }
  2672. $styles = wp_style_engine_get_stylesheet_from_context( $store_name, $options );
  2673. if ( ! empty( $styles ) ) {
  2674. $key = "wp-style-engine-$store_name";
  2675. wp_register_style( $key, false, array(), true, true );
  2676. wp_add_inline_style( $key, $styles );
  2677. wp_enqueue_style( $key );
  2678. }
  2679. }
  2680. }
  2681. /**
  2682. * Enqueues a stylesheet for a specific block.
  2683. *
  2684. * If the theme has opted-in to separate-styles loading,
  2685. * then the stylesheet will be enqueued on-render,
  2686. * otherwise when the block inits.
  2687. *
  2688. * @since 5.9.0
  2689. *
  2690. * @param string $block_name The block-name, including namespace.
  2691. * @param array $args An array of arguments [handle,src,deps,ver,media].
  2692. */
  2693. function wp_enqueue_block_style( $block_name, $args ) {
  2694. $args = wp_parse_args(
  2695. $args,
  2696. array(
  2697. 'handle' => '',
  2698. 'src' => '',
  2699. 'deps' => array(),
  2700. 'ver' => false,
  2701. 'media' => 'all',
  2702. )
  2703. );
  2704. /**
  2705. * Callback function to register and enqueue styles.
  2706. *
  2707. * @param string $content When the callback is used for the render_block filter,
  2708. * the content needs to be returned so the function parameter
  2709. * is to ensure the content exists.
  2710. * @return string Block content.
  2711. */
  2712. $callback = static function( $content ) use ( $args ) {
  2713. // Register the stylesheet.
  2714. if ( ! empty( $args['src'] ) ) {
  2715. wp_register_style( $args['handle'], $args['src'], $args['deps'], $args['ver'], $args['media'] );
  2716. }
  2717. // Add `path` data if provided.
  2718. if ( isset( $args['path'] ) ) {
  2719. wp_style_add_data( $args['handle'], 'path', $args['path'] );
  2720. // Get the RTL file path.
  2721. $rtl_file_path = str_replace( '.css', '-rtl.css', $args['path'] );
  2722. // Add RTL stylesheet.
  2723. if ( file_exists( $rtl_file_path ) ) {
  2724. wp_style_add_data( $args['handle'], 'rtl', 'replace' );
  2725. if ( is_rtl() ) {
  2726. wp_style_add_data( $args['handle'], 'path', $rtl_file_path );
  2727. }
  2728. }
  2729. }
  2730. // Enqueue the stylesheet.
  2731. wp_enqueue_style( $args['handle'] );
  2732. return $content;
  2733. };
  2734. $hook = did_action( 'wp_enqueue_scripts' ) ? 'wp_footer' : 'wp_enqueue_scripts';
  2735. if ( wp_should_load_separate_core_block_assets() ) {
  2736. /**
  2737. * Callback function to register and enqueue styles.
  2738. *
  2739. * @param string $content The block content.
  2740. * @param array $block The full block, including name and attributes.
  2741. * @return string Block content.
  2742. */
  2743. $callback_separate = static function( $content, $block ) use ( $block_name, $callback ) {
  2744. if ( ! empty( $block['blockName'] ) && $block_name === $block['blockName'] ) {
  2745. return $callback( $content );
  2746. }
  2747. return $content;
  2748. };
  2749. /*
  2750. * The filter's callback here is an anonymous function because
  2751. * using a named function in this case is not possible.
  2752. *
  2753. * The function cannot be unhooked, however, users are still able
  2754. * to dequeue the stylesheets registered/enqueued by the callback
  2755. * which is why in this case, using an anonymous function
  2756. * was deemed acceptable.
  2757. */
  2758. add_filter( 'render_block', $callback_separate, 10, 2 );
  2759. return;
  2760. }
  2761. /*
  2762. * The filter's callback here is an anonymous function because
  2763. * using a named function in this case is not possible.
  2764. *
  2765. * The function cannot be unhooked, however, users are still able
  2766. * to dequeue the stylesheets registered/enqueued by the callback
  2767. * which is why in this case, using an anonymous function
  2768. * was deemed acceptable.
  2769. */
  2770. add_filter( $hook, $callback );
  2771. // Enqueue assets in the editor.
  2772. add_action( 'enqueue_block_assets', $callback );
  2773. }
  2774. /**
  2775. * Runs the theme.json webfonts handler.
  2776. *
  2777. * Using `WP_Theme_JSON_Resolver`, it gets the fonts defined
  2778. * in the `theme.json` for the current selection and style
  2779. * variations, validates the font-face properties, generates
  2780. * the '@font-face' style declarations, and then enqueues the
  2781. * styles for both the editor and front-end.
  2782. *
  2783. * Design Notes:
  2784. * This is not a public API, but rather an internal handler.
  2785. * A future public Webfonts API will replace this stopgap code.
  2786. *
  2787. * This code design is intentional.
  2788. * a. It hides the inner-workings.
  2789. * b. It does not expose API ins or outs for consumption.
  2790. * c. It only works with a theme's `theme.json`.
  2791. *
  2792. * Why?
  2793. * a. To avoid backwards-compatibility issues when
  2794. * the Webfonts API is introduced in Core.
  2795. * b. To make `fontFace` declarations in `theme.json` work.
  2796. *
  2797. * @link https://github.com/WordPress/gutenberg/issues/40472
  2798. *
  2799. * @since 6.0.0
  2800. * @access private
  2801. */
  2802. function _wp_theme_json_webfonts_handler() {
  2803. // Block themes are unavailable during installation.
  2804. if ( wp_installing() ) {
  2805. return;
  2806. }
  2807. // Webfonts to be processed.
  2808. $registered_webfonts = array();
  2809. /**
  2810. * Gets the webfonts from theme.json.
  2811. *
  2812. * @since 6.0.0
  2813. *
  2814. * @return array Array of defined webfonts.
  2815. */
  2816. $fn_get_webfonts_from_theme_json = static function() {
  2817. // Get settings from theme.json.
  2818. $settings = WP_Theme_JSON_Resolver::get_merged_data()->get_settings();
  2819. // If in the editor, add webfonts defined in variations.
  2820. if ( is_admin() || ( defined( 'REST_REQUEST' ) && REST_REQUEST ) ) {
  2821. $variations = WP_Theme_JSON_Resolver::get_style_variations();
  2822. foreach ( $variations as $variation ) {
  2823. // Skip if fontFamilies are not defined in the variation.
  2824. if ( empty( $variation['settings']['typography']['fontFamilies'] ) ) {
  2825. continue;
  2826. }
  2827. // Initialize the array structure.
  2828. if ( empty( $settings['typography'] ) ) {
  2829. $settings['typography'] = array();
  2830. }
  2831. if ( empty( $settings['typography']['fontFamilies'] ) ) {
  2832. $settings['typography']['fontFamilies'] = array();
  2833. }
  2834. if ( empty( $settings['typography']['fontFamilies']['theme'] ) ) {
  2835. $settings['typography']['fontFamilies']['theme'] = array();
  2836. }
  2837. // Combine variations with settings. Remove duplicates.
  2838. $settings['typography']['fontFamilies']['theme'] = array_merge( $settings['typography']['fontFamilies']['theme'], $variation['settings']['typography']['fontFamilies']['theme'] );
  2839. $settings['typography']['fontFamilies'] = array_unique( $settings['typography']['fontFamilies'] );
  2840. }
  2841. }
  2842. // Bail out early if there are no settings for webfonts.
  2843. if ( empty( $settings['typography']['fontFamilies'] ) ) {
  2844. return array();
  2845. }
  2846. $webfonts = array();
  2847. // Look for fontFamilies.
  2848. foreach ( $settings['typography']['fontFamilies'] as $font_families ) {
  2849. foreach ( $font_families as $font_family ) {
  2850. // Skip if fontFace is not defined.
  2851. if ( empty( $font_family['fontFace'] ) ) {
  2852. continue;
  2853. }
  2854. // Skip if fontFace is not an array of webfonts.
  2855. if ( ! is_array( $font_family['fontFace'] ) ) {
  2856. continue;
  2857. }
  2858. $webfonts = array_merge( $webfonts, $font_family['fontFace'] );
  2859. }
  2860. }
  2861. return $webfonts;
  2862. };
  2863. /**
  2864. * Transforms each 'src' into an URI by replacing 'file:./'
  2865. * placeholder from theme.json.
  2866. *
  2867. * The absolute path to the webfont file(s) cannot be defined in
  2868. * theme.json. `file:./` is the placeholder which is replaced by
  2869. * the theme's URL path to the theme's root.
  2870. *
  2871. * @since 6.0.0
  2872. *
  2873. * @param array $src Webfont file(s) `src`.
  2874. * @return array Webfont's `src` in URI.
  2875. */
  2876. $fn_transform_src_into_uri = static function( array $src ) {
  2877. foreach ( $src as $key => $url ) {
  2878. // Tweak the URL to be relative to the theme root.
  2879. if ( ! str_starts_with( $url, 'file:./' ) ) {
  2880. continue;
  2881. }
  2882. $src[ $key ] = get_theme_file_uri( str_replace( 'file:./', '', $url ) );
  2883. }
  2884. return $src;
  2885. };
  2886. /**
  2887. * Converts the font-face properties (i.e. keys) into kebab-case.
  2888. *
  2889. * @since 6.0.0
  2890. *
  2891. * @param array $font_face Font face to convert.
  2892. * @return array Font faces with each property in kebab-case format.
  2893. */
  2894. $fn_convert_keys_to_kebab_case = static function( array $font_face ) {
  2895. foreach ( $font_face as $property => $value ) {
  2896. $kebab_case = _wp_to_kebab_case( $property );
  2897. $font_face[ $kebab_case ] = $value;
  2898. if ( $kebab_case !== $property ) {
  2899. unset( $font_face[ $property ] );
  2900. }
  2901. }
  2902. return $font_face;
  2903. };
  2904. /**
  2905. * Validates a webfont.
  2906. *
  2907. * @since 6.0.0
  2908. *
  2909. * @param array $webfont The webfont arguments.
  2910. * @return array|false The validated webfont arguments, or false if the webfont is invalid.
  2911. */
  2912. $fn_validate_webfont = static function( $webfont ) {
  2913. $webfont = wp_parse_args(
  2914. $webfont,
  2915. array(
  2916. 'font-family' => '',
  2917. 'font-style' => 'normal',
  2918. 'font-weight' => '400',
  2919. 'font-display' => 'fallback',
  2920. 'src' => array(),
  2921. )
  2922. );
  2923. // Check the font-family.
  2924. if ( empty( $webfont['font-family'] ) || ! is_string( $webfont['font-family'] ) ) {
  2925. trigger_error( __( 'Webfont font family must be a non-empty string.' ) );
  2926. return false;
  2927. }
  2928. // Check that the `src` property is defined and a valid type.
  2929. if ( empty( $webfont['src'] ) || ( ! is_string( $webfont['src'] ) && ! is_array( $webfont['src'] ) ) ) {
  2930. trigger_error( __( 'Webfont src must be a non-empty string or an array of strings.' ) );
  2931. return false;
  2932. }
  2933. // Validate the `src` property.
  2934. foreach ( (array) $webfont['src'] as $src ) {
  2935. if ( ! is_string( $src ) || '' === trim( $src ) ) {
  2936. trigger_error( __( 'Each webfont src must be a non-empty string.' ) );
  2937. return false;
  2938. }
  2939. }
  2940. // Check the font-weight.
  2941. if ( ! is_string( $webfont['font-weight'] ) && ! is_int( $webfont['font-weight'] ) ) {
  2942. trigger_error( __( 'Webfont font weight must be a properly formatted string or integer.' ) );
  2943. return false;
  2944. }
  2945. // Check the font-display.
  2946. if ( ! in_array( $webfont['font-display'], array( 'auto', 'block', 'fallback', 'swap' ), true ) ) {
  2947. $webfont['font-display'] = 'fallback';
  2948. }
  2949. $valid_props = array(
  2950. 'ascend-override',
  2951. 'descend-override',
  2952. 'font-display',
  2953. 'font-family',
  2954. 'font-stretch',
  2955. 'font-style',
  2956. 'font-weight',
  2957. 'font-variant',
  2958. 'font-feature-settings',
  2959. 'font-variation-settings',
  2960. 'line-gap-override',
  2961. 'size-adjust',
  2962. 'src',
  2963. 'unicode-range',
  2964. );
  2965. foreach ( $webfont as $prop => $value ) {
  2966. if ( ! in_array( $prop, $valid_props, true ) ) {
  2967. unset( $webfont[ $prop ] );
  2968. }
  2969. }
  2970. return $webfont;
  2971. };
  2972. /**
  2973. * Registers webfonts declared in theme.json.
  2974. *
  2975. * @since 6.0.0
  2976. *
  2977. * @uses $registered_webfonts To access and update the registered webfonts registry (passed by reference).
  2978. * @uses $fn_get_webfonts_from_theme_json To run the function that gets the webfonts from theme.json.
  2979. * @uses $fn_convert_keys_to_kebab_case To run the function that converts keys into kebab-case.
  2980. * @uses $fn_validate_webfont To run the function that validates each font-face (webfont) from theme.json.
  2981. */
  2982. $fn_register_webfonts = static function() use ( &$registered_webfonts, $fn_get_webfonts_from_theme_json, $fn_convert_keys_to_kebab_case, $fn_validate_webfont, $fn_transform_src_into_uri ) {
  2983. $registered_webfonts = array();
  2984. foreach ( $fn_get_webfonts_from_theme_json() as $webfont ) {
  2985. if ( ! is_array( $webfont ) ) {
  2986. continue;
  2987. }
  2988. $webfont = $fn_convert_keys_to_kebab_case( $webfont );
  2989. $webfont = $fn_validate_webfont( $webfont );
  2990. $webfont['src'] = $fn_transform_src_into_uri( (array) $webfont['src'] );
  2991. // Skip if not valid.
  2992. if ( empty( $webfont ) ) {
  2993. continue;
  2994. }
  2995. $registered_webfonts[] = $webfont;
  2996. }
  2997. };
  2998. /**
  2999. * Orders 'src' items to optimize for browser support.
  3000. *
  3001. * @since 6.0.0
  3002. *
  3003. * @param array $webfont Webfont to process.
  3004. * @return array Ordered `src` items.
  3005. */
  3006. $fn_order_src = static function( array $webfont ) {
  3007. $src = array();
  3008. $src_ordered = array();
  3009. foreach ( $webfont['src'] as $url ) {
  3010. // Add data URIs first.
  3011. if ( str_starts_with( trim( $url ), 'data:' ) ) {
  3012. $src_ordered[] = array(
  3013. 'url' => $url,
  3014. 'format' => 'data',
  3015. );
  3016. continue;
  3017. }
  3018. $format = pathinfo( $url, PATHINFO_EXTENSION );
  3019. $src[ $format ] = $url;
  3020. }
  3021. // Add woff2.
  3022. if ( ! empty( $src['woff2'] ) ) {
  3023. $src_ordered[] = array(
  3024. 'url' => sanitize_url( $src['woff2'] ),
  3025. 'format' => 'woff2',
  3026. );
  3027. }
  3028. // Add woff.
  3029. if ( ! empty( $src['woff'] ) ) {
  3030. $src_ordered[] = array(
  3031. 'url' => sanitize_url( $src['woff'] ),
  3032. 'format' => 'woff',
  3033. );
  3034. }
  3035. // Add ttf.
  3036. if ( ! empty( $src['ttf'] ) ) {
  3037. $src_ordered[] = array(
  3038. 'url' => sanitize_url( $src['ttf'] ),
  3039. 'format' => 'truetype',
  3040. );
  3041. }
  3042. // Add eot.
  3043. if ( ! empty( $src['eot'] ) ) {
  3044. $src_ordered[] = array(
  3045. 'url' => sanitize_url( $src['eot'] ),
  3046. 'format' => 'embedded-opentype',
  3047. );
  3048. }
  3049. // Add otf.
  3050. if ( ! empty( $src['otf'] ) ) {
  3051. $src_ordered[] = array(
  3052. 'url' => sanitize_url( $src['otf'] ),
  3053. 'format' => 'opentype',
  3054. );
  3055. }
  3056. $webfont['src'] = $src_ordered;
  3057. return $webfont;
  3058. };
  3059. /**
  3060. * Compiles the 'src' into valid CSS.
  3061. *
  3062. * @since 6.0.0
  3063. *
  3064. * @param string $font_family Font family.
  3065. * @param array $value Value to process.
  3066. * @return string The CSS.
  3067. */
  3068. $fn_compile_src = static function( $font_family, array $value ) {
  3069. $src = "local($font_family)";
  3070. foreach ( $value as $item ) {
  3071. if (
  3072. str_starts_with( $item['url'], site_url() ) ||
  3073. str_starts_with( $item['url'], home_url() )
  3074. ) {
  3075. $item['url'] = wp_make_link_relative( $item['url'] );
  3076. }
  3077. $src .= ( 'data' === $item['format'] )
  3078. ? ", url({$item['url']})"
  3079. : ", url('{$item['url']}') format('{$item['format']}')";
  3080. }
  3081. return $src;
  3082. };
  3083. /**
  3084. * Compiles the font variation settings.
  3085. *
  3086. * @since 6.0.0
  3087. *
  3088. * @param array $font_variation_settings Array of font variation settings.
  3089. * @return string The CSS.
  3090. */
  3091. $fn_compile_variations = static function( array $font_variation_settings ) {
  3092. $variations = '';
  3093. foreach ( $font_variation_settings as $key => $value ) {
  3094. $variations .= "$key $value";
  3095. }
  3096. return $variations;
  3097. };
  3098. /**
  3099. * Builds the font-family's CSS.
  3100. *
  3101. * @since 6.0.0
  3102. *
  3103. * @uses $fn_compile_src To run the function that compiles the src.
  3104. * @uses $fn_compile_variations To run the function that compiles the variations.
  3105. *
  3106. * @param array $webfont Webfont to process.
  3107. * @return string This font-family's CSS.
  3108. */
  3109. $fn_build_font_face_css = static function( array $webfont ) use ( $fn_compile_src, $fn_compile_variations ) {
  3110. $css = '';
  3111. // Wrap font-family in quotes if it contains spaces.
  3112. if (
  3113. str_contains( $webfont['font-family'], ' ' ) &&
  3114. ! str_contains( $webfont['font-family'], '"' ) &&
  3115. ! str_contains( $webfont['font-family'], "'" )
  3116. ) {
  3117. $webfont['font-family'] = '"' . $webfont['font-family'] . '"';
  3118. }
  3119. foreach ( $webfont as $key => $value ) {
  3120. /*
  3121. * Skip "provider", since it's for internal API use,
  3122. * and not a valid CSS property.
  3123. */
  3124. if ( 'provider' === $key ) {
  3125. continue;
  3126. }
  3127. // Compile the "src" parameter.
  3128. if ( 'src' === $key ) {
  3129. $value = $fn_compile_src( $webfont['font-family'], $value );
  3130. }
  3131. // If font-variation-settings is an array, convert it to a string.
  3132. if ( 'font-variation-settings' === $key && is_array( $value ) ) {
  3133. $value = $fn_compile_variations( $value );
  3134. }
  3135. if ( ! empty( $value ) ) {
  3136. $css .= "$key:$value;";
  3137. }
  3138. }
  3139. return $css;
  3140. };
  3141. /**
  3142. * Gets the '@font-face' CSS styles for locally-hosted font files.
  3143. *
  3144. * @since 6.0.0
  3145. *
  3146. * @uses $registered_webfonts To access and update the registered webfonts registry (passed by reference).
  3147. * @uses $fn_order_src To run the function that orders the src.
  3148. * @uses $fn_build_font_face_css To run the function that builds the font-face CSS.
  3149. *
  3150. * @return string The `@font-face` CSS.
  3151. */
  3152. $fn_get_css = static function() use ( &$registered_webfonts, $fn_order_src, $fn_build_font_face_css ) {
  3153. $css = '';
  3154. foreach ( $registered_webfonts as $webfont ) {
  3155. // Order the webfont's `src` items to optimize for browser support.
  3156. $webfont = $fn_order_src( $webfont );
  3157. // Build the @font-face CSS for this webfont.
  3158. $css .= '@font-face{' . $fn_build_font_face_css( $webfont ) . '}';
  3159. }
  3160. return $css;
  3161. };
  3162. /**
  3163. * Generates and enqueues webfonts styles.
  3164. *
  3165. * @since 6.0.0
  3166. *
  3167. * @uses $fn_get_css To run the function that gets the CSS.
  3168. */
  3169. $fn_generate_and_enqueue_styles = static function() use ( $fn_get_css ) {
  3170. // Generate the styles.
  3171. $styles = $fn_get_css();
  3172. // Bail out if there are no styles to enqueue.
  3173. if ( '' === $styles ) {
  3174. return;
  3175. }
  3176. // Enqueue the stylesheet.
  3177. wp_register_style( 'wp-webfonts', '' );
  3178. wp_enqueue_style( 'wp-webfonts' );
  3179. // Add the styles to the stylesheet.
  3180. wp_add_inline_style( 'wp-webfonts', $styles );
  3181. };
  3182. /**
  3183. * Generates and enqueues editor styles.
  3184. *
  3185. * @since 6.0.0
  3186. *
  3187. * @uses $fn_get_css To run the function that gets the CSS.
  3188. */
  3189. $fn_generate_and_enqueue_editor_styles = static function() use ( $fn_get_css ) {
  3190. // Generate the styles.
  3191. $styles = $fn_get_css();
  3192. // Bail out if there are no styles to enqueue.
  3193. if ( '' === $styles ) {
  3194. return;
  3195. }
  3196. wp_add_inline_style( 'wp-block-library', $styles );
  3197. };
  3198. add_action( 'wp_loaded', $fn_register_webfonts );
  3199. add_action( 'wp_enqueue_scripts', $fn_generate_and_enqueue_styles );
  3200. add_action( 'admin_init', $fn_generate_and_enqueue_editor_styles );
  3201. }
  3202. /**
  3203. * Loads classic theme styles on classic themes in the frontend.
  3204. *
  3205. * This is needed for backwards compatibility for button blocks specifically.
  3206. *
  3207. * @since 6.1.0
  3208. */
  3209. function wp_enqueue_classic_theme_styles() {
  3210. if ( ! WP_Theme_JSON_Resolver::theme_has_support() ) {
  3211. $suffix = wp_scripts_get_suffix();
  3212. wp_register_style( 'classic-theme-styles', '/' . WPINC . "/css/classic-themes$suffix.css", array(), true );
  3213. wp_enqueue_style( 'classic-theme-styles' );
  3214. }
  3215. }
  3216. /**
  3217. * Loads classic theme styles on classic themes in the editor.
  3218. *
  3219. * This is needed for backwards compatibility for button blocks specifically.
  3220. *
  3221. * @since 6.1.0
  3222. *
  3223. * @param array $editor_settings The array of editor settings.
  3224. * @return array A filtered array of editor settings.
  3225. */
  3226. function wp_add_editor_classic_theme_styles( $editor_settings ) {
  3227. if ( WP_Theme_JSON_Resolver::theme_has_support() ) {
  3228. return $editor_settings;
  3229. }
  3230. $suffix = wp_scripts_get_suffix();
  3231. $classic_theme_styles = ABSPATH . WPINC . "/css/classic-themes$suffix.css";
  3232. // This follows the pattern of get_block_editor_theme_styles,
  3233. // but we can't use get_block_editor_theme_styles directly as it
  3234. // only handles external files or theme files.
  3235. $classic_theme_styles_settings = array(
  3236. 'css' => file_get_contents( $classic_theme_styles ),
  3237. '__unstableType' => 'core',
  3238. 'isGlobalStyles' => false,
  3239. );
  3240. // Add these settings to the start of the array so that themes can override them.
  3241. array_unshift( $editor_settings['styles'], $classic_theme_styles_settings );
  3242. return $editor_settings;
  3243. }