Нема описа

api-helpers.php 84KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590
  1. <?php
  2. /*
  3. * acf_is_array
  4. *
  5. * This function will return true for a non empty array
  6. *
  7. * @type function
  8. * @date 6/07/2016
  9. * @since 5.4.0
  10. *
  11. * @param $array (array)
  12. * @return (boolean)
  13. */
  14. function acf_is_array( $array ) {
  15. return ( is_array( $array ) && ! empty( $array ) );
  16. }
  17. /**
  18. * acf_has_setting
  19. *
  20. * alias of acf()->has_setting()
  21. *
  22. * @date 2/2/18
  23. * @since 5.6.5
  24. *
  25. * @param n/a
  26. * @return n/a
  27. */
  28. function acf_has_setting( $name = '' ) {
  29. return acf()->has_setting( $name );
  30. }
  31. /**
  32. * acf_raw_setting
  33. *
  34. * alias of acf()->get_setting()
  35. *
  36. * @date 2/2/18
  37. * @since 5.6.5
  38. *
  39. * @param n/a
  40. * @return n/a
  41. */
  42. function acf_raw_setting( $name = '' ) {
  43. return acf()->get_setting( $name );
  44. }
  45. /*
  46. * acf_update_setting
  47. *
  48. * alias of acf()->update_setting()
  49. *
  50. * @type function
  51. * @date 28/09/13
  52. * @since 5.0.0
  53. *
  54. * @param $name (string)
  55. * @param $value (mixed)
  56. * @return n/a
  57. */
  58. function acf_update_setting( $name, $value ) {
  59. // validate name
  60. $name = acf_validate_setting( $name );
  61. // update
  62. return acf()->update_setting( $name, $value );
  63. }
  64. /**
  65. * acf_validate_setting
  66. *
  67. * Returns the changed setting name if available.
  68. *
  69. * @date 2/2/18
  70. * @since 5.6.5
  71. *
  72. * @param n/a
  73. * @return n/a
  74. */
  75. function acf_validate_setting( $name = '' ) {
  76. return apply_filters( 'acf/validate_setting', $name );
  77. }
  78. /*
  79. * acf_get_setting
  80. *
  81. * alias of acf()->get_setting()
  82. *
  83. * @type function
  84. * @date 28/09/13
  85. * @since 5.0.0
  86. *
  87. * @param n/a
  88. * @return n/a
  89. */
  90. function acf_get_setting( $name, $value = null ) {
  91. // validate name
  92. $name = acf_validate_setting( $name );
  93. // check settings
  94. if ( acf_has_setting( $name ) ) {
  95. $value = acf_raw_setting( $name );
  96. }
  97. // filter
  98. $value = apply_filters( "acf/settings/{$name}", $value );
  99. // return
  100. return $value;
  101. }
  102. /*
  103. * acf_append_setting
  104. *
  105. * This function will add a value into the settings array found in the acf object
  106. *
  107. * @type function
  108. * @date 28/09/13
  109. * @since 5.0.0
  110. *
  111. * @param $name (string)
  112. * @param $value (mixed)
  113. * @return n/a
  114. */
  115. function acf_append_setting( $name, $value ) {
  116. // vars
  117. $setting = acf_raw_setting( $name );
  118. // bail ealry if not array
  119. if ( ! is_array( $setting ) ) {
  120. $setting = array();
  121. }
  122. // append
  123. $setting[] = $value;
  124. // update
  125. return acf_update_setting( $name, $setting );
  126. }
  127. /**
  128. * acf_get_data
  129. *
  130. * Returns data.
  131. *
  132. * @date 28/09/13
  133. * @since 5.0.0
  134. *
  135. * @param string $name
  136. * @return mixed
  137. */
  138. function acf_get_data( $name ) {
  139. return acf()->get_data( $name );
  140. }
  141. /**
  142. * acf_set_data
  143. *
  144. * Sets data.
  145. *
  146. * @date 28/09/13
  147. * @since 5.0.0
  148. *
  149. * @param string $name
  150. * @param mixed $value
  151. * @return n/a
  152. */
  153. function acf_set_data( $name, $value ) {
  154. return acf()->set_data( $name, $value );
  155. }
  156. /**
  157. * Appends data to an existing key.
  158. *
  159. * @date 11/06/2020
  160. * @since 5.9.0
  161. *
  162. * @param string $name The data name.
  163. * @return array $data The data array.
  164. */
  165. function acf_append_data( $name, $data ) {
  166. $prev_data = acf()->get_data( $name );
  167. if ( is_array( $prev_data ) ) {
  168. $data = array_merge( $prev_data, $data );
  169. }
  170. acf()->set_data( $name, $data );
  171. }
  172. /*
  173. * acf_init
  174. *
  175. * alias of acf()->init()
  176. *
  177. * @type function
  178. * @date 28/09/13
  179. * @since 5.0.0
  180. *
  181. * @param n/a
  182. * @return n/a
  183. */
  184. function acf_init() {
  185. acf()->init();
  186. }
  187. /*
  188. * acf_has_done
  189. *
  190. * This function will return true if this action has already been done
  191. *
  192. * @type function
  193. * @date 16/12/2015
  194. * @since 5.3.2
  195. *
  196. * @param $name (string)
  197. * @return (boolean)
  198. */
  199. function acf_has_done( $name ) {
  200. // return true if already done
  201. if ( acf_raw_setting( "has_done_{$name}" ) ) {
  202. return true;
  203. }
  204. // update setting and return
  205. acf_update_setting( "has_done_{$name}", true );
  206. return false;
  207. }
  208. /*
  209. * acf_get_external_path
  210. *
  211. * This function will return the path to a file within an external folder
  212. *
  213. * @type function
  214. * @date 22/2/17
  215. * @since 5.5.8
  216. *
  217. * @param $file (string)
  218. * @param $path (string)
  219. * @return (string)
  220. */
  221. function acf_get_external_path( $file, $path = '' ) {
  222. return plugin_dir_path( $file ) . $path;
  223. }
  224. /*
  225. * acf_get_external_dir
  226. *
  227. * This function will return the url to a file within an external folder
  228. *
  229. * @type function
  230. * @date 22/2/17
  231. * @since 5.5.8
  232. *
  233. * @param $file (string)
  234. * @param $path (string)
  235. * @return (string)
  236. */
  237. function acf_get_external_dir( $file, $path = '' ) {
  238. return acf_plugin_dir_url( $file ) . $path;
  239. }
  240. /**
  241. * acf_plugin_dir_url
  242. *
  243. * This function will calculate the url to a plugin folder.
  244. * Different to the WP plugin_dir_url(), this function can calculate for urls outside of the plugins folder (theme include).
  245. *
  246. * @date 13/12/17
  247. * @since 5.6.8
  248. *
  249. * @param type $var Description. Default.
  250. * @return type Description.
  251. */
  252. function acf_plugin_dir_url( $file ) {
  253. // vars
  254. $path = plugin_dir_path( $file );
  255. $path = wp_normalize_path( $path );
  256. // check plugins
  257. $check_path = wp_normalize_path( realpath( WP_PLUGIN_DIR ) );
  258. if ( strpos( $path, $check_path ) === 0 ) {
  259. return str_replace( $check_path, plugins_url(), $path );
  260. }
  261. // check wp-content
  262. $check_path = wp_normalize_path( realpath( WP_CONTENT_DIR ) );
  263. if ( strpos( $path, $check_path ) === 0 ) {
  264. return str_replace( $check_path, content_url(), $path );
  265. }
  266. // check root
  267. $check_path = wp_normalize_path( realpath( ABSPATH ) );
  268. if ( strpos( $path, $check_path ) === 0 ) {
  269. return str_replace( $check_path, site_url( '/' ), $path );
  270. }
  271. // return
  272. return plugin_dir_url( $file );
  273. }
  274. /*
  275. * acf_parse_args
  276. *
  277. * This function will merge together 2 arrays and also convert any numeric values to ints
  278. *
  279. * @type function
  280. * @date 18/10/13
  281. * @since 5.0.0
  282. *
  283. * @param $args (array)
  284. * @param $defaults (array)
  285. * @return $args (array)
  286. */
  287. function acf_parse_args( $args, $defaults = array() ) {
  288. // parse args
  289. $args = wp_parse_args( $args, $defaults );
  290. // parse types
  291. $args = acf_parse_types( $args );
  292. // return
  293. return $args;
  294. }
  295. /*
  296. * acf_parse_types
  297. *
  298. * This function will convert any numeric values to int and trim strings
  299. *
  300. * @type function
  301. * @date 18/10/13
  302. * @since 5.0.0
  303. *
  304. * @param $var (mixed)
  305. * @return $var (mixed)
  306. */
  307. function acf_parse_types( $array ) {
  308. return array_map( 'acf_parse_type', $array );
  309. }
  310. /*
  311. * acf_parse_type
  312. *
  313. * description
  314. *
  315. * @type function
  316. * @date 11/11/2014
  317. * @since 5.0.9
  318. *
  319. * @param $post_id (int)
  320. * @return $post_id (int)
  321. */
  322. function acf_parse_type( $v ) {
  323. // Check if is string.
  324. if ( is_string( $v ) ) {
  325. // Trim ("Word " = "Word").
  326. $v = trim( $v );
  327. // Convert int strings to int ("123" = 123).
  328. if ( is_numeric( $v ) && strval( intval( $v ) ) === $v ) {
  329. $v = intval( $v );
  330. }
  331. }
  332. // return.
  333. return $v;
  334. }
  335. /**
  336. * This function will load in a file from the 'admin/views' folder and allow variables to be passed through
  337. *
  338. * @date 28/09/13
  339. * @since 5.0.0
  340. *
  341. * @param string $view_path
  342. * @param array $view_args
  343. *
  344. * @return void
  345. */
  346. function acf_get_view( $view_path = '', $view_args = array() ) {
  347. // allow view file name shortcut
  348. if ( substr( $view_path, -4 ) !== '.php' ) {
  349. $view_path = acf_get_path( "includes/admin/views/{$view_path}.php" );
  350. }
  351. // include
  352. if ( file_exists( $view_path ) ) {
  353. // Use `EXTR_SKIP` here to prevent `$view_path` from being accidentally/maliciously overridden.
  354. extract( $view_args, EXTR_SKIP );
  355. include $view_path;
  356. }
  357. }
  358. /*
  359. * acf_merge_atts
  360. *
  361. * description
  362. *
  363. * @type function
  364. * @date 2/11/2014
  365. * @since 5.0.9
  366. *
  367. * @param $post_id (int)
  368. * @return $post_id (int)
  369. */
  370. function acf_merge_atts( $atts, $extra = array() ) {
  371. // bail ealry if no $extra
  372. if ( empty( $extra ) ) {
  373. return $atts;
  374. }
  375. // trim
  376. $extra = array_map( 'trim', $extra );
  377. $extra = array_filter( $extra );
  378. // merge in new atts
  379. foreach ( $extra as $k => $v ) {
  380. // append
  381. if ( $k == 'class' || $k == 'style' ) {
  382. $atts[ $k ] .= ' ' . $v;
  383. // merge
  384. } else {
  385. $atts[ $k ] = $v;
  386. }
  387. }
  388. // return
  389. return $atts;
  390. }
  391. /*
  392. * acf_nonce_input
  393. *
  394. * This function will create a basic nonce input
  395. *
  396. * @type function
  397. * @date 24/5/17
  398. * @since 5.6.0
  399. *
  400. * @param $post_id (int)
  401. * @return $post_id (int)
  402. */
  403. function acf_nonce_input( $nonce = '' ) {
  404. echo '<input type="hidden" name="_acf_nonce" value="' . wp_create_nonce( $nonce ) . '" />';
  405. }
  406. /*
  407. * acf_extract_var
  408. *
  409. * This function will remove the var from the array, and return the var
  410. *
  411. * @type function
  412. * @date 2/10/13
  413. * @since 5.0.0
  414. *
  415. * @param $array (array)
  416. * @param $key (string)
  417. * @return (mixed)
  418. */
  419. function acf_extract_var( &$array, $key, $default = null ) {
  420. // check if exists
  421. // - uses array_key_exists to extract NULL values (isset will fail)
  422. if ( is_array( $array ) && array_key_exists( $key, $array ) ) {
  423. // store value
  424. $v = $array[ $key ];
  425. // unset
  426. unset( $array[ $key ] );
  427. // return
  428. return $v;
  429. }
  430. // return
  431. return $default;
  432. }
  433. /*
  434. * acf_extract_vars
  435. *
  436. * This function will remove the vars from the array, and return the vars
  437. *
  438. * @type function
  439. * @date 8/10/13
  440. * @since 5.0.0
  441. *
  442. * @param $post_id (int)
  443. * @return $post_id (int)
  444. */
  445. function acf_extract_vars( &$array, $keys ) {
  446. $r = array();
  447. foreach ( $keys as $key ) {
  448. $r[ $key ] = acf_extract_var( $array, $key );
  449. }
  450. return $r;
  451. }
  452. /*
  453. * acf_get_sub_array
  454. *
  455. * This function will return a sub array of data
  456. *
  457. * @type function
  458. * @date 15/03/2016
  459. * @since 5.3.2
  460. *
  461. * @param $post_id (int)
  462. * @return $post_id (int)
  463. */
  464. function acf_get_sub_array( $array, $keys ) {
  465. $r = array();
  466. foreach ( $keys as $key ) {
  467. $r[ $key ] = $array[ $key ];
  468. }
  469. return $r;
  470. }
  471. /**
  472. * acf_get_post_types
  473. *
  474. * Returns an array of post type names.
  475. *
  476. * @date 7/10/13
  477. * @since 5.0.0
  478. *
  479. * @param array $args Optional. An array of key => value arguments to match against the post type objects. Default empty array.
  480. * @return array A list of post type names.
  481. */
  482. function acf_get_post_types( $args = array() ) {
  483. // vars
  484. $post_types = array();
  485. // extract special arg
  486. $exclude = acf_extract_var( $args, 'exclude', array() );
  487. $exclude[] = 'acf-field';
  488. $exclude[] = 'acf-field-group';
  489. // get post type objects
  490. $objects = get_post_types( $args, 'objects' );
  491. // loop
  492. foreach ( $objects as $i => $object ) {
  493. // bail early if is exclude
  494. if ( in_array( $i, $exclude ) ) {
  495. continue;
  496. }
  497. // bail early if is builtin (WP) private post type
  498. // - nav_menu_item, revision, customize_changeset, etc
  499. if ( $object->_builtin && ! $object->public ) {
  500. continue;
  501. }
  502. // append
  503. $post_types[] = $i;
  504. }
  505. // filter
  506. $post_types = apply_filters( 'acf/get_post_types', $post_types, $args );
  507. // return
  508. return $post_types;
  509. }
  510. function acf_get_pretty_post_types( $post_types = array() ) {
  511. // get post types
  512. if ( empty( $post_types ) ) {
  513. // get all custom post types
  514. $post_types = acf_get_post_types();
  515. }
  516. // get labels
  517. $ref = array();
  518. $r = array();
  519. foreach ( $post_types as $post_type ) {
  520. // vars
  521. $label = acf_get_post_type_label( $post_type );
  522. // append to r
  523. $r[ $post_type ] = $label;
  524. // increase counter
  525. if ( ! isset( $ref[ $label ] ) ) {
  526. $ref[ $label ] = 0;
  527. }
  528. $ref[ $label ]++;
  529. }
  530. // get slugs
  531. foreach ( array_keys( $r ) as $i ) {
  532. // vars
  533. $post_type = $r[ $i ];
  534. if ( $ref[ $post_type ] > 1 ) {
  535. $r[ $i ] .= ' (' . $i . ')';
  536. }
  537. }
  538. // return
  539. return $r;
  540. }
  541. /*
  542. * acf_get_post_type_label
  543. *
  544. * This function will return a pretty label for a specific post_type
  545. *
  546. * @type function
  547. * @date 5/07/2016
  548. * @since 5.4.0
  549. *
  550. * @param $post_type (string)
  551. * @return (string)
  552. */
  553. function acf_get_post_type_label( $post_type ) {
  554. // vars
  555. $label = $post_type;
  556. // check that object exists
  557. // - case exists when importing field group from another install and post type does not exist
  558. if ( post_type_exists( $post_type ) ) {
  559. $obj = get_post_type_object( $post_type );
  560. $label = $obj->labels->singular_name;
  561. }
  562. // return
  563. return $label;
  564. }
  565. /*
  566. * acf_verify_nonce
  567. *
  568. * This function will look at the $_POST['_acf_nonce'] value and return true or false
  569. *
  570. * @type function
  571. * @date 15/10/13
  572. * @since 5.0.0
  573. *
  574. * @param $nonce (string)
  575. * @return (boolean)
  576. */
  577. function acf_verify_nonce( $value ) {
  578. // vars
  579. $nonce = acf_maybe_get_POST( '_acf_nonce' );
  580. // bail early nonce does not match (post|user|comment|term)
  581. if ( ! $nonce || ! wp_verify_nonce( $nonce, $value ) ) {
  582. return false;
  583. }
  584. // reset nonce (only allow 1 save)
  585. $_POST['_acf_nonce'] = false;
  586. // return
  587. return true;
  588. }
  589. /*
  590. * acf_verify_ajax
  591. *
  592. * This function will return true if the current AJAX request is valid
  593. * It's action will also allow WPML to set the lang and avoid AJAX get_posts issues
  594. *
  595. * @type function
  596. * @date 7/08/2015
  597. * @since 5.2.3
  598. *
  599. * @param n/a
  600. * @return (boolean)
  601. */
  602. function acf_verify_ajax() {
  603. // vars
  604. $nonce = isset( $_REQUEST['nonce'] ) ? $_REQUEST['nonce'] : '';
  605. // bail early if not acf nonce
  606. if ( ! $nonce || ! wp_verify_nonce( $nonce, 'acf_nonce' ) ) {
  607. return false;
  608. }
  609. // action for 3rd party customization
  610. do_action( 'acf/verify_ajax' );
  611. // return
  612. return true;
  613. }
  614. /*
  615. * acf_get_image_sizes
  616. *
  617. * This function will return an array of available image sizes
  618. *
  619. * @type function
  620. * @date 23/10/13
  621. * @since 5.0.0
  622. *
  623. * @param n/a
  624. * @return (array)
  625. */
  626. function acf_get_image_sizes() {
  627. // vars
  628. $sizes = array(
  629. 'thumbnail' => __( 'Thumbnail', 'acf' ),
  630. 'medium' => __( 'Medium', 'acf' ),
  631. 'large' => __( 'Large', 'acf' ),
  632. );
  633. // find all sizes
  634. $all_sizes = get_intermediate_image_sizes();
  635. // add extra registered sizes
  636. if ( ! empty( $all_sizes ) ) {
  637. foreach ( $all_sizes as $size ) {
  638. // bail early if already in array
  639. if ( isset( $sizes[ $size ] ) ) {
  640. continue;
  641. }
  642. // append to array
  643. $label = str_replace( '-', ' ', $size );
  644. $label = ucwords( $label );
  645. $sizes[ $size ] = $label;
  646. }
  647. }
  648. // add sizes
  649. foreach ( array_keys( $sizes ) as $s ) {
  650. // vars
  651. $data = acf_get_image_size( $s );
  652. // append
  653. if ( $data['width'] && $data['height'] ) {
  654. $sizes[ $s ] .= ' (' . $data['width'] . ' x ' . $data['height'] . ')';
  655. }
  656. }
  657. // add full end
  658. $sizes['full'] = __( 'Full Size', 'acf' );
  659. // filter for 3rd party customization
  660. $sizes = apply_filters( 'acf/get_image_sizes', $sizes );
  661. // return
  662. return $sizes;
  663. }
  664. function acf_get_image_size( $s = '' ) {
  665. // global
  666. global $_wp_additional_image_sizes;
  667. // rename for nicer code
  668. $_sizes = $_wp_additional_image_sizes;
  669. // vars
  670. $data = array(
  671. 'width' => isset( $_sizes[ $s ]['width'] ) ? $_sizes[ $s ]['width'] : get_option( "{$s}_size_w" ),
  672. 'height' => isset( $_sizes[ $s ]['height'] ) ? $_sizes[ $s ]['height'] : get_option( "{$s}_size_h" ),
  673. );
  674. // return
  675. return $data;
  676. }
  677. /**
  678. * acf_version_compare
  679. *
  680. * Similar to the version_compare() function but with extra functionality.
  681. *
  682. * @date 21/11/16
  683. * @since 5.5.0
  684. *
  685. * @param string $left The left version number.
  686. * @param string $compare The compare operator.
  687. * @param string $right The right version number.
  688. * @return bool
  689. */
  690. function acf_version_compare( $left = '', $compare = '>', $right = '' ) {
  691. // Detect 'wp' placeholder.
  692. if ( $left === 'wp' ) {
  693. global $wp_version;
  694. $left = $wp_version;
  695. }
  696. // Return result.
  697. return version_compare( $left, $right, $compare );
  698. }
  699. /*
  700. * acf_get_full_version
  701. *
  702. * This function will remove any '-beta1' or '-RC1' strings from a version
  703. *
  704. * @type function
  705. * @date 24/11/16
  706. * @since 5.5.0
  707. *
  708. * @param $version (string)
  709. * @return (string)
  710. */
  711. function acf_get_full_version( $version = '1' ) {
  712. // remove '-beta1' or '-RC1'
  713. if ( $pos = strpos( $version, '-' ) ) {
  714. $version = substr( $version, 0, $pos );
  715. }
  716. // return
  717. return $version;
  718. }
  719. /*
  720. * acf_get_terms
  721. *
  722. * This function is a wrapper for the get_terms() function
  723. *
  724. * @type function
  725. * @date 28/09/2016
  726. * @since 5.4.0
  727. *
  728. * @param $args (array)
  729. * @return (array)
  730. */
  731. function acf_get_terms( $args ) {
  732. // defaults
  733. $args = wp_parse_args(
  734. $args,
  735. array(
  736. 'taxonomy' => null,
  737. 'hide_empty' => false,
  738. 'update_term_meta_cache' => false,
  739. )
  740. );
  741. // parameters changed in version 4.5
  742. if ( acf_version_compare( 'wp', '<', '4.5' ) ) {
  743. return get_terms( $args['taxonomy'], $args );
  744. }
  745. // return
  746. return get_terms( $args );
  747. }
  748. /*
  749. * acf_get_taxonomy_terms
  750. *
  751. * This function will return an array of available taxonomy terms
  752. *
  753. * @type function
  754. * @date 7/10/13
  755. * @since 5.0.0
  756. *
  757. * @param $taxonomies (array)
  758. * @return (array)
  759. */
  760. function acf_get_taxonomy_terms( $taxonomies = array() ) {
  761. // force array
  762. $taxonomies = acf_get_array( $taxonomies );
  763. // get pretty taxonomy names
  764. $taxonomies = acf_get_pretty_taxonomies( $taxonomies );
  765. // vars
  766. $r = array();
  767. // populate $r
  768. foreach ( array_keys( $taxonomies ) as $taxonomy ) {
  769. // vars
  770. $label = $taxonomies[ $taxonomy ];
  771. $is_hierarchical = is_taxonomy_hierarchical( $taxonomy );
  772. $terms = acf_get_terms(
  773. array(
  774. 'taxonomy' => $taxonomy,
  775. 'hide_empty' => false,
  776. )
  777. );
  778. // bail early i no terms
  779. if ( empty( $terms ) ) {
  780. continue;
  781. }
  782. // sort into hierachial order!
  783. if ( $is_hierarchical ) {
  784. $terms = _get_term_children( 0, $terms, $taxonomy );
  785. }
  786. // add placeholder
  787. $r[ $label ] = array();
  788. // add choices
  789. foreach ( $terms as $term ) {
  790. $k = "{$taxonomy}:{$term->slug}";
  791. $r[ $label ][ $k ] = acf_get_term_title( $term );
  792. }
  793. }
  794. // return
  795. return $r;
  796. }
  797. /*
  798. * acf_decode_taxonomy_terms
  799. *
  800. * This function decodes the $taxonomy:$term strings into a nested array
  801. *
  802. * @type function
  803. * @date 27/02/2014
  804. * @since 5.0.0
  805. *
  806. * @param $terms (array)
  807. * @return (array)
  808. */
  809. function acf_decode_taxonomy_terms( $strings = false ) {
  810. // bail early if no terms
  811. if ( empty( $strings ) ) {
  812. return false;
  813. }
  814. // vars
  815. $terms = array();
  816. // loop
  817. foreach ( $strings as $string ) {
  818. // vars
  819. $data = acf_decode_taxonomy_term( $string );
  820. $taxonomy = $data['taxonomy'];
  821. $term = $data['term'];
  822. // create empty array
  823. if ( ! isset( $terms[ $taxonomy ] ) ) {
  824. $terms[ $taxonomy ] = array();
  825. }
  826. // append
  827. $terms[ $taxonomy ][] = $term;
  828. }
  829. // return
  830. return $terms;
  831. }
  832. /*
  833. * acf_decode_taxonomy_term
  834. *
  835. * This function will return the taxonomy and term slug for a given value
  836. *
  837. * @type function
  838. * @date 31/03/2014
  839. * @since 5.0.0
  840. *
  841. * @param $string (string)
  842. * @return (array)
  843. */
  844. function acf_decode_taxonomy_term( $value ) {
  845. // vars
  846. $data = array(
  847. 'taxonomy' => '',
  848. 'term' => '',
  849. );
  850. // int
  851. if ( is_numeric( $value ) ) {
  852. $data['term'] = $value;
  853. // string
  854. } elseif ( is_string( $value ) ) {
  855. $value = explode( ':', $value );
  856. $data['taxonomy'] = isset( $value[0] ) ? $value[0] : '';
  857. $data['term'] = isset( $value[1] ) ? $value[1] : '';
  858. // error
  859. } else {
  860. return false;
  861. }
  862. // allow for term_id (Used by ACF v4)
  863. if ( is_numeric( $data['term'] ) ) {
  864. // global
  865. global $wpdb;
  866. // find taxonomy
  867. if ( ! $data['taxonomy'] ) {
  868. $data['taxonomy'] = $wpdb->get_var( $wpdb->prepare( "SELECT taxonomy FROM $wpdb->term_taxonomy WHERE term_id = %d LIMIT 1", $data['term'] ) );
  869. }
  870. // find term (may have numeric slug '123')
  871. $term = get_term_by( 'slug', $data['term'], $data['taxonomy'] );
  872. // attempt get term via ID (ACF4 uses ID)
  873. if ( ! $term ) {
  874. $term = get_term( $data['term'], $data['taxonomy'] );
  875. }
  876. // bail early if no term
  877. if ( ! $term ) {
  878. return false;
  879. }
  880. // update
  881. $data['taxonomy'] = $term->taxonomy;
  882. $data['term'] = $term->slug;
  883. }
  884. // return
  885. return $data;
  886. }
  887. /**
  888. * acf_array
  889. *
  890. * Casts the value into an array.
  891. *
  892. * @date 9/1/19
  893. * @since 5.7.10
  894. *
  895. * @param mixed $val The value to cast.
  896. * @return array
  897. */
  898. function acf_array( $val = array() ) {
  899. return (array) $val;
  900. }
  901. /**
  902. * Returns a non-array value.
  903. *
  904. * @date 11/05/2020
  905. * @since 5.8.10
  906. *
  907. * @param mixed $val The value to review.
  908. * @return mixed
  909. */
  910. function acf_unarray( $val ) {
  911. if ( is_array( $val ) ) {
  912. return reset( $val );
  913. }
  914. return $val;
  915. }
  916. /*
  917. * acf_get_array
  918. *
  919. * This function will force a variable to become an array
  920. *
  921. * @type function
  922. * @date 4/02/2014
  923. * @since 5.0.0
  924. *
  925. * @param $var (mixed)
  926. * @return (array)
  927. */
  928. function acf_get_array( $var = false, $delimiter = '' ) {
  929. // array
  930. if ( is_array( $var ) ) {
  931. return $var;
  932. }
  933. // bail early if empty
  934. if ( acf_is_empty( $var ) ) {
  935. return array();
  936. }
  937. // string
  938. if ( is_string( $var ) && $delimiter ) {
  939. return explode( $delimiter, $var );
  940. }
  941. // place in array
  942. return (array) $var;
  943. }
  944. /*
  945. * acf_get_numeric
  946. *
  947. * This function will return numeric values
  948. *
  949. * @type function
  950. * @date 15/07/2016
  951. * @since 5.4.0
  952. *
  953. * @param $value (mixed)
  954. * @return (mixed)
  955. */
  956. function acf_get_numeric( $value = '' ) {
  957. // vars
  958. $numbers = array();
  959. $is_array = is_array( $value );
  960. // loop
  961. foreach ( (array) $value as $v ) {
  962. if ( is_numeric( $v ) ) {
  963. $numbers[] = (int) $v;
  964. }
  965. }
  966. // bail early if is empty
  967. if ( empty( $numbers ) ) {
  968. return false;
  969. }
  970. // convert array
  971. if ( ! $is_array ) {
  972. $numbers = $numbers[0];
  973. }
  974. // return
  975. return $numbers;
  976. }
  977. /**
  978. * acf_get_posts
  979. *
  980. * Similar to the get_posts() function but with extra functionality.
  981. *
  982. * @date 3/03/15
  983. * @since 5.1.5
  984. *
  985. * @param array $args The query args.
  986. * @return array
  987. */
  988. function acf_get_posts( $args = array() ) {
  989. // Vars.
  990. $posts = array();
  991. // Apply default args.
  992. $args = wp_parse_args(
  993. $args,
  994. array(
  995. 'posts_per_page' => -1,
  996. 'post_type' => '',
  997. 'post_status' => 'any',
  998. 'update_post_meta_cache' => false,
  999. 'update_post_term_cache' => false,
  1000. )
  1001. );
  1002. // Avoid default 'post' post_type by providing all public types.
  1003. if ( ! $args['post_type'] ) {
  1004. $args['post_type'] = acf_get_post_types();
  1005. }
  1006. // Check if specifc post ID's have been provided.
  1007. if ( $args['post__in'] ) {
  1008. // Clean value into an array of IDs.
  1009. $args['post__in'] = array_map( 'intval', acf_array( $args['post__in'] ) );
  1010. }
  1011. // Query posts.
  1012. $posts = get_posts( $args );
  1013. // Remove any potential empty results.
  1014. $posts = array_filter( $posts );
  1015. // Manually order results.
  1016. if ( $posts && $args['post__in'] ) {
  1017. $order = array();
  1018. foreach ( $posts as $i => $post ) {
  1019. $order[ $i ] = array_search( $post->ID, $args['post__in'] );
  1020. }
  1021. array_multisort( $order, $posts );
  1022. }
  1023. // Return posts.
  1024. return $posts;
  1025. }
  1026. /*
  1027. * _acf_query_remove_post_type
  1028. *
  1029. * This function will remove the 'wp_posts.post_type' WHERE clause completely
  1030. * When using 'post__in', this clause is unneccessary and slow.
  1031. *
  1032. * @type function
  1033. * @date 4/03/2015
  1034. * @since 5.1.5
  1035. *
  1036. * @param $sql (string)
  1037. * @return $sql
  1038. */
  1039. function _acf_query_remove_post_type( $sql ) {
  1040. // global
  1041. global $wpdb;
  1042. // bail ealry if no 'wp_posts.ID IN'
  1043. if ( strpos( $sql, "$wpdb->posts.ID IN" ) === false ) {
  1044. return $sql;
  1045. }
  1046. // get bits
  1047. $glue = 'AND';
  1048. $bits = explode( $glue, $sql );
  1049. // loop through $where and remove any post_type queries
  1050. foreach ( $bits as $i => $bit ) {
  1051. if ( strpos( $bit, "$wpdb->posts.post_type" ) !== false ) {
  1052. unset( $bits[ $i ] );
  1053. }
  1054. }
  1055. // join $where back together
  1056. $sql = implode( $glue, $bits );
  1057. // return
  1058. return $sql;
  1059. }
  1060. /*
  1061. * acf_get_grouped_posts
  1062. *
  1063. * This function will return all posts grouped by post_type
  1064. * This is handy for select settings
  1065. *
  1066. * @type function
  1067. * @date 27/02/2014
  1068. * @since 5.0.0
  1069. *
  1070. * @param $args (array)
  1071. * @return (array)
  1072. */
  1073. function acf_get_grouped_posts( $args ) {
  1074. // vars
  1075. $data = array();
  1076. // defaults
  1077. $args = wp_parse_args(
  1078. $args,
  1079. array(
  1080. 'posts_per_page' => -1,
  1081. 'paged' => 0,
  1082. 'post_type' => 'post',
  1083. 'orderby' => 'menu_order title',
  1084. 'order' => 'ASC',
  1085. 'post_status' => 'any',
  1086. 'suppress_filters' => false,
  1087. 'update_post_meta_cache' => false,
  1088. )
  1089. );
  1090. // find array of post_type
  1091. $post_types = acf_get_array( $args['post_type'] );
  1092. $post_types_labels = acf_get_pretty_post_types( $post_types );
  1093. $is_single_post_type = ( count( $post_types ) == 1 );
  1094. // attachment doesn't work if it is the only item in an array
  1095. if ( $is_single_post_type ) {
  1096. $args['post_type'] = reset( $post_types );
  1097. }
  1098. // add filter to orderby post type
  1099. if ( ! $is_single_post_type ) {
  1100. add_filter( 'posts_orderby', '_acf_orderby_post_type', 10, 2 );
  1101. }
  1102. // get posts
  1103. $posts = get_posts( $args );
  1104. // remove this filter (only once)
  1105. if ( ! $is_single_post_type ) {
  1106. remove_filter( 'posts_orderby', '_acf_orderby_post_type', 10, 2 );
  1107. }
  1108. // loop
  1109. foreach ( $post_types as $post_type ) {
  1110. // vars
  1111. $this_posts = array();
  1112. $this_group = array();
  1113. // populate $this_posts
  1114. foreach ( $posts as $post ) {
  1115. if ( $post->post_type == $post_type ) {
  1116. $this_posts[] = $post;
  1117. }
  1118. }
  1119. // bail early if no posts for this post type
  1120. if ( empty( $this_posts ) ) {
  1121. continue;
  1122. }
  1123. // sort into hierachial order!
  1124. // this will fail if a search has taken place because parents wont exist
  1125. if ( is_post_type_hierarchical( $post_type ) && empty( $args['s'] ) ) {
  1126. // vars
  1127. $post_id = $this_posts[0]->ID;
  1128. $parent_id = acf_maybe_get( $args, 'post_parent', 0 );
  1129. $offset = 0;
  1130. $length = count( $this_posts );
  1131. // get all posts from this post type
  1132. $all_posts = get_posts(
  1133. array_merge(
  1134. $args,
  1135. array(
  1136. 'posts_per_page' => -1,
  1137. 'paged' => 0,
  1138. 'post_type' => $post_type,
  1139. )
  1140. )
  1141. );
  1142. // find starting point (offset)
  1143. foreach ( $all_posts as $i => $post ) {
  1144. if ( $post->ID == $post_id ) {
  1145. $offset = $i;
  1146. break;
  1147. }
  1148. }
  1149. // order posts
  1150. $ordered_posts = get_page_children( $parent_id, $all_posts );
  1151. // compare aray lengths
  1152. // if $ordered_posts is smaller than $all_posts, WP has lost posts during the get_page_children() function
  1153. // this is possible when get_post( $args ) filter out parents (via taxonomy, meta and other search parameters)
  1154. if ( count( $ordered_posts ) == count( $all_posts ) ) {
  1155. $this_posts = array_slice( $ordered_posts, $offset, $length );
  1156. }
  1157. }
  1158. // populate $this_posts
  1159. foreach ( $this_posts as $post ) {
  1160. $this_group[ $post->ID ] = $post;
  1161. }
  1162. // group by post type
  1163. $label = $post_types_labels[ $post_type ];
  1164. $data[ $label ] = $this_group;
  1165. }
  1166. // return
  1167. return $data;
  1168. }
  1169. function _acf_orderby_post_type( $ordeby, $wp_query ) {
  1170. // global
  1171. global $wpdb;
  1172. // get post types
  1173. $post_types = $wp_query->get( 'post_type' );
  1174. // prepend SQL
  1175. if ( is_array( $post_types ) ) {
  1176. $post_types = implode( "','", $post_types );
  1177. $ordeby = "FIELD({$wpdb->posts}.post_type,'$post_types')," . $ordeby;
  1178. }
  1179. // return
  1180. return $ordeby;
  1181. }
  1182. function acf_get_post_title( $post = 0, $is_search = false ) {
  1183. // vars
  1184. $post = get_post( $post );
  1185. $title = '';
  1186. $prepend = '';
  1187. $append = '';
  1188. // bail early if no post
  1189. if ( ! $post ) {
  1190. return '';
  1191. }
  1192. // title
  1193. $title = get_the_title( $post->ID );
  1194. // empty
  1195. if ( $title === '' ) {
  1196. $title = __( '(no title)', 'acf' );
  1197. }
  1198. // status
  1199. if ( get_post_status( $post->ID ) != 'publish' ) {
  1200. $append .= ' (' . get_post_status( $post->ID ) . ')';
  1201. }
  1202. // ancestors
  1203. if ( $post->post_type !== 'attachment' ) {
  1204. // get ancestors
  1205. $ancestors = get_ancestors( $post->ID, $post->post_type );
  1206. $prepend .= str_repeat( '- ', count( $ancestors ) );
  1207. // add parent
  1208. /*
  1209. removed in 5.6.5 as not used by the UI
  1210. if( $is_search && !empty($ancestors) ) {
  1211. // reverse
  1212. $ancestors = array_reverse($ancestors);
  1213. // convert id's into titles
  1214. foreach( $ancestors as $i => $id ) {
  1215. $ancestors[ $i ] = get_the_title( $id );
  1216. }
  1217. // append
  1218. $append .= ' | ' . __('Parent', 'acf') . ': ' . implode(' / ', $ancestors);
  1219. }
  1220. */
  1221. }
  1222. // merge
  1223. $title = $prepend . $title . $append;
  1224. // return
  1225. return $title;
  1226. }
  1227. function acf_order_by_search( $array, $search ) {
  1228. // vars
  1229. $weights = array();
  1230. $needle = strtolower( $search );
  1231. // add key prefix
  1232. foreach ( array_keys( $array ) as $k ) {
  1233. $array[ '_' . $k ] = acf_extract_var( $array, $k );
  1234. }
  1235. // add search weight
  1236. foreach ( $array as $k => $v ) {
  1237. // vars
  1238. $weight = 0;
  1239. $haystack = strtolower( $v );
  1240. $strpos = strpos( $haystack, $needle );
  1241. // detect search match
  1242. if ( $strpos !== false ) {
  1243. // set eright to length of match
  1244. $weight = strlen( $search );
  1245. // increase weight if match starts at begining of string
  1246. if ( $strpos == 0 ) {
  1247. $weight++;
  1248. }
  1249. }
  1250. // append to wights
  1251. $weights[ $k ] = $weight;
  1252. }
  1253. // sort the array with menu_order ascending
  1254. array_multisort( $weights, SORT_DESC, $array );
  1255. // remove key prefix
  1256. foreach ( array_keys( $array ) as $k ) {
  1257. $array[ substr( $k, 1 ) ] = acf_extract_var( $array, $k );
  1258. }
  1259. // return
  1260. return $array;
  1261. }
  1262. /*
  1263. * acf_get_pretty_user_roles
  1264. *
  1265. * description
  1266. *
  1267. * @type function
  1268. * @date 23/02/2016
  1269. * @since 5.3.2
  1270. *
  1271. * @param $post_id (int)
  1272. * @return $post_id (int)
  1273. */
  1274. function acf_get_pretty_user_roles( $allowed = false ) {
  1275. // vars
  1276. $editable_roles = get_editable_roles();
  1277. $allowed = acf_get_array( $allowed );
  1278. $roles = array();
  1279. // loop
  1280. foreach ( $editable_roles as $role_name => $role_details ) {
  1281. // bail early if not allowed
  1282. if ( ! empty( $allowed ) && ! in_array( $role_name, $allowed ) ) {
  1283. continue;
  1284. }
  1285. // append
  1286. $roles[ $role_name ] = translate_user_role( $role_details['name'] );
  1287. }
  1288. // return
  1289. return $roles;
  1290. }
  1291. /*
  1292. * acf_get_grouped_users
  1293. *
  1294. * This function will return all users grouped by role
  1295. * This is handy for select settings
  1296. *
  1297. * @type function
  1298. * @date 27/02/2014
  1299. * @since 5.0.0
  1300. *
  1301. * @param $args (array)
  1302. * @return (array)
  1303. */
  1304. function acf_get_grouped_users( $args = array() ) {
  1305. // vars
  1306. $r = array();
  1307. // defaults
  1308. $args = wp_parse_args(
  1309. $args,
  1310. array(
  1311. 'users_per_page' => -1,
  1312. 'paged' => 0,
  1313. 'role' => '',
  1314. 'orderby' => 'login',
  1315. 'order' => 'ASC',
  1316. )
  1317. );
  1318. // offset
  1319. $i = 0;
  1320. $min = 0;
  1321. $max = 0;
  1322. $users_per_page = acf_extract_var( $args, 'users_per_page' );
  1323. $paged = acf_extract_var( $args, 'paged' );
  1324. if ( $users_per_page > 0 ) {
  1325. // prevent paged from being -1
  1326. $paged = max( 0, $paged );
  1327. // set min / max
  1328. $min = ( ( $paged - 1 ) * $users_per_page ) + 1; // 1, 11
  1329. $max = ( $paged * $users_per_page ); // 10, 20
  1330. }
  1331. // find array of post_type
  1332. $user_roles = acf_get_pretty_user_roles( $args['role'] );
  1333. // fix role
  1334. if ( is_array( $args['role'] ) ) {
  1335. // global
  1336. global $wp_version, $wpdb;
  1337. // vars
  1338. $roles = acf_extract_var( $args, 'role' );
  1339. // new WP has role__in
  1340. if ( version_compare( $wp_version, '4.4', '>=' ) ) {
  1341. $args['role__in'] = $roles;
  1342. // old WP doesn't have role__in
  1343. } else {
  1344. // vars
  1345. $blog_id = get_current_blog_id();
  1346. $meta_query = array( 'relation' => 'OR' );
  1347. // loop
  1348. foreach ( $roles as $role ) {
  1349. $meta_query[] = array(
  1350. 'key' => $wpdb->get_blog_prefix( $blog_id ) . 'capabilities',
  1351. 'value' => '"' . $role . '"',
  1352. 'compare' => 'LIKE',
  1353. );
  1354. }
  1355. // append
  1356. $args['meta_query'] = $meta_query;
  1357. }
  1358. }
  1359. // get posts
  1360. $users = get_users( $args );
  1361. // loop
  1362. foreach ( $user_roles as $user_role_name => $user_role_label ) {
  1363. // vars
  1364. $this_users = array();
  1365. $this_group = array();
  1366. // populate $this_posts
  1367. foreach ( array_keys( $users ) as $key ) {
  1368. // bail ealry if not correct role
  1369. if ( ! in_array( $user_role_name, $users[ $key ]->roles ) ) {
  1370. continue;
  1371. }
  1372. // extract user
  1373. $user = acf_extract_var( $users, $key );
  1374. // increase
  1375. $i++;
  1376. // bail ealry if too low
  1377. if ( $min && $i < $min ) {
  1378. continue;
  1379. }
  1380. // bail early if too high (don't bother looking at any more users)
  1381. if ( $max && $i > $max ) {
  1382. break;
  1383. }
  1384. // group by post type
  1385. $this_users[ $user->ID ] = $user;
  1386. }
  1387. // bail early if no posts for this post type
  1388. if ( empty( $this_users ) ) {
  1389. continue;
  1390. }
  1391. // append
  1392. $r[ $user_role_label ] = $this_users;
  1393. }
  1394. // return
  1395. return $r;
  1396. }
  1397. /**
  1398. * acf_json_encode
  1399. *
  1400. * Returns json_encode() ready for file / database use.
  1401. *
  1402. * @date 29/4/19
  1403. * @since 5.0.0
  1404. *
  1405. * @param array $json The array of data to encode.
  1406. * @return string
  1407. */
  1408. function acf_json_encode( $json ) {
  1409. return json_encode( $json, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE );
  1410. }
  1411. /*
  1412. * acf_str_exists
  1413. *
  1414. * This function will return true if a sub string is found
  1415. *
  1416. * @type function
  1417. * @date 1/05/2014
  1418. * @since 5.0.0
  1419. *
  1420. * @param $needle (string)
  1421. * @param $haystack (string)
  1422. * @return (boolean)
  1423. */
  1424. function acf_str_exists( $needle, $haystack ) {
  1425. // return true if $haystack contains the $needle
  1426. if ( is_string( $haystack ) && strpos( $haystack, $needle ) !== false ) {
  1427. return true;
  1428. }
  1429. // return
  1430. return false;
  1431. }
  1432. /*
  1433. * acf_debug
  1434. *
  1435. * description
  1436. *
  1437. * @type function
  1438. * @date 2/05/2014
  1439. * @since 5.0.0
  1440. *
  1441. * @param $post_id (int)
  1442. * @return $post_id (int)
  1443. */
  1444. function acf_debug() {
  1445. // vars
  1446. $args = func_get_args();
  1447. $s = array_shift( $args );
  1448. $o = '';
  1449. $nl = "\r\n";
  1450. // start script
  1451. $o .= '<script type="text/javascript">' . $nl;
  1452. $o .= 'console.log("' . $s . '"';
  1453. if ( ! empty( $args ) ) {
  1454. foreach ( $args as $arg ) {
  1455. if ( is_object( $arg ) || is_array( $arg ) ) {
  1456. $arg = json_encode( $arg );
  1457. } elseif ( is_bool( $arg ) ) {
  1458. $arg = $arg ? 'true' : 'false';
  1459. } elseif ( is_string( $arg ) ) {
  1460. $arg = '"' . $arg . '"';
  1461. }
  1462. $o .= ', ' . $arg;
  1463. }
  1464. }
  1465. $o .= ');' . $nl;
  1466. // end script
  1467. $o .= '</script>' . $nl;
  1468. // echo
  1469. echo $o;
  1470. }
  1471. function acf_debug_start() {
  1472. acf_update_setting( 'debug_start', memory_get_usage() );
  1473. }
  1474. function acf_debug_end() {
  1475. $start = acf_get_setting( 'debug_start' );
  1476. $end = memory_get_usage();
  1477. return $end - $start;
  1478. }
  1479. /*
  1480. * acf_encode_choices
  1481. *
  1482. * description
  1483. *
  1484. * @type function
  1485. * @date 4/06/2014
  1486. * @since 5.0.0
  1487. *
  1488. * @param $post_id (int)
  1489. * @return $post_id (int)
  1490. */
  1491. function acf_encode_choices( $array = array(), $show_keys = true ) {
  1492. // bail early if not array (maybe a single string)
  1493. if ( ! is_array( $array ) ) {
  1494. return $array;
  1495. }
  1496. // bail early if empty array
  1497. if ( empty( $array ) ) {
  1498. return '';
  1499. }
  1500. // vars
  1501. $string = '';
  1502. // if allowed to show keys (good for choices, not for default values)
  1503. if ( $show_keys ) {
  1504. // loop
  1505. foreach ( $array as $k => $v ) {
  1506. // ignore if key and value are the same
  1507. if ( strval( $k ) == strval( $v ) ) {
  1508. continue;
  1509. }
  1510. // show key in the value
  1511. $array[ $k ] = $k . ' : ' . $v;
  1512. }
  1513. }
  1514. // implode
  1515. $string = implode( "\n", $array );
  1516. // return
  1517. return $string;
  1518. }
  1519. function acf_decode_choices( $string = '', $array_keys = false ) {
  1520. // bail early if already array
  1521. if ( is_array( $string ) ) {
  1522. return $string;
  1523. // allow numeric values (same as string)
  1524. } elseif ( is_numeric( $string ) ) {
  1525. // do nothing
  1526. // bail early if not a string
  1527. } elseif ( ! is_string( $string ) ) {
  1528. return array();
  1529. // bail early if is empty string
  1530. } elseif ( $string === '' ) {
  1531. return array();
  1532. }
  1533. // vars
  1534. $array = array();
  1535. // explode
  1536. $lines = explode( "\n", $string );
  1537. // key => value
  1538. foreach ( $lines as $line ) {
  1539. // vars
  1540. $k = trim( $line );
  1541. $v = trim( $line );
  1542. // look for ' : '
  1543. if ( acf_str_exists( ' : ', $line ) ) {
  1544. $line = explode( ' : ', $line );
  1545. $k = trim( $line[0] );
  1546. $v = trim( $line[1] );
  1547. }
  1548. // append
  1549. $array[ $k ] = $v;
  1550. }
  1551. // return only array keys? (good for checkbox default_value)
  1552. if ( $array_keys ) {
  1553. return array_keys( $array );
  1554. }
  1555. // return
  1556. return $array;
  1557. }
  1558. /*
  1559. * acf_str_replace
  1560. *
  1561. * This function will replace an array of strings much like str_replace
  1562. * The difference is the extra logic to avoid replacing a string that has alread been replaced
  1563. * This is very useful for replacing date characters as they overlap with eachother
  1564. *
  1565. * @type function
  1566. * @date 21/06/2016
  1567. * @since 5.3.8
  1568. *
  1569. * @param $post_id (int)
  1570. * @return $post_id (int)
  1571. */
  1572. function acf_str_replace( $string = '', $search_replace = array() ) {
  1573. // vars
  1574. $ignore = array();
  1575. // remove potential empty search to avoid PHP error
  1576. unset( $search_replace[''] );
  1577. // loop over conversions
  1578. foreach ( $search_replace as $search => $replace ) {
  1579. // ignore this search, it was a previous replace
  1580. if ( in_array( $search, $ignore ) ) {
  1581. continue;
  1582. }
  1583. // bail early if subsctring not found
  1584. if ( strpos( $string, $search ) === false ) {
  1585. continue;
  1586. }
  1587. // replace
  1588. $string = str_replace( $search, $replace, $string );
  1589. // append to ignore
  1590. $ignore[] = $replace;
  1591. }
  1592. // return
  1593. return $string;
  1594. }
  1595. /*
  1596. * date & time formats
  1597. *
  1598. * These settings contain an association of format strings from PHP => JS
  1599. *
  1600. * @type function
  1601. * @date 21/06/2016
  1602. * @since 5.3.8
  1603. *
  1604. * @param n/a
  1605. * @return n/a
  1606. */
  1607. acf_update_setting(
  1608. 'php_to_js_date_formats',
  1609. array(
  1610. // Year
  1611. 'Y' => 'yy', // Numeric, 4 digits 1999, 2003
  1612. 'y' => 'y', // Numeric, 2 digits 99, 03
  1613. // Month
  1614. 'm' => 'mm', // Numeric, with leading zeros 01–12
  1615. 'n' => 'm', // Numeric, without leading zeros 1–12
  1616. 'F' => 'MM', // Textual full January – December
  1617. 'M' => 'M', // Textual three letters Jan - Dec
  1618. // Weekday
  1619. 'l' => 'DD', // Full name (lowercase 'L') Sunday – Saturday
  1620. 'D' => 'D', // Three letter name Mon – Sun
  1621. // Day of Month
  1622. 'd' => 'dd', // Numeric, with leading zeros 01–31
  1623. 'j' => 'd', // Numeric, without leading zeros 1–31
  1624. 'S' => '', // The English suffix for the day of the month st, nd or th in the 1st, 2nd or 15th.
  1625. )
  1626. );
  1627. acf_update_setting(
  1628. 'php_to_js_time_formats',
  1629. array(
  1630. 'a' => 'tt', // Lowercase Ante meridiem and Post meridiem am or pm
  1631. 'A' => 'TT', // Uppercase Ante meridiem and Post meridiem AM or PM
  1632. 'h' => 'hh', // 12-hour format of an hour with leading zeros 01 through 12
  1633. 'g' => 'h', // 12-hour format of an hour without leading zeros 1 through 12
  1634. 'H' => 'HH', // 24-hour format of an hour with leading zeros 00 through 23
  1635. 'G' => 'H', // 24-hour format of an hour without leading zeros 0 through 23
  1636. 'i' => 'mm', // Minutes with leading zeros 00 to 59
  1637. 's' => 'ss', // Seconds, with leading zeros 00 through 59
  1638. )
  1639. );
  1640. /*
  1641. * acf_split_date_time
  1642. *
  1643. * This function will split a format string into seperate date and time
  1644. *
  1645. * @type function
  1646. * @date 26/05/2016
  1647. * @since 5.3.8
  1648. *
  1649. * @param $date_time (string)
  1650. * @return $formats (array)
  1651. */
  1652. function acf_split_date_time( $date_time = '' ) {
  1653. // vars
  1654. $php_date = acf_get_setting( 'php_to_js_date_formats' );
  1655. $php_time = acf_get_setting( 'php_to_js_time_formats' );
  1656. $chars = str_split( $date_time );
  1657. $type = 'date';
  1658. // default
  1659. $data = array(
  1660. 'date' => '',
  1661. 'time' => '',
  1662. );
  1663. // loop
  1664. foreach ( $chars as $i => $c ) {
  1665. // find type
  1666. // - allow misc characters to append to previous type
  1667. if ( isset( $php_date[ $c ] ) ) {
  1668. $type = 'date';
  1669. } elseif ( isset( $php_time[ $c ] ) ) {
  1670. $type = 'time';
  1671. }
  1672. // append char
  1673. $data[ $type ] .= $c;
  1674. }
  1675. // trim
  1676. $data['date'] = trim( $data['date'] );
  1677. $data['time'] = trim( $data['time'] );
  1678. // return
  1679. return $data;
  1680. }
  1681. /*
  1682. * acf_convert_date_to_php
  1683. *
  1684. * This fucntion converts a date format string from JS to PHP
  1685. *
  1686. * @type function
  1687. * @date 20/06/2014
  1688. * @since 5.0.0
  1689. *
  1690. * @param $date (string)
  1691. * @return (string)
  1692. */
  1693. function acf_convert_date_to_php( $date = '' ) {
  1694. // vars
  1695. $php_to_js = acf_get_setting( 'php_to_js_date_formats' );
  1696. $js_to_php = array_flip( $php_to_js );
  1697. // return
  1698. return acf_str_replace( $date, $js_to_php );
  1699. }
  1700. /*
  1701. * acf_convert_date_to_js
  1702. *
  1703. * This fucntion converts a date format string from PHP to JS
  1704. *
  1705. * @type function
  1706. * @date 20/06/2014
  1707. * @since 5.0.0
  1708. *
  1709. * @param $date (string)
  1710. * @return (string)
  1711. */
  1712. function acf_convert_date_to_js( $date = '' ) {
  1713. // vars
  1714. $php_to_js = acf_get_setting( 'php_to_js_date_formats' );
  1715. // return
  1716. return acf_str_replace( $date, $php_to_js );
  1717. }
  1718. /*
  1719. * acf_convert_time_to_php
  1720. *
  1721. * This fucntion converts a time format string from JS to PHP
  1722. *
  1723. * @type function
  1724. * @date 20/06/2014
  1725. * @since 5.0.0
  1726. *
  1727. * @param $time (string)
  1728. * @return (string)
  1729. */
  1730. function acf_convert_time_to_php( $time = '' ) {
  1731. // vars
  1732. $php_to_js = acf_get_setting( 'php_to_js_time_formats' );
  1733. $js_to_php = array_flip( $php_to_js );
  1734. // return
  1735. return acf_str_replace( $time, $js_to_php );
  1736. }
  1737. /*
  1738. * acf_convert_time_to_js
  1739. *
  1740. * This fucntion converts a date format string from PHP to JS
  1741. *
  1742. * @type function
  1743. * @date 20/06/2014
  1744. * @since 5.0.0
  1745. *
  1746. * @param $time (string)
  1747. * @return (string)
  1748. */
  1749. function acf_convert_time_to_js( $time = '' ) {
  1750. // vars
  1751. $php_to_js = acf_get_setting( 'php_to_js_time_formats' );
  1752. // return
  1753. return acf_str_replace( $time, $php_to_js );
  1754. }
  1755. /*
  1756. * acf_update_user_setting
  1757. *
  1758. * description
  1759. *
  1760. * @type function
  1761. * @date 15/07/2014
  1762. * @since 5.0.0
  1763. *
  1764. * @param $post_id (int)
  1765. * @return $post_id (int)
  1766. */
  1767. function acf_update_user_setting( $name, $value ) {
  1768. // get current user id
  1769. $user_id = get_current_user_id();
  1770. // get user settings
  1771. $settings = get_user_meta( $user_id, 'acf_user_settings', true );
  1772. // ensure array
  1773. $settings = acf_get_array( $settings );
  1774. // delete setting (allow 0 to save)
  1775. if ( acf_is_empty( $value ) ) {
  1776. unset( $settings[ $name ] );
  1777. // append setting
  1778. } else {
  1779. $settings[ $name ] = $value;
  1780. }
  1781. // update user data
  1782. return update_metadata( 'user', $user_id, 'acf_user_settings', $settings );
  1783. }
  1784. /*
  1785. * acf_get_user_setting
  1786. *
  1787. * description
  1788. *
  1789. * @type function
  1790. * @date 15/07/2014
  1791. * @since 5.0.0
  1792. *
  1793. * @param $post_id (int)
  1794. * @return $post_id (int)
  1795. */
  1796. function acf_get_user_setting( $name = '', $default = false ) {
  1797. // get current user id
  1798. $user_id = get_current_user_id();
  1799. // get user settings
  1800. $settings = get_user_meta( $user_id, 'acf_user_settings', true );
  1801. // ensure array
  1802. $settings = acf_get_array( $settings );
  1803. // bail arly if no settings
  1804. if ( ! isset( $settings[ $name ] ) ) {
  1805. return $default;
  1806. }
  1807. // return
  1808. return $settings[ $name ];
  1809. }
  1810. /*
  1811. * acf_in_array
  1812. *
  1813. * description
  1814. *
  1815. * @type function
  1816. * @date 22/07/2014
  1817. * @since 5.0.0
  1818. *
  1819. * @param $post_id (int)
  1820. * @return $post_id (int)
  1821. */
  1822. function acf_in_array( $value = '', $array = false ) {
  1823. // bail early if not array
  1824. if ( ! is_array( $array ) ) {
  1825. return false;
  1826. }
  1827. // find value in array
  1828. return in_array( $value, $array );
  1829. }
  1830. /*
  1831. * acf_get_valid_post_id
  1832. *
  1833. * This function will return a valid post_id based on the current screen / parameter
  1834. *
  1835. * @type function
  1836. * @date 8/12/2013
  1837. * @since 5.0.0
  1838. *
  1839. * @param $post_id (mixed)
  1840. * @return $post_id (mixed)
  1841. */
  1842. function acf_get_valid_post_id( $post_id = 0 ) {
  1843. // allow filter to short-circuit load_value logic
  1844. $preload = apply_filters( 'acf/pre_load_post_id', null, $post_id );
  1845. if ( $preload !== null ) {
  1846. return $preload;
  1847. }
  1848. // vars
  1849. $_post_id = $post_id;
  1850. // if not $post_id, load queried object
  1851. if ( ! $post_id ) {
  1852. // try for global post (needed for setup_postdata)
  1853. $post_id = (int) get_the_ID();
  1854. // try for current screen
  1855. if ( ! $post_id ) {
  1856. $post_id = get_queried_object();
  1857. }
  1858. }
  1859. // $post_id may be an object.
  1860. // todo: Compare class types instead.
  1861. if ( is_object( $post_id ) ) {
  1862. // post
  1863. if ( isset( $post_id->post_type, $post_id->ID ) ) {
  1864. $post_id = $post_id->ID;
  1865. // user
  1866. } elseif ( isset( $post_id->roles, $post_id->ID ) ) {
  1867. $post_id = 'user_' . $post_id->ID;
  1868. // term
  1869. } elseif ( isset( $post_id->taxonomy, $post_id->term_id ) ) {
  1870. $post_id = 'term_' . $post_id->term_id;
  1871. // comment
  1872. } elseif ( isset( $post_id->comment_ID ) ) {
  1873. $post_id = 'comment_' . $post_id->comment_ID;
  1874. // default
  1875. } else {
  1876. $post_id = 0;
  1877. }
  1878. }
  1879. // allow for option == options
  1880. if ( $post_id === 'option' ) {
  1881. $post_id = 'options';
  1882. }
  1883. // append language code
  1884. if ( $post_id == 'options' ) {
  1885. $dl = acf_get_setting( 'default_language' );
  1886. $cl = acf_get_setting( 'current_language' );
  1887. if ( $cl && $cl !== $dl ) {
  1888. $post_id .= '_' . $cl;
  1889. }
  1890. }
  1891. // filter for 3rd party
  1892. $post_id = apply_filters( 'acf/validate_post_id', $post_id, $_post_id );
  1893. // return
  1894. return $post_id;
  1895. }
  1896. /*
  1897. * acf_get_post_id_info
  1898. *
  1899. * This function will return the type and id for a given $post_id string
  1900. *
  1901. * @type function
  1902. * @date 2/07/2016
  1903. * @since 5.4.0
  1904. *
  1905. * @param $post_id (mixed)
  1906. * @return $info (array)
  1907. */
  1908. function acf_get_post_id_info( $post_id = 0 ) {
  1909. // vars
  1910. $info = array(
  1911. 'type' => 'post',
  1912. 'id' => 0,
  1913. );
  1914. // bail early if no $post_id
  1915. if ( ! $post_id ) {
  1916. return $info;
  1917. }
  1918. // check cache
  1919. // - this function will most likely be called multiple times (saving loading fields from post)
  1920. // $cache_key = "get_post_id_info/post_id={$post_id}";
  1921. // if( acf_isset_cache($cache_key) ) return acf_get_cache($cache_key);
  1922. // numeric
  1923. if ( is_numeric( $post_id ) ) {
  1924. $info['id'] = (int) $post_id;
  1925. // string
  1926. } elseif ( is_string( $post_id ) ) {
  1927. // vars
  1928. $glue = '_';
  1929. $type = explode( $glue, $post_id );
  1930. $id = array_pop( $type );
  1931. $type = implode( $glue, $type );
  1932. $meta = array( 'post', 'user', 'comment', 'term' );
  1933. // check if is taxonomy (ACF < 5.5)
  1934. // - avoid scenario where taxonomy exists with name of meta type
  1935. if ( ! in_array( $type, $meta ) && acf_isset_termmeta( $type ) ) {
  1936. $type = 'term';
  1937. }
  1938. // meta
  1939. if ( is_numeric( $id ) && in_array( $type, $meta ) ) {
  1940. $info['type'] = $type;
  1941. $info['id'] = (int) $id;
  1942. // option
  1943. } else {
  1944. $info['type'] = 'option';
  1945. $info['id'] = $post_id;
  1946. }
  1947. }
  1948. // update cache
  1949. // acf_set_cache($cache_key, $info);
  1950. // filter
  1951. $info = apply_filters( 'acf/get_post_id_info', $info, $post_id );
  1952. // return
  1953. return $info;
  1954. }
  1955. /*
  1956. acf_log( acf_get_post_id_info(4) );
  1957. acf_log( acf_get_post_id_info('post_4') );
  1958. acf_log( acf_get_post_id_info('user_123') );
  1959. acf_log( acf_get_post_id_info('term_567') );
  1960. acf_log( acf_get_post_id_info('category_204') );
  1961. acf_log( acf_get_post_id_info('comment_6') );
  1962. acf_log( acf_get_post_id_info('options_lol!') );
  1963. acf_log( acf_get_post_id_info('option') );
  1964. acf_log( acf_get_post_id_info('options') );
  1965. */
  1966. /*
  1967. * acf_isset_termmeta
  1968. *
  1969. * This function will return true if the termmeta table exists
  1970. * https://developer.wordpress.org/reference/functions/get_term_meta/
  1971. *
  1972. * @type function
  1973. * @date 3/09/2016
  1974. * @since 5.4.0
  1975. *
  1976. * @param $post_id (int)
  1977. * @return $post_id (int)
  1978. */
  1979. function acf_isset_termmeta( $taxonomy = '' ) {
  1980. // bail ealry if no table
  1981. if ( get_option( 'db_version' ) < 34370 ) {
  1982. return false;
  1983. }
  1984. // check taxonomy
  1985. if ( $taxonomy && ! taxonomy_exists( $taxonomy ) ) {
  1986. return false;
  1987. }
  1988. // return
  1989. return true;
  1990. }
  1991. /*
  1992. * acf_upload_files
  1993. *
  1994. * This function will walk througfh the $_FILES data and upload each found
  1995. *
  1996. * @type function
  1997. * @date 25/10/2014
  1998. * @since 5.0.9
  1999. *
  2000. * @param $ancestors (array) an internal parameter, not required
  2001. * @return n/a
  2002. */
  2003. function acf_upload_files( $ancestors = array() ) {
  2004. // vars
  2005. $file = array(
  2006. 'name' => '',
  2007. 'type' => '',
  2008. 'tmp_name' => '',
  2009. 'error' => '',
  2010. 'size' => '',
  2011. );
  2012. // populate with $_FILES data
  2013. foreach ( array_keys( $file ) as $k ) {
  2014. $file[ $k ] = $_FILES['acf'][ $k ];
  2015. }
  2016. // walk through ancestors
  2017. if ( ! empty( $ancestors ) ) {
  2018. foreach ( $ancestors as $a ) {
  2019. foreach ( array_keys( $file ) as $k ) {
  2020. $file[ $k ] = $file[ $k ][ $a ];
  2021. }
  2022. }
  2023. }
  2024. // is array?
  2025. if ( is_array( $file['name'] ) ) {
  2026. foreach ( array_keys( $file['name'] ) as $k ) {
  2027. $_ancestors = array_merge( $ancestors, array( $k ) );
  2028. acf_upload_files( $_ancestors );
  2029. }
  2030. return;
  2031. }
  2032. // bail ealry if file has error (no file uploaded)
  2033. if ( $file['error'] ) {
  2034. return;
  2035. }
  2036. // assign global _acfuploader for media validation
  2037. $_POST['_acfuploader'] = end( $ancestors );
  2038. // file found!
  2039. $attachment_id = acf_upload_file( $file );
  2040. // update $_POST
  2041. array_unshift( $ancestors, 'acf' );
  2042. acf_update_nested_array( $_POST, $ancestors, $attachment_id );
  2043. }
  2044. /*
  2045. * acf_upload_file
  2046. *
  2047. * This function will uploade a $_FILE
  2048. *
  2049. * @type function
  2050. * @date 27/10/2014
  2051. * @since 5.0.9
  2052. *
  2053. * @param $uploaded_file (array) array found from $_FILE data
  2054. * @return $id (int) new attachment ID
  2055. */
  2056. function acf_upload_file( $uploaded_file ) {
  2057. // required
  2058. // require_once( ABSPATH . "/wp-load.php" ); // WP should already be loaded
  2059. require_once ABSPATH . '/wp-admin/includes/media.php'; // video functions
  2060. require_once ABSPATH . '/wp-admin/includes/file.php';
  2061. require_once ABSPATH . '/wp-admin/includes/image.php';
  2062. // required for wp_handle_upload() to upload the file
  2063. $upload_overrides = array( 'test_form' => false );
  2064. // upload
  2065. $file = wp_handle_upload( $uploaded_file, $upload_overrides );
  2066. // bail ealry if upload failed
  2067. if ( isset( $file['error'] ) ) {
  2068. return $file['error'];
  2069. }
  2070. // vars
  2071. $url = $file['url'];
  2072. $type = $file['type'];
  2073. $file = $file['file'];
  2074. $filename = basename( $file );
  2075. // Construct the object array
  2076. $object = array(
  2077. 'post_title' => $filename,
  2078. 'post_mime_type' => $type,
  2079. 'guid' => $url,
  2080. );
  2081. // Save the data
  2082. $id = wp_insert_attachment( $object, $file );
  2083. // Add the meta-data
  2084. wp_update_attachment_metadata( $id, wp_generate_attachment_metadata( $id, $file ) );
  2085. /** This action is documented in wp-admin/custom-header.php */
  2086. do_action( 'wp_create_file_in_uploads', $file, $id ); // For replication
  2087. // return new ID
  2088. return $id;
  2089. }
  2090. /*
  2091. * acf_update_nested_array
  2092. *
  2093. * This function will update a nested array value. Useful for modifying the $_POST array
  2094. *
  2095. * @type function
  2096. * @date 27/10/2014
  2097. * @since 5.0.9
  2098. *
  2099. * @param $array (array) target array to be updated
  2100. * @param $ancestors (array) array of keys to navigate through to find the child
  2101. * @param $value (mixed) The new value
  2102. * @return (boolean)
  2103. */
  2104. function acf_update_nested_array( &$array, $ancestors, $value ) {
  2105. // if no more ancestors, update the current var
  2106. if ( empty( $ancestors ) ) {
  2107. $array = $value;
  2108. // return
  2109. return true;
  2110. }
  2111. // shift the next ancestor from the array
  2112. $k = array_shift( $ancestors );
  2113. // if exists
  2114. if ( isset( $array[ $k ] ) ) {
  2115. return acf_update_nested_array( $array[ $k ], $ancestors, $value );
  2116. }
  2117. // return
  2118. return false;
  2119. }
  2120. /*
  2121. * acf_is_screen
  2122. *
  2123. * This function will return true if all args are matched for the current screen
  2124. *
  2125. * @type function
  2126. * @date 9/12/2014
  2127. * @since 5.1.5
  2128. *
  2129. * @param $post_id (int)
  2130. * @return $post_id (int)
  2131. */
  2132. function acf_is_screen( $id = '' ) {
  2133. // bail early if not defined
  2134. if ( ! function_exists( 'get_current_screen' ) ) {
  2135. return false;
  2136. }
  2137. // vars
  2138. $current_screen = get_current_screen();
  2139. // no screen
  2140. if ( ! $current_screen ) {
  2141. return false;
  2142. // array
  2143. } elseif ( is_array( $id ) ) {
  2144. return in_array( $current_screen->id, $id );
  2145. // string
  2146. } else {
  2147. return ( $id === $current_screen->id );
  2148. }
  2149. }
  2150. /*
  2151. * acf_maybe_get
  2152. *
  2153. * This function will return a var if it exists in an array
  2154. *
  2155. * @type function
  2156. * @date 9/12/2014
  2157. * @since 5.1.5
  2158. *
  2159. * @param $array (array) the array to look within
  2160. * @param $key (key) the array key to look for. Nested values may be found using '/'
  2161. * @param $default (mixed) the value returned if not found
  2162. * @return $post_id (int)
  2163. */
  2164. function acf_maybe_get( $array = array(), $key = 0, $default = null ) {
  2165. return isset( $array[ $key ] ) ? $array[ $key ] : $default;
  2166. }
  2167. function acf_maybe_get_POST( $key = '', $default = null ) {
  2168. return isset( $_POST[ $key ] ) ? $_POST[ $key ] : $default;
  2169. }
  2170. function acf_maybe_get_GET( $key = '', $default = null ) {
  2171. return isset( $_GET[ $key ] ) ? $_GET[ $key ] : $default;
  2172. }
  2173. /**
  2174. * Returns an array of attachment data.
  2175. *
  2176. * @date 05/01/2015
  2177. * @since 5.1.5
  2178. *
  2179. * @param int|WP_Post The attachment ID or object.
  2180. * @return array|false
  2181. */
  2182. function acf_get_attachment( $attachment ) {
  2183. // Allow filter to short-circuit load attachment logic.
  2184. // Alternatively, this filter may be used to switch blogs for multisite media functionality.
  2185. $response = apply_filters( 'acf/pre_load_attachment', null, $attachment );
  2186. if ( $response !== null ) {
  2187. return $response;
  2188. }
  2189. // Get the attachment post object.
  2190. $attachment = get_post( $attachment );
  2191. if ( ! $attachment ) {
  2192. return false;
  2193. }
  2194. if ( $attachment->post_type !== 'attachment' ) {
  2195. return false;
  2196. }
  2197. // Load various attachment details.
  2198. $meta = wp_get_attachment_metadata( $attachment->ID );
  2199. $attached_file = get_attached_file( $attachment->ID );
  2200. if ( strpos( $attachment->post_mime_type, '/' ) !== false ) {
  2201. list( $type, $subtype ) = explode( '/', $attachment->post_mime_type );
  2202. } else {
  2203. list( $type, $subtype ) = array( $attachment->post_mime_type, '' );
  2204. }
  2205. // Generate response.
  2206. $response = array(
  2207. 'ID' => $attachment->ID,
  2208. 'id' => $attachment->ID,
  2209. 'title' => $attachment->post_title,
  2210. 'filename' => wp_basename( $attached_file ),
  2211. 'filesize' => 0,
  2212. 'url' => wp_get_attachment_url( $attachment->ID ),
  2213. 'link' => get_attachment_link( $attachment->ID ),
  2214. 'alt' => get_post_meta( $attachment->ID, '_wp_attachment_image_alt', true ),
  2215. 'author' => $attachment->post_author,
  2216. 'description' => $attachment->post_content,
  2217. 'caption' => $attachment->post_excerpt,
  2218. 'name' => $attachment->post_name,
  2219. 'status' => $attachment->post_status,
  2220. 'uploaded_to' => $attachment->post_parent,
  2221. 'date' => $attachment->post_date_gmt,
  2222. 'modified' => $attachment->post_modified_gmt,
  2223. 'menu_order' => $attachment->menu_order,
  2224. 'mime_type' => $attachment->post_mime_type,
  2225. 'type' => $type,
  2226. 'subtype' => $subtype,
  2227. 'icon' => wp_mime_type_icon( $attachment->ID ),
  2228. );
  2229. // Append filesize data.
  2230. if ( isset( $meta['filesize'] ) ) {
  2231. $response['filesize'] = $meta['filesize'];
  2232. } elseif ( file_exists( $attached_file ) ) {
  2233. $response['filesize'] = filesize( $attached_file );
  2234. }
  2235. // Restrict the loading of image "sizes".
  2236. $sizes_id = 0;
  2237. // Type specific logic.
  2238. switch ( $type ) {
  2239. case 'image':
  2240. $sizes_id = $attachment->ID;
  2241. $src = wp_get_attachment_image_src( $attachment->ID, 'full' );
  2242. if ( $src ) {
  2243. $response['url'] = $src[0];
  2244. $response['width'] = $src[1];
  2245. $response['height'] = $src[2];
  2246. }
  2247. break;
  2248. case 'video':
  2249. $response['width'] = acf_maybe_get( $meta, 'width', 0 );
  2250. $response['height'] = acf_maybe_get( $meta, 'height', 0 );
  2251. if ( $featured_id = get_post_thumbnail_id( $attachment->ID ) ) {
  2252. $sizes_id = $featured_id;
  2253. }
  2254. break;
  2255. case 'audio':
  2256. if ( $featured_id = get_post_thumbnail_id( $attachment->ID ) ) {
  2257. $sizes_id = $featured_id;
  2258. }
  2259. break;
  2260. }
  2261. // Load array of image sizes.
  2262. if ( $sizes_id ) {
  2263. $sizes = get_intermediate_image_sizes();
  2264. $sizes_data = array();
  2265. foreach ( $sizes as $size ) {
  2266. $src = wp_get_attachment_image_src( $sizes_id, $size );
  2267. if ( $src ) {
  2268. $sizes_data[ $size ] = $src[0];
  2269. $sizes_data[ $size . '-width' ] = $src[1];
  2270. $sizes_data[ $size . '-height' ] = $src[2];
  2271. }
  2272. }
  2273. $response['sizes'] = $sizes_data;
  2274. }
  2275. /**
  2276. * Filters the attachment $response after it has been loaded.
  2277. *
  2278. * @date 16/06/2020
  2279. * @since 5.9.0
  2280. *
  2281. * @param array $response Array of loaded attachment data.
  2282. * @param WP_Post $attachment Attachment object.
  2283. * @param array|false $meta Array of attachment meta data, or false if there is none.
  2284. */
  2285. return apply_filters( 'acf/load_attachment', $response, $attachment, $meta );
  2286. }
  2287. /*
  2288. * acf_get_truncated
  2289. *
  2290. * This function will truncate and return a string
  2291. *
  2292. * @type function
  2293. * @date 8/08/2014
  2294. * @since 5.0.0
  2295. *
  2296. * @param $text (string)
  2297. * @param $length (int)
  2298. * @return (string)
  2299. */
  2300. function acf_get_truncated( $text, $length = 64 ) {
  2301. // vars
  2302. $text = trim( $text );
  2303. $the_length = strlen( $text );
  2304. // cut
  2305. $return = substr( $text, 0, ( $length - 3 ) );
  2306. // ...
  2307. if ( $the_length > ( $length - 3 ) ) {
  2308. $return .= '...';
  2309. }
  2310. // return
  2311. return $return;
  2312. }
  2313. /*
  2314. * acf_current_user_can_admin
  2315. *
  2316. * This function will return true if the current user can administrate the ACF field groups
  2317. *
  2318. * @type function
  2319. * @date 9/02/2015
  2320. * @since 5.1.5
  2321. *
  2322. * @param $post_id (int)
  2323. * @return $post_id (int)
  2324. */
  2325. function acf_current_user_can_admin() {
  2326. if ( acf_get_setting( 'show_admin' ) && current_user_can( acf_get_setting( 'capability' ) ) ) {
  2327. return true;
  2328. }
  2329. // return
  2330. return false;
  2331. }
  2332. /*
  2333. * acf_get_filesize
  2334. *
  2335. * This function will return a numeric value of bytes for a given filesize string
  2336. *
  2337. * @type function
  2338. * @date 18/02/2015
  2339. * @since 5.1.5
  2340. *
  2341. * @param $size (mixed)
  2342. * @return (int)
  2343. */
  2344. function acf_get_filesize( $size = 1 ) {
  2345. // vars
  2346. $unit = 'MB';
  2347. $units = array(
  2348. 'TB' => 4,
  2349. 'GB' => 3,
  2350. 'MB' => 2,
  2351. 'KB' => 1,
  2352. );
  2353. // look for $unit within the $size parameter (123 KB)
  2354. if ( is_string( $size ) ) {
  2355. // vars
  2356. $custom = strtoupper( substr( $size, -2 ) );
  2357. foreach ( $units as $k => $v ) {
  2358. if ( $custom === $k ) {
  2359. $unit = $k;
  2360. $size = substr( $size, 0, -2 );
  2361. }
  2362. }
  2363. }
  2364. // calc bytes
  2365. $bytes = floatval( $size ) * pow( 1024, $units[ $unit ] );
  2366. // return
  2367. return $bytes;
  2368. }
  2369. /*
  2370. * acf_format_filesize
  2371. *
  2372. * This function will return a formatted string containing the filesize and unit
  2373. *
  2374. * @type function
  2375. * @date 18/02/2015
  2376. * @since 5.1.5
  2377. *
  2378. * @param $size (mixed)
  2379. * @return (int)
  2380. */
  2381. function acf_format_filesize( $size = 1 ) {
  2382. // convert
  2383. $bytes = acf_get_filesize( $size );
  2384. // vars
  2385. $units = array(
  2386. 'TB' => 4,
  2387. 'GB' => 3,
  2388. 'MB' => 2,
  2389. 'KB' => 1,
  2390. );
  2391. // loop through units
  2392. foreach ( $units as $k => $v ) {
  2393. $result = $bytes / pow( 1024, $v );
  2394. if ( $result >= 1 ) {
  2395. return $result . ' ' . $k;
  2396. }
  2397. }
  2398. // return
  2399. return $bytes . ' B';
  2400. }
  2401. /*
  2402. * acf_get_valid_terms
  2403. *
  2404. * This function will replace old terms with new split term ids
  2405. *
  2406. * @type function
  2407. * @date 27/02/2015
  2408. * @since 5.1.5
  2409. *
  2410. * @param $terms (int|array)
  2411. * @param $taxonomy (string)
  2412. * @return $terms
  2413. */
  2414. function acf_get_valid_terms( $terms = false, $taxonomy = 'category' ) {
  2415. // force into array
  2416. $terms = acf_get_array( $terms );
  2417. // force ints
  2418. $terms = array_map( 'intval', $terms );
  2419. // bail early if function does not yet exist or
  2420. if ( ! function_exists( 'wp_get_split_term' ) || empty( $terms ) ) {
  2421. return $terms;
  2422. }
  2423. // attempt to find new terms
  2424. foreach ( $terms as $i => $term_id ) {
  2425. $new_term_id = wp_get_split_term( $term_id, $taxonomy );
  2426. if ( $new_term_id ) {
  2427. $terms[ $i ] = $new_term_id;
  2428. }
  2429. }
  2430. // return
  2431. return $terms;
  2432. }
  2433. /*
  2434. * acf_validate_attachment
  2435. *
  2436. * This function will validate an attachment based on a field's restrictions and return an array of errors
  2437. *
  2438. * @type function
  2439. * @date 3/07/2015
  2440. * @since 5.2.3
  2441. *
  2442. * @param $attachment (array) attachment data. Changes based on context
  2443. * @param $field (array) field settings containing restrictions
  2444. * @param $context (string) $file is different when uploading / preparing
  2445. * @return $errors (array)
  2446. */
  2447. function acf_validate_attachment( $attachment, $field, $context = 'prepare' ) {
  2448. // vars
  2449. $errors = array();
  2450. $file = array(
  2451. 'type' => '',
  2452. 'width' => 0,
  2453. 'height' => 0,
  2454. 'size' => 0,
  2455. );
  2456. // upload
  2457. if ( $context == 'upload' ) {
  2458. // vars
  2459. $file['type'] = pathinfo( $attachment['name'], PATHINFO_EXTENSION );
  2460. $file['size'] = filesize( $attachment['tmp_name'] );
  2461. if ( strpos( $attachment['type'], 'image' ) !== false ) {
  2462. $size = getimagesize( $attachment['tmp_name'] );
  2463. $file['width'] = acf_maybe_get( $size, 0 );
  2464. $file['height'] = acf_maybe_get( $size, 1 );
  2465. }
  2466. // prepare
  2467. } elseif ( $context == 'prepare' ) {
  2468. $use_path = isset( $attachment['filename'] ) ? $attachment['filename'] : $attachment['url'];
  2469. $file['type'] = pathinfo( $use_path, PATHINFO_EXTENSION );
  2470. $file['size'] = acf_maybe_get( $attachment, 'filesizeInBytes', 0 );
  2471. $file['width'] = acf_maybe_get( $attachment, 'width', 0 );
  2472. $file['height'] = acf_maybe_get( $attachment, 'height', 0 );
  2473. // custom
  2474. } else {
  2475. $file = array_merge( $file, $attachment );
  2476. $use_path = isset( $attachment['filename'] ) ? $attachment['filename'] : $attachment['url'];
  2477. $file['type'] = pathinfo( $use_path, PATHINFO_EXTENSION );
  2478. }
  2479. // image
  2480. if ( $file['width'] || $file['height'] ) {
  2481. // width
  2482. $min_width = (int) acf_maybe_get( $field, 'min_width', 0 );
  2483. $max_width = (int) acf_maybe_get( $field, 'max_width', 0 );
  2484. if ( $file['width'] ) {
  2485. if ( $min_width && $file['width'] < $min_width ) {
  2486. // min width
  2487. $errors['min_width'] = sprintf( __( 'Image width must be at least %dpx.', 'acf' ), $min_width );
  2488. } elseif ( $max_width && $file['width'] > $max_width ) {
  2489. // min width
  2490. $errors['max_width'] = sprintf( __( 'Image width must not exceed %dpx.', 'acf' ), $max_width );
  2491. }
  2492. }
  2493. // height
  2494. $min_height = (int) acf_maybe_get( $field, 'min_height', 0 );
  2495. $max_height = (int) acf_maybe_get( $field, 'max_height', 0 );
  2496. if ( $file['height'] ) {
  2497. if ( $min_height && $file['height'] < $min_height ) {
  2498. // min height
  2499. $errors['min_height'] = sprintf( __( 'Image height must be at least %dpx.', 'acf' ), $min_height );
  2500. } elseif ( $max_height && $file['height'] > $max_height ) {
  2501. // min height
  2502. $errors['max_height'] = sprintf( __( 'Image height must not exceed %dpx.', 'acf' ), $max_height );
  2503. }
  2504. }
  2505. }
  2506. // file size
  2507. if ( $file['size'] ) {
  2508. $min_size = acf_maybe_get( $field, 'min_size', 0 );
  2509. $max_size = acf_maybe_get( $field, 'max_size', 0 );
  2510. if ( $min_size && $file['size'] < acf_get_filesize( $min_size ) ) {
  2511. // min width
  2512. $errors['min_size'] = sprintf( __( 'File size must be at least %s.', 'acf' ), acf_format_filesize( $min_size ) );
  2513. } elseif ( $max_size && $file['size'] > acf_get_filesize( $max_size ) ) {
  2514. // min width
  2515. $errors['max_size'] = sprintf( __( 'File size must not exceed %s.', 'acf' ), acf_format_filesize( $max_size ) );
  2516. }
  2517. }
  2518. // file type
  2519. if ( $file['type'] ) {
  2520. $mime_types = acf_maybe_get( $field, 'mime_types', '' );
  2521. // lower case
  2522. $file['type'] = strtolower( $file['type'] );
  2523. $mime_types = strtolower( $mime_types );
  2524. // explode
  2525. $mime_types = str_replace( array( ' ', '.' ), '', $mime_types );
  2526. $mime_types = explode( ',', $mime_types ); // split pieces
  2527. $mime_types = array_filter( $mime_types ); // remove empty pieces
  2528. if ( ! empty( $mime_types ) && ! in_array( $file['type'], $mime_types ) ) {
  2529. // glue together last 2 types
  2530. if ( count( $mime_types ) > 1 ) {
  2531. $last1 = array_pop( $mime_types );
  2532. $last2 = array_pop( $mime_types );
  2533. $mime_types[] = $last2 . ' ' . __( 'or', 'acf' ) . ' ' . $last1;
  2534. }
  2535. $errors['mime_types'] = sprintf( __( 'File type must be %s.', 'acf' ), implode( ', ', $mime_types ) );
  2536. }
  2537. }
  2538. /**
  2539. * Filters the errors for a file before it is uploaded or displayed in the media modal.
  2540. *
  2541. * @date 3/07/2015
  2542. * @since 5.2.3
  2543. *
  2544. * @param array $errors An array of errors.
  2545. * @param array $file An array of data for a single file.
  2546. * @param array $attachment An array of attachment data which differs based on the context.
  2547. * @param array $field The field array.
  2548. * @param string $context The curent context (uploading, preparing)
  2549. */
  2550. $errors = apply_filters( "acf/validate_attachment/type={$field['type']}", $errors, $file, $attachment, $field, $context );
  2551. $errors = apply_filters( "acf/validate_attachment/name={$field['_name']}", $errors, $file, $attachment, $field, $context );
  2552. $errors = apply_filters( "acf/validate_attachment/key={$field['key']}", $errors, $file, $attachment, $field, $context );
  2553. $errors = apply_filters( 'acf/validate_attachment', $errors, $file, $attachment, $field, $context );
  2554. // return
  2555. return $errors;
  2556. }
  2557. /*
  2558. * _acf_settings_uploader
  2559. *
  2560. * Dynamic logic for uploader setting
  2561. *
  2562. * @type function
  2563. * @date 7/05/2015
  2564. * @since 5.2.3
  2565. *
  2566. * @param $uploader (string)
  2567. * @return $uploader
  2568. */
  2569. add_filter( 'acf/settings/uploader', '_acf_settings_uploader' );
  2570. function _acf_settings_uploader( $uploader ) {
  2571. // if can't upload files
  2572. if ( ! current_user_can( 'upload_files' ) ) {
  2573. $uploader = 'basic';
  2574. }
  2575. // return
  2576. return $uploader;
  2577. }
  2578. /*
  2579. * acf_translate_keys
  2580. *
  2581. * description
  2582. *
  2583. * @type function
  2584. * @date 7/12/2015
  2585. * @since 5.3.2
  2586. *
  2587. * @param $post_id (int)
  2588. * @return $post_id (int)
  2589. */
  2590. /*
  2591. function acf_translate_keys( $array, $keys ) {
  2592. // bail early if no keys
  2593. if( empty($keys) ) return $array;
  2594. // translate
  2595. foreach( $keys as $k ) {
  2596. // bail ealry if not exists
  2597. if( !isset($array[ $k ]) ) continue;
  2598. // translate
  2599. $array[ $k ] = acf_translate( $array[ $k ] );
  2600. }
  2601. // return
  2602. return $array;
  2603. }
  2604. */
  2605. /*
  2606. * acf_translate
  2607. *
  2608. * This function will translate a string using the new 'l10n_textdomain' setting
  2609. * Also works for arrays which is great for fields - select -> choices
  2610. *
  2611. * @type function
  2612. * @date 4/12/2015
  2613. * @since 5.3.2
  2614. *
  2615. * @param $string (mixed) string or array containins strings to be translated
  2616. * @return $string
  2617. */
  2618. function acf_translate( $string ) {
  2619. // vars
  2620. $l10n = acf_get_setting( 'l10n' );
  2621. $textdomain = acf_get_setting( 'l10n_textdomain' );
  2622. // bail early if not enabled
  2623. if ( ! $l10n ) {
  2624. return $string;
  2625. }
  2626. // bail early if no textdomain
  2627. if ( ! $textdomain ) {
  2628. return $string;
  2629. }
  2630. // is array
  2631. if ( is_array( $string ) ) {
  2632. return array_map( 'acf_translate', $string );
  2633. }
  2634. // bail early if not string
  2635. if ( ! is_string( $string ) ) {
  2636. return $string;
  2637. }
  2638. // bail early if empty
  2639. if ( $string === '' ) {
  2640. return $string;
  2641. }
  2642. // allow for var_export export
  2643. if ( acf_get_setting( 'l10n_var_export' ) ) {
  2644. // bail early if already translated
  2645. if ( substr( $string, 0, 7 ) === '!!__(!!' ) {
  2646. return $string;
  2647. }
  2648. // return
  2649. return "!!__(!!'" . $string . "!!', !!'" . $textdomain . "!!')!!";
  2650. }
  2651. // vars
  2652. return __( $string, $textdomain );
  2653. }
  2654. /*
  2655. * acf_maybe_add_action
  2656. *
  2657. * This function will determine if the action has already run before adding / calling the function
  2658. *
  2659. * @type function
  2660. * @date 13/01/2016
  2661. * @since 5.3.2
  2662. *
  2663. * @param $post_id (int)
  2664. * @return $post_id (int)
  2665. */
  2666. function acf_maybe_add_action( $tag, $function_to_add, $priority = 10, $accepted_args = 1 ) {
  2667. // if action has already run, execute it
  2668. // - if currently doing action, allow $tag to be added as per usual to allow $priority ordering needed for 3rd party asset compatibility
  2669. if ( did_action( $tag ) && ! doing_action( $tag ) ) {
  2670. call_user_func( $function_to_add );
  2671. // if action has not yet run, add it
  2672. } else {
  2673. add_action( $tag, $function_to_add, $priority, $accepted_args );
  2674. }
  2675. }
  2676. /*
  2677. * acf_is_row_collapsed
  2678. *
  2679. * This function will return true if the field's row is collapsed
  2680. *
  2681. * @type function
  2682. * @date 2/03/2016
  2683. * @since 5.3.2
  2684. *
  2685. * @param $post_id (int)
  2686. * @return $post_id (int)
  2687. */
  2688. function acf_is_row_collapsed( $field_key = '', $row_index = 0 ) {
  2689. // collapsed
  2690. $collapsed = acf_get_user_setting( 'collapsed_' . $field_key, '' );
  2691. // cookie fallback ( version < 5.3.2 )
  2692. if ( $collapsed === '' ) {
  2693. $collapsed = acf_extract_var( $_COOKIE, "acf_collapsed_{$field_key}", '' );
  2694. $collapsed = str_replace( '|', ',', $collapsed );
  2695. // update
  2696. acf_update_user_setting( 'collapsed_' . $field_key, $collapsed );
  2697. }
  2698. // explode
  2699. $collapsed = explode( ',', $collapsed );
  2700. $collapsed = array_filter( $collapsed, 'is_numeric' );
  2701. // collapsed class
  2702. return in_array( $row_index, $collapsed );
  2703. }
  2704. /*
  2705. * acf_get_attachment_image
  2706. *
  2707. * description
  2708. *
  2709. * @type function
  2710. * @date 24/10/16
  2711. * @since 5.5.0
  2712. *
  2713. * @param $post_id (int)
  2714. * @return $post_id (int)
  2715. */
  2716. function acf_get_attachment_image( $attachment_id = 0, $size = 'thumbnail' ) {
  2717. // vars
  2718. $url = wp_get_attachment_image_src( $attachment_id, 'thumbnail' );
  2719. $alt = get_post_meta( $attachment_id, '_wp_attachment_image_alt', true );
  2720. // bail early if no url
  2721. if ( ! $url ) {
  2722. return '';
  2723. }
  2724. // return
  2725. $value = '<img src="' . $url . '" alt="' . $alt . '" />';
  2726. }
  2727. /*
  2728. * acf_get_post_thumbnail
  2729. *
  2730. * This function will return a thumbail image url for a given post
  2731. *
  2732. * @type function
  2733. * @date 3/05/2016
  2734. * @since 5.3.8
  2735. *
  2736. * @param $post (obj)
  2737. * @param $size (mixed)
  2738. * @return (string)
  2739. */
  2740. function acf_get_post_thumbnail( $post = null, $size = 'thumbnail' ) {
  2741. // vars
  2742. $data = array(
  2743. 'url' => '',
  2744. 'type' => '',
  2745. 'html' => '',
  2746. );
  2747. // post
  2748. $post = get_post( $post );
  2749. // bail early if no post
  2750. if ( ! $post ) {
  2751. return $data;
  2752. }
  2753. // vars
  2754. $thumb_id = $post->ID;
  2755. $mime_type = acf_maybe_get( explode( '/', $post->post_mime_type ), 0 );
  2756. // attachment
  2757. if ( $post->post_type === 'attachment' ) {
  2758. // change $thumb_id
  2759. if ( $mime_type === 'audio' || $mime_type === 'video' ) {
  2760. $thumb_id = get_post_thumbnail_id( $post->ID );
  2761. }
  2762. // post
  2763. } else {
  2764. $thumb_id = get_post_thumbnail_id( $post->ID );
  2765. }
  2766. // try url
  2767. $data['url'] = wp_get_attachment_image_src( $thumb_id, $size );
  2768. $data['url'] = acf_maybe_get( $data['url'], 0 );
  2769. // default icon
  2770. if ( ! $data['url'] && $post->post_type === 'attachment' ) {
  2771. $data['url'] = wp_mime_type_icon( $post->ID );
  2772. $data['type'] = 'icon';
  2773. }
  2774. // html
  2775. $data['html'] = '<img src="' . $data['url'] . '" alt="" />';
  2776. // return
  2777. return $data;
  2778. }
  2779. /**
  2780. * acf_get_browser
  2781. *
  2782. * Returns the name of the current browser.
  2783. *
  2784. * @date 17/01/2014
  2785. * @since 5.0.0
  2786. *
  2787. * @param void
  2788. * @return string
  2789. */
  2790. function acf_get_browser() {
  2791. // Check server var.
  2792. if ( isset( $_SERVER['HTTP_USER_AGENT'] ) ) {
  2793. $agent = $_SERVER['HTTP_USER_AGENT'];
  2794. // Loop over search terms.
  2795. $browsers = array(
  2796. 'Firefox' => 'firefox',
  2797. 'Trident' => 'msie',
  2798. 'MSIE' => 'msie',
  2799. 'Edge' => 'edge',
  2800. 'Chrome' => 'chrome',
  2801. 'Safari' => 'safari',
  2802. );
  2803. foreach ( $browsers as $k => $v ) {
  2804. if ( strpos( $agent, $k ) !== false ) {
  2805. return $v;
  2806. }
  2807. }
  2808. }
  2809. // Return default.
  2810. return '';
  2811. }
  2812. /*
  2813. * acf_is_ajax
  2814. *
  2815. * This function will reutrn true if performing a wp ajax call
  2816. *
  2817. * @type function
  2818. * @date 7/06/2016
  2819. * @since 5.3.8
  2820. *
  2821. * @param n/a
  2822. * @return (boolean)
  2823. */
  2824. function acf_is_ajax( $action = '' ) {
  2825. // vars
  2826. $is_ajax = false;
  2827. // check if is doing ajax
  2828. if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
  2829. $is_ajax = true;
  2830. }
  2831. // check $action
  2832. if ( $action && acf_maybe_get( $_POST, 'action' ) !== $action ) {
  2833. $is_ajax = false;
  2834. }
  2835. // return
  2836. return $is_ajax;
  2837. }
  2838. /*
  2839. * acf_format_date
  2840. *
  2841. * This function will accept a date value and return it in a formatted string
  2842. *
  2843. * @type function
  2844. * @date 16/06/2016
  2845. * @since 5.3.8
  2846. *
  2847. * @param $value (string)
  2848. * @return $format (string)
  2849. */
  2850. function acf_format_date( $value, $format ) {
  2851. // bail early if no value
  2852. if ( ! $value ) {
  2853. return $value;
  2854. }
  2855. // vars
  2856. $unixtimestamp = 0;
  2857. // numeric (either unix or YYYYMMDD)
  2858. if ( is_numeric( $value ) && strlen( $value ) !== 8 ) {
  2859. $unixtimestamp = $value;
  2860. } else {
  2861. $unixtimestamp = strtotime( $value );
  2862. }
  2863. // return
  2864. return date_i18n( $format, $unixtimestamp );
  2865. }
  2866. /**
  2867. * acf_clear_log
  2868. *
  2869. * Deletes the debug.log file.
  2870. *
  2871. * @date 21/1/19
  2872. * @since 5.7.10
  2873. *
  2874. * @param type $var Description. Default.
  2875. * @return type Description.
  2876. */
  2877. function acf_clear_log() {
  2878. unlink( WP_CONTENT_DIR . '/debug.log' );
  2879. }
  2880. /*
  2881. * acf_log
  2882. *
  2883. * description
  2884. *
  2885. * @type function
  2886. * @date 24/06/2016
  2887. * @since 5.3.8
  2888. *
  2889. * @param $post_id (int)
  2890. * @return $post_id (int)
  2891. */
  2892. function acf_log() {
  2893. // vars
  2894. $args = func_get_args();
  2895. // loop
  2896. foreach ( $args as $i => $arg ) {
  2897. // array | object
  2898. if ( is_array( $arg ) || is_object( $arg ) ) {
  2899. $arg = print_r( $arg, true );
  2900. // bool
  2901. } elseif ( is_bool( $arg ) ) {
  2902. $arg = 'bool(' . ( $arg ? 'true' : 'false' ) . ')';
  2903. }
  2904. // update
  2905. $args[ $i ] = $arg;
  2906. }
  2907. // log
  2908. error_log( implode( ' ', $args ) );
  2909. }
  2910. /**
  2911. * acf_dev_log
  2912. *
  2913. * Used to log variables only if ACF_DEV is defined
  2914. *
  2915. * @date 25/8/18
  2916. * @since 5.7.4
  2917. *
  2918. * @param mixed
  2919. * @return void
  2920. */
  2921. function acf_dev_log() {
  2922. if ( defined( 'ACF_DEV' ) && ACF_DEV ) {
  2923. call_user_func_array( 'acf_log', func_get_args() );
  2924. }
  2925. }
  2926. /*
  2927. * acf_doing
  2928. *
  2929. * This function will tell ACF what task it is doing
  2930. *
  2931. * @type function
  2932. * @date 28/06/2016
  2933. * @since 5.3.8
  2934. *
  2935. * @param $event (string)
  2936. * @param context (string)
  2937. * @return n/a
  2938. */
  2939. function acf_doing( $event = '', $context = '' ) {
  2940. acf_update_setting( 'doing', $event );
  2941. acf_update_setting( 'doing_context', $context );
  2942. }
  2943. /*
  2944. * acf_is_doing
  2945. *
  2946. * This function can be used to state what ACF is doing, or to check
  2947. *
  2948. * @type function
  2949. * @date 28/06/2016
  2950. * @since 5.3.8
  2951. *
  2952. * @param $event (string)
  2953. * @param context (string)
  2954. * @return (boolean)
  2955. */
  2956. function acf_is_doing( $event = '', $context = '' ) {
  2957. // vars
  2958. $doing = false;
  2959. // task
  2960. if ( acf_get_setting( 'doing' ) === $event ) {
  2961. $doing = true;
  2962. }
  2963. // context
  2964. if ( $context && acf_get_setting( 'doing_context' ) !== $context ) {
  2965. $doing = false;
  2966. }
  2967. // return
  2968. return $doing;
  2969. }
  2970. /*
  2971. * acf_is_plugin_active
  2972. *
  2973. * This function will return true if the ACF plugin is active
  2974. * - May be included within a theme or other plugin
  2975. *
  2976. * @type function
  2977. * @date 13/07/2016
  2978. * @since 5.4.0
  2979. *
  2980. * @param $basename (int)
  2981. * @return $post_id (int)
  2982. */
  2983. function acf_is_plugin_active() {
  2984. // vars
  2985. $basename = acf_get_setting( 'basename' );
  2986. // ensure is_plugin_active() exists (not on frontend)
  2987. if ( ! function_exists( 'is_plugin_active' ) ) {
  2988. include_once ABSPATH . 'wp-admin/includes/plugin.php';
  2989. }
  2990. // return
  2991. return is_plugin_active( $basename );
  2992. }
  2993. /*
  2994. * acf_send_ajax_results
  2995. *
  2996. * This function will print JSON data for a Select2 AJAX query
  2997. *
  2998. * @type function
  2999. * @date 19/07/2016
  3000. * @since 5.4.0
  3001. *
  3002. * @param $response (array)
  3003. * @return n/a
  3004. */
  3005. function acf_send_ajax_results( $response ) {
  3006. // validate
  3007. $response = wp_parse_args(
  3008. $response,
  3009. array(
  3010. 'results' => array(),
  3011. 'more' => false,
  3012. 'limit' => 0,
  3013. )
  3014. );
  3015. // limit
  3016. if ( $response['limit'] && $response['results'] ) {
  3017. // vars
  3018. $total = 0;
  3019. foreach ( $response['results'] as $result ) {
  3020. // parent
  3021. $total++;
  3022. // children
  3023. if ( ! empty( $result['children'] ) ) {
  3024. $total += count( $result['children'] );
  3025. }
  3026. }
  3027. // calc
  3028. if ( $total >= $response['limit'] ) {
  3029. $response['more'] = true;
  3030. }
  3031. }
  3032. // return
  3033. wp_send_json( $response );
  3034. }
  3035. /*
  3036. * acf_is_sequential_array
  3037. *
  3038. * This function will return true if the array contains only numeric keys
  3039. *
  3040. * @source http://stackoverflow.com/questions/173400/how-to-check-if-php-array-is-associative-or-sequential
  3041. * @type function
  3042. * @date 9/09/2016
  3043. * @since 5.4.0
  3044. *
  3045. * @param $array (array)
  3046. * @return (boolean)
  3047. */
  3048. function acf_is_sequential_array( $array ) {
  3049. // bail ealry if not array
  3050. if ( ! is_array( $array ) ) {
  3051. return false;
  3052. }
  3053. // loop
  3054. foreach ( $array as $key => $value ) {
  3055. // bail ealry if is string
  3056. if ( is_string( $key ) ) {
  3057. return false;
  3058. }
  3059. }
  3060. // return
  3061. return true;
  3062. }
  3063. /*
  3064. * acf_is_associative_array
  3065. *
  3066. * This function will return true if the array contains one or more string keys
  3067. *
  3068. * @source http://stackoverflow.com/questions/173400/how-to-check-if-php-array-is-associative-or-sequential
  3069. * @type function
  3070. * @date 9/09/2016
  3071. * @since 5.4.0
  3072. *
  3073. * @param $array (array)
  3074. * @return (boolean)
  3075. */
  3076. function acf_is_associative_array( $array ) {
  3077. // bail ealry if not array
  3078. if ( ! is_array( $array ) ) {
  3079. return false;
  3080. }
  3081. // loop
  3082. foreach ( $array as $key => $value ) {
  3083. // bail ealry if is string
  3084. if ( is_string( $key ) ) {
  3085. return true;
  3086. }
  3087. }
  3088. // return
  3089. return false;
  3090. }
  3091. /*
  3092. * acf_add_array_key_prefix
  3093. *
  3094. * This function will add a prefix to all array keys
  3095. * Useful to preserve numeric keys when performing array_multisort
  3096. *
  3097. * @type function
  3098. * @date 15/09/2016
  3099. * @since 5.4.0
  3100. *
  3101. * @param $array (array)
  3102. * @param $prefix (string)
  3103. * @return (array)
  3104. */
  3105. function acf_add_array_key_prefix( $array, $prefix ) {
  3106. // vars
  3107. $array2 = array();
  3108. // loop
  3109. foreach ( $array as $k => $v ) {
  3110. $k2 = $prefix . $k;
  3111. $array2[ $k2 ] = $v;
  3112. }
  3113. // return
  3114. return $array2;
  3115. }
  3116. /*
  3117. * acf_remove_array_key_prefix
  3118. *
  3119. * This function will remove a prefix to all array keys
  3120. * Useful to preserve numeric keys when performing array_multisort
  3121. *
  3122. * @type function
  3123. * @date 15/09/2016
  3124. * @since 5.4.0
  3125. *
  3126. * @param $array (array)
  3127. * @param $prefix (string)
  3128. * @return (array)
  3129. */
  3130. function acf_remove_array_key_prefix( $array, $prefix ) {
  3131. // vars
  3132. $array2 = array();
  3133. $l = strlen( $prefix );
  3134. // loop
  3135. foreach ( $array as $k => $v ) {
  3136. $k2 = ( substr( $k, 0, $l ) === $prefix ) ? substr( $k, $l ) : $k;
  3137. $array2[ $k2 ] = $v;
  3138. }
  3139. // return
  3140. return $array2;
  3141. }
  3142. /*
  3143. * acf_strip_protocol
  3144. *
  3145. * This function will remove the proticol from a url
  3146. * Used to allow licenses to remain active if a site is switched to https
  3147. *
  3148. * @type function
  3149. * @date 10/01/2017
  3150. * @since 5.5.4
  3151. * @author Aaron
  3152. *
  3153. * @param $url (string)
  3154. * @return (string)
  3155. */
  3156. function acf_strip_protocol( $url ) {
  3157. // strip the protical
  3158. return str_replace( array( 'http://', 'https://' ), '', $url );
  3159. }
  3160. /*
  3161. * acf_connect_attachment_to_post
  3162. *
  3163. * This function will connect an attacment (image etc) to the post
  3164. * Used to connect attachements uploaded directly to media that have not been attaced to a post
  3165. *
  3166. * @type function
  3167. * @date 11/01/2017
  3168. * @since 5.8.0 Added filter to prevent connection.
  3169. * @since 5.5.4
  3170. *
  3171. * @param int $attachment_id The attachment ID.
  3172. * @param int $post_id The post ID.
  3173. * @return bool True if attachment was connected.
  3174. */
  3175. function acf_connect_attachment_to_post( $attachment_id = 0, $post_id = 0 ) {
  3176. // Bail ealry if $attachment_id is not valid.
  3177. if ( ! $attachment_id || ! is_numeric( $attachment_id ) ) {
  3178. return false;
  3179. }
  3180. // Bail ealry if $post_id is not valid.
  3181. if ( ! $post_id || ! is_numeric( $post_id ) ) {
  3182. return false;
  3183. }
  3184. /**
  3185. * Filters whether or not to connect the attachment.
  3186. *
  3187. * @date 8/11/18
  3188. * @since 5.8.0
  3189. *
  3190. * @param bool $bool Returning false will prevent the connection. Default true.
  3191. * @param int $attachment_id The attachment ID.
  3192. * @param int $post_id The post ID.
  3193. */
  3194. if ( ! apply_filters( 'acf/connect_attachment_to_post', true, $attachment_id, $post_id ) ) {
  3195. return false;
  3196. }
  3197. // vars
  3198. $post = get_post( $attachment_id );
  3199. // Check if is valid post.
  3200. if ( $post && $post->post_type == 'attachment' && $post->post_parent == 0 ) {
  3201. // update
  3202. wp_update_post(
  3203. array(
  3204. 'ID' => $post->ID,
  3205. 'post_parent' => $post_id,
  3206. )
  3207. );
  3208. // return
  3209. return true;
  3210. }
  3211. // return
  3212. return true;
  3213. }
  3214. /*
  3215. * acf_encrypt
  3216. *
  3217. * This function will encrypt a string using PHP
  3218. * https://bhoover.com/using-php-openssl_encrypt-openssl_decrypt-encrypt-decrypt-data/
  3219. *
  3220. * @type function
  3221. * @date 27/2/17
  3222. * @since 5.5.8
  3223. *
  3224. * @param $data (string)
  3225. * @return (string)
  3226. */
  3227. function acf_encrypt( $data = '' ) {
  3228. // bail ealry if no encrypt function
  3229. if ( ! function_exists( 'openssl_encrypt' ) ) {
  3230. return base64_encode( $data );
  3231. }
  3232. // generate a key
  3233. $key = wp_hash( 'acf_encrypt' );
  3234. // Generate an initialization vector
  3235. $iv = openssl_random_pseudo_bytes( openssl_cipher_iv_length( 'aes-256-cbc' ) );
  3236. // Encrypt the data using AES 256 encryption in CBC mode using our encryption key and initialization vector.
  3237. $encrypted_data = openssl_encrypt( $data, 'aes-256-cbc', $key, 0, $iv );
  3238. // The $iv is just as important as the key for decrypting, so save it with our encrypted data using a unique separator (::)
  3239. return base64_encode( $encrypted_data . '::' . $iv );
  3240. }
  3241. /*
  3242. * acf_decrypt
  3243. *
  3244. * This function will decrypt an encrypted string using PHP
  3245. * https://bhoover.com/using-php-openssl_encrypt-openssl_decrypt-encrypt-decrypt-data/
  3246. *
  3247. * @type function
  3248. * @date 27/2/17
  3249. * @since 5.5.8
  3250. *
  3251. * @param $data (string)
  3252. * @return (string)
  3253. */
  3254. function acf_decrypt( $data = '' ) {
  3255. // bail ealry if no decrypt function
  3256. if ( ! function_exists( 'openssl_decrypt' ) ) {
  3257. return base64_decode( $data );
  3258. }
  3259. // generate a key
  3260. $key = wp_hash( 'acf_encrypt' );
  3261. // To decrypt, split the encrypted data from our IV - our unique separator used was "::"
  3262. list($encrypted_data, $iv) = explode( '::', base64_decode( $data ), 2 );
  3263. // decrypt
  3264. return openssl_decrypt( $encrypted_data, 'aes-256-cbc', $key, 0, $iv );
  3265. }
  3266. /**
  3267. * acf_parse_markdown
  3268. *
  3269. * A very basic regex-based Markdown parser function based off [slimdown](https://gist.github.com/jbroadway/2836900).
  3270. *
  3271. * @date 6/8/18
  3272. * @since 5.7.2
  3273. *
  3274. * @param string $text The string to parse.
  3275. * @return string
  3276. */
  3277. function acf_parse_markdown( $text = '' ) {
  3278. // trim
  3279. $text = trim( $text );
  3280. // rules
  3281. $rules = array(
  3282. '/=== (.+?) ===/' => '<h2>$1</h2>', // headings
  3283. '/== (.+?) ==/' => '<h3>$1</h3>', // headings
  3284. '/= (.+?) =/' => '<h4>$1</h4>', // headings
  3285. '/\[([^\[]+)\]\(([^\)]+)\)/' => '<a href="$2">$1</a>', // links
  3286. '/(\*\*)(.*?)\1/' => '<strong>$2</strong>', // bold
  3287. '/(\*)(.*?)\1/' => '<em>$2</em>', // intalic
  3288. '/`(.*?)`/' => '<code>$1</code>', // inline code
  3289. '/\n\*(.*)/' => "\n<ul>\n\t<li>$1</li>\n</ul>", // ul lists
  3290. '/\n[0-9]+\.(.*)/' => "\n<ol>\n\t<li>$1</li>\n</ol>", // ol lists
  3291. '/<\/ul>\s?<ul>/' => '', // fix extra ul
  3292. '/<\/ol>\s?<ol>/' => '', // fix extra ol
  3293. );
  3294. foreach ( $rules as $k => $v ) {
  3295. $text = preg_replace( $k, $v, $text );
  3296. }
  3297. // autop
  3298. $text = wpautop( $text );
  3299. // return
  3300. return $text;
  3301. }
  3302. /**
  3303. * acf_get_sites
  3304. *
  3305. * Returns an array of sites for a network.
  3306. *
  3307. * @date 29/08/2016
  3308. * @since 5.4.0
  3309. *
  3310. * @param void
  3311. * @return array
  3312. */
  3313. function acf_get_sites() {
  3314. $results = array();
  3315. $sites = get_sites( array( 'number' => 0 ) );
  3316. if ( $sites ) {
  3317. foreach ( $sites as $site ) {
  3318. $results[] = get_site( $site )->to_array();
  3319. }
  3320. }
  3321. return $results;
  3322. }
  3323. /**
  3324. * acf_convert_rules_to_groups
  3325. *
  3326. * Converts an array of rules from ACF4 to an array of groups for ACF5
  3327. *
  3328. * @date 25/8/18
  3329. * @since 5.7.4
  3330. *
  3331. * @param array $rules An array of rules.
  3332. * @param string $anyorall The anyorall setting used in ACF4. Defaults to 'any'.
  3333. * @return array
  3334. */
  3335. function acf_convert_rules_to_groups( $rules, $anyorall = 'any' ) {
  3336. // vars
  3337. $groups = array();
  3338. $index = 0;
  3339. // loop
  3340. foreach ( $rules as $rule ) {
  3341. // extract vars
  3342. $group = acf_extract_var( $rule, 'group_no' );
  3343. $order = acf_extract_var( $rule, 'order_no' );
  3344. // calculate group if not defined
  3345. if ( $group === null ) {
  3346. $group = $index;
  3347. // use $anyorall to determine if a new group is needed
  3348. if ( $anyorall == 'any' ) {
  3349. $index++;
  3350. }
  3351. }
  3352. // calculate order if not defined
  3353. if ( $order === null ) {
  3354. $order = isset( $groups[ $group ] ) ? count( $groups[ $group ] ) : 0;
  3355. }
  3356. // append to group
  3357. $groups[ $group ][ $order ] = $rule;
  3358. // sort groups
  3359. ksort( $groups[ $group ] );
  3360. }
  3361. // sort groups
  3362. ksort( $groups );
  3363. // return
  3364. return $groups;
  3365. }
  3366. /**
  3367. * acf_register_ajax
  3368. *
  3369. * Regsiters an ajax callback.
  3370. *
  3371. * @date 5/10/18
  3372. * @since 5.7.7
  3373. *
  3374. * @param string $name The ajax action name.
  3375. * @param array $callback The callback function or array.
  3376. * @param bool $public Whether to allow access to non logged in users.
  3377. * @return void
  3378. */
  3379. function acf_register_ajax( $name = '', $callback = false, $public = false ) {
  3380. // vars
  3381. $action = "acf/ajax/$name";
  3382. // add action for logged-in users
  3383. add_action( "wp_ajax_$action", $callback );
  3384. // add action for non logged-in users
  3385. if ( $public ) {
  3386. add_action( "wp_ajax_nopriv_$action", $callback );
  3387. }
  3388. }
  3389. /**
  3390. * acf_str_camel_case
  3391. *
  3392. * Converts a string into camelCase.
  3393. * Thanks to https://stackoverflow.com/questions/31274782/convert-array-keys-from-underscore-case-to-camelcase-recursively
  3394. *
  3395. * @date 24/10/18
  3396. * @since 5.8.0
  3397. *
  3398. * @param string $string The string ot convert.
  3399. * @return string
  3400. */
  3401. function acf_str_camel_case( $string = '' ) {
  3402. return lcfirst( str_replace( ' ', '', ucwords( str_replace( '_', ' ', $string ) ) ) );
  3403. }
  3404. /**
  3405. * acf_array_camel_case
  3406. *
  3407. * Converts all aray keys to camelCase.
  3408. *
  3409. * @date 24/10/18
  3410. * @since 5.8.0
  3411. *
  3412. * @param array $array The array to convert.
  3413. * @return array
  3414. */
  3415. function acf_array_camel_case( $array = array() ) {
  3416. $array2 = array();
  3417. foreach ( $array as $k => $v ) {
  3418. $array2[ acf_str_camel_case( $k ) ] = $v;
  3419. }
  3420. return $array2;
  3421. }
  3422. /**
  3423. * Returns true if the current screen is using the block editor.
  3424. *
  3425. * @date 13/12/18
  3426. * @since 5.8.0
  3427. *
  3428. * @return bool
  3429. */
  3430. function acf_is_block_editor() {
  3431. if ( function_exists( 'get_current_screen' ) ) {
  3432. $screen = get_current_screen();
  3433. if ( $screen && method_exists( $screen, 'is_block_editor' ) ) {
  3434. return $screen->is_block_editor();
  3435. }
  3436. }
  3437. return false;
  3438. }