LfW:78_wp_keep_alive_customize_changeset_dependent_auto_drafts</** * Sets up object properties. * * @since 2.0.8 */znc0n=C:\wordpress\stop4lunch\wp-includes\class-wp-object-cache.php!Sf#W8WP_Navigation_Fallback::update_wp_navigation_post_schemas3?3?3?3?VFfԾ}~=Cache key must be an integer or a non-empty string, %s given.Lf֊ff@f f@MffpLf֊ff@ fXLffsff fLf"Of@fXLf fwOfLffxff_f fLffwffLf f{9a:2:{s:8:"messages";a:0:{}s:16:"instant_messages";a:0:{}}er.phpphpEa:2:{s:6:"status";s:7:"in_sync";s:9:"timestamp";d:1722085273.186781;}y֊f} fXLfPf}y֊f@( f~Pf Zfy֊fLf f}Pfwy֊fxLf f@fPfLfy֊f@x fxPfLfYf@ Sf8LfPfZffLfPfLfPff@PfZff@fXffx:OfPf0LfOfx`[f@@֊f_fPf  fxLffxLf@֊f@fPf8LfLfqSG-5G/(?:(.+)-)?([a-z]{2,3}(?:_[A-Z]{2})?(?:_[a-z0-9]+)?)\.(?:mo|l10n\.php)/`Lf bAC:\wordpress\stop4lunch/wp-admin/includes/translation-install.phpLfLf(4Q,=r Lft0 =\\ff\fZfc[fXfPDf@KfZff(Yf ]fLfTf@ff)f fpLf  NvDC:\wordpress\stop4lunch\wp-includes\class-wp-textdomain-registry.phpD/** * Core class used for switching locales. * * @since 4.7.0 */-EE@C:\wordpress\stop4lunch\wp-includes\class-wp-locale-switcher.phpB/** * Original locale. * * @since 4.7.0 * @var string */fjF 3T#Awpml.WPML\Media\Translate\Endpoint\PrepareForTranslation.lock.keyfDs:60:"O:8:"stdClass":1:{s:21:"total_vulnerabilities";s:5:"66957";}";:a:2:{i:126;a:1:{i:0;s:3:"125";}i:120;a:1:{i:0;s:3:"136";}}fLf:a:2:{i:126;a:1:{i:0;s:3:"125";}i:120;a:1:{i:0;s:3:"136";}}fC["contact","conversational","subscription","registration","custom"]f;a:2:{i:1;a:1:{s:5:"title";s:0:"";}s:12:"_multiwidget";i:1;}f0LfAa:1:{s:4:"wpml";s:40:"https://cdn.wpml.org/wpml-bucket-55.json";}Lf@fYf@POf %.28<@FL^bfjs 'BNRVZcjtz~SS:::::SS:S:: ::::::::{{:SS::::S::{{{:{{{::::SSBBBBBBBBBB B wB oB gB _BWBOBGB?B7B/B'BBBBBBBBB B B B B BBBBBBBBBwBoBgB_BWBOBGB?B7B/B 'B!B"B#BBBBBBBBBBBBB B B B B BBwBoBgB_BWBOBGB?B7B/B'BBBBBBBBBBBBBBBBBBBBBB wB oBgB_BWBOBGB?B7B/B'BBB B B B B BBBBBBBBBBBBBBBwBoB gB _B WB OB GB?B7B/B'BBBBBBBBBBBBBBB B!B"B#B$B%B&B'wB(oB)gB*_B+WB,OB-GB.?B/7B0/B1'B2B3B4B5B6B7B8B9B:B;B<B=B>B?B@BABBBCBDBEBFBGwBHoBIgBJ_BKWBLOBMGBN?BO7BP/BQ'BRBSBTBUBVBWBXBYBZB\B]B^B_B`BaBbBcBdBeBfBgBhwBioBjgBl_BmWBnOBoGBp?Bq7Br/Bs'BtBuBvBwBxByBzB{B|B}B~BBBBBBBBBBBwBoBgB_BWBOBGB?B7B/B'BBBBBBBBBBBBBBBBBBBBBBwBoBgB_BWBOBGB?B7B/B'BBBBBBBBBBBBBBBBBBBBBBwBoBgB_BWBOBGB?B7B/B'BBBBBBBBBBBBBBBBBBBBBBwBoBgB_BWBOBGB?B7B/B'BBBBBBBBBBBBB B B B B BBBB(%s), ProvisioningSuccessExpected = %s%s: Ngc policy is false { NgcQueryEnabled reported that provisioning is expected to fail }.NgcPolicy::GetJoinInfoNgcPolicyCheckLsaLookupUserAccountTypeNgcPolicy::GetUserAccountTypeLsaGetSSOAccountType%s: { %s } User does not have a PRT, LSaGetSSOAccountType has not returned SSOEnabled%s: { %s } User does not have an AAD account%s: { %s } User type is DJ++ and user has a PRT ( domain join + AAD Join )%s: { %s } User type is AAD and user has a PRTNgcPolicy::GetUserSid%s: { %s } User SID %sNgcPolicy::GetNgcPolicyState%s: { %s } Platform policy returned by NgcQueryEnabled. NgcEnabledState = %d (%s), NgcPolicySource = %s, NgcPolicyModifiers = %s, ProvisioningSuccessExpected = %s%s: NGC certificate is not required for onprem auth. Set cert enrollment method to none.%s - hr: 0x%08x. ngcEnabled = %d (%s), provisioningSuccessExpected = %s. ngcCertEnrollmentMethod = %d (%s), ngcPolicySource = %d (%s), ngcEnabledModifiers = %lu (%s).NgcPolicy::VerifyNgcIsEnabled%s: { %s } stage succeeded { User is AAD and NGC policy is %s } %s: { %s } stage succeeded { NGC policy is %s } %s: { %s } stage failed { NGC policy is not enabled %s } IsCloudTgtAvailableNgcPolicy::VerifyAccountHasCloudTgt%s: %s failed with NT status: 0x%08x.%s - hr: 0x%08x. UseCloudTrustForOnPremAuth = %s, CertificateRequiredForOnPremise = %s, AccountHasCloudTgt = %s, CloudTgtPresent = %s.NgcPolicy::VerifyMachineMeetsNgcRequirements%s: { %s } stage failed { provisioning is expected to fail on this machine, machine hardware does not meet policy requirements } %s: { %s } stage succeeded { provisioning is expected to succeed on this machine } flagsNgcPolicy::IsDestructiveResetAvailable%s started. %s: %lu.available%s - hr: 0x%08x. flags = %d, supportsInstantOn = %s, available = %s.GetUserSidNgcPolicy::IsNonDestructiveResetAvailableNgcIsPinRecoveryEnabledNgcPolicy::VerifyLogonCertRAEnrollmentIsoL$0foT$@fo\$PHL$pHT$xL$L$HhH uHNHL$HT$LD$LL$ HhfD$ fL$0fT$@f\$PHH 7foD$ foL$0foT$@fo\$PHL$pHT$xL$L$HhHHL$HT$LD$LL$ HhfD$ fL$0fT$@f\$PHH ̕ofoD$ foL$0foT$@fo\$PHL$pHT$xL$L$HhHuH&HL$HT$LD$LL$ HhfD$ fL$0fT$@f\$PHH OfoD$ foL$0foT$@fo\$PHL$pHT$xL$L$HhHHL$HT$LD$LL$ HhfD$ fL$0fT$@f\$PHH GfoD$ foL$0foT$@fo\$PHL$pHT$xL$L$HhHHL$HT$LD$LL$ HhfD$ fL$0fT$@f\$PHH yfoD$ foL$0foT$@fo\$PHL$pHT$xL$L$HhHuHMHHL$HT$LD$LL$ HhfD$ fL$0fT$@f\$PHH  foD$ foL$0foT$@fo\$PHL$pHT$xL$L$HhHHL$HT$LD$LL$ HhfD$ fL$0fT$@f\$PHH foD$ foL$0foT$@fo\$PHL$pHT$xL$L$HhHHL$HT$LD$LL$ HhfD$ fL$0fT$@f\$PHH foD$ foL$0foT$@fo\$PHL$pHT$xL$L$HhHrHHDQHdHRHHDHrHpHƭH$!HHL$HT$LD$LL$ HhfD$ fL$0fT$@f\$PHH 覾foD$ foL$0foT$@fo\$PHL$pHT$xL$L$HhHשHͩrHHL$HT$LD$LL$ HhfD$ fL$0fT$@f\$PHH TfoD$ foL$0foT$@fo\$PHL$pHT$xL$L$HhH8HcH\H H H{H HWHH.3H!HjHH6HyHHH֭CH\HBH H[HqH7HHH;HHL$HT$LD$LL$ HhfD$ fL$0fT$@f\$PHH 蘻foD$ foL$0foT$@fo\$PHL$pHT$xL$L$HhHQHL$HT$LD$LL$ HhfD$ fL$0fT$@f\$PHH  foD$ foL$0foT$@fo\$PHL$pHT$xL$L$HhHVHL$HT$LD$LL$ HhfD$ fL$0fT$@f\$PHH ?肺foD$ foL$0foT$@fo\$PHL$pHT$xL$L$HhHHL$HT$LD$LL$ HhfD$ fL$0fT$@f\$PHH ԍfoD$ foL$0foT$@fo\$PHL$pHT$xL$L$HhHuHcHQH?H-HާH HjHPHHHHHHĦyHgHЦUHNH4H~HlH֥ZHHH6Hh$HNH,HHHH HHHHNH,HL$HT$LD$LL$ HhfD$ fL$0fT$@f\$PHH foD$ foL$0foT$@fo\$PHL$pHT$xL$L$HhHHHMH3HHHkHCHGHϥ5H#HHQHL$HT$LD$LL$ HhfD$ fL$0fT$@f\$PHH ‰襵foD$ foL$0foT$@fo\$PHL$pHT$xL$L$HhHΡuHġcHPH?Hn-HdHz H(HḤHjHpLD A HHpH 2fD A |AHpH 2$F E ,P!p(UU[@6\[ [L[)[ \ \)[ )([~]+H`onecoreuap\admin\enterprisemgmt\dmcertutils\lib\dmcertutils.cppInstallSoftware\Microsoft\SCEP\KeyProtectionntdll.dllMicrosoftTelemetryAssertTriggeredUMJsonHttpRequest::InitializeDsrHKeyUserHandle::Close%s: RegCloseKey failed with error: 0x%08x..%s: ElevatePrivileges failed with error: 0x%08x..DsrHKeyUserHandle::OpenElevatePrivilegesRegUnLoadKeyWSetProcessPrivilegeDsrHKeyUserHandle::ElevatePrivilegesRegLoadKeyWSeBackupPrivilegeDsrHKeyUserHandle::SetProcessPrivilegeLookupPrivilegeValueSeRestorePrivilegePrivilegeProfileImagePathSOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileListAdjustTokenPrivilegesDsrHKeyUserHandle::ReadHKeyUserInfo%s: DsrHKeyUserHandle::ReadHKeyUserInfo unexpected type found while reading sid value from %s.\NtUser.dat%s: DsrHKeyUserHandle::ReadHKeyUserInfo unexpected type found at %s.SidULongAddRegEnumKeyExServerPathWaitForCompleteEventRequestCallbackCreateCompleteEventSendAsyncJsonHttpRequest::SendAsync%s: Sending the http request.%s: Http response code: %dGetCopyOfResponseBuffer%s: CoWaitForMultipleHandles: dwResult %d%s: CoWaitForMultipleHandles: Unexpected dwResult %dJsonHttpRequest::WaitForCompleteEvent%s: Http complete event has been signaled%s: CreateEventEx failed with error code: 0x%08xJsonHttpRequest::OnHttpStatusReceived%s: CoWaitForMultipleHandles returned 0x%08xJsonHttpRequest::CreateCompleteEvent%s: Context.CompleteEvent is NULL%s: Context.CompleteEvent is setJsonHttpRequest::OnResponseComplete%s: Request operation result is 0x%08x. "ܔܔ $`@"y is considered successfully finalized.%s: Recovery join certificate not found. Finalizing recovery is not possible.%s: Device ID is the same after recovery. Suppressing server unregistration of the device.%s: AadPluginController::PerformPostCertificateDeleteTasks failed. Error code: 0x%08x. Ignoring this error...%s: NgcReg::NgcRemoveRegistration failed to clear NGC registration. Error code: 0x%08x. Ignoring this error...NgcRegisterKey%s: Invalid NGC request type: %dprovisionNgcNeedProvisionNgcPolicy::IsDeviceStateReadyCore%s: NGC post logon task is not enabled.%s: Max number of attestation retries has reached.%s: NgcStatusStorage::GetRetryAttempts failed with error code: 0x%08x. Ignore and continue...NULL%s - hr: 0x%08x. %s: %s.DsrGetDomainRegistrationDataDirectoryServerUtil::GetRegistrationDataDsrFreeDomainRegistrationData%s finishedDsrGetPrtAuthorityInfoppPrtAuthorityInfoAadPluginController::GetPrtAuthorityNgcGetLogonCertPolicypszUserSidpszTenantIdpolicyEnableduseRaEnrollmentNgcQueryEnabledLocal\SM0:%d:%d:%hsuT:Au<:Aud:Aul:Au$:AuD:Au:Au\:Aut:AuL:Au,:Au4:A5:AppszComputerDnDirectoryServerUtil::GetComputerObjectDnNameFullyQualifiedDNGetComputerObjectNameW%s: %s failed with error code: 0x%08x%s: DN of the computer object is %sppRegistrationDataLdapServer::ConnectDirectoryServerUtil::GetObjectGuidUsingLdapDirectoryServerUtil::GetAutoSigningCertUsingLdapDirectoryServerUtil::GetObjectSidUsingLdapLdapServer::GetConnectedServerHostnameGetAutoJoinDomainConfigurationpLdapServerpcszComputerDnpAutoSigningCertpAutoSigningCertLenuserCertificate(objectclass=*)%s: There was no auto join signing certificate found in the directory.LdapServer::GetAttributeValues%s: Found %lu user certificate(s) in the directory. Looking for subject name "%s" in them...%s: Failed to check if the user cert is a valid auto signing cert. %lu of %lu cert(s). RegistrationCertHelper::Ir code: 0x%08x. Ignoring...%s: No device cert is found. The device is not joined.%s: No device cert is found. The device is not joined. Returning success...%s: RegistrationCertStatus::GetTenantId failed with error code: 0x%08x. Ignore and continue unjoin.%s: RegistrationCertStatus::GetDeviceId failed with error code: 0x%08x. Ignore and continue unjoin.%s: JoinStatusStorage::ReadJoinStatus(%s) failed with error code: 0x%08x. Ignore and continue unjoin.%s: Failed to get current logon user's UPN with error 0x%08x. Ignore...DeviceRegistrationApi::BeginAutoJoin%s: Unable to verify or update the signing cert for DEVICE_AUTO join..%04d-%02d-%02d %02d:%02d:%02dZStringCatDiscoveryController::InitializeDiscoveryController::GetDiscoveryMetadataAzureDeviceRegistrationApi::LocalUnjoinImpl%s: Invalid unjoin type %d. Only WORKPLACE_UNJOIN and DEVICE_UNJOIN are allowed.RegistrationCertStatus::GetDeviceCertificatesAadPluginController::PerformUnjoinTasksDeviceRegistrationApi::LocalUnjoinDeviceCertificateJoinStatusStorage::ClearAllJoinStatus(TRUE)AadPluginController::PerformPostCertificateDeleteTasks%s: RegistrationController::DeleteCertificatesRDP failed with error code: 0x%08x. Continuing with deleting the Device Join Certificate.%s: Notifying WAM of unjoin failed with error code: 0x%08x.%s: Skipping WAM notification of unjoin due to SYSTEM context%s: Device sync task disabled.%s: Failed to disable device sync task with error 0x%08x.RegistrationCertStatus::GetWorkplaceCertificatesJoinStatusStorage::ClearAllJoinStatus(FALSE)DeviceRegistrationApi::AsyncAutoJoinDiscoverCallback<Present>%s: Discovery request returned code: 0x%08x. Discovery data: %s. Calling the original callback.%s: Discovery was successful. Continuing with the auto device registration%s: DeviceRegistrationApi::BeginJoin failed with error code: 0x%08x. Calling the original callback.DeviceRegistrationApi::AsyncJoinCallback%s: Need to callN>n(?n nG6> nt S><>mp2 S><g*?m uN>Pnp(?llSU&?l)?Pn>`n)?`(T q>nB>nPAX*?@`AX*?0pAX*? AX*?AX*?AX*?AX*?A>8TnD>@TnD>np_*?nPBpV*?`tpV*?pt)?pHTq>nB>nPAX*?P`AX*?@pAN>n(?nnG6>nt S><>nP2>XToDpV*?Pt S><>o`2>@`T0oD>@hT@oD>Pop_*?PoPBpV*?`tpV*?pt)?pTq>`oB>`oPAX*?`AX*?pAN>po(?pooG)?`Tq>oB>oPAX*?@`AX*?0pAN>o@?&?ooH6>ot S><>@oP2>ToDpV*?Pt S><>o`2>0ToD>op_*?oPBpV*?`tpV*?pt)?Tq>pB>pPAX*?`AX*?pAN>p(?p pG)?PpTq>0pB>0pPAX*?0`AX*? pAN>@p@?&?@p pH6> pt S><>op2>pT`pDpV*?pPt S><>`p2> TpD>pp_*?pPBpV*?`tpV*?пpt)?Tq>pB>pPAX*?`AX*?p AN>p(?pp G)?@`T q>p B>pP AX*? ` AX*?p AN>p @?&?pp H6>p t S><>p 2>`Tq DpV*?`P t S> <>q 2>T q D>0q p_*?0qP BpV*?н` tpV*?p t)?нU q>@q X*? rAX*? rA> (&`1rD> 0&p1rD>1rp_*?1PrBpV*? `rtpV*? prt)?  8&rq>1rB>1PrAX*?` `rAX*?P psAN>1r(?11sG6>1st S>r<>p1Ps2> H&1sDpV*? Pst S>s<>1`s2>P P&1sD>P X&2sD>2sp_*?2PsBpV*? `stpV*? pst)?  `&sq> 2sB> 2PsAX*? `sAX*? ptAN>02s(?02@2tG)?p  p&uq>P2uB>P2PuAX*?P `uAX*?@ pvAN>`2u@?&?`2@2vH6>@2vt S>s<>2Pv2>&2vDpV*?Pvt S>v<>2`v2>@&2vD>2vp_*?2PvBpV*?`vtpV*?pvt)?&vq>2vB>2PvAX*?`vAX*?pwAN>2v(?22wG)?`&xq>2xB>2PxAX*?@`xAX*?0pyAN>3x@?&?32yH6>2yt S>v<>2py2 S>s<>1py2>@&03yDpV*?@Pyt S>y<>03y2>&P3yD>`3yp_*?`3PyBpV*?`ytpV*?pyt)?&yq>p3yB>p3PyAX*?p`yAX*?`pzAN>3y(?33zG)?0&{q>3{B>3P{AX*?`{AX*?p|AN>3{@?&?33|H6>3|t S>y<>P3|2>0&3|DpV*?0P|t S>|<>3|2>&3|D>4|p_*?4P|BpV*?`|tpV*?p|t)?&|q>4|B>4P|AX*?``|AX*?Pp}AN> 4|(? 404}G)? '~q>@4~B>@4P~AX*?`~AX*?pAN>P4~@?&?P404H6>04t S>|<>32 S>r<g*?`1 uN>4rVV`= ``}|` @k  <y is considered successfully finalized.%s: Recovery join certificate not found. Finalizing recovery is not possible.%s: Device ID is the same after recovery. Suppressing server unregistration of the device.%s: AadPluginController::PerformPostCertificateDeleteTasks failed. Error code: 0x%08x. Ignoring this error...%s: NgcReg::NgcRemoveRegistration failed to clear NGC registration. Error code: 0x%08x. Ignoring this error...NgcRegisterKey%s: Invalid NGC request type: %dprovisionNgcNeedProvisionNgcPolicy::IsDeviceStateReadyCore%s: NGC post logon task is not enabled.%s: Max number of attestation retries has reached.%s: NgcStatusStorage::GetRetryAttempts failed with error code: 0x%08x. Ignore and continue...NULL%s - hr: 0x%08x. %s: %s.DsrGetDomainRegistrationDataDirectoryServerUtil::GetRegistrationDataDsrFreeDomainRegistrationData%s finishedDsrGetPrtAuthorityInfoppPrtAuthorityInfoAadPluginController::GetPrtAuthorityNgcGetLogonCertPolicypszUserSidpszTenantIdpolicyEnableduseRaEnrollmentNgcQueryEnabledLocal\SM0:%d:%d:%hsuT:Au<:Aud:Aul:Au$:AuD:Au:Au\:Aut:AuL:Au,:Au4:A5:AppszComputerDnDirectoryServerUtil::GetComputerObjectDnNameFullyQualifiedDNGetComputerObjectNameW%s: %s failed with error code: 0x%08x%s: DN of the computer object is %sppRegistrationDataLdapServer::ConnectDirectoryServerUtil::GetObjectGuidUsingLdapDirectoryServerUtil::GetAutoSigningCertUsingLdapDirectoryServerUtil::GetObjectSidUsingLdapLdapServer::GetConnectedServerHostnameGetAutoJoinDomainConfigurationpLdapServerpcszComputerDnpAutoSigningCertpAutoSigningCertLenuserCertificate(objectclass=*)%s: There was no auto join signing certificate found in the directory.LdapServer::GetAttributeValues%s: Found %lu user certificate(s) in the directory. Looking for subject name "%s" in them...%s: Failed to check if the user cert is a valid auto signing cert. %lu of %lu cert(s). RegistrationCertHelper::Ip\_Ӓ_&]_p _ _pp+_pp+_']_3?p _ _pp+_pp+_8']_3?]_]_ˎ_@\_p\_V_ Ӓ_p _ _pp+_pp+_U_3?]_]_`y̎_@\_p\_~̎_0[_p _ _pp+_pp+_p']_3?p _ _pp+_pp+_']_3?]_]_ˎ_@\_p\_~̎_Y_p _ _pp+_pp+_']_3?є_PY_8yJ_pp+_pp+_`>U_V_p~Z_@۔_W_]_@\_p\_~̎_ V_p _ _pp+_pp+_U_3?]_]_ˎ_@\_p\_Ӓ_(]_p _ _pp+_pp+_P(]_3?p _ _pp+_pp+_(]_3?]_]_ˎ_@\_p\_V_ Ӓ_p _ _pp+_pp+_U_V_`9]_@۔_W_]_@\_p\_~̎_ V_p _ _pp+_pp+_U_3?]_]_ˎ_W_]_@\_p\_Ӓ_h)]_p _ _pp+_pp+_)]_3?p _ _pp+_pp+_)]_3?]_]_`y̎_@\_p\_Ӓ_*]_p _ _pp+_pp+_H*]_3?p _ _pp+_pp+_*]_3?]_]_`y̎_SAS]A@]F]@]B< ]$$@#$@$P!$Ux5|555555555555555555555555555555555666 66666 6$6(6,6064686<6@6D6H6L6P6T6X6\6`6d6h6l6p6t6x6|666666666666666666666666666666666777 77777 7$7(7,7074787<7@7D7H7L7P7T7X7\7`7d7h7l7p7t7x7|777777777777777777777777777777777888 88888 8$8(8,8084888<8@8D8H8L8P8T8X8\8`8d8h8l8p8t8x8|888888888888888888888888888888888999 99999 9$9(9,9094989<9@9D9H9L9P9T9X9\9`9d9h9l9p9t9x9|999999999999999999999999999999999::: ::::: :$:(:,:0:4:8:<:@:D:H:L:P:T:X:\:`:d:h:l:p:t:x:|:::::::::::::::::::::::::::::::::;;; ;;;;; ;$;(;,;0;4;8;<;@;D;H;L;P;T;X;\;`;d;h;l;p;t;x;|;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<<<<< <(<0<8<@U??0!0B0F0L0P0V0Z0r0v0|0000000000000000000161V1r1v1|111111111111111111 222&2.2X2e2w222222222(3X3334I4i4{4444557778888899_9 ::-:}::::::;;H;u;\<l>|>? ?A?Q?? 000000000&1>1S11112)2H2a222222222 3333 4Z4x4|5556<6G6R6x666666 7Y7m777777788#8E8p8~888888899"9/969F999999:!:0:K:x:::::;+;2;F;S;Z;j;{;;;;;;>>$>4>c>>>>?E?h?w??0 030:0g0p0000C1x1111122,252;2x222223V3{333(434=4N44444525A5z5555556!6<6L6Z6667)707N7g7s7777788888888889999999999,:B:X:;;;;;;<1<<<<*>;>>>>>>>>?????;?L?T?[?b?i?p?w?~????????R0000 11.1X1j1{111 22&232:2A2H2f2w222222222223h333334&4d4s4444445+5>5G5M5a5555646D6i66667B7g777748H88888888%9.9F9W9w999999*:O::::;*;C;;;;;;;;; <<">X>b>r>>>>>??h?o??????0"0G0h000011-1O1t111122h2o2222223"3G3h333344-4O4t44444 5'555L5W5d5k5{55556?6L6^6o6x66667z7777E88888 99b999999999 ::1:7:>:E:[:m::::::::h;z;;;;<8<<v>>>>??(?X?h??????T00%0,030:0A0H0O0V0]0d0k0r0y00000000000000001112'2|222222'3F3h3o333333333333333>44444 5545=5Z55556(666y6666667717c7777777778 88c8888S99999999: :::,:@:G:N:U::::;?;P;;;;;;;;<.>,>Q>c>q>>>>>>>Y?n????? 080F0Z0|000000;1E1y1111112(292J2[22223343b33333333333334 444"4)484E4K4R4Y4`4g4n4u4|44444445556*6E6S6Z6e6u6|66666666666 77)7v77777778*8<8K8Y8`8o8~88888888899&9L9S9^9i9{99999999:,:A:::::::::;;!;8;H;v;;;;;;;;"<-<8<<<<<="=X=j======>>$>+>:>C>N>V>_>f>>>>;?_?q??????L0+040K0X0_0f0m00000001121X1111282G2l2223333f4r4y4444444455!5*5<5h5w5556 666!6(6/666=6D6K6R6Y6j6{6666677?777777788/868=8D8K8R8Y8`8g8n8u8|88888888,9N9\999999:::-:;:I:}::::::;!;(;6;D;R;`;u;;;; <'<4 >>??;?R???Y0s0000'1A1{1111+2A2222B3h3333333333444%4;4M4l4v444444555556696H6O66666777Z7f7z777777777777777788Z8d888 99q9~999::;X;g;;:<<====(>7>r>>>>?4?? 0+0D0000 1-1G111)2M2g223L3p38444444!5A5a555687J7e7k7q7}777777777888#88L9Q9^99 ::::::;8;;;;;(<5E>{>>>;?S?Z?a?h???0d000&010m0t000000041f111111111111111111222"2,262@2Y22223 33!3+353?3I3S3]3g3q33333333'40464>4D4[4t4{4444444445V55555566L6Z6n6x666666666B7N7U7\777778 88 8'8.8>8888887999+:2:T:::;\;;;;;;;;;;eam, each a master of their respective craft. " button_color="Accent-Color" desktop_cols_flickity="3" desktop_small_cols_flickity="2" tablet_cols_flickity="1" column_padding="0" border_radius="10px"][item id="1504038676473-46596-9e8f" title="Item" tab_id="1508882258172-9"][team_member image_url="https://themenectar.com/img/demo-media/unsplash/webp/team-member-1-small-cropped.webp" bio_image_url="https://themenectar.com/img/demo-media/unsplash/webp/team-member-full-silhouette.webp" team_memeber_style="bio_fullscreen" name="Ethan Young" job_position="Team Leader" team_member_bio="Far far away, behind the word mountains, far from the countries Vokalia and Consonantia, there live the blind texts. Separated they live in Bookmarksgrove right at the coast of the Semantics, a large language ocean. A small river named Duden flows by their place and supplies it with the necessary regelialia. It is a paradisematic country, in which roasted parts of sentences fly into your mouth. " social_icon_1="fa fa-facebook" social_link_1="#" social_icon_2="fa fa-instagram" social_link_2="#" social_icon_3="fa fa-linkedin" social_link_3="#"][/item][item id="1504038676473-46596-56gj" title="Item" tab_id="1508882258184-4"][team_member image_url="https://themenectar.com/img/demo-media/unsplash/webp/team-member-2-small-cropped.webp" bio_image_url="https://themenectar.com/img/demo-media/unsplash/webp/team-member-full-silhouette.webp" team_memeber_style="bio_fullscreen" name="Ava Morgan" job_position="The SEO Expert" team_member_bio="Far far away, behind the word mountains, far from the countries Vokalia and Consonantia, there live the blind texts. Separated they live in Bookmarksgrove right at the coast of the Semantics, a large language ocean. A small river named Duden flows by their place and supplies it with the necessary regelialia. It is a paradisematic country, in which roasted parts of sentences fly into your mouth. " social_icon_1="fa fa-instagram" social_link_1="#" social_icon_2="fa fa-twitter" social_link_2="#"][/item][item id="1504038676738-86596-mh3d" title="Item" tab_id="1508882258210-7"][team_member image_url="https://themenectar.com/img/demo-media/unsplash/webp/team-member-3-small-cropped.webp" bio_image_url="https://themenectar.com/img/demo-media/unsplash/webp/team-member-full-silhouette.webp" team_memeber_style="bio_fullscreen" name="James Anderson" job_position="Front-end Developer" team_member_bio="Far far away, behind the word mountains, far from the countries Vokalia and Consonantia, there live the blind texts. Separated they live in Bookmarksgrove right at the coast of the Semantics, a large language ocean. A small river named Duden flows by their place and supplies it with the necessary regelialia. It is a paradisematic country, in which roasted parts of sentences fly into your mouth. " social_icon_1="fa fa-twitter" social_link_1="#" social_icon_2="fa fa-youtube-play" social_link_2="#"][/item][item id="1504038677047-76596-33hf" title="Item" tab_id="1508882258235-10"][team_member image_url="https://themenectar.com/img/demo-media/unsplash/webp/team-member-4-small-cropped.webp" bio_image_url="https://themenectar.com/img/demo-media/unsplash/webp/team-member-full-silhouette.webp" team_memeber_style="bio_fullscreen" name="Mark Jones" job_position="Back-end Developer" team_member_bio="Far far away, behind the word mountains, far from the countries Vokalia and Consonantia, there live the blind texts. Separated they live in Bookmarksgrove right at the coast of the Semantics, a large language ocean. A small river named Duden flows by their place and supplies it with the necessary regelialia. It is a paradisematic country, in which roasted parts of sentences fly into your mouth. " social_icon_1="fa fa-github-alt" social_icon_2="fa fa-instagram" social_icon_3="fa fa-facebook"][/item][/carousel][/vc_column][/vc_row] CONTENT; vc_add_default_templates( $data ); $data = array(); $data['name'] = esc_html__( 'Team About Us Blurb', 'js_composer' ); $data['cat_display_name'] = $cat_display_names['about']; $data['custom_class'] = 'about dT; vc_add_default_templates( $data ); $data = array(); $data['name'] = esc_html__( 'Nonprofit Reveal Image and Text', 'js_composer' ); $data['cat_display_name'] = $cat_display_names['hero_section']; $data['custom_class'] = 'general date-20-Jan-2020'; $data['image_path'] = preg_replace( '/\s/', '%20', SALIENT_CORE_PLUGIN_PATH . '/includes/img/templates/npo-image-overlap.jpg' ); $data['content'] = <<Nature can be fully saved through love from people [/vc_column_text][vc_column_text css_animation="none" css=".vc_custom_1579198858100{margin-bottom: 40px !important;}" max_width="550"]Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Nulla consequat massa quis enim. Sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus lorem mus.[/vc_column_text][nectar_cta btn_style="arrow-animation" hetttttttt      <$@*<p'  \99@ 9I\$@9Ab=LbAbffz99tW@\FWȋȋ#s5WAb܋LbVsVsWp=P1%=WRrP1%==WP1 WHpkqq@\O@\u ˍ@\@\3+{:&.\Abk0Abp^N梭NX\ ^$@$~$p$^z;. ^= ^Ω$\\ʍPݨݨ=p^U{`p1% ^ C@ C@pˍHpΩ9\9 pGhppҍpGp&sL#00!t?HNHH|$`HLD$HI8LL$/MHI@HT$0L HBHzH;NPL?HL$.LNHH|$`LLD$HI8IHI@HT$0H HBHzL;NPHWH~@HNHH@( HL$.HFHH\$`HLD$HIIHIxHT$0H HzHZH;FPHHFHHD$hH1H L H9uHp[_^HL$hH12yAWAVAUATVWSH@LH H1HD$8HL)H9MHIW)D$ HD$0Hv=HGH!HHALELHmIJ/H Ld$ H\$(HD$0 Ld$ A\$IL9M9L9LLI胂AINLL$7MxLD$ LD$ LL$(MHH@H; |$7yH H#|$0HL$ HNHD$8H1H H9uHH@[_^A\A]A^A_ МHL$8H1wALB LJ(M)IIMI9vLJH@M HAHBP DAALJ LR(M)IHLM9v?LRO@OTDAALJ LR(M)ILM9vK@ADHAHBP AWAVAUATVWUSH(LLIHϋ$skIHG8HHIOH IE1Lh8IkIHFO ID$M|$H^I$Mt$I\$ AL$(Al$,$AD$0$AD$4LnjL`H UHHO8HAID$HG8LfG H([]_^A\A]A^A_H(M9t AHЀ vLHH(MHL$PЉIM9tEEZA w= } AB裛LJ@HB8I)I:!DA(t4M9IJHA HHy M9ININA(LB8LJ@M)II9v`HM LQL;Y AsM9rII@H;BAEtM9sEtHAHBP&HuHAHBP A8Q4u HAI@PHAI@PLVWH(HH~HHIHtHHHZHHNHtHHm@t HJHH(_^VWH(HHHHIHtHH!HHHNHtHH@t 8HzJHH(_^VA(LB8LJ@M)II9LJHMLA,;A0LO@ILZ LR(M)IML9sXLROLZ Hr(L)HIH9s8OTLR LZ(M)IML9sCDHDQ0AIL9u^ !HAHBPVH Ht HIHH ^ AHDI@PAWAVATVWUSHPMHH H1HD$HM9u)L6HD$HH1H f H9umHHP[]_^A\A^A_LHLa8iL|$@ILMKMM9tCʼnD$0l$(Ld$ Lt$8HLIM6|HL$HH1qAWAVAUATVWUSH8MLHHH H1HD$0L|$(LXM?L9u-L9t%LcM9tA?\uMl$L9t{(tNA?\t2IL>HD$0H1H a H9HH8[]_^A\A]A^A_ÊSHyIĄIEH&oL|$(LHD$(HLMMaLl$(I9uI9tmL{M9td;\u_Iǀ{)LEI9tOGWPeHO8HQHPHMHhHAHG8H@HG8HL$0H1p`AWAVAUATVWUSHXLHHS H1HD$PM9tDID$$H$<*tSMLcM9<\uIL9t{{t\HHD$PH1H H9~HHX[]_^A\A]A^A_DHD$(HL$ D$0L1IIHHD$LHD$ H\$@LHMM`LM9M9A<,tVIXL9<\HAx}IEL9DHcT$LHD$(HL$ D$0LII IHD$<HD$ H\$@LHMHL9trHXL9ti8\udHÀx}HEH9tTLcD$HD$0H1H H9u}HH8[_^A\A^A_L|$(HLMIM?AVB܃:gHAHMSHIMM9HD$8H1H  H9uHH@[_^A^A_ˑHL$8H1kAWAVAUATVWUSHXLMHHH H1HD$PLa8iL|$HILMM9I9A$tC^t(_HK8HQAD#CAHPH)._HK8HQAD#CAHPHH@HAHC8H@HC8LD$HILD$HM9u/LHD$PH1H H9HHX[]_^A\A]A^A_ËCʼnD$0l$(Ld$ Lt$@HLI躞MHmDkC$LD$HILD$HL|$@HLIvMLDqHV>H(/H `H(qHV>H H*H (H$qHV>HIHH{HH}HqHV>HHZ2H[ H<2H*H62Ho H2H H 2H3 HT2qHV>H qHV>H qHV>HHXHhHpWATAUAVAWHP3H(XH E3DcD`DCXHX\$@H##Dd$8st$0DCE3HD$(H\(H ؍\$@H-!\$8L5\$0DCLLt$(H+(H l蟍\$@L= Dd$8DC\$0H(MH\$(H l\$@H'Dd$8H \$0E3DH\$(A\$@Dk\$8L '\$0H'ELt$(H \$@L '\$8H'\$0H ELt$(\$@H'\$8H +\$0LELt$(跌\$@\$8H'\$0H LLt$(E荌\$@H="\$8Hw'\$0H <LLt$(E\\$@Ha'Dd$8H \$0E3DH\$(1\$@L%N'\$8H [\$0MHM'Lt$(HE3H D$@EʼnD$8HӉD$0Lt$(L5M΋3DFD$@H mD$8MωD$0HHD$(衋3H&\$@H D$8E3ɉ\$0DH\$(q\$@H&D$8H w\$0E3DH\$(C\$@D$8\$0E3H\$(DH}&H \$@Hn&D$8H \$0E3DH\$(\$@DFD$8H<&\$0H MH\$(踊\$@H%&\$8H \$0LHEH\$(臊3H&D$@H +D$8E3ɉD$0DHD$(W3H%t$@H t$8Lωt$0EH\$(+t$@EED$8H%t$0H 1E3Ht$(t$@H%t$8L %t$0H H5)EHHt$(ĉ3LωD$@D$8D$0HHD$(EH 5H蕉3L T%D$@H D$8EʼnD$0HHlHD$(b3L 1%D$@H VD$8EʼnD$0HH9HD$(/3H&\$@H%\$8H \$0LEHD$(\$@L $\$8H ^\$0EH$Ht$(Hˈ3H D$@LωD$8EʼnD$0HHHD$(蜈d$@HA}E3ɉ|$8EEDl$0H ]HHD$(h3EE\$@H[$|$8H \$0E3H\$(;\$@\$8H=,\$0LH|$(EHH g \$@kD$8H$\$0H DH\$(E3ه\$@Hv\$8EE\$0H#E3HD$(H t觇\$@L #\$8H#\$0H EH|$(y\$@H#D$8H \$0E3H\$(]DH3H#D$@H $D$8E3ɉD$0DHD$(3Hg#D$@L !D$8H D$0EHH|$(3L TD$@H 1D$8EʼnD$0HH|$(蹆3D$@D$8D$0L |"EH|$(HH 荆3H"\$@H ID$8E3ɉ\$0DH\$(]\$@EED$8H"\$0H MH\$(.\$@EE\$8HC\$0H PE3H|$(\$@EE \$8Hh"\$0H E3Ht$(؅\$@EED$8HI"\$0H fMH\$(詅E3EED|$@HD|$8H D|$0E3H|$(xD|$@H"D|$8H D|$0MEH|$(KD|$@H!D|$8H D|$0MEH|$(D|$@H!D|$8H D|$0MEH|$(D|$@H!D|$8H !D|$0MEH|$(ĄD|$@HD|$8H D|$0MEH|$(藄D|$@H{D|$8H 7D|$0MEH|$(jD|$@EuDt$8Dm}Dl$0H5E3DHt$(H H +D|$@HD|$8DED|$0HMHD$(H #D|$@H Dt$8H D|$0E3DL|$(ɃD|$@]Dt$8H} D|$0H ADL|$(E3虃D|$@Dt$8D|$0E3L|$(DHh H lD|$@DEDt$8Hg D|$0H S E3L|$(>D|$@HR Dt$8H D|$0E3DL|$(D|$@DEAH& \$8H k D|$0E3L|$(D|$@DE\$8H D|$0H E3L|$(贂D|$@DE \$8H D|$0H | E3L|$(臂D|$@DE!\$8H l$0H  E3Ht$([D|$@DE"\$8H D$0H E3Ht$(+D|$@Du\$8DE#Dt$0HE3Ht$(H  D|$@\$8DeDd$0DE$E3Ht$(HH ɁD|$@DE%\$8D}D|$0HE3Ht$(H 蘁d$@DE&\$8H|$0H E3Ht$(lDt$@DE'\$8HD$0 H 9E3Ht$(<Dt$@DE(\$8HxD$0 H E3Ht$( kE3ɉl$@DC+\$8H[D$0 H DHt$(ڀDd$@{ \$8DC,|$0H?E3Ht$(H 諀Dd$@EE,\$8H']E3ɉ\$0H VHt$(|Dd$@E3D$8D$0Ht$(EE-HH Hd$@EE.D$8Hl$0H eE3Ht$(Dt$@EE/D$8HD$0 H E3Ht$(EE3ɉD$@H5sD$8EE0Dl$0HH hHt$(EnE3HzHxHtPHH^PH@HT$UH HLE0H٩LHU833w@UH HM@H ]˘@UH HM 賘H ]@UH HH ]@UH0HHHL$(T$ L _LEpUhHM`H0]@UHH3Ɂ8]HT$UH HHH ]@UH H} uLMxLEpHUhHM`螩H ]@SUH(HHM@HM0HE0HHM(HE(8csmt E E "膠HM(HHE0HX~HFH(][@UH H} uLMpLE(HUXHMPH ]qHV>H(H 5HtcH(qHV>H iDqHV>H(=uu.H,HtIpT2uH 諒H HtH(qHV>H(=u.HHtIpT1uH H 讠H(qHV>H(H PH H%H 1TqHV>H IqHV>H UpAVWVUSH@HAIHut'G;_rG| +}bGDD+A;~@HO;Y&HcHHLoD$0HHHH HT$0PuA;H@[]^_A^ËH@[]^_A^MfDBHx1HLfDAAPHT1HWVUSH8HHIHzOi|?HO;ioHcHHLoD$(HHHH HT$(Puͅ}WCHH8[]^_HG;hHcHHDoHH8[]^_WVUSH8HAI;_vE| O+;}EH;}?HO;YHcHHLoD$(HHHH HT$(Pu;|H8[]^_ËH8[]^_MfDAD+H/HDDAL3H/HAVWVUSH@HHHH P`RHH `]b]HHK73~~mHN;iʧHcLIJL1oD$0HHHH HT$0Pt*HN;iJL1oD$0HHT$0a0;n|HH@[]^_A^WVUSH8HHIHF3~~@HN;i=HcHHLoD$(HHHH HT$(Pu;n|WCHH8[]^_HF;hHcHHDoHH8[]^_H(DAL3-H(H(HA9P},xt@=v;}‹-H(H8ELAIL$ 3ɉL$(IL3CH8AVWVUSH0HIAD$N+A;} &EHNDt$ 3҉T$(LDYCH0[]^_A^UWVSH8Hl$PHeHHAHtHDt DHODGDD$ E3DD$(LD3BHe[^_]UWVSH8Hi0Hl$0HmPrDHH8[^_]H8LAIL$ 3ɉL$(IL3E3BH8WVH8HHH+tBHH; ]tH ]H HHoD$(HT$(-H8^_3H8^_WVUSHHHHH YYoH3~~KHN;is[HcHHLoD$8oD$(HHT$8LD$(HH@@P u;n|3HH[]^_øHH[]^_VH HDFE~HN3 D3FFH ^H(LD$ DAL3*H(H(E3LD$ DAL3\*H(AVWVUSH0HAIL$} ?}?M+;} ?BLt$ HMDLpCH0[]^_A^WVH(HH \HH¢HOHHH(^_LfQH)*HUH@Hl$@HeHMHUHMBHMH HZH;t HHUHMHUHoEHU*HE@He]UH0Hi Hl$ Hm@H BZHHMOBHH0]WVH(HHVHN;QuVH(HFVJN;PsHcHHDoFH(^_oUWVH@Hl$PHeLE HHM AHM H HYH;t HHU wH΋LE IAoELEHe^_]UWVH0Hi Hl$ HmPH 2Y|HHM ?AHH0^_]WVH(H;wr p=H XHW;rsHcHHT HHoH(^_`DHHtHH;Xt3Hu Hu33øWVSH HI;^r t >t6(a &Vhju h^~ ] ̋US3SSSSRQUt&=ttt~ EE3[]̋USV4Q3W;tf9-u;G;u3 _^[]ff0 wwk ;wӃ;rՅtuE3̋UQQVu~-+~ -!~-~- SWtNjN`MS  ߉M}  ؉]K )K ]  MfwMI  fwuNNG NG NG NG NG N G G ؍N"G _[=s3 ^̋U(S 3ʼnEVuW$u%3 Gf;wL@$rVMm M_3^̊I -}uE;ts;sWff0f wbwZrwPj Zj ؋ZʉE;w+r;w%}ڃ;ur}t u E8X3 _^[̋UQVW}9>tM} ME>_^̋US]V{1t jV ZE u,C8EWC<{PEC E C2EC0E$CHE(CLCp(CPuxc K֋_xC1^[]4̋UQVuEPN`(}t uN(~,E F EF@uEF,MM 3^̋ tVQpxc ^̋U8S 3ʼnEVWEȨvEhv3EwEvE`wE(wEwEwEXxExExExEytWHb YYt F r2M_3^̋U3SVWمtEEEPSX hȂPb EYYt@u;Esx EPujSP x EPSl x Eeux ux _^[̋UQVuEWPN\[} ML8_3^̋UQVuEPN\t[M FDFHAM83^̋UQVuEWPN\3[} N 'F Me8_3^̋UQVuEPN\ZE N.M183^̋UQVuEPN\ZE N<M73^̋UVu~9uE N$^3]̋UVu~9uOE N(^3]̋UQVuW~9uEPNhZ} N0'F0M:7_3^̋U4S 3ĉD$0S] D$VuWPNdY~ID; if ( 'trash' !== $post->post_status ) { return false; } $previous_status = get_post_meta( $post_id, '_wp_trash_meta_status', true ); /** * Filters whether a post untrashing should take place. * * @since 4.9.0 * @since 5.6.0 The `$previous_status` parameter was added. * * @param bool|null $untrash Whether to go forward with untrashing. * @param WP_Post $post Post object. * @param string $previous_status The status of the post at the point where it was trashed. */ $check = apply_filters( 'pre_untrash_post', null, $post, $previous_status ); if ( null !== $check ) { return $check; } /** * Fires before a post is restored from the Trash. * * @since 2.9.0 * @since 5.6.0 The `$previous_status` parameter was added. * * @param int $post_id Post ID. * @param string $previous_status The status of the post at the point where it was trashed. */ do_action( 'untrash_post', $post_id, $previous_status ); $new_status = ( 'attachment' === $post->post_type ) ? 'inherit' : 'draft'; /** * Filters the status that a post gets assigned when it is restored from the trash (untrashed). * * By default posts that are restored will be assigned a status of 'draft'. Return the value of `$previous_status` * in order to assign the status that the post had before it was trashed. The `wp_untrash_post_set_previous_status()` * function is available for this. * * Prior to WordPress 5.6.0, restored posts were always assigned their original status. * * @since 5.6.0 * * @param string $new_status The new status of the post being restored. * @param int $post_id The ID of the post being restored. * @param string $previous_status The status of the post at the point where it was trashed. */ $post_status = apply_filters( 'wp_untrash_post_status', $new_status, $post_id, $previous_status ); delete_post_meta( $post_id, '_wp_trash_meta_status' ); delete_post_meta( $post_id, '_wp_trash_meta_time' ); $post_updated = wp_update_post( array( 'ID' => $post_id, 'post_status' => $post_status, ) ); if ( ! $post_updated ) { return false; } wp_untrash_post_comments( $post_id ); /** * Fires after a post is restored from the Trash. * * @since 2.9.0 * @since 5.6.0 The `$previous_status` parameter was added. * * @param int $post_id Post ID. * @param string $previous_status The status of the post at the point where it was trashed. */ do_action( 'untrashed_post', $post_id, $previous_status ); return $post; } /** * Moves comments for a post to the Trash. * * @since 2.9.0 * * @global wpdb $wpdb WordPress database abstraction object. * * @param int|WP_Post|null $post Optional. Post ID or post object. Defaults to global $post. * @return mixed|void False on failure. */ function wp_trash_post_comments( $post = null ) { global $wpdb; $post = get_post( $post ); if ( ! $post ) { return; } $post_id = $post->ID; /** * Fires before comments are sent to the Trash. * * @since 2.9.0 * * @param int $post_id Post ID. */ do_action( 'trash_post_comments', $post_id ); $comments = $wpdb->get_results( $wpdb->prepare( "SELECT comment_ID, comment_approved FROM $wpdb->comments WHERE comment_post_ID = %d", $post_id ) ); if ( ! $comments ) { return; } // Cache current status for each comment. $statuses = array(); foreach ( $comments as $comment ) { $statuses[ $comment->comment_ID ] = $comment->comment_approved; } add_post_meta( $post_id, '_wp_trash_meta_comments_status', $statuses ); // Set status for all comments to post-trashed. $result = $wpdb->update( $wpdb->comments, array( 'comment_approved' => 'post-trashed' ), array( 'comment_post_ID' => $post_id ) ); clean_comment_cache( array_keys( $statuses ) ); /** * Fires after comments are sent to the Trash. * * @since 2.9.0 * * @param int $post_id Post ID. * @param array $statuses Array of comment statuses. */ do_action( 'trashed_post_comments', $post_id, $statuses ); return $result; } /** * Restore comments for a post from the Trash. * * @since 2.9.0 * * @global wpdb $wpdb WordPress database abstraction object. * * @param int|WP_Post|null $post Optional. Post ID or post object. Defaults to global $post. * @return true|void */ function wp_untrash_post_comments( $post = null ) { global $wpdb; $post = get_post( $post ); if ( ! $post ) { return; } $post_id = $post->ID; $statuses = get_post_meta( $post_id, '_wp_trash_meta_comments_status', true ); if ( ! $statuses ) { return true; } /** * Fires before comments are restored for a post from the Trash. * * @since 2.9.0 * * @param int $post_id Post ID. */ do_action( 'untrash_post_comments', $post_id ); // Restore each comment to its original status. $group_by_status = array(); foreach ( $statuses as $comment_id => $comment_status ) { $group_by_status[ $comment_status ][] = $comment_id; } foreach ( $group_by_status as $status => $comments ) { // Sanity check. This shouldn't happen. if ( 'post-trashed' === $status ) { $status = '0'; } $comments_in = implode( ', ', array_map( 'intval', $comments ) ); $wpdb->query( $wpdb->prepare( "UPDATE $wpdb->comments SET comment_approved = %s WHERE comment_ID IN ($comments_in)", $status ) ); } clean_comment_cache( array_keys( $statuses ) ); delete_post_meta( $post_id, '_wp_trash_meta_comments_status' ); /** * Fires after comments are restored for a post from the Trash. * * @since 2.9.0 * * @param int $post_id Post ID. */ do_action( 'untrashed_post_comments', $post_id ); } /** * Retrieve the list of categories for a post. * * Compatibility layer for themes and plugins. Also an easy layer of abstraction * away from the complexity of the taxonomy layer. * * @since 2.1.0 * * @see wp_get_object_terms() * * @param int $post_id Optional. The Post ID. Does not default to the ID of the * global $post. Default 0. * @param array $args Optional. Category query parameters. Default empty array. * See WP_Term_Query::__construct() for supported arguments. * @return array|WP_Error List of categories. If the `$fields` argument passed via `$args` is 'all' or * 'all_with_object_id', an array of WP_Term objects will be returned. If `$fields` * is 'ids', an array of category IDs. If `$fields` is 'names', an array of category names. * WP_Error object if 'category' taxonomy doesn't exist. */ function wp_get_post_categories( $post_id = 0, $args = array() ) { $post_id = (int) $post_id; $defaults = array( 'fields' => 'ids' ); $args = wp_parse_args( $args, $defaults ); $cats = wp_get_object_terms( $post_id, 'category', $args ); return $cats; } /** * Retrieve the tags for a post. * * There is only one default for this function, called 'fields' and by default * is set to 'all'. There are other defaults that can be overridden in * wp_get_object_terms(). * * @since 2.3.0 * * @param int $post_id Optional. The Post ID. Does not default to the ID of the * global $post. Default 0. * @param array $args Optional. Tag query parameters. Default empty array. * See WP_Term_Query::__construct() for supported arguments. * @return array|WP_Error Array of WP_Term objects on success or empty array if no tags were found. * WP_Error object if 'post_tag' taxonomy doesn't exist. */ function wp_get_post_tags( $post_id = 0, $args = array() ) { return wp_get_post_terms( $post_id, 'post_tag', $args ); } /** * Retrieves the terms for a post. * * @since 2.8.0 * * @param int $post_id Optional. The Post ID. Does not default to the ID of the * global $post. Default 0. * @param string|string[] $taxonomy Optional. The taxonomy slug or array of slugs for which * to retrieve terms. Default 'post_tag'. * @param array $args { * Optional. Term query parameters. See WP_Term_Query::__construct() for supported arguments. * * @type string $fields Term fields to retrieve. Default 'all'. * } * @return array|WP_Error Array of WP_Term objects on success or empty array if no terms were found. * WP_Error object if `$taxonomy` doesn't exist. */ function wp_get_post_terms( $post_id = 0, $taxonomy = 'post_tag', $args = array() ) { $post_id = (int) $post_id; $defaults = array( 'fields' => 'all' ); $args = wp_parse_args( $args, $defaults ); $tags = wp_get_object_terms( $post_id, $taxonomy, $args ); return $tags; } /** * Retrieve a number of recent posts. * * @since 1.0.0 * * @see get_posts() * * @param array $args Optional. Arguments to retrieve posts. Default empty array. * @param string $output Optional. The required return type. One of OBJECT or ARRAY_A, which * correspond to a WP_Post object or an associative array, respectively. * Default ARRAY_A. * @return array|false Array of recent posts, where the type of each element is determined * by the `$output` parameter. Empty array on failure. */ function wp_get_recent_posts( $args = array(), $output = ARRAY_A ) { if ( is_numeric( $args ) ) { _deprecated_argument( __FUNCTION__, '3.1.0', __( 'Passing an integer number of posts is deprecated. Pass an array of arguments instead.' ) ); $args = array( 'numberposts' => absint( $args ) ); } // Set default arguments. $defaults = array( 'numberposts' => 10, 'offset' => 0, 'category' => 0, 'orderby' => 'post_date', 'order' => 'DESC', 'include' => '', 'exclude' => '', 'meta_key' => '', 'meta_value' => '', 'post_type' => 'post', 'post_status' => 'draft, publish, future, pending, private', 'suppress_filters' => true, ); $parsed_args = wp_parse_args( $args, $defaults ); $results = get_posts( $parsed_args ); // Backward compatibility. Prior to 3.1 expected posts to be returned in array. if ( ARRAY_A === $output ) { foreach ( $results as $key => $result ) { $results[ $key ] = get_object_vars( $result ); } return $results ? $results : array(); } return $results ? $results : false; } /** * Insert or update a post. * * If the $postarr parameter has 'ID' set to a value, then post will be updated. * * You can set the post date manually, by setting the values for 'post_date' * and 'post_date_gmt' keys. You can close the comments or open the comments by * setting the value for 'comment_status' key. * * @since 1.0.0 * @since 2.6.0 Added the `$wp_error` parameter to allow a WP_Error to be returned on failure. * @since 4.2.0 Support was added for encoding emoji in the post title, content, and excerpt. * @since 4.4.0 A 'meta_input' array can now be passed to `$postarr` to add post meta data. * @since 5.6.0 Added the `$fire_after_hooks` parameter. * * @see sanitize_post() * @global wpdb $wpdb WordPress database abstraction object. * * @param array $postarr { * An array of elements that make up a post to update or insert. * * @type int $ID The post ID. If equal to something other than 0, * the post with that ID will be updated. Default 0. * @type int $post_author The ID of the user who added the post. Default is * the current user ID. * @type string $post_date The date of the post. Default is the current time. * @type string $post_date_gmt The date of the post in the GMT timezone. Default is * the value of `$post_date`. * @type string $post_content The post content. Default empty. * @type string $post_content_filtered The filtered post content. Default empty. * @type string $post_title The post title. Default empty. * @type string $post_excerpt The post excerpt. Default empty. * @type string $post_status The post status. Default 'draft'. * @type string $post_type The post type. Default 'post'. * @type string $comment_status Whether the post can accept comments. Accepts 'open' or 'closed'. * Default is the value of 'default_comment_status' option. * @type string $ping_status Whether the post can accept pings. Accepts 'open' or 'closed'. * Default is the value of 'default_ping_status' option. * @type string $post_password The password to access the post. Default empty. * @type string $post_name The post name. Default is the sanitized post title * when creating a new post. * @type string $to_ping Space or carriage return-separated list of URLs to ping. * Default empty. * @type string $pinged Space or carriage return-separated list of URLs that have * been pinged. Default empty. * @type string $post_modified The date when the post was last modified. Default is * the current time. * @type string $post_modified_gmt The date when the post was last modified in the GMT * timezone. Default is the current time. * @type int $post_parent Set this for the post it belongs to, if any. Default 0. * @type int $menu_order The order the post should be displayed in. Default 0. * @type string $post_mime_type The mime type of the post. Default empty. * @type string $guid Global Unique ID for referencing the post. Default empty. * @type int $import_id The post ID to be used when inserting a new post. * If specified, must not match any existing post ID. Default 0. * @type int[] $post_category Array of category IDs. * Defaults to value of the 'default_category' option. * @type array $tags_input Array of tag names, slugs, or IDs. Default empty. * @type array $tax_input An array of taxonomy terms keyed by their taxonomy name. * If the taxonomy is hierarchical, the term list needs to be * either an array of term IDs or a comma-separated string of IDs. * If the taxonomy is non-hierarchical, the term list can be an array * that contains term names or slugs, or a comma-separated string * of names or slugs. This is because, in hierarchical taxonomy, * child terms can have the same names with different parent terms, * so the only way to connect them is using ID. Default empty. * @type array $meta_input Array of post meta values keyed by their post meta key. Default empty. * } * @param bool $wp_error Optional. Whether to return a WP_Error on failure. Default false. * @param bool $fire_after_hooks Optional. Whether to fire the after insert hooks. Default true. * @return int|WP_Error The post ID on success. The value 0 or WP_Error on failure. */ function wp_insert_post( $postarr, $wp_error = false, $fire_after_hooks = true ) { global $wpdb; // Capture original pre-sanitized array for passing into filters. $unsanitized_postarr = $postarr; $user_id = get_current_user_id(); $defaults = array( 'post_author' => $user_id, 'post_content' => '', 'post_content_filtered' => '', 'post_title' => '', 'post_excerpt' => '', 'post_status' => 'draft', 'post_type' => 'post', 'comment_status' => '', 'ping_status' => '', 'post_password' => '', 'to_ping' => '', 'pinged' => '', 'post_parent' => 0, 'menu_order' => 0, 'guid' => '', 'import_id' => 0, 'context' => '', 'post_date' => '', 'post_date_gmt' => '', ); $postarr = wp_parse_args( $postarr, $defaults ); unset( $postarr['filter'] ); $postarr = sanitize_post( $postarr, 'db' ); // Are we updating or creating? $post_ID = 0; $update = false; $guid = $postarr['guid']; if ( ! empty( $postarr['ID'] ) ) { $update = true; // Get the post ID and GUID. $post_ID = $postarr['ID']; $post_before = get_post( $post_ID ); if ( is_null( $post_before ) ) { if ( $wp_error ) { return new WP_Error( 'invalid_post', __( 'Invalid post ID.' ) ); } return 0; } $guid = get_post_field( 'guid', $post_ID ); $previous_status = get_post_field( 'post_status', $post_ID ); } else { $previous_status = 'new'; $post_before = null; } $post_type = empty( $postarr['post_type'] ) ? 'post' : $postarr['post_type']; $post_title = $postarr['post_title']; $post_content = $postarr['post_content']; $post_excerpt = $postarr['post_excerpt']; if ( isset( $postarr['post_name'] ) ) { $post_name = $postarr['post_name']; } elseif ( $update ) { // For an update, don't modify the post_name if it wasn't supplied as an argument. $post_name = $post_before->post_name; } $maybe_empty = 'attachment' !== $post_type && ! $post_content && ! $post_title && ! $post_excerpt && post_type_supports( $post_type, 'editor' ) && post_type_supports( $post_type, 'title' ) && post_type_supports( $post_type, 'excerpt' ); /** * Filters whether the post should be considered "empty". * * The post is considered "empty" if both: * 1. The post type supports the title, editor, and excerpt fields * 2. The title, editor, and excerpt fields are all empty * * Returning a truthy value from the filter will effectively short-circuit * the new post being inserted and return 0. If $wp_error is true, a WP_Error * will be returned instead. * * @since 3.3.0 * * @param bool $maybe_empty Whether the post should be considered "empty". * @param array $postarr Array of post data. */ if ( apply_filters( 'wp_insert_post_empty_content', $maybe_empty, $postarr ) ) { if ( $wp_error ) { return new WP_Error( 'empty_content', __( 'Content, title, and excerpt are empty.' ) ); } else { return 0; } } $post_status = empty( $postarr['post_status'] ) ? 'draft' : $postarr['post_status']; if ( 'attachment' === $post_type && ! in_array( $post_status, array( 'inherit', 'private', 'trash', 'auto-draft' ), true ) ) { $post_status = 'inherit'; } if ( ! empty( $postarr['post_category'] ) ) { // Filter out empty terms. $post_category = array_filter( $postarr['post_category'] ); } // Make sure we set a valid category. if ( empty( $post_category ) || 0 === count( $post_category ) || ! is_array( $post_category ) ) { // 'post' requires at least one category. if ( 'post' === $post_type && 'auto-draft' !== $post_status ) { $post_category = array( get_option( 'default_category' ) ); } else { $post_category = array(); } } /* * Don't allow contributors to set the post slug for pending review posts. * * For new posts check the primitive capability, for updates check the meta capability. */ $post_type_object = get_post_type_object( $post_type ); if ( ! $update && 'pending' === $post_status && ! current_user_can( $post_type_object->cap->publish_posts ) ) { $post_name = ''; } elseif ( $update && 'pending' === $post_status && ! current_user_can( 'publish_post', $post_ID ) ) { $post_name = ''; } /* * Create a valid post name. Drafts and pending posts are allowed to have * an empty post name. */ if ( empty( $post_name ) ) { if ( ! in_array( $post_status, array( 'draft', 'pending', 'auto-draft' ), true ) ) { $post_name = sanitize_title( $post_title ); } else { $post_name = ''; } } else { // On updates, we need to check to see if it's using the old, fixed sanitization context. $check_name = sanitize_title( $post_name, '', 'old-save' ); if ( $update && strtolower( urlencode( $post_name ) ) == $check_name && get_post_field( 'post_name', $post_ID ) == $check_name ) { $post_name = $check_name; } else { // new post, or slug has changed. $post_name = sanitize_title( $post_name ); } } /* * Resolve the post date from any provided post date or post date GMT strings; * if none are provided, the date will be set to now. */ $post_date = wp_resolve_post_date( $postarr['post_date'], $postarr['post_date_gmt'] ); if ( ! $post_date ) { if ( $wp_error ) { return new WP_Error( 'invalid_date', __( 'Invalid date.' ) ); } else { return 0; } } if ( empty( $postarr['post_date_gmt'] ) || '0000-00-00 00:00:00' === $postarr['post_date_gmt'] ) { if ( ! in_array( $post_status, get_post_stati( array( 'date_floating' => true ) ), true ) ) { $post_date_gmt = get_gmt_from_date( $post_date ); } else { $post_date_gmt = '0000-00-00 00:00:00'; } } else { $post_date_gmt = $postarr['post_date_gmt']; } if ( $update || '0000-00-00 00:00:00' === $post_date ) { $post_modified = current_time( 'mysql' ); $post_modified_gmt = current_time( 'mysql', 1 ); } else { $post_modified = $post_date; $post_modified_gmt = $post_date_gmt; } if ( 'attachment' !== $post_type ) { $now = gmdate( 'Y-m-d H:i:s' ); if ( 'publish' === $post_status ) { if ( strtotime( $post_date_gmt ) - strtotime( $now ) >= MINUTE_IN_SECONDS ) { $post_status = 'future'; } } elseif ( 'future' === $post_status ) { if ( strtotime( $post_date_gmt ) - strtotime( $now ) < MINUTE_IN_SECONDS ) { $post_status = 'publish'; } } } // Comment status. if ( empty( $postarr['comment_status'] ) ) { if ( $update ) { $comment_status = 'closed'; } else { $comment_status = get_default_comment_status( $post_type ); } } else { $comment_status = $postarr['comment_status']; } // These variables are needed by compact() later. $post_content_filtered = $postarr['post_content_filtered']; $post_author = isset( $postarr['post_author'] ) ? $postarr['post_author'] : $user_id; $ping_status = empty( $postarr['ping_status'] ) ? get_default_comment_status( $post_type, 'pingback' ) : $postarr['ping_status']; $to_ping = isset( $postarr['to_ping'] ) ? sanitize_trackback_urls( $postarr['to_ping'] ) : ''; $pinged = isset( $postarr['pinged'] ) ? $postarr['pinged'] : ''; $import_id = isset( $postarr['import_id'] ) ? $postarr['import_id'] : 0; /* * The 'wp_insert_post_parent' filter expects all variables to be present. * Previously, these variables would have already been extracted */ if ( isset( $postarr['menu_order'] ) ) { $menu_order = (int) $postarr['menu_order']; } else { $menu_order = 0; } $post_password = isset( $postarr['post_password'] ) ? $postarr['post_password'] : ''; if ( 'private' === $post_status ) { $post_password = ''; } if ( isset( $postarr['post_parent'] ) ) { $post_parent = (int) $postarr['post_parent']; } else { $post_parent = 0; } $new_postarr = array_merge( array( 'ID' => $post_ID, ), compact( array_diff( array_keys( $defaults ), array( 'context', 'filter' ) ) ) ); /** * Filters the post parent -- used to check for and prevent hierarchy loops. * * @since 3.1.0 * * @param int $post_parent Post parent ID. * @param int $post_ID Post ID. * @param array $new_postarr Array of parsed post data. * @param array $postarr Array of sanitized, but otherwise unmodified post data. */ $post_parent = apply_filters( 'wp_insert_post_parent', $post_parent, $post_ID, $new_postarr, $postarr ); /* * If the post is being untrashed and it has a desired slug stored in post meta, * reassign it. */ if ( 'trash' === $previous_status && 'trash' !== $post_status ) { $desired_post_slug = get_post_meta( $post_ID, '_wp_desired_post_slug', true ); if ( $desired_post_slug ) { delete_post_meta( $post_ID, '_wp_desired_post_slug' ); $post_name = $desired_post_slug; } } // If a trashed post has the desired slug, change it and let this post have it. if ( 'trash' !== $post_status && $post_name ) { /** * Filters whether or not to add a `__trashed` suffix to trashed posts that match the name of the updated post. * * @since 5.4.0 * * @param bool $add_trashed_suffix Whether to attempt to add the suffix. * @param string $post_name The name of the post being updated. * @param int $post_ID Post ID. */ $add_trashed_suffix = apply_filters( 'add_trashed_suffix_to_trashed_posts', true, $post_name, $post_ID ); if ( $add_trashed_suffix ) { wp_add_trashed_suffix_to_post_name_for_trashed_posts( $post_name, $post_ID ); } } // When trashing an existing post, change its slug to allow non-trashed posts to use it. if ( 'trash' === $post_status && 'trash' !== $previous_status && 'new' !== $previous_status ) { $post_name = wp_add_trashed_suffix_to_post_name_for_post( $post_ID ); } $post_name = wp_unique_post_slug( $post_name, $post_ID, $post_status, $post_type, $post_parent ); // Don't unslash. $post_mime_type = isset( $postarr['post_mime_type'] ) ? $postarr['post_mime_type'] : ''; // Expected_slashed (everything!). $data = compact( 'post_author', 'post_date', 'post_date_gmt', 'post_content', 'post_content_filtered', 'post_title', 'post_excerpt', 'post_status', 'post_type', 'comment_status', 'ping_status', 'post_password', 'post_name', 'to_ping', 'pinged', 'post_modified', 'post_modified_gmt', 'post_parent', 'menu_order', 'post_mime_type', 'guid' ); $emoji_fields = array( 'post_title', 'post_content', 'post_excerpt' ); foreach ( $emoji_fields as $emoji_field ) { if ( isset( $data[ $emoji_field ] ) ) { $charset = $wpdb->get_col_charset( $wpdb->posts, $emoji_field ); if ( 'utf8' === $charset ) { $data[ $emoji_field ] = wp_encode_emoji( $data[ $emoji_field ] ); } } } if ( 'attachment' === $post_type ) { /** * Filters attachment post data before it is updated in or added to the database. * * @since 3.9.0 * @since 5.4.1 The `$unsanitized_postarr` parameter was added. * @since 6.0.0 The `$update` parameter was added. * * @param array $data An array of slashed, sanitized, and processed attachment post data. * @param array $postarr An array of slashed and sanitized attachment post data, but not processed. * @param array $unsanitized_postarr An array of slashed yet *unsanitized* and unprocessed attachment post data * as originally passed to wp_insert_post(). * @param bool $update Whether this is an existing attachment post being updated. */ $data = apply_filters( 'wp_insert_attachment_data', $data, $postarr, $unsanitized_postarr, $update ); } else { /** * Filters slashed post data just before it is inserted into the database. * * @since 2.7.0 * @since 5.4.1 The `$unsanitized_postarr` parameter was added. * @since 6.0.0 The `$update` parameter was added. * * @param array $data An array of slashed, sanitized, and processed post data. * @param array $postarr An array of sanitized (and slashed) but otherwise unmodified post data. * @param array $unsanitized_postarr An array of slashed yet *unsanitized* and unprocessed post data as * originally passed to wp_insert_post(). * @param bool $update Whether this is an existing post being updated. */ $data = apply_filters( 'wp_insert_post_data', $data, $postarr, $unsanitized_postarr, $update ); } $data = wp_unslash( $data ); $where = array( 'ID' => $post_ID ); if ( $update ) { /** * Fires immediately before an existing post is updated in the database. * * @since 2.5.0 * * @param int $post_ID Post ID. * @param array $data Array of unslashed post data. */ do_action( 'pre_post_update', $post_ID, $data ); if ( false === $wpdb->update( $wpdb->posts, $data, $where ) ) { if ( $wp_error ) { if ( 'attachment' === $post_type ) { $message = __( 'Could not update attachment in the database.' ); } else { $message = __( 'Could not update post in the database.' ); } return new WP_Error( 'db_update_error', $message, $wpdb->last_error ); } else { return 0; } } } else { // If there is a suggested ID, use it if not already present. if ( ! empty( $import_id ) ) { $import_id = (int) $import_id; if ( ! $wpdb->get_var( $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE ID = %d", $import_id ) ) ) { $data['ID'] = $import_id; } } if ( false === $wpdb->insert( $wpdb->posts, $data ) ) { if ( $wp_error ) { if ( 'attachment' === $post_type ) { $message = __( 'Could not insert attachment into the database.' ); } else { $message = __( 'Could not insert post into the database.' ); } return new WP_Error( 'db_insert_error', $message, $wpdb->last_error ); } else { return 0; } } $post_ID = (int) $wpdb->insert_id; // Use the newly generated $post_ID. $where = array( 'ID' => $post_ID ); } if ( empty( $data['post_name'] ) && ! in_array( $data['post_status'], array( 'draft', 'pending', 'auto-draft' ), true ) ) { $data['post_name'] = wp_unique_post_slug( sanitize_title( $data['post_title'], $post_ID ), $post_ID, $data['post_status'], $post_type, $post_parent ); $wpdb->update( $wpdb->posts, array( 'post_name' => $data['post_name'] ), $where ); clean_post_cache( $post_ID ); } if ( is_object_in_taxonomy( $post_type, 'category' ) ) { wp_set_post_categories( $post_ID, $post_category ); } if ( isset( $postarr['tags_input'] ) && is_object_in_taxonomy( $post_type, 'post_tag' ) ) { wp_set_post_tags( $post_ID, $postarr['tags_input'] ); } // Add default term for all associated custom taxonomies. if ( 'auto-draft' !== $post_status ) { foreach ( get_object_taxonomies( $post_type, 'object' ) as $taxonomy => $tax_object ) { if ( ! empty( $tax_object->default_term ) ) { // Filter out empty terms. if ( isset( $postarr['tax_input'][ $taxonomy ] ) && is_array( $postarr['tax_input'][ $taxonomy ] ) ) { $postarr['tax_input'][ $taxonomy ] = array_filter( $postarr['tax_input'][ $taxonomy ] ); } // Passed custom taxonomy list overwrites the existing list if not empty. $terms = wp_get_object_terms( $post_ID, $taxonomy, array( 'fields' => 'ids' ) ); if ( ! empty( $terms ) && empty( $postarr['tax_input'][ $taxonomy ] ) ) { $postarr['tax_input'][ $taxonomy ] = $terms; } if ( empty( $postarr['tax_input'][ $taxonomy ] ) ) { $default_term_id = get_option( 'default_term_' . $taxonomy ); if ( ! empty( $default_term_id ) ) { $postarr['tax_input'][ $taxonomy ] = array( (int) $default_term_id ); } } } } } // New-style support for all custom taxonomies. if ( ! empty( $postarr['tax_input'] ) ) { foreach ( $postarr['tax_input'] as $taxonomy => $tags ) { $taxonomy_obj = get_taxonomy( $taxonomy ); if ( ! $taxonomy_obj ) { /* translators: %s: Taxonomy name. */ _doing_it_wrong( __FUNCTION__, sprintf( __( 'Invalid taxonomy: %s.' ), $taxonomy ), '4.4.0' ); continue; } // array = hierarchical, string = non-hierarchical. if ( is_array( $tags ) ) { $tags = array_filter( $tags ); } if ( current_user_can( $taxonomy_obj->cap->assign_terms ) ) { wp_set_post_terms( $post_ID, $tags, $taxonomy ); } } } if ( ! empty( $postarr['meta_input'] ) ) { foreach ( $postarr['meta_input'] as $field => $value ) { update_post_meta( $post_ID, $field, $value ); } } $current_guid = get_post_field( 'guid', $post_ID ); // Set GUID. if ( ! $update && '' === $current_guid ) { $wpdb->update( $wpdb->posts, array( 'guid' => get_permalink( $post_ID ) ), $where ); } if ( 'attachment' === $postarr['post_type'] ) { if ( ! empty( $postarr['file'] ) ) { update_attached_file( $post_ID, $postarr['file'] ); } if ( ! empty( $postarr['context'] ) ) { add_post_meta( $post_ID, '_wp_attachment_context', $postarr['context'], true ); } } // Set or remove featured image. if ( isset( $postarr['_thumbnail_id'] ) ) { $thumbnail_support = current_theme_supports( 'post-thumbnails', $post_type ) && post_type_supports( $post_type, 'thumbnail' ) || 'revision' === $post_type; if ( ! $thumbnail_support && 'attachment' === $post_type && $post_mime_type ) { if ( wp_attachment_is( 'audio', $post_ID ) ) { $thumbnail_support = post_type_supports( 'attachment:audio', 'thumbnail' ) || current_theme_supports( 'post-thumbnails', 'attachment:audio' ); } elseif ( wp_attachment_is( 'video', $post_ID ) ) { $thumbnail_support = post_type_supports( 'attachment:video', 'thumbnail' ) || current_theme_supports( 'post-thumbnails', 'attachment:video' ); } } if ( $thumbnail_support ) { $thumbnail_id = (int) $postarr['_thumbnail_id']; if ( -1 === $thumbnail_id ) { delete_post_thumbnail( $post_ID ); } else { set_post_thumbnail( $post_ID, $thumbnail_id ); } } } clean_post_cache( $post_ID ); $post = get_post( $post_ID ); if ( ! empty( $postarr['page_template'] ) ) { $post->page_template = $postarr['page_template']; $page_templates = wp_get_theme()->get_page_templates( $post ); if ( 'default' !== $postarr['page_template'] && ! isset( $page_templates[ $postarr['page_template'] ] ) ) { if ( $wp_error ) { return new WP_Error( 'invalid_page_template', __( 'Invalid page template.' ) ); } update_post_meta( $post_ID, '_wp_page_template', 'default' ); } else { update_post_meta( $post_ID, '_wp_page_template', $postarr['page_template'] ); } } if ( 'attachment' !== $postarr['post_type'] ) { wp_transition_post_status( $data['post_status'], $previous_status, $post ); } else { if ( $update ) { /** * Fires once an existing attachment has been updated. * * @since 2.0.0 * * @param int $post_ID Attachment ID. */ do_action( 'edit_attachment', $post_ID ); $post_after = get_post( $post_ID ); /** * Fires once an existing attachment has been updated. * * @since 4.4.0 * * @param int $post_ID Post ID. * @param WP_Post $post_after Post object following the update. * @param WP_Post $post_before Post object before the update. */ do_action( 'attachment_updated', $post_ID, $post_after, $post_before ); } else { /** * Fires once an attachment has been added. * * @since 2.0.0 * * @param int $post_ID Attachment ID. */ do_action( 'add_attachment', $post_ID ); } return $post_ID; } if ( $update ) { /** * Fires once an existing post has been updated. * * The dynamic portion of the hook name, `$post->post_type`, refers to * the post type slug. * * Possible hook names include: * * - `edit_post_post` * - `edit_post_page` * * @since 5.1.0 * * @param int $post_ID Post ID. * @param WP_Post $post Post object. */ do_action( "edit_post_{$post->post_type}", $post_ID, $post ); /** * Fires once an existing post has been updated. * * @since 1.2.0 * * @param int $post_ID Post ID. * @param WP_Post $post Post object. */ do_action( 'edit_post', $post_ID, $post ); $post_after = get_post( $post_ID ); /** * Fires once an existing post has been updated. * * @since 3.0.0 * * @param int $post_ID Post ID. * @param WP_Post $post_after Post object following the update. * @param WP_Post $post_before Post object before the update. */ do_action( 'post_updated', $post_ID, $post_after, $post_before ); } /** * Fires once a post has been saved. * * The dynamic portion of the hook name, `$post->post_type`, refers to * the post type slug. * * Possible hook names include: * * - `save_post_post` * - `save_post_page` * * @since 3.7.0 * * @param int $post_ID Post ID. * @param WP_Post $post Post object. * @param bool $update Whether this is an existing post being updated. */ do_action( "save_post_{$post->post_type}", $post_ID, $post, $update ); /** * Fires once a post has been saved. * * @since 1.5.0 * * @param int $post_ID Post ID. * @param WP_Post $post Post object. * @param bool $update Whether this is an existing post being updated. */ do_action( 'save_post', $post_ID, $post, $update ); /** * Fires once a post has been saved. * * @since 2.0.0 * * @param int $post_ID Post ID. * @param WP_Post $post Post object. * @param bool $update Whether this is an existing post being updated. */ do_action( 'wp_insert_post', $post_ID, $post, $update ); if ( $fire_after_hooks ) { wp_after_insert_post( $post, $update, $post_before ); } return $post_ID; } /** * Update a post with new post data. * * The date does not have to be set for drafts. You can set the date and it will * not be overridden. * * @since 1.0.0 * @since 3.5.0 Added the `$wp_error` parameter to allow a WP_Error to be returned on failure. * @since 5.6.0 Added the `$fire_after_hooks` parameter. * * @param array|object $postarr Optional. Post data. Arrays are expected to be escaped, * objects are not. See wp_insert_post() for accepted arguments. * Default array. * @param bool $wp_error Optional. Whether to return a WP_Error on failure. Default false. * @param bool $fire_after_hooks Optional. Whether to fire the after insert hooks. Default true. * @return int|WP_Error The post ID on success. The value 0 or WP_Error on failure. */ function wp_update_post( $postarr = array(), $wp_error = false, $fire_after_hooks = true ) { if ( is_object( $postarr ) ) { // Non-escaped post was passed. $postarr = get_object_vars( $postarr ); $postarr = wp_slash( $postarr ); } // First, get all of the original fields. $post = get_post( $postarr['ID'], ARRAY_A ); if ( is_null( $post ) ) { if ( $wp_error ) { return new WP_Error( 'invalid_post', __( 'Invalid post ID.' ) ); } return 0; } // Escape data pulled from DB. $post = wp_slash( $post ); // Passed post category list overwrites existing category list if not empty. if ( isset( $postarr['post_category'] ) && is_array( $postarr['post_category'] ) && count( $postarr['post_category'] ) > 0 ) { $post_cats = $postarr['post_category']; } else { $post_cats = $post['post_category']; } // Drafts shouldn't be assigned a date unless explicitly done so by the user. if ( isset( $post['post_status'] ) && in_array( $post['post_status'], array( 'draft', 'pending', 'auto-draft' ), true ) && empty( $postarr['edit_date'] ) && ( '0000-00-00 00:00:00' === $post['post_date_gmt'] ) ) { $clear_date = true; } else { $clear_date = false; } // Merge old and new fields with new fields overwriting old ones. $postarr = array_merge( $post, $postarr ); $postarr['post_category'] = $post_cats; if ( $clear_date ) { $postarr['post_date'] = current_time( 'mysql' ); $postarr['post_date_gmt'] = ''; } if ( 'attachment' === $postarr['post_type'] ) { return wp_insert_attachment( $postarr, false, 0, $wp_error ); } // Discard 'tags_input' parameter if it's the same as existing post tags. if ( isset( $postarr['tags_input'] ) && is_object_in_taxonomy( $postarr['post_type'], 'post_tag' ) ) { $tags = get_the_terms( $postarr['ID'], 'post_tag' ); $tag_names = array(); if ( $tags && ! is_wp_error( $tags ) ) { $tag_names = wp_list_pluck( $tags, 'name' ); } if ( $postarr['tags_input'] === $tag_names ) { unset( $postarr['tags_input'] ); } } return wp_insert_post( $postarr, $wp_error, $fire_after_hooks ); } /** * Publish a post by transitioning the post status. * * @since 2.1.0 * * @global wpdb $wpdb WordPress database abstraction object. * * @param int|WP_Post $post Post ID or post object. */ function wp_publish_post( $post ) { global $wpdb; $post = get_post( $post ); if ( ! $post ) { return; } if ( 'publish' === $post->post_status ) { return; } $post_before = get_post( $post->ID ); // Ensure at least one term is applied for taxonomies with a default term. foreach ( get_object_taxonomies( $post->post_type, 'object' ) as $taxonomy => $tax_object ) { // Skip taxonomy if no default term is set. if ( 'category' !== $taxonomy && empty( $tax_object->default_term ) ) { continue; } // Do not modify previously set terms. if ( ! empty( get_the_terms( $post, $taxonomy ) ) ) { continue; } if ( 'category' === $taxonomy ) { $default_term_id = (int) get_option( 'default_category', 0 ); } else { $default_term_id = (int) get_option( 'default_term_' . $taxonomy, 0 ); } if ( ! $default_term_id ) { continue; } wp_set_post_terms( $post->ID, array( $default_term_id ), $taxonomy ); } $wpdb->update( $wpdb->posts, array( 'post_status' => 'publish' ), array( 'ID' => $post->ID ) ); clean_post_cache( $post->ID ); $old_status = $post->post_status; $post->post_status = 'publish'; wp_transition_post_status( 'publish', $old_status, $post ); /** This action is documented in wp-includes/post.php */ do_action( "edit_post_{$post->post_type}", $post->ID, $post ); /** This action is documented in wp-includes/post.php */ do_action( 'edit_post', $post->ID, $post ); /** This action is documented in wp-includes/post.php */ do_action( "save_post_{$post->post_type}", $post->ID, $post, true ); /** This action is documented in wp-includes/post.php */ do_action( 'save_post', $post->ID, $post, true ); /** This action is documented in wp-includes/post.php */ do_action( 'wp_insert_post', $post->ID, $post, true ); wp_after_insert_post( $post, true, $post_before ); } /** * Publish future post and make sure post ID has future post status. * * Invoked by cron 'publish_future_post' event. This safeguard prevents cron * from publishing drafts, etc. * * @since 2.5.0 * * @param int|WP_Post $post_id Post ID or post object. */ function check_and_publish_future_post( $post_id ) { $post = get_post( $post_id ); if ( ! $post ) { return; } if ( 'future' !== $post->post_status ) { return; } $time = strtotime( $post->post_date_gmt . ' GMT' ); // Uh oh, someone jumped the gun! if ( $time > time() ) { wp_clear_scheduled_hook( 'publish_future_post', array( $post_id ) ); // Clear anything else in the system. wp_schedule_single_event( $time, 'publish_future_post', array( $post_id ) ); return; } // wp_publish_post() returns no meaningful value. wp_publish_post( $post_id ); } /** * Uses wp_checkdate to return a valid Gregorian-calendar value for post_date. * If post_date is not provided, this first checks post_date_gmt if provided, * then falls back to use the current time. * * For back-compat purposes in wp_insert_post, an empty post_date and an invalid * post_date_gmt will continue to return '1970-01-01 00:00:00' rather than false. * * @since 5.7.0 * * @param string $post_date The date in mysql format. * @param string $post_date_gmt The GMT date in mysql format. * @return string|false A valid Gregorian-calendar date string, or false on failure. */ function wp_resolve_post_date( $post_date = '', $post_date_gmt = '' ) { // If the date is empty, set the date to now. if ( empty( $post_date ) || '0000-00-00 00:00:00' === $post_date ) { if ( empty( $post_date_gmt ) || '0000-00-00 00:00:00' === $post_date_gmt ) { $post_date = current_time( 'mysql' ); } else { $post_date = get_date_from_gmt( $post_date_gmt ); } } // Validate the date. $month = substr( $post_date, 5, 2 ); $day = substr( $post_date, 8, 2 ); $year = substr( $post_date, 0, 4 ); $valid_date = wp_checkdate( $month, $day, $year, $post_date ); if ( ! $valid_date ) { return false; } return $post_date; } /** * Computes a unique slug for the post, when given the desired slug and some post details. * * @since 2.8.0 * * @global wpdb $wpdb WordPress database abstraction object. * @global WP_Rewrite $wp_rewrite WordPress rewrite component. * * @param string $slug The desired slug (post_name). * @param int $post_ID Post ID. * @param string $post_status No uniqueness checks are made if the post is still draft or pending. * @param string $post_type Post type. * @param int $post_parent Post parent ID. * @return string Unique slug for the post, based on $post_name (with a -1, -2, etc. suffix) */ function wp_unique_post_slug( $slug, $post_ID, $post_status, $post_type, $post_parent ) { if ( in_array( $post_status, array( 'draft', 'pending', 'auto-draft' ), true ) || ( 'inherit' === $post_status && 'revision' === $post_type ) || 'user_request' === $post_type ) { return $slug; } /** * Filters the post slug before it is generated to be unique. * * Returning a non-null value will short-circuit the * unique slug generation, returning the passed value instead. * * @since 5.1.0 * * @param string|null $override_slug Short-circuit return value. * @param string $slug The desired slug (post_name). * @param int $post_ID Post ID. * @param string $post_status The post status. * @param string $post_type Post type. * @param int $post_parent Post parent ID. */ $override_slug = apply_filters( 'pre_wp_unique_post_slug', null, $slug, $post_ID, $post_status, $post_type, $post_parent ); if ( null !== $override_slug ) { return $override_slug; } global $wpdb, $wp_rewrite; $original_slug = $slug; $feeds = $wp_rewrite->feeds; if ( ! is_array( $feeds ) ) { $feeds = array(); } if ( 'attachment' === $post_type ) { // Attachment slugs must be unique across all types. $check_sql = "SELECT post_name FROM $wpdb->posts WHERE post_name = %s AND ID != %d LIMIT 1"; $post_name_check = $wpdb->get_var( $wpdb->prepare( $check_sql, $slug, $post_ID ) ); /** * Filters whether the post slug would make a bad attachment slug. * * @since 3.1.0 * * @param bool $bad_slug Whether the slug would be bad as an attachment slug. * @param string $slug The post slug. */ $is_bad_attachment_slug = apply_filters( 'wp_unique_post_slug_is_bad_attachment_slug', false, $slug ); if ( $post_name_check || in_array( $slug, $feeds, true ) || 'embed' === $slug || $is_bad_attachment_slug ) { $suffix = 2; do { $alt_post_name = _truncate_post_slug( $slug, 200 - ( strlen( $suffix ) + 1 ) ) . "-$suffix"; $post_name_check = $wpdb->get_var( $wpdb->prepare( $check_sql, $alt_post_name, $post_ID ) ); $suffix++; } while ( $post_name_check ); $slug = $alt_post_name; } } elseif ( is_post_type_hierarchical( $post_type ) ) { if ( 'nav_menu_item' === $post_type ) { return $slug; } /* * Page slugs must be unique within their own trees. Pages are in a separate * namespace than posts so page slugs are allowed to overlap post slugs. */ $check_sql = "SELECT post_name FROM $wpdb->posts WHERE post_name = %s AND post_type IN ( %s, 'attachment' ) AND ID != %d AND post_parent = %d LIMIT 1"; $post_name_check = $wpdb->get_var( $wpdb->prepare( $check_sql, $slug, $post_type, $post_ID, $post_parent ) ); /** * Filters whether the post slug would make a bad hierarchical post slug. * * @since 3.1.0 * * @param bool $bad_slug Whether the post slug would be bad in a hierarchical post context. * @param string $slug The post slug. * @param string $post_type Post type. * @param int $post_parent Post parent ID. */ $is_bad_hierarchical_slug = apply_filters( 'wp_unique_post_slug_is_bad_hierarchical_slug', false, $slug, $post_type, $post_parent ); if ( $post_name_check || in_array( $slug, $feeds, true ) || 'embed' === $slug || preg_match( "@^($wp_rewrite->pagination_base)?\d+$@", $slug ) || $is_bad_hierarchical_slug ) { $suffix = 2; do { $alt_post_name = _truncate_post_slug( $slug, 200 - ( strlen( $suffix ) + 1 ) ) . "-$suffix"; $post_name_check = $wpdb->get_var( $wpdb->prepare( $check_sql, $alt_post_name, $post_type, $post_ID, $post_parent ) ); $suffix++; } while ( $post_name_check ); $slug = $alt_post_name; } } else { // Post slugs must be unique across all posts. $check_sql = "SELECT post_name FROM $wpdb->posts WHERE post_name = %s AND post_type = %s AND ID != %d LIMIT 1"; $post_name_check = $wpdb->get_var( $wpdb->prepare( $check_sql, $slug, $post_type, $post_ID ) ); $post = get_post( $post_ID ); // Prevent new post slugs that could result in URLs that conflict with date archives. $conflicts_with_date_archive = false; if ( 'post' === $post_type && ( ! $post || $post->post_name !== $slug ) && preg_match( '/^[0-9]+$/', $slug ) ) { $slug_num = (int) $slug; if ( $slug_num ) { $permastructs = array_values( array_filter( explode( '/', get_option( 'permalink_structure' ) ) ) ); $postname_index = array_search( '%postname%', $permastructs, true ); /* * Potential date clashes are as follows: * * - Any integer in the first permastruct position could be a year. * - An integer between 1 and 12 that follows 'year' conflicts with 'monthnum'. * - An integer between 1 and 31 that follows 'monthnum' conflicts with 'day'. */ if ( 0 === $postname_index || ( $postname_index && '%year%' === $permastructs[ $postname_index - 1 ] && 13 > $slug_num ) || ( $postname_index && '%monthnum%' === $permastructs[ $postname_index - 1 ] && 32 > $slug_num ) ) { $conflicts_with_date_archive = true; } } } /** * Filters whether the post slug would be bad as a flat slug. * * @since 3.1.0 * * @param bool $bad_slug Whether the post slug would be bad as a flat slug. * @param string $slug The post slug. * @param string $post_type Post type. */ $is_bad_flat_slug = apply_filters( 'wp_unique_post_slug_is_bad_flat_slug', false, $slug, $post_type ); if ( $post_name_check || in_array( $slug, $feeds, true ) || 'embed' === $slug || $conflicts_with_date_archive || $is_bad_flat_slug ) { $suffix = 2; do { $alt_post_name = _truncate_post_slug( $slug, 200 - ( strlen( $suffix ) + 1 ) ) . "-$suffix"; $post_name_check = $wpdb->get_var( $wpdb->prepare( $check_sql, $alt_post_name, $post_type, $post_ID ) ); $suffix++; } while ( $post_name_check ); $slug = $alt_post_name; } } /** * Filters the unique post slug. * * @since 3.3.0 * * @param string $slug The post slug. * @param int $post_ID Post ID. * @param string $post_status The post status. * @param string $post_type Post type. * @param int $post_parent Post parent ID * @param string $original_slug The original post slug. */ return apply_filters( 'wp_unique_post_slug', $slug, $post_ID, $post_status, $post_type, $post_parent, $original_slug ); } /** * Truncate a post slug. * * @since 3.6.0 * @access private * * @see utf8_uri_encode() * * @param string $slug The slug to truncate. * @param int $length Optional. Max length of the slug. Default 200 (characters). * @return string The truncated slug. */ function _truncate_post_slug( $slug, $length = 200 ) { if ( strlen( $slug ) > $length ) { $decoded_slug = urldecode( $slug ); if ( $decoded_slug === $slug ) { $slug = substr( $slug, 0, $length ); } else { $slug = utf8_uri_encode( $decoded_slug, $length, true ); } } return rtrim( $slug, '-' ); } /** * Add tags to a post. * * @see wp_set_post_tags() * * @since 2.3.0 * * @param int $post_id Optional. The Post ID. Does not default to the ID of the global $post. * @param string|array $tags Optional. An array of tags to set for the post, or a string of tags * separated by commas. Default empty. * @return array|false|WP_Error Array of affected term IDs. WP_Error or false on failure. */ function wp_add_post_tags( $post_id = 0, $tags = '' ) { return wp_set_post_tags( $post_id, $tags, true ); } /** * Set the tags for a post. * * @since 2.3.0 * * @see wp_set_object_terms() * * @param int $post_id Optional. The Post ID. Does not default to the ID of the global $post. * @param string|array $tags Optional. An array of tags to set for the post, or a string of tags * separated by commas. Default empty. * @param bool $append Optional. If true, don't delete existing tags, just add on. If false, * replace the tags with the new tags. Default false. * @return array|false|WP_Error Array of term taxonomy IDs of affected terms. WP_Error or false on failure. */ function wp_set_post_tags( $post_id = 0, $tags = '', $append = false ) { return wp_set_post_terms( $post_id, $tags, 'post_tag', $append ); } /** * Set the terms for a post. * * @since 2.8.0 * * @see wp_set_object_terms() * * @param int $post_id Optional. The Post ID. Does not default to the ID of the global $post. * @param string|array $tags Optional. An array of terms to set for the post, or a string of terms * separated by commas. Hierarchical taxonomies must always pass IDs rather * than names so that children with the same names but different parents * aren't confused. Default empty. * @param string $taxonomy Optional. Taxonomy name. Default 'post_tag'. * @param bool $append Optional. If true, don't delete existing terms, just add on. If false, * replace the terms with the new terms. Default false. * @return array|false|WP_Error Array of term taxonomy IDs of affected terms. WP_Error or false on failure. */ function wp_set_post_terms( $post_id = 0, $tags = '', $taxonomy = 'post_tag', $append = false ) { $post_id = (int) $post_id; if ( ! $post_id ) { return false; } if ( empty( $tags ) ) { $tags = array(); } if ( ! is_array( $tags ) ) { $comma = _x( ',', 'tag delimiter' ); if ( ',' !== $comma ) { $tags = str_replace( $comma, ',', $tags ); } $tags = explode( ',', trim( $tags, " \n\t\r\0\x0B," ) ); } /* * Hierarchical taxonomies must always pass IDs rather than names so that * children with the same names but different parents aren't confused. */ if ( is_taxonomy_hierarchical( $taxonomy ) ) { $tags = array_unique( array_map( 'intval', $tags ) ); } return wp_set_object_terms( $post_id, $tags, $taxonomy, $append ); } /** * Set categories for a post. * * If no categories are provided, the default category is used. * * @since 2.1.0 * * @param int $post_ID Optional. The Post ID. Does not default to the ID * of the global $post. Default 0. * @param int[]|int $post_categories Optional. List of category IDs, or the ID of a single category. * Default empty array. * @param bool $append If true, don't delete existing categories, just add on. * If false, replace the categories with the new categories. * @return array|false|WP_Error Array of term taxonomy IDs of affected categories. WP_Error or false on failure. */ function wp_set_post_categories( $post_ID = 0, $post_categories = array(), $append = false ) { $post_ID = (int) $post_ID; $post_type = get_post_type( $post_ID ); $post_status = get_post_status( $post_ID ); // If $post_categories isn't already an array, make it one. $post_categories = (array) $post_categories; if ( empty( $post_categories ) ) { /** * Filters post types (in addition to 'post') that require a default category. * * @since 5.5.0 * * @param string[] $post_types An array of post type names. Default empty array. */ $default_category_post_types = apply_filters( 'default_category_post_types', array() ); // Regular posts always require a default category. $default_category_post_types = array_merge( $default_category_post_types, array( 'post' ) ); if ( in_array( $post_type, $default_category_post_types, true ) && is_object_in_taxonomy( $post_type, 'category' ) && 'auto-draft' !== $post_status ) { $post_categories = array( get_option( 'default_category' ) ); $append = false; } else { $post_categories = array(); } } elseif ( 1 === count( $post_categories ) && '' === reset( $post_categories ) ) { return true; } return wp_set_post_terms( $post_ID, $post_categories, 'category', $append ); } /** * Fires actions related to the transitioning of a post's status. * * When a post is saved, the post status is "transitioned" from one status to another, * though this does not always mean the status has actually changed before and after * the save. This function fires a number of action hooks related to that transition: * the generic {@see 'transition_post_status'} action, as well as the dynamic hooks * {@see '$old_status_to_$new_status'} and {@see '$new_status_$post->post_type'}. Note * that the function does not transition the post object in the database. * * For instance: When publishing a post for the first time, the post status may transition * from 'draft' – or some other status – to 'publish'. However, if a post is already * published and is simply being updated, the "old" and "new" statuses may both be 'publish' * before and after the transition. * * @since 2.3.0 * * @param string $new_status Transition to this post status. * @param string $old_status Previous post status. * @param WP_Post $post Post data. */ function wp_transition_post_status( $new_status, $old_status, $post ) { /** * Fires when a post is transitioned from one status to another. * * @since 2.3.0 * * @param string $new_status New post status. * @param string $old_status Old post status. * @param WP_Post $post Post object. */ do_action( 'transition_post_status', $new_status, $old_status, $post ); /** * Fires when a post is transitioned from one status to another. * * The dynamic portions of the hook name, `$new_status` and `$old_status`, * refer to the old and new post statuses, respectively. * * Possible hook names include: * * - `draft_to_publish` * - `publish_to_trash` * - `pending_to_draft` * * @since 2.3.0 * * @param WP_Post $post Post object. */ do_action( "{$old_status}_to_{$new_status}", $post ); /** * Fires when a post is transitioned from one status to another. * * The dynamic portions of the hook name, `$new_status` and `$post->post_type`, * refer to the new post status and post type, respectively. * * Possible hook names include: * * - `draft_post` * - `future_post` * - `pending_post` * - `private_post` * - `publish_post` * - `trash_post` * - `draft_page` * - `future_page` * - `pending_page` * - `private_page` * - `publish_page` * - `trash_page` * - `publish_attachment` * - `trash_attachment` * * Please note: When this action is hooked using a particular post status (like * 'publish', as `publish_{$post->post_type}`), it will fire both when a post is * first transitioned to that status from something else, as well as upon * subsequent post updates (old and new status are both the same). * * Therefore, if you are looking to only fire a callback when a post is first * transitioned to a status, use the {@see 'transition_post_status'} hook instead. * * @since 2.3.0 * @since 5.9.0 Added `$old_status` parameter. * * @param int $post_id Post ID. * @param WP_Post $post Post object. * @param string $old_status Old post status. */ do_action( "{$new_status}_{$post->post_type}", $post->ID, $post, $old_status ); } /** * Fires actions after a post, its terms and meta data has been saved. * * @since 5.6.0 * * @param int|WP_Post $post The post ID or object that has been saved. * @param bool $update Whether this is an existing post being updated. * @param null|WP_Post $post_before Null for new posts, the WP_Post object prior * to the update for updated posts. */ function wp_after_insert_post( $post, $update, $post_before ) { $post = get_post( $post ); if ( ! $post ) { return; } $post_id = $post->ID; /** * Fires once a post, its terms and meta data has been saved. * * @since 5.6.0 * * @param int $post_id Post ID. * @param WP_Post $post Post object. * @param bool $update Whether this is an existing post being updated. * @param null|WP_Post $post_before Null for new posts, the WP_Post object prior * to the update for updated posts. */ do_action( 'wp_after_insert_post', $post_id, $post, $update, $post_before ); } // // Comment, trackback, and pingback functions. // /** * Add a URL to those already pinged. * * @since 1.5.0 * @since 4.7.0 `$post_id` can be a WP_Post object. * @since 4.7.0 `$uri` can be an array of URIs. * * @global wpdb $wpdb WordPress database abstraction object. * * @param int|WP_Post $post_id Post object or ID. * @param string|array $uri Ping URI or array of URIs. * @return int|false How many rows were updated. */ function add_ping( $post_id, $uri ) { global $wpdb; $post = get_post( $post_id ); if ( ! $post ) { return false; } $pung = trim( $post->pinged ); $pung = preg_split( '/\s/', $pung ); if ( is_array( $uri ) ) { $pung = array_merge( $pung, $uri ); } else { $pung[] = $uri; } $new = implode( "\n", $pung ); /** * Filters the new ping URL to add for the given post. * * @since 2.0.0 * * @param string $new New ping URL to add. */ $new = apply_filters( 'add_ping', $new ); $return = $wpdb->update( $wpdb->posts, array( 'pinged' => $new ), array( 'ID' => $post->ID ) ); clean_post_cache( $post->ID ); return $return; } /** * Retrieve enclosures already enclosed for a post. * * @since 1.5.0 * * @param int $post_id Post ID. * @return string[] Array of enclosures for the given post. */ function get_enclosed( $post_id ) { $custom_fields = get_post_custom( $post_id ); $pung = array(); if ( ! is_array( $custom_fields ) ) { return $pung; } foreach ( $custom_fields as $key => $val ) { if ( 'enclosure' !== $key || ! is_array( $val ) ) { continue; } foreach ( $val as $enc ) { $enclosure = explode( "\n", $enc ); $pung[] = trim( $enclosure[0] ); } } /** * Filters the list of enclosures already enclosed for the given post. * * @since 2.0.0 * * @param string[] $pung Array of enclosures for the given post. * @param int $post_id Post ID. */ return apply_filters( 'get_enclosed', $pung, $post_id ); } /** * Retrieve URLs already pinged for a post. * * @since 1.5.0 * * @since 4.7.0 `$post_id` can be a WP_Post object. * * @param int|WP_Post $post_id Post ID or object. * @return string[]|false Array of URLs already pinged for the given post, false if the post is not found. */ function get_pung( $post_id ) { $post = get_post( $post_id ); if ( ! $post ) { return false; } $pung = trim( $post->pinged ); $pung = preg_split( '/\s/', $pung ); /** * Filters the list of already-pinged URLs for the given post. * * @since 2.0.0 * * @param string[] $pung Array of URLs already pinged for the given post. */ return apply_filters( 'get_pung', $pung ); } /** * Retrieve URLs that need to be pinged. * * @since 1.5.0 * @since 4.7.0 `$post_id` can be a WP_Post object. * * @param int|WP_Post $post_id Post Object or ID * @return string[]|false List of URLs yet to ping. */ function get_to_ping( $post_id ) { $post = get_post( $post_id ); if ( ! $post ) { return false; } $to_ping = sanitize_trackback_urls( $post->to_ping ); $to_ping = preg_split( '/\s/', $to_ping, -1, PREG_SPLIT_NO_EMPTY ); /** * Filters the list of URLs yet to ping for the given post. * * @since 2.0.0 * * @param string[] $to_ping List of URLs yet to ping. */ return apply_filters( 'get_to_ping', $to_ping ); } /** * Do trackbacks for a list of URLs. * * @since 1.0.0 * * @param string $tb_list Comma separated list of URLs. * @param int $post_id Post ID. */ function trackback_url_list( $tb_list, $post_id ) { if ( ! empty( $tb_list ) ) { // Get post data. $postdata = get_post( $post_id, ARRAY_A ); // Form an excerpt. $excerpt = strip_tags( $postdata['post_excerpt'] ? $postdata['post_excerpt'] : $postdata['post_content'] ); if ( strlen( $excerpt ) > 255 ) { $excerpt = substr( $excerpt, 0, 252 ) . '…'; } $trackback_urls = explode( ',', $tb_list ); foreach ( (array) $trackback_urls as $tb_url ) { $tb_url = trim( $tb_url ); trackback( $tb_url, wp_unslash( $postdata['post_title'] ), $excerpt, $post_id ); } } } // // Page functions. // /** * Get a list of page IDs. * * @since 2.0.0 * * @global wpdb $wpdb WordPress database abstraction object. * * @return string[] List of page IDs as strings. */ function get_all_page_ids() { global $wpdb; $page_ids = wp_cache_get( 'all_page_ids', 'posts' ); if ( ! is_array( $page_ids ) ) { $page_ids = $wpdb->get_col( "SELECT ID FROM $wpdb->posts WHERE post_type = 'page'" ); wp_cache_add( 'all_page_ids', $page_ids, 'posts' ); } return $page_ids; } /** * Retrieves page data given a page ID or page object. * * Use get_post() instead of get_page(). * * @since 1.5.1 * @deprecated 3.5.0 Use get_post() * * @param int|WP_Post $page Page object or page ID. Passed by reference. * @param string $output Optional. The required return type. One of OBJECT, ARRAY_A, or ARRAY_N, which * correspond to a WP_Post object, an associative array, or a numeric array, * respectively. Default OBJECT. * @param string $filter Optional. How the return value should be filtered. Accepts 'raw', * 'edit', 'db', 'display'. Default 'raw'. * @return WP_Post|array|null WP_Post or array on success, null on failure. */ function get_page( $page, $output = OBJECT, $filter = 'raw' ) { return get_post( $page, $output, $filter ); } /** * Retrieves a page given its path. * * @since 2.1.0 * * @global wpdb $wpdb WordPress database abstraction object. * * @param string $page_path Page path. * @param string $output Optional. The required return type. One of OBJECT, ARRAY_A, or ARRAY_N, which * correspond to a WP_Post object, an associative array, or a numeric array, * respectively. Default OBJECT. * @param string|array $post_type Optional. Post type or array of post types. Default 'page'. * @return WP_Post|array|null WP_Post (or array) on success, or null on failure. */ function get_page_by_path( $page_path, $output = OBJECT, $post_type = 'page' ) { global $wpdb; $last_changed = wp_cache_get_last_changed( 'posts' ); $hash = md5( $page_path . serialize( $post_type ) ); $cache_key = "get_page_by_path:$hash:$last_changed"; $cached = wp_cache_get( $cache_key, 'posts' ); if ( false !== $cached ) { // Special case: '0' is a bad `$page_path`. if ( '0' === $cached || 0 === $cached ) { return; } else { return get_post( $cached, $output ); } } $page_path = rawurlencode( urldecode( $page_path ) ); $page_path = str_replace( '%2F', '/', $page_path ); $page_path = str_replace( '%20', ' ', $page_path ); $parts = explode( '/', trim( $page_path, '/' ) ); $parts = array_map( 'sanitize_title_for_query', $parts ); $escaped_parts = esc_sql( $parts ); $in_string = "'" . implode( "','", $escaped_parts ) . "'"; if ( is_array( $post_type ) ) { $post_types = $post_type; } else { $post_types = array( $post_type, 'attachment' ); } $post_types = esc_sql( $post_types ); $post_type_in_string = "'" . implode( "','", $post_types ) . "'"; $sql = " SELECT ID, post_name, post_parent, post_type FROM $wpdb->posts WHERE post_name IN ($in_string) AND post_type IN ($post_type_in_string) "; $pages = $wpdb->get_results( $sql, OBJECT_K ); $revparts = array_reverse( $parts ); $foundid = 0; foreach ( (array) $pages as $page ) { if ( $page->post_name == $revparts[0] ) { $count = 0; $p = $page; /* * Loop through the given path parts from right to left, * ensuring each matches the post ancestry. */ while ( 0 != $p->post_parent && isset( $pages[ $p->post_parent ] ) ) { $count++; $parent = $pages[ $p->post_parent ]; if ( ! isset( $revparts[ $count ] ) || $parent->post_name != $revparts[ $count ] ) { break; } $p = $parent; } if ( 0 == $p->post_parent && count( $revparts ) == $count + 1 && $p->post_name == $revparts[ $count ] ) { $foundid = $page->ID; if ( $page->post_type == $post_type ) { break; } } } } // We cache misses as well as hits. wp_cache_set( $cache_key, $foundid, 'posts' ); if ( $foundid ) { return get_post( $foundid, $output ); } return null; } /** * Retrieve a page given its title. * * If more than one post uses the same title, the post with the smallest ID will be returned. * Be careful: in case of more than one post having the same title, it will check the oldest * publication date, not the smallest ID. * * Because this function uses the MySQL '=' comparison, $page_title will usually be matched * as case-insensitive with default collation. * * @since 2.1.0 * @since 3.0.0 The `$post_type` parameter was added. * * @global wpdb $wpdb WordPress database abstraction object. * * @param string $page_title Page title. * @param string $output Optional. The required return type. One of OBJECT, ARRAY_A, or ARRAY_N, which * correspond to a WP_Post object, an associative array, or a numeric array, * respectively. Default OBJECT. * @param string|array $post_type Optional. Post type or array of post types. Default 'page'. * @return WP_Post|array|null WP_Post (or array) on success, or null on failure. */ function get_page_by_title( $page_title, $output = OBJECT, $post_type = 'page' ) { global $wpdb; if ( is_array( $post_type ) ) { $post_type = esc_sql( $post_type ); $post_type_in_string = "'" . implode( "','", $post_type ) . "'"; $sql = $wpdb->prepare( " SELECT ID FROM $wpdb->posts WHERE post_title = %s AND post_type IN ($post_type_in_string) ", $page_title ); } else { $sql = $wpdb->prepare( " SELECT ID FROM $wpdb->posts WHERE post_title = %s AND post_type = %s ", $page_title, $post_type ); } $page = $wpdb->get_var( $sql ); if ( $page ) { return get_post( $page, $output ); } return null; } /** * Identify descendants of a given page ID in a list of page objects. * * Descendants are identified from the `$pages` array passed to the function. No database queries are performed. * * @since 1.5.1 * * @param int $page_id Page ID. * @param array $pages List of page objects from which descendants should be identified. * @return array List of page children. */ function get_page_children( $page_id, $pages ) { // Build a hash of ID -> children. $children = array(); foreach ( (array) $pages as $page ) { $children[ (int) $page->post_parent ][] = $page; } $page_list = array(); // Start the search by looking at immediate children. if ( isset( $children[ $page_id ] ) ) { // Always start at the end of the stack in order to preserve original `$pages` order. $to_look = array_reverse( $children[ $page_id ] ); while ( $to_look ) { $p = array_pop( $to_look ); $page_list[] = $p; if ( isset( $children[ $p->ID ] ) ) { foreach ( array_reverse( $children[ $p->ID ] ) as $child ) { // Append to the `$to_look` stack to descend the tree. $to_look[] = $child; } } } } return $page_list; } /** * Order the pages with children under parents in a flat list. * * It uses auxiliary structure to hold parent-children relationships and * runs in O(N) complexity * * @since 2.0.0 * * @param WP_Post[] $pages Posts array (passed by reference). * @param int $page_id Optional. Parent page ID. Default 0. * @return string[] Array of post names keyed by ID and arranged by hierarchy. Children immediately follow their parents. */ function get_page_hierarchy( &$pages, $page_id = 0 ) { if ( empty( $pages ) ) { return array(); } $children = array(); foreach ( (array) $pages as $p ) { $parent_id = (int) $p->post_parent; $children[ $parent_id ][] = $p; } $result = array(); _page_traverse_name( $page_id, $children, $result ); return $result; } /** * Traverse and return all the nested children post names of a root page. * * $children contains parent-children relations * * @since 2.9.0 * @access private * * @see _page_traverse_name() * * @param int $page_id Page ID. * @param array $children Parent-children relations (passed by reference). * @param string[] $result Array of page names keyed by ID (passed by reference). */ function _page_traverse_name( $page_id, &$children, &$result ) { if ( isset( $children[ $page_id ] ) ) { foreach ( (array) $children[ $page_id ] as $child ) { $result[ $child->ID ] = $child->post_name; _page_traverse_name( $child->ID, $children, $result ); } } } /** * Build the URI path for a page. * * Sub pages will be in the "directory" under the parent page post name. * * @since 1.5.0 * @since 4.6.0 The `$page` parameter was made optional. * * @param WP_Post|object|int $page Optional. Page ID or WP_Post object. Default is global $post. * @return string|false Page URI, false on error. */ function get_page_uri( $page = 0 ) { if ( ! $page instanceof WP_Post ) { $page = get_post( $page ); } if ( ! $page ) { return false; } $uri = $page->post_name; foreach ( $page->ancestors as $parent ) { $parent = get_post( $parent ); if ( $parent && $parent->post_name ) { $uri = $parent->post_name . '/' . $uri; } } /** * Filters the URI for a page. * * @since 4.4.0 * * @param string $uri Page URI. * @param WP_Post $page Page object. */ return apply_filters( 'get_page_uri', $uri, $page ); } /** * Retrieve an array of pages (or hierarchical post type items). * * @global wpdb $wpdb WordPress database abstraction object. * * @since 1.5.0 * * @param array|string $args { * Optional. Array or string of arguments to retrieve pages. * * @type int $child_of Page ID to return child and grandchild pages of. Note: The value * of `$hierarchical` has no bearing on whether `$child_of` returns * hierarchical results. Default 0, or no restriction. * @type string $sort_order How to sort retrieved pages. Accepts 'ASC', 'DESC'. Default 'ASC'. * @type string $sort_column What columns to sort pages by, comma-separated. Accepts 'post_author', * 'post_date', 'post_title', 'post_name', 'post_modified', 'menu_order', * 'post_modified_gmt', 'post_parent', 'ID', 'rand', 'comment_count'. * 'post_' can be omitted for any values that start with it. * Default 'post_title'. * @type bool $hierarchical Whether to return pages hierarchically. If false in conjunction with * `$child_of` also being false, both arguments will be disregarded. * Default true. * @type int[] $exclude Array of page IDs to exclude. Default empty array. * @type int[] $include Array of page IDs to include. Cannot be used with `$child_of`, * `$parent`, `$exclude`, `$meta_key`, `$meta_value`, or `$hierarchical`. * Default empty array. * @type string $meta_key Only include pages with this meta key. Default empty. * @type string $meta_value Only include pages with this meta value. Requires `$meta_key`. * Default empty. * @type string $authors A comma-separated list of author IDs. Default empty. * @type int $parent Page ID to return direct children of. Default -1, or no restriction. * @type string|int[] $exclude_tree Comma-separated string or array of page IDs to exclude. * Default empty array. * @type int $number The number of pages to return. Default 0, or all pages. * @type int $offset The number of pages to skip before returning. Requires `$number`. * Default 0. * @type string $post_type The post type to query. Default 'page'. * @type string|array $post_status A comma-separated list or array of post statuses to include. * Default 'publish'. * } * @return WP_Post[]|int[]|false Array of pages (or hierarchical post type items). Boolean false if the * specified post type is not hierarchical or the specified status is not * supported by the post type. */ function get_pages( $args = array() ) { global $wpdb; $defaults = array( 'child_of' => 0, 'sort_order' => 'ASC', 'sort_column' => 'post_title', 'hierarchical' => 1, 'exclude' => array(), 'include' => array(), 'meta_key' => '', 'meta_value' => '', 'authors' => '', 'parent' => -1, 'exclude_tree' => array(), 'number' => '', 'offset' => 0, 'post_type' => 'page', 'post_status' => 'publish', ); $parsed_args = wp_parse_args( $args, $defaults ); $number = (int) $parsed_args['number']; $offset = (int) $parsed_args['offset']; $child_of = (int) $parsed_args['child_of']; $hierarchical = $parsed_args['hierarchical']; $exclude = $parsed_args['exclude']; $meta_key = $parsed_args['meta_key']; $meta_value = $parsed_args['meta_value']; $parent = $parsed_args['parent']; $post_status = $parsed_args['post_status']; // Make sure the post type is hierarchical. $hierarchical_post_types = get_post_types( array( 'hierarchical' => true ) ); if ( ! in_array( $parsed_args['post_type'], $hierarchical_post_types, true ) ) { return false; } if ( $parent > 0 && ! $child_of ) { $hierarchical = false; } // Make sure we have a valid post status. if ( ! is_array( $post_status ) ) { $post_status = explode( ',', $post_status ); } if ( array_diff( $post_status, get_post_stati() ) ) { return false; } // $args can be whatever, only use the args defined in defaults to compute the key. $key = md5( serialize( wp_array_slice_assoc( $parsed_args, array_keys( $defaults ) ) ) ); $last_changed = wp_cache_get_last_changed( 'posts' ); $cache_key = "get_pages:$key:$last_changed"; $cache = wp_cache_get( $cache_key, 'posts' ); if ( false !== $cache ) { _prime_post_caches( $cache, false, false ); // Convert to WP_Post instances. $pages = array_map( 'get_post', $cache ); /** This filter is documented in wp-includes/post.php */ $pages = apply_filters( 'get_pages', $pages, $parsed_args ); return $pages; } $inclusions = ''; if ( ! empty( $parsed_args['include'] ) ) { $child_of = 0; // Ignore child_of, parent, exclude, meta_key, and meta_value params if using include. $parent = -1; $exclude = ''; $meta_key = ''; $meta_value = ''; $hierarchical = false; $incpages = wp_parse_id_list( $parsed_args['include'] ); if ( ! empty( $incpages ) ) { $inclusions = ' AND ID IN (' . implode( ',', $incpages ) . ')'; } } $exclusions = ''; if ( ! empty( $exclude ) ) { $expages = wp_parse_id_list( $exclude ); if ( ! empty( $expages ) ) { $exclusions = ' AND ID NOT IN (' . implode( ',', $expages ) . ')'; } } $author_query = ''; if ( ! empty( $parsed_args['authors'] ) ) { $post_authors = wp_parse_list( $parsed_args['authors'] ); if ( ! empty( $post_authors ) ) { foreach ( $post_authors as $post_author ) { // Do we have an author id or an author login? if ( 0 == (int) $post_author ) { $post_author = get_user_by( 'login', $post_author ); if ( empty( $post_author ) ) { continue; } if ( empty( $post_author->ID ) ) { continue; } $post_author = $post_author->ID; } if ( '' === $author_query ) { $author_query = $wpdb->prepare( ' post_author = %d ', $post_author ); } else { $author_query .= $wpdb->prepare( ' OR post_author = %d ', $post_author ); } } if ( '' !== $author_query ) { $author_query = " AND ($author_query)"; } } } $join = ''; $where = "$exclusions $inclusions "; if ( '' !== $meta_key || '' !== $meta_value ) { $join = " LEFT JOIN $wpdb->postmeta ON ( $wpdb->posts.ID = $wpdb->postmeta.post_id )"; // meta_key and meta_value might be slashed. $meta_key = wp_unslash( $meta_key ); $meta_value = wp_unslash( $meta_value ); if ( '' !== $meta_key ) { $where .= $wpdb->prepare( " AND $wpdb->postmeta.meta_key = %s", $meta_key ); } if ( '' !== $meta_value ) { $where .= $wpdb->prepare( " AND $wpdb->postmeta.meta_value = %s", $meta_value ); } } if ( is_array( $parent ) ) { $post_parent__in = implode( ',', array_map( 'absint', (array) $parent ) ); if ( ! empty( $post_parent__in ) ) { $where .= " AND post_parent IN ($post_parent__in)"; } } elseif ( $parent >= 0 ) { $where .= $wpdb->prepare( ' AND post_parent = %d ', $parent ); } if ( 1 === count( $post_status ) ) { $where_post_type = $wpdb->prepare( 'post_type = %s AND post_status = %s', $parsed_args['post_type'], reset( $post_status ) ); } else { $post_status = implode( "', '", $post_status ); $where_post_type = $wpdb->prepare( "post_type = %s AND post_status IN ('$post_status')", $parsed_args['post_type'] ); } $orderby_array = array(); $allowed_keys = array( 'author', 'post_author', 'date', 'post_date', 'title', 'post_title', 'name', 'post_name', 'modified', 'post_modified', 'modified_gmt', 'post_modified_gmt', 'menu_order', 'parent', 'post_parent', 'ID', 'rand', 'comment_count', ); foreach ( explode( ',', $parsed_args['sort_column'] ) as $orderby ) { $orderby = trim( $orderby ); if ( ! in_array( $orderby, $allowed_keys, true ) ) { continue; } switch ( $orderby ) { case 'menu_order': break; case 'ID': $orderby = "$wpdb->posts.ID"; break; case 'rand': $orderby = 'RAND()'; break; case 'comment_count': $orderby = "$wpdb->posts.comment_count"; break; default: if ( 0 === strpos( $orderby, 'post_' ) ) { $orderby = "$wpdb->posts." . $orderby; } else { $orderby = "$wpdb->posts.post_" . $orderby; } } $orderby_array[] = $orderby; } $sort_column = ! empty( $orderby_array ) ? implode( ',', $orderby_array ) : "$wpdb->posts.post_title"; $sort_order = strtoupper( $parsed_args['sort_order'] ); if ( '' !== $sort_order && ! in_array( $sort_order, array( 'ASC', 'DESC' ), true ) ) { $sort_order = 'ASC'; } $query = "SELECT * FROM $wpdb->posts $join WHERE ($where_post_type) $where "; $query .= $author_query; $query .= ' ORDER BY ' . $sort_column . ' ' . $sort_order; if ( ! empty( $number ) ) { $query .= ' LIMIT ' . $offset . ',' . $number; } $pages = $wpdb->get_results( $query ); if ( empty( $pages ) ) { wp_cache_set( $cache_key, array(), 'posts' ); /** This filter is documented in wp-includes/post.php */ $pages = apply_filters( 'get_pages', array(), $parsed_args ); return $pages; } // Sanitize before caching so it'll only get done once. $num_pages = count( $pages ); for ( $i = 0; $i < $num_pages; $i++ ) { $pages[ $i ] = sanitize_post( $pages[ $i ], 'raw' ); } // Update cache. update_post_cache( $pages ); if ( $child_of || $hierarchical ) { $pages = get_page_children( $child_of, $pages ); } if ( ! empty( $parsed_args['exclude_tree'] ) ) { $exclude = wp_parse_id_list( $parsed_args['exclude_tree'] ); foreach ( $exclude as $id ) { $children = get_page_children( $id, $pages ); foreach ( $children as $child ) { $exclude[] = $child->ID; } } $num_pages = count( $pages ); for ( $i = 0; $i < $num_pages; $i++ ) { if ( in_array( $pages[ $i ]->ID, $exclude, true ) ) { unset( $pages[ $i ] ); } } } $page_structure = array(); foreach ( $pages as $page ) { $page_structure[] = $page->ID; } wp_cache_set( $cache_key, $page_structure, 'posts' ); // Convert to WP_Post instances. $pages = array_map( 'get_post', $pages ); /** * Filters the retrieved list of pages. * * @since 2.1.0 * * @param WP_Post[] $pages Array of page objects. * @param array $parsed_args Array of get_pages() arguments. */ return apply_filters( 'get_pages', $pages, $parsed_args ); } // // Attachment functions. // /** * Determines whether an attachment URI is local and really an attachment. * * For more information on this and similar theme functions, check out * the {@link https://developer.wordpress.org/themes/basics/conditional-tags/ * Conditional Tags} article in the Theme Developer Handbook. * * @since 2.0.0 * * @param string $url URL to check * @return bool True on success, false on failure. */ function is_local_attachment( $url ) { if ( strpos( $url, home_url() ) === false ) { return false; } if ( strpos( $url, home_url( '/?attachment_id=' ) ) !== false ) { return true; } $id = url_to_postid( $url ); if ( $id ) { $post = get_post( $id ); if ( 'attachment' === $post->post_type ) { return true; } } return false; } /** * Insert an attachment. * * If you set the 'ID' in the $args parameter, it will mean that you are * updating and attempt to update the attachment. You can also set the * attachment name or title by setting the key 'post_name' or 'post_title'. * * You can set the dates for the attachment manually by setting the 'post_date' * and 'post_date_gmt' keys' values. * * By default, the comments will use the default settings for whether the * comments are allowed. You can close them manually or keep them open by * setting the value for the 'comment_status' key. * * @since 2.0.0 * @since 4.7.0 Added the `$wp_error` parameter to allow a WP_Error to be returned on failure. * @since 5.6.0 Added the `$fire_after_hooks` parameter. * * @see wp_insert_post() * * @param string|array $args Arguments for inserting an attachment. * @param string|false $file Optional. Filename. * @param int $parent Optional. Parent post ID. * @param bool $wp_error Optional. Whether to return a WP_Error on failure. Default false. * @param bool $fire_after_hooks Optional. Whether to fire the after insert hooks. Default true. * @return int|WP_Error The attachment ID on success. The value 0 or WP_Error on failure. */ function wp_insert_attachment( $args, $file = false, $parent = 0, $wp_error = false, $fire_after_hooks = true ) { $defaults = array( 'file' => $file, 'post_parent' => 0, ); $data = wp_parse_args( $args, $defaults ); if ( ! empty( $parent ) ) { $data['post_parent'] = $parent; } $data['post_type'] = 'attachment'; return wp_insert_post( $data, $wp_error, $fire_after_hooks ); } /** * Trash or delete an attachment. * * When an attachment is permanently deleted, the file will also be removed. * Deletion removes all post meta fields, taxonomy, comments, etc. associated * with the attachment (except the main post). * * The attachment is moved to the Trash instead of permanently deleted unless Trash * for media is disabled, item is already in the Trash, or $force_delete is true. * * @since 2.0.0 * * @global wpdb $wpdb WordPress database abstraction object. * * @param int $post_id Attachment ID. * @param bool $force_delete Optional. Whether to bypass Trash and force deletion. * Default false. * @return WP_Post|false|null Post data on success, false or null on failure. */ function wp_delete_attachment( $post_id, $force_delete = false ) { global $wpdb; $post = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $wpdb->posts WHERE ID = %d", $post_id ) ); if ( ! $post ) { return $post; } $post = get_post( $post ); if ( 'attachment' !== $post->post_type ) { return false; } if ( ! $force_delete && EMPTY_TRASH_DAYS && MEDIA_TRASH && 'trash' !== $post->post_status ) { return wp_trash_post( $post_id ); } /** * Filters whether an attachment deletion should take place. * * @since 5.5.0 * * @param WP_Post|false|null $delete Whether to go forward with deletion. @TODO description * @param WP_Post $post Post object. * @param bool $force_delete Whether to bypass the Trash. */ $check = apply_filters( 'pre_delete_attachment', null, $post, $force_delete ); if ( null !== $check ) { return $check; } delete_post_meta( $post_id, '_wp_trash_meta_status' ); delete_post_meta( $post_id, '_wp_trash_meta_time' ); $meta = wp_get_attachment_metadata( $post_id ); $backup_sizes = get_post_meta( $post->ID, '_wp_attachment_backup_sizes', true ); $file = get_attached_file( $post_id ); if ( is_multisite() && is_string( $file ) && ! empty( $file ) ) { clean_dirsize_cache( $file ); } /** * Fires before an attachment is deleted, at the start of wp_delete_attachment(). * * @since 2.0.0 * @since 5.5.0 Added the `$post` parameter. * * @param int $post_id Attachment ID. * @param WP_Post $post Post object. */ do_action( 'delete_attachment', $post_id, $post ); wp_delete_object_term_relationships( $post_id, array( 'category', 'post_tag' ) ); wp_delete_object_term_relationships( $post_id, get_object_taxonomies( $post->post_type ) ); // Delete all for any posts. delete_metadata( 'post', null, '_thumbnail_id', $post_id, true ); wp_defer_comment_counting( true ); $comment_ids = $wpdb->get_col( $wpdb->prepare( "SELECT comment_ID FROM $wpdb->comments WHERE comment_post_ID = %d ORDER BY comment_ID DESC", $post_id ) ); foreach ( $comment_ids as $comment_id ) { wp_delete_comment( $comment_id, true ); } wp_defer_comment_counting( false ); $post_meta_ids = $wpdb->get_col( $wpdb->prepare( "SELECT meta_id FROM $wpdb->postmeta WHERE post_id = %d ", $post_id ) ); foreach ( $post_meta_ids as $mid ) { delete_metadata_by_mid( 'post', $mid ); } /** This action is documented in wp-includes/post.php */ do_action( 'delete_post', $post_id, $post ); $result = $wpdb->delete( $wpdb->posts, array( 'ID' => $post_id ) ); if ( ! $result ) { return false; } /** This action is documented in wp-includes/post.php */ do_action( 'deleted_post', $post_id, $post ); wp_delete_attachment_files( $post_id, $meta, $backup_sizes, $file ); clean_post_cache( $post ); return $post; } /** * Deletes all files that belong to the given attachment. * * @since 4.9.7 * * @global wpdb $wpdb WordPress database abstraction object. * * @param int $post_id Attachment ID. * @param array $meta The attachment's meta data. * @param array $backup_sizes The meta data for the attachment's backup images. * @param string $file Absolute path to the attachment's file. * @return bool True on success, false on failure. */ function wp_delete_attachment_files( $post_id, $meta, $backup_sizes, $file ) { global $wpdb; $uploadpath = wp_get_upload_dir(); $deleted = true; if ( ! empty( $meta['thumb'] ) ) { // Don't delete the thumb if another attachment uses it. if ( ! $wpdb->get_row( $wpdb->prepare( "SELECT meta_id FROM $wpdb->postmeta WHERE meta_key = '_wp_attachment_metadata' AND meta_value LIKE %s AND post_id <> %d", '%' . $wpdb->esc_like( $meta['thumb'] ) . '%', $post_id ) ) ) { $thumbfile = str_replace( wp_basename( $file ), $meta['thumb'], $file ); if ( ! empty( $thumbfile ) ) { $thumbfile = path_join( $uploadpath['basedir'], $thumbfile ); $thumbdir = path_join( $uploadpath['basedir'], dirname( $file ) ); if ( ! wp_delete_file_from_directory( $thumbfile, $thumbdir ) ) { $deleted = false; } } } } // Remove intermediate and backup images if there are any. if ( isset( $meta['sizes'] ) && is_array( $meta['sizes'] ) ) { $intermediate_dir = path_join( $uploadpath['basedir'], dirname( $file ) ); foreach ( $meta['sizes'] as $size => $sizeinfo ) { $intermediate_file = str_replace( wp_basename( $file ), $sizeinfo['file'], $file ); if ( ! empty( $intermediate_file ) ) { $intermediate_file = path_join( $uploadpath['basedir'], $intermediate_file ); if ( ! wp_delete_file_from_directory( $intermediate_file, $intermediate_dir ) ) { $deleted = false; } } } } if ( ! empty( $meta['original_image'] ) ) { if ( empty( $intermediate_dir ) ) { $intermediate_dir = path_join( $uploadpath['basedir'], dirname( $file ) ); } $original_image = str_replace( wp_basename( $file ), $meta['original_image'], $file ); if ( ! empty( $original_image ) ) { $original_image = path_join( $uploadpath['basedir'], $original_image ); if ( ! wp_delete_file_from_directory( $original_image, $intermediate_dir ) ) { $deleted = false; } } } if ( is_array( $backup_sizes ) ) { $del_dir = path_join( $uploadpath['basedir'], dirname( $meta['file'] ) ); foreach ( $backup_sizes as $size ) { $del_file = path_join( dirname( $meta['file'] ), $size['file'] ); if ( ! empty( $del_file ) ) { $del_file = path_join( $uploadpath['basedir'], $del_file ); if ( ! wp_delete_file_from_directory( $del_file, $del_dir ) ) { $deleted = false; } } } } if ( ! wp_delete_file_from_directory( $file, $uploadpath['basedir'] ) ) { $deleted = false; } return $deleted; } /** * Retrieves attachment metadata for attachment ID. * * @since 2.1.0 * * @param int $attachment_id Attachment post ID. Defaults to global $post. * @param bool $unfiltered Optional. If true, filters are not run. Default false. * @return array|false { * Attachment metadata. False on failure. * * @type int $width The width of the attachment. * @type int $height The height of the attachment. * @type string $file The file path relative to `wp-content/uploads`. * @type array $sizes Keys are size slugs, each value is an array containing * 'file', 'width', 'height', and 'mime-type'. * @type array $image_meta Image metadata. * @type int $filesize File size of the attachment. * } */ function wp_get_attachment_metadata( $attachment_id = 0, $unfiltered = false ) { $attachment_id = (int) $attachment_id; if ( ! $attachment_id ) { $post = get_post(); if ( ! $post ) { return false; } $attachment_id = $post->ID; } $data = get_post_meta( $attachment_id, '_wp_attachment_metadata', true ); if ( ! $data ) { return false; } if ( $unfiltered ) { return $data; } /** * Filters the attachment meta data. * * @since 2.1.0 * * @param array $data Array of meta data for the given attachment. * @param int $attachment_id Attachment post ID. */ return apply_filters( 'wp_get_attachment_metadata', $data, $attachment_id ); } /** * Updates metadata for an attachment. * * @since 2.1.0 * * @param int $attachment_id Attachment post ID. * @param array $data Attachment meta data. * @return int|false False if $post is invalid. */ function wp_update_attachment_metadata( $attachment_id, $data ) { $attachment_id = (int) $attachment_id; $post = get_post( $attachment_id ); if ( ! $post ) { return false; } /** * Filters the updated attachment meta data. * * @since 2.1.0 * * @param array $data Array of updated attachment meta data. * @param int $attachment_id Attachment post ID. */ $data = apply_filters( 'wp_update_attachment_metadata', $data, $post->ID ); if ( $data ) { return update_post_meta( $post->ID, '_wp_attachment_metadata', $data ); } else { return delete_post_meta( $post->ID, '_wp_attachment_metadata' ); } } /** * Retrieve the URL for an attachment. * * @since 2.1.0 * * @global string $pagenow The filename of the current screen. * * @param int $attachment_id Optional. Attachment post ID. Defaults to global $post. * @return string|false Attachment URL, otherwise false. */ function wp_get_attachment_url( $attachment_id = 0 ) { global $pagenow; $attachment_id = (int) $attachment_id; $post = get_post( $attachment_id ); if ( ! $post ) { return false; } if ( 'attachment' !== $post->post_type ) { return false; } $url = ''; // Get attached file. $file = get_post_meta( $post->ID, '_wp_attached_file', true ); if ( $file ) { // Get upload directory. $uploads = wp_get_upload_dir(); if ( $uploads && false === $uploads['error'] ) { // Check that the upload base exists in the file location. if ( 0 === strpos( $file, $uploads['basedir'] ) ) { // Replace file location with url location. $url = str_replace( $uploads['basedir'], $uploads['baseurl'], $file ); } elseif ( false !== strpos( $file, 'wp-content/uploads' ) ) { // Get the directory name relative to the basedir (back compat for pre-2.7 uploads). $url = trailingslashit( $uploads['baseurl'] . '/' . _wp_get_attachment_relative_path( $file ) ) . wp_basename( $file ); } else { // It's a newly-uploaded file, therefore $file is relative to the basedir. $url = $uploads['baseurl'] . "/$file"; } } } /* * If any of the above options failed, Fallback on the GUID as used pre-2.7, * not recommended to rely upon this. */ if ( ! $url ) { $url = get_the_guid( $post->ID ); } // On SSL front end, URLs should be HTTPS. if ( is_ssl() && ! is_admin() && 'wp-login.php' !== $pagenow ) { $url = set_url_scheme( $url ); } /** * Filters the attachment URL. * * @since 2.1.0 * * @param string $url URL for the given attachment. * @param int $attachment_id Attachment post ID. */ $url = apply_filters( 'wp_get_attachment_url', $url, $post->ID ); if ( ! $url ) { return false; } return $url; } /** * Retrieves the caption for an attachment. * * @since 4.6.0 * * @param int $post_id Optional. Attachment ID. Default is the ID of the global `$post`. * @return string|false Attachment caption on success, false on failure. */ function wp_get_attachment_caption( $post_id = 0 ) { $post_id = (int) $post_id; $post = get_post( $post_id ); if ( ! $post ) { return false; } if ( 'attachment' !== $post->post_type ) { return false; } $caption = $post->post_excerpt; /** * Filters the attachment caption. * * @since 4.6.0 * * @param string $caption Caption for the given attachment. * @param int $post_id Attachment ID. */ return apply_filters( 'wp_get_attachment_caption', $caption, $post->ID ); } /** * Retrieve thumbnail for an attachment. * * @since 2.1.0 * * @param int $post_id Optional. Attachment ID. Default is the ID of the global `$post`. * @return string|false Thumbnail file path on success, false on failure. */ function wp_get_attachment_thumb_file( $post_id = 0 ) { $post_id = (int) $post_id; $post = get_post( $post_id ); if ( ! $post ) { return false; } $imagedata = wp_get_attachment_metadata( $post->ID ); if ( ! is_array( $imagedata ) ) { return false; } $file = get_attached_file( $post->ID ); if ( ! empty( $imagedata['thumb'] ) ) { $thumbfile = str_replace( wp_basename( $file ), $imagedata['thumb'], $file ); if ( file_exists( $thumbfile ) ) { /** * Filters the attachment thumbnail file path. * * @since 2.1.0 * * @param string $thumbfile File path to the attachment thumbnail. * @param int $post_id Attachment ID. */ return apply_filters( 'wp_get_attachment_thumb_file', $thumbfile, $post->ID ); } } return false; } /** * Retrieve URL for an attachment thumbnail. * * @since 2.1.0 * * @param int $post_id Optional. Attachment ID. Default is the ID of the global `$post`. * @return string|false Thumbnail URL on success, false on failure. */ function wp_get_attachment_thumb_url( $post_id = 0 ) { $post_id = (int) $post_id; $post = get_post( $post_id ); if ( ! $post ) { return false; } $url = wp_get_attachment_url( $post->ID ); if ( ! $url ) { return false; } $sized = image_downsize( $post_id, 'thumbnail' ); if ( $sized ) { return $sized[0]; } $thumb = wp_get_attachment_thumb_file( $post->ID ); if ( ! $thumb ) { return false; } $url = str_replace( wp_basename( $url ), wp_basename( $thumb ), $url ); /** * Filters the attachment thumbnail URL. * * @since 2.1.0 * * @param string $url URL for the attachment thumbnail. * @param int $post_id Attachment ID. */ return apply_filters( 'wp_get_attachment_thumb_url', $url, $post->ID ); } /** * Verifies an attachment is of a given type. * * @since 4.2.0 * * @param string $type Attachment type. Accepts 'image', 'audio', or 'video'. * @param int|WP_Post $post Optional. Attachment ID or object. Default is global $post. * @return bool True if one of the accepted types, false otherwise. */ function wp_attachment_is( $type, $post = null ) { $post = get_post( $post ); if ( ! $post ) { return false; } $file = get_attached_file( $post->ID ); if ( ! $file ) { return false; } if ( 0 === strpos( $post->post_mime_type, $type . '/' ) ) { return true; } $check = wp_check_filetype( $file ); if ( empty( $check['ext'] ) ) { return false; } $ext = $check['ext']; if ( 'import' !== $post->post_mime_type ) { return $type === $ext; } switch ( $type ) { case 'image': $image_exts = array( 'jpg', 'jpeg', 'jpe', 'gif', 'png', 'webp' ); return in_array( $ext, $image_exts, true ); case 'audio': return in_array( $ext, wp_get_audio_extensions(), true ); case 'video': return in_array( $ext, wp_get_video_extensions(), true ); default: return $type === $ext; } } /** * Determines whether an attachment is an image. * * For more information on this and similar theme functions, check out * the {@link https://developer.wordpress.org/themes/basics/conditional-tags/ * Conditional Tags} article in the Theme Developer Handbook. * * @since 2.1.0 * @since 4.2.0 Modified into wrapper for wp_attachment_is() and * allowed WP_Post object to be passed. * * @param int|WP_Post $post Optional. Attachment ID or object. Default is global $post. * @return bool Whether the attachment is an image. */ function wp_attachment_is_image( $post = null ) { return wp_attachment_is( 'image', $post ); } /** * Retrieve the icon for a MIME type or attachment. * * @since 2.1.0 * * @param string|int $mime MIME type or attachment ID. * @return string|false Icon, false otherwise. */ function wp_mime_type_icon( $mime = 0 ) { if ( ! is_numeric( $mime ) ) { $icon = wp_cache_get( "mime_type_icon_$mime" ); } $post_id = 0; if ( empty( $icon ) ) { $post_mimes = array(); if ( is_numeric( $mime ) ) { $mime = (int) $mime; $post = get_post( $mime ); if ( $post ) { $post_id = (int) $post->ID; $file = get_attached_file( $post_id ); $ext = preg_replace( '/^.+?\.([^.]+)$/', '$1', $file ); if ( ! empty( $ext ) ) { $post_mimes[] = $ext; $ext_type = wp_ext2type( $ext ); if ( $ext_type ) { $post_mimes[] = $ext_type; } } $mime = $post->post_mime_type; } else { $mime = 0; } } else { $post_mimes[] = $mime; } $icon_files = wp_cache_get( 'icon_files' ); if ( ! is_array( $icon_files ) ) { /** * Filters the icon directory path. * * @since 2.0.0 * * @param string $path Icon directory absolute path. */ $icon_dir = apply_filters( 'icon_dir', ABSPATH . WPINC . '/images/media' ); /** * Filters the icon directory URI. * * @since 2.0.0 * * @param string $uri Icon directory URI. */ $icon_dir_uri = apply_filters( 'icon_dir_uri', includes_url( 'images/media' ) ); /** * Filters the array of icon directory URIs. * * @since 2.5.0 * * @param string[] $uris Array of icon directory URIs keyed by directory absolute path. */ $dirs = apply_filters( 'icon_dirs', array( $icon_dir => $icon_dir_uri ) ); $icon_files = array(); while ( $dirs ) { $keys = array_keys( $dirs ); $dir = array_shift( $keys ); $uri = array_shift( $dirs ); $dh = opendir( $dir ); if ( $dh ) { while ( false !== $file = readdir( $dh ) ) { $file = wp_basename( $file ); if ( '.' === substr( $file, 0, 1 ) ) { continue; } $ext = strtolower( substr( $file, -4 ) ); if ( ! in_array( $ext, array( '.png', '.gif', '.jpg' ), true ) ) { if ( is_dir( "$dir/$file" ) ) { $dirs[ "$dir/$file" ] = "$uri/$file"; } continue; } $icon_files[ "$dir/$file" ] = "$uri/$file"; } closedir( $dh ); } } wp_cache_add( 'icon_files', $icon_files, 'default', 600 ); } $types = array(); // Icon wp_basename - extension = MIME wildcard. foreach ( $icon_files as $file => $uri ) { $types[ preg_replace( '/^([^.]*).*$/', '$1', wp_basename( $file ) ) ] =& $icon_files[ $file ]; } if ( ! empty( $mime ) ) { $post_mimes[] = substr( $mime, 0, strpos( $mime, '/' ) ); $post_mimes[] = substr( $mime, strpos( $mime, '/' ) + 1 ); $post_mimes[] = str_replace( '/', '_', $mime ); } $matches = wp_match_mime_types( array_keys( $types ), $post_mimes ); $matches['default'] = array( 'default' ); foreach ( $matches as $match => $wilds ) { foreach ( $wilds as $wild ) { if ( ! isset( $types[ $wild ] ) ) { continue; } $icon = $types[ $wild ]; if ( ! is_numeric( $mime ) ) { wp_cache_add( "mime_type_icon_$mime", $icon ); } break 2; } } } /** * Filters the mime type icon. * * @since 2.1.0 * * @param string $icon Path to the mime type icon. * @param string $mime Mime type. * @param int $post_id Attachment ID. Will equal 0 if the function passed * the mime type. */ return apply_filters( 'wp_mime_type_icon', $icon, $mime, $post_id ); } /** * Check for changed slugs for published post objects and save the old slug. * * The function is used when a post object of any type is updated, * by comparing the current and previous post objects. * * If the slug was changed and not already part of the old slugs then it will be * added to the post meta field ('_wp_old_slug') for storing old slugs for that * post. * * The most logically usage of this function is redirecting changed post objects, so * that those that linked to an changed post will be redirected to the new post. * * @since 2.1.0 * * @param int $post_id Post ID. * @param WP_Post $post The Post Object * @param WP_Post $post_before The Previous Post Object */ function wp_check_for_changed_slugs( $post_id, $post, $post_before ) { // Don't bother if it hasn't changed. if ( $post->post_name == $post_before->post_name ) { return; } // We're only concerned with published, non-hierarchical objects. if ( ! ( 'publish' === $post->post_status || ( 'attachment' === get_post_type( $post ) && 'inherit' === $post->post_status ) ) || is_post_type_hierarchical( $post->post_type ) ) { return; } $old_slugs = (array) get_post_meta( $post_id, '_wp_old_slug' ); // If we haven't added this old slug before, add it now. if ( ! empty( $post_before->post_name ) && ! in_array( $post_before->post_name, $old_slugs, true ) ) { add_post_meta( $post_id, '_wp_old_slug', $post_before->post_name ); } // If the new slug was used previously, delete it from the list. if ( in_array( $post->post_name, $old_slugs, true ) ) { delete_post_meta( $post_id, '_wp_old_slug', $post->post_name ); } } /** * Check for changed dates for published post objects and save the old date. * * The function is used when a post object of any type is updated, * by comparing the current and previous post objects. * * If the date was changed and not already part of the old dates then it will be * added to the post meta field ('_wp_old_date') for storing old dates for that * post. * * The most logically usage of this function is redirecting changed post objects, so * that those that linked to an changed post will be redirected to the new post. * * @since 4.9.3 * * @param int $post_id Post ID. * @param WP_Post $post The Post Object * @param WP_Post $post_before The Previous Post Object */ function wp_check_for_changed_dates( $post_id, $post, $post_before ) { $previous_date = gmdate( 'Y-m-d', strtotime( $post_before->post_date ) ); $new_date = gmdate( 'Y-m-d', strtotime( $post->post_date ) ); // Don't bother if it hasn't changed. if ( $new_date == $previous_date ) { return; } // We're only concerned with published, non-hierarchical objects. if ( ! ( 'publish' === $post->post_status || ( 'attachment' === get_post_type( $post ) && 'inherit' === $post->post_status ) ) || is_post_type_hierarchical( $post->post_type ) ) { return; } $old_dates = (array) get_post_meta( $post_id, '_wp_old_date' ); // If we haven't added this old date before, add it now. if ( ! empty( $previous_date ) && ! in_array( $previous_date, $old_dates, true ) ) { add_post_meta( $post_id, '_wp_old_date', $previous_date ); } // If the new slug was used previously, delete it from the list. if ( in_array( $new_date, $old_dates, true ) ) { delete_post_meta( $post_id, '_wp_old_date', $new_date ); } } /** * Retrieve the private post SQL based on capability. * * This function provides a standardized way to appropriately select on the * post_status of a post type. The function will return a piece of SQL code * that can be added to a WHERE clause; this SQL is constructed to allow all * published posts, and all private posts to which the user has access. * * @since 2.2.0 * @since 4.3.0 Added the ability to pass an array to `$post_type`. * * @param string|array $post_type Single post type or an array of post types. Currently only supports 'post' or 'page'. * @return string SQL code that can be added to a where clause. */ function get_private_posts_cap_sql( $post_type ) { return get_posts_by_author_sql( $post_type, false ); } /** * Retrieve the post SQL based on capability, author, and type. * * @since 3.0.0 * @since 4.3.0 Introduced the ability to pass an array of post types to `$post_type`. * * @see get_private_posts_cap_sql() * @global wpdb $wpdb WordPress database abstraction object. * * @param string|string[] $post_type Single post type or an array of post types. * @param bool $full Optional. Returns a full WHERE statement instead of just * an 'andalso' term. Default true. * @param int $post_author Optional. Query posts having a single author ID. Default null. * @param bool $public_only Optional. Only return public posts. Skips cap checks for * $current_user. Default false. * @return string SQL WHERE code that can be added to a query. */ function get_posts_by_author_sql( $post_type, $full = true, $post_author = null, $public_only = false ) { global $wpdb; if ( is_array( $post_type ) ) { $post_types = $post_type; } else { $post_types = array( $post_type ); } $post_type_clauses = array(); foreach ( $post_types as $post_type ) { $post_type_obj = get_post_type_object( $post_type ); if ( ! $post_type_obj ) { continue; } /** * Filters the capability to read private posts for a custom post type * when generating SQL for getting posts by author. * * @since 2.2.0 * @deprecated 3.2.0 The hook transitioned from "somewhat useless" to "totally useless". * * @param string $cap Capability. */ $cap = apply_filters_deprecated( 'pub_priv_sql_capability', array( '' ), '3.2.0' ); if ( ! $cap ) { $cap = current_user_can( $post_type_obj->cap->read_private_posts ); } // Only need to check the cap if $public_only is false. $post_status_sql = "post_status = 'publish'"; if ( false === $public_only ) { if ( $cap ) { // Does the user have the capability to view private posts? Guess so. $post_status_sql .= " OR post_status = 'private'"; } elseif ( is_user_logged_in() ) { // Users can view their own private posts. $id = get_current_user_id(); if ( null === $post_author || ! $full ) { $post_status_sql .= " OR post_status = 'private' AND post_author = $id"; } elseif ( $id == (int) $post_author ) { $post_status_sql .= " OR post_status = 'private'"; } // Else none. } // Else none. } $post_type_clauses[] = "( post_type = '" . $post_type . "' AND ( $post_status_sql ) )"; } if ( empty( $post_type_clauses ) ) { return $full ? 'WHERE 1 = 0' : '1 = 0'; } $sql = '( ' . implode( ' OR ', $post_type_clauses ) . ' )'; if ( null !== $post_author ) { $sql .= $wpdb->prepare( ' AND post_author = %d', $post_author ); } if ( $full ) { $sql = 'WHERE ' . $sql; } return $sql; } /** * Retrieves the most recent time that a post on the site was published. * * The server timezone is the default and is the difference between GMT and * server time. The 'blog' value is the date when the last post was posted. * The 'gmt' is when the last post was posted in GMT formatted date. * * @since 0.71 * @since 4.4.0 The `$post_type` argument was added. * * @param string $timezone Optional. The timezone for the timestamp. Accepts 'server', 'blog', or 'gmt'. * 'server' uses the server's internal timezone. * 'blog' uses the `post_date` field, which proxies to the timezone set for the site. * 'gmt' uses the `post_date_gmt` field. * Default 'server'. * @param string $post_type Optional. The post type to check. Default 'any'. * @return string The date of the last post, or false on failure. */ function get_lastpostdate( $timezone = 'server', $post_type = 'any' ) { $lastpostdate = _get_last_post_time( $timezone, 'date', $post_type ); /** * Filters the most recent time that a post on the site was published. * * @since 2.3.0 * @since 5.5.0 Added the `$post_type` parameter. * * @param string|false $lastpostdate The most recent time that a post was published, * in 'Y-m-d H:i:s' format. False on failure. * @param string $timezone Location to use for getting the post published date. * See get_lastpostdate() for accepted `$timezone` values. * @param string $post_type The post type to check. */ return apply_filters( 'get_lastpostdate', $lastpostdate, $timezone, $post_type ); } /** * Get the most recent time that a post on the site was modified. * * The server timezone is the default and is the difference between GMT and * server time. The 'blog' value is just when the last post was modified. * The 'gmt' is when the last post was modified in GMT time. * * @since 1.2.0 * @since 4.4.0 The `$post_type` argument was added. * * @param string $timezone Optional. The timezone for the timestamp. See get_lastpostdate() * for information on accepted values. * Default 'server'. * @param string $post_type Optional. The post type to check. Default 'any'. * @return string The timestamp in 'Y-m-d H:i:s' format, or false on failure. */ function get_lastpostmodified( $timezone = 'server', $post_type = 'any' ) { /** * Pre-filter the return value of get_lastpostmodified() before the query is run. * * @since 4.4.0 * * @param string|false $lastpostmodified The most recent time that a post was modified, * in 'Y-m-d H:i:s' format, or false. Returning anything * other than false will short-circuit the function. * @param string $timezone Location to use for getting the post modified date. * See get_lastpostdate() for accepted `$timezone` values. * @param string $post_type The post type to check. */ $lastpostmodified = apply_filters( 'pre_get_lastpostmodified', false, $timezone, $post_type ); if ( false !== $lastpostmodified ) { return $lastpostmodified; } $lastpostmodified = _get_last_post_time( $timezone, 'modified', $post_type ); $lastpostdate = get_lastpostdate( $timezone, $post_type ); if ( $lastpostdate > $lastpostmodified ) { $lastpostmodified = $lastpostdate; } /** * Filters the most recent time that a post on the site was modified. * * @since 2.3.0 * @since 5.5.0 Added the `$post_type` parameter. * * @param string|false $lastpostmodified The most recent time that a post was modified, * in 'Y-m-d H:i:s' format. False on failure. * @param string $timezone Location to use for getting the post modified date. * See get_lastpostdate() for accepted `$timezone` values. * @param string $post_type The post type to check. */ return apply_filters( 'get_lastpostmodified', $lastpostmodified, $timezone, $post_type ); } /** * Gets the timestamp of the last time any post was modified or published. * * @since 3.1.0 * @since 4.4.0 The `$post_type` argument was added. * @access private * * @global wpdb $wpdb WordPress database abstraction object. * * @param string $timezone The timezone for the timestamp. See get_lastpostdate(). * for information on accepted values. * @param string $field Post field to check. Accepts 'date' or 'modified'. * @param string $post_type Optional. The post type to check. Default 'any'. * @return string|false The timestamp in 'Y-m-d H:i:s' format, or false on failure. */ function _get_last_post_time( $timezone, $field, $post_type = 'any' ) { global $wpdb; if ( ! in_array( $field, array( 'date', 'modified' ), true ) ) { return false; } $timezone = strtolower( $timezone ); $key = "lastpost{$field}:$timezone"; if ( 'any' !== $post_type ) { $key .= ':' . sanitize_key( $post_type ); } $date = wp_cache_get( $key, 'timeinfo' ); if ( false !== $date ) { return $date; } if ( 'any' === $post_type ) { $post_types = get_post_types( array( 'public' => true ) ); array_walk( $post_types, array( $wpdb, 'escape_by_ref' ) ); $post_types = "'" . implode( "', '", $post_types ) . "'"; } else { $post_types = "'" . sanitize_key( $post_type ) . "'"; } switch ( $timezone ) { case 'gmt': $date = $wpdb->get_var( "SELECT post_{$field}_gmt FROM $wpdb->posts WHERE post_status = 'publish' AND post_type IN ({$post_types}) ORDER BY post_{$field}_gmt DESC LIMIT 1" ); break; case 'blog': $date = $wpdb->get_var( "SELECT post_{$field} FROM $wpdb->posts WHERE post_status = 'publish' AND post_type IN ({$post_types}) ORDER BY post_{$field}_gmt DESC LIMIT 1" ); break; case 'server': $add_seconds_server = gmdate( 'Z' ); $date = $wpdb->get_var( "SELECT DATE_ADD(post_{$field}_gmt, INTERVAL '$add_seconds_server' SECOND) FROM $wpdb->posts WHERE post_status = 'publish' AND post_type IN ({$post_types}) ORDER BY post_{$field}_gmt DESC LIMIT 1" ); break; } if ( $date ) { wp_cache_set( $key, $date, 'timeinfo' ); return $date; } return false; } /** * Updates posts in cache. * * @since 1.5.1 * * @param WP_Post[] $posts Array of post objects (passed by reference). */ function update_post_cache( &$posts ) { if ( ! $posts ) { return; } $data = array(); foreach ( $posts as $post ) { if ( empty( $post->filter ) || 'raw' !== $post->filter ) { $post = sanitize_post( $post, 'raw' ); } $data[ $post->ID ] = $post; } wp_cache_add_multiple( $data, 'posts' ); } /** * Will clean the post in the cache. * * Cleaning means delete from the cache of the post. Will call to clean the term * object cache associated with the post ID. * * This function not run if $_wp_suspend_cache_invalidation is not empty. See * wp_suspend_cache_invalidation(). * * @since 2.0.0 * * @global bool $_wp_suspend_cache_invalidation * * @param int|WP_Post $post Post ID or post object to remove from the cache. */ function clean_post_cache( $post ) { global $_wp_suspend_cache_invalidation; if ( ! empty( $_wp_suspend_cache_invalidation ) ) { return; } $post = get_post( $post ); if ( ! $post ) { return; } wp_cache_delete( $post->ID, 'posts' ); wp_cache_delete( $post->ID, 'post_meta' ); clean_object_term_cache( $post->ID, $post->post_type ); wp_cache_delete( 'wp_get_archives', 'general' ); /** * Fires immediately after the given post's cache is cleaned. * * @since 2.5.0 * * @param int $post_id Post ID. * @param WP_Post $post Post object. */ do_action( 'clean_post_cache', $post->ID, $post ); if ( 'page' === $post->post_type ) { wp_cache_delete( 'all_page_ids', 'posts' ); /** * Fires immediately after the given page's cache is cleaned. * * @since 2.5.0 * * @param int $post_id Post ID. */ do_action( 'clean_page_cache', $post->ID ); } wp_cache_set( 'last_changed', microtime(), 'posts' ); } /** * Call major cache updating functions for list of Post objects. * * @since 1.5.0 * * @param WP_Post[] $posts Array of Post objects * @param string $post_type Optional. Post type. Default 'post'. * @param bool $update_term_cache Optional. Whether to update the term cache. Default true. * @param bool $update_meta_cache Optional. Whether to update the meta cache. Default true. */ function update_post_caches( &$posts, $post_type = 'post', $update_term_cache = true, $update_meta_cache = true ) { // No point in doing all this work if we didn't match any posts. if ( ! $posts ) { return; } update_post_cache( $posts ); $post_ids = array(); foreach ( $posts as $post ) { $post_ids[] = $post->ID; } if ( ! $post_type ) { $post_type = 'any'; } if ( $update_term_cache ) { if ( is_array( $post_type ) ) { $ptypes = $post_type; } elseif ( 'any' === $post_type ) { $ptypes = array(); // Just use the post_types in the supplied posts. foreach ( $posts as $post ) { $ptypes[] = $post->post_type; } $ptypes = array_unique( $ptypes ); } else { $ptypes = array( $post_type ); } if ( ! empty( $ptypes ) ) { update_object_term_cache( $post_ids, $ptypes ); } } if ( $update_meta_cache ) { update_postmeta_cache( $post_ids ); } } /** * Updates metadata cache for list of post IDs. * * Performs SQL query to retrieve the metadata for the post IDs and updates the * metadata cache for the posts. Therefore, the functions, which call this * function, do not need to perform SQL queries on their own. * * @since 2.1.0 * * @param int[] $post_ids Array of post IDs. * @return array|false An array of metadata on success, false if there is nothing to update. */ function update_postmeta_cache( $post_ids ) { return update_meta_cache( 'post', $post_ids ); } /** * Will clean the attachment in the cache. * * Cleaning means delete from the cache. Optionally will clean the term * object cache associated with the attachment ID. * * This function will not run if $_wp_suspend_cache_invalidation is not empty. * * @since 3.0.0 * * @global bool $_wp_suspend_cache_invalidation * * @param int $id The attachment ID in the cache to clean. * @param bool $clean_terms Optional. Whether to clean terms cache. Default false. */ function clean_attachment_cache( $id, $clean_terms = false ) { global $_wp_suspend_cache_invalidation; if ( ! empty( $_wp_suspend_cache_invalidation ) ) { return; } $id = (int) $id; wp_cache_delete( $id, 'posts' ); wp_cache_delete( $id, 'post_meta' ); if ( $clean_terms ) { clean_object_term_cache( $id, 'attachment' ); } /** * Fires after the given attachment's cache is cleaned. * * @since 3.0.0 * * @param int $id Attachment ID. */ do_action( 'clean_attachment_cache', $id ); } // // Hooks. // /** * Hook for managing future post transitions to published. * * @since 2.3.0 * @access private * * @see wp_clear_scheduled_hook() * @global wpdb $wpdb WordPress database abstraction object. * * @param string $new_status New post status. * @param string $old_status Previous post status. * @param WP_Post $post Post object. */ function _transition_post_status( $new_status, $old_status, $post ) { global $wpdb; if ( 'publish' !== $old_status && 'publish' === $new_status ) { // Reset GUID if transitioning to publish and it is empty. if ( '' === get_the_guid( $post->ID ) ) { $wpdb->update( $wpdb->posts, array( 'guid' => get_permalink( $post->ID ) ), array( 'ID' => $post->ID ) ); } /** * Fires when a post's status is transitioned from private to published. * * @since 1.5.0 * @deprecated 2.3.0 Use {@see 'private_to_publish'} instead. * * @param int $post_id Post ID. */ do_action_deprecated( 'private_to_published', array( $post->ID ), '2.3.0', 'private_to_publish' ); } // If published posts changed clear the lastpostmodified cache. if ( 'publish' === $new_status || 'publish' === $old_status ) { foreach ( array( 'server', 'gmt', 'blog' ) as $timezone ) { wp_cache_delete( "lastpostmodified:$timezone", 'timeinfo' ); wp_cache_delete( "lastpostdate:$timezone", 'timeinfo' ); wp_cache_delete( "lastpostdate:$timezone:{$post->post_type}", 'timeinfo' ); } } if ( $new_status !== $old_status ) { wp_cache_delete( _count_posts_cache_key( $post->post_type ), 'counts' ); wp_cache_delete( _count_posts_cache_key( $post->post_type, 'readable' ), 'counts' ); } // Always clears the hook in case the post status bounced from future to draft. wp_clear_scheduled_hook( 'publish_future_post', array( $post->ID ) ); } /** * Hook used to schedule publication for a post marked for the future. * * The $post properties used and must exist are 'ID' and 'post_date_gmt'. * * @since 2.3.0 * @access private * * @param int $deprecated Not used. Can be set to null. Never implemented. Not marked * as deprecated with _deprecated_argument() as it conflicts with * wp_transition_post_status() and the default filter for _future_post_hook(). * @param WP_Post $post Post object. */ function _future_post_hook( $deprecated, $post ) { wp_clear_scheduled_hook( 'publish_future_post', array( $post->ID ) ); wp_schedule_single_event( strtotime( get_gmt_from_date( $post->post_date ) . ' GMT' ), 'publish_future_post', array( $post->ID ) ); } /** * Hook to schedule pings and enclosures when a post is published. * * Uses XMLRPC_REQUEST and WP_IMPORTING constants. * * @since 2.3.0 * @access private * * @param int $post_id The ID of the post being published. */ function _publish_post_hook( $post_id ) { if ( defined( 'XMLRPC_REQUEST' ) ) { /** * Fires when _publish_post_hook() is called during an XML-RPC request. * * @since 2.1.0 * * @param int $post_id Post ID. */ do_action( 'xmlrpc_publish_post', $post_id ); } if ( defined( 'WP_IMPORTING' ) ) { return; } if ( get_option( 'default_pingback_flag' ) ) { add_post_meta( $post_id, '_pingme', '1', true ); } add_post_meta( $post_id, '_encloseme', '1', true ); $to_ping = get_to_ping( $post_id ); if ( ! empty( $to_ping ) ) { add_post_meta( $post_id, '_trackbackme', '1' ); } if ( ! wp_next_scheduled( 'do_pings' ) ) { wp_schedule_single_event( time(), 'do_pings' ); } } /** * Returns the ID of the post's parent. * * @since 3.1.0 * @since 5.9.0 The `$post` parameter was made optional. * * @param int|WP_Post|null $post Optional. Post ID or post object. Defaults to global $post. * @return int|false Post parent ID (which can be 0 if there is no parent), * or false if the post does not exist. */ function wp_get_post_parent_id( $post = null ) { $post = get_post( $post ); if ( ! $post || is_wp_error( $post ) ) { return false; } return (int) $post->post_parent; } /** * Check the given subset of the post hierarchy for hierarchy loops. * * Prevents loops from forming and breaks those that it finds. Attached * to the {@see 'wp_insert_post_parent'} filter. * * @since 3.1.0 * * @see wp_find_hierarchy_loop() * * @param int $post_parent ID of the parent for the post we're checking. * @param int $post_ID ID of the post we're checking. * @return int The new post_parent for the post, 0 otherwise. */ function wp_check_post_hierarchy_for_loops( $post_parent, $post_ID ) { // Nothing fancy here - bail. if ( ! $post_parent ) { return 0; } // New post can't cause a loop. if ( ! $post_ID ) { return $post_parent; } // Can't be its own parent. if ( $post_parent == $post_ID ) { return 0; } // Now look for larger loops. $loop = wp_find_hierarchy_loop( 'wp_get_post_parent_id', $post_ID, $post_parent ); if ( ! $loop ) { return $post_parent; // No loop. } // Setting $post_parent to the given value causes a loop. if ( isset( $loop[ $post_ID ] ) ) { return 0; } // There's a loop, but it doesn't contain $post_ID. Break the loop. foreach ( array_keys( $loop ) as $loop_member ) { wp_update_post( array( 'ID' => $loop_member, 'post_parent' => 0, ) ); } return $post_parent; } /** * Sets the post thumbnail (featured image) for the given post. * * @since 3.1.0 * * @param int|WP_Post $post Post ID or post object where thumbnail should be attached. * @param int $thumbnail_id Thumbnail to attach. * @return int|bool True on success, false on failure. */ function set_post_thumbnail( $post, $thumbnail_id ) { $post = get_post( $post ); $thumbnail_id = absint( $thumbnail_id ); if ( $post && $thumbnail_id && get_post( $thumbnail_id ) ) { if ( wp_get_attachment_image( $thumbnail_id, 'thumbnail' ) ) { return update_post_meta( $post->ID, '_thumbnail_id', $thumbnail_id ); } else { return delete_post_meta( $post->ID, '_thumbnail_id' ); } } return false; } /** * Removes the thumbnail (featured image) from the given post. * * @since 3.3.0 * * @param int|WP_Post $post Post ID or post object from which the thumbnail should be removed. * @return bool True on success, false on failure. */ function delete_post_thumbnail( $post ) { $post = get_post( $post ); if ( $post ) { return delete_post_meta( $post->ID, '_thumbnail_id' ); } return false; } /** * Delete auto-drafts for new posts that are > 7 days old. * * @since 3.4.0 * * @global wpdb $wpdb WordPress database abstraction object. */ function wp_delete_auto_drafts() { global $wpdb; // Cleanup old auto-drafts more than 7 days old. $old_posts = $wpdb->get_col( "SELECT ID FROM $wpdb->posts WHERE post_status = 'auto-draft' AND DATE_SUB( NOW(), INTERVAL 7 DAY ) > post_date" ); foreach ( (array) $old_posts as $delete ) { // Force delete. wp_delete_post( $delete, true ); } } /** * Queues posts for lazy-loading of term meta. * * @since 4.5.0 * * @param array $posts Array of WP_Post objects. */ function wp_queue_posts_for_term_meta_lazyload( $posts ) { $post_type_taxonomies = array(); $term_ids = array(); foreach ( $posts as $post ) { if ( ! ( $post instanceof WP_Post ) ) { continue; } if ( ! isset( $post_type_taxonomies[ $post->post_type ] ) ) { $post_type_taxonomies[ $post->post_type ] = get_object_taxonomies( $post->post_type ); } foreach ( $post_type_taxonomies[ $post->post_type ] as $taxonomy ) { // Term cache should already be primed by `update_post_term_cache()`. $terms = get_object_term_cache( $post->ID, $taxonomy ); if ( false !== $terms ) { foreach ( $terms as $term ) { if ( ! in_array( $term->term_id, $term_ids, true ) ) { $term_ids[] = $term->term_id; } } } } } if ( $term_ids ) { $lazyloader = wp_metadata_lazyloader(); $lazyloader->queue_objects( 'term', $term_ids ); } } /** * Update the custom taxonomies' term counts when a post's status is changed. * * For example, default posts term counts (for custom taxonomies) don't include * private / draft posts. * * @since 3.3.0 * @access private * * @param string $new_status New post status. * @param string $old_status Old post status. * @param WP_Post $post Post object. */ function _update_term_count_on_transition_post_status( $new_status, $old_status, $post ) { // Update counts for the post's terms. foreach ( (array) get_object_taxonomies( $post->post_type ) as $taxonomy ) { $tt_ids = wp_get_object_terms( $post->ID, $taxonomy, array( 'fields' => 'tt_ids' ) ); wp_update_term_count( $tt_ids, $taxonomy ); } } /** * Adds any posts from the given IDs to the cache that do not already exist in cache. * * @since 3.4.0 * @access private * * @see update_post_caches() * * @global wpdb $wpdb WordPress database abstraction object. * * @param array $ids ID list. * @param bool $update_term_cache Optional. Whether to update the term cache. Default true. * @param bool $update_meta_cache Optional. Whether to update the meta cache. Default true. */ function _prime_post_caches( $ids, $update_term_cache = true, $update_meta_cache = true ) { global $wpdb; $non_cached_ids = _get_non_cached_ids( $ids, 'posts' ); if ( ! empty( $non_cached_ids ) ) { $fresh_posts = $wpdb->get_results( sprintf( "SELECT $wpdb->posts.* FROM $wpdb->posts WHERE ID IN (%s)", implode( ',', $non_cached_ids ) ) ); update_post_caches( $fresh_posts, 'any', $update_term_cache, $update_meta_cache ); } } /** * Adds a suffix if any trashed posts have a given slug. * * Store its desired (i.e. current) slug so it can try to reclaim it * if the post is untrashed. * * For internal use. * * @since 4.5.0 * @access private * * @param string $post_name Post slug. * @param int $post_ID Optional. Post ID that should be ignored. Default 0. */ function wp_add_trashed_suffix_to_post_name_for_trashed_posts( $post_name, $post_ID = 0 ) { $trashed_posts_with_desired_slug = get_posts( array( 'name' => $post_name, 'post_status' => 'trash', 'post_type' => 'any', 'nopaging' => true, 'post__not_in' => array( $post_ID ), ) ); if ( ! empty( $trashed_posts_with_desired_slug ) ) { foreach ( $trashed_posts_with_desired_slug as $_post ) { wp_add_trashed_suffix_to_post_name_for_post( $_post ); } } } /** * Adds a trashed suffix for a given post. * * Store its desired (i.e. current) slug so it can try to reclaim it * if the post is untrashed. * * For internal use. * * @since 4.5.0 * @access private * * @param WP_Post $post The post. * @return string New slug for the post. */ function wp_add_trashed_suffix_to_post_name_for_post( $post ) { global $wpdb; $post = get_post( $post ); if ( '__trashed' === substr( $post->post_name, -9 ) ) { return $post->post_name; } add_post_meta( $post->ID, '_wp_desired_post_slug', $post->post_name ); $post_name = _truncate_post_slug( $post->post_name, 191 ) . '__trashed'; $wpdb->update( $wpdb->posts, array( 'post_name' => $post_name ), array( 'ID' => $post->ID ) ); clean_post_cache( $post->ID ); return $post_name; } /** * Filters the SQL clauses of an attachment query to include filenames. * * @since 4.7.0 * @access private * * @global wpdb $wpdb WordPress database abstraction object. * * @param string[] $clauses An array including WHERE, GROUP BY, JOIN, ORDER BY, * DISTINCT, fields (SELECT), and LIMITS clauses. * @return string[] The modified array of clauses. */ function _filter_query_attachment_filenames( $clauses ) { global $wpdb; remove_filter( 'posts_clauses', __FUNCTION__ ); // Add a LEFT JOIN of the postmeta table so we don't trample existing JOINs. $clauses['join'] .= " LEFT JOIN {$wpdb->postmeta} AS sq1 ON ( {$wpdb->posts}.ID = sq1.post_id AND sq1.meta_key = '_wp_attached_file' )"; $clauses['groupby'] = "{$wpdb->posts}.ID"; $clauses['where'] = preg_replace( "/\({$wpdb->posts}.post_content (NOT LIKE|LIKE) (\'[^']+\')\)/", '$0 OR ( sq1.meta_value $1 $2 )', $clauses['where'] ); return $clauses; } /** * Sets the last changed time for the 'posts' cache group. * * @since 5.0.0 */ function wp_cache_set_posts_last_changed() { wp_cache_set( 'last_changed', microtime(), 'posts' ); } /** * Get all available post MIME types for a given post type. * * @since 2.5.0 * * @global wpdb $wpdb WordPress database abstraction object. * * @param string $type * @return mixed */ function get_available_post_mime_types( $type = 'attachment' ) { global $wpdb; $types = $wpdb->get_col( $wpdb->prepare( "SELECT DISTINCT post_mime_type FROM $wpdb->posts WHERE post_type = %s", $type ) ); return $types; } /** * Retrieves the path to an uploaded image file. * * Similar to `get_attached_file()` however some images may have been processed after uploading * to make them suitable for web use. In this case the attached "full" size file is usually replaced * with a scaled down version of the original image. This function always returns the path * to the originally uploaded image file. * * @since 5.3.0 * @since 5.4.0 Added the `$unfiltered` parameter. * * @param int $attachment_id Attachment ID. * @param bool $unfiltered Optional. Passed through to `get_attached_file()`. Default false. * @return string|false Path to the original image file or false if the attachment is not an image. */ function wp_get_original_image_path( $attachment_id, $unfiltered = false ) { if ( ! wp_attachment_is_image( $attachment_id ) ) { return false; } $image_meta = wp_get_attachment_metadata( $attachment_id ); $image_file = get_attached_file( $attachment_id, $unfiltered ); if ( empty( $image_meta['original_image'] ) ) { $original_image = $image_file; } else { $original_image = path_join( dirname( $image_file ), $image_meta['original_image'] ); } /** * Filters the path to the original image. * * @since 5.3.0 * * @param string $original_image Path to original image file. * @param int $attachment_id Attachment ID. */ return apply_filters( 'wp_get_original_image_path', $original_image, $attachment_id ); } /** * Retrieve the URL to an original attachment image. * * Similar to `wp_get_attachment_url()` however some images may have been * processed after uploading. In this case this function returns the URL * to the originally uploaded image file. * * @since 5.3.0 * * @param int $attachment_id Attachment post ID. * @return string|false Attachment image URL, false on error or if the attachment is not an image. */ function wp_get_original_image_url( $attachment_id ) { if ( ! wp_attachment_is_image( $attachment_id ) ) { return false; } $image_url = wp_get_attachment_url( $attachment_id ); if ( ! $image_url ) { return false; } $image_meta = wp_get_attachment_metadata( $attachment_id ); if ( empty( $image_meta['original_image'] ) ) { $original_image_url = $image_url; } else { $original_image_url = path_join( dirname( $image_url ), $image_meta['original_image'] ); } /** * Filters the URL to the original attachment image. * * @since 5.3.0 * * @param string $original_image_url URL to original image. * @param int $attachment_id Attachment ID. */ return apply_filters( 'wp_get_original_image_url', $original_image_url, $attachment_id ); } /** * Filter callback which sets the status of an untrashed post to its previous status. * * This can be used as a callback on the `wp_untrash_post_status` filter. * * @since 5.6.0 * * @param string $new_status The new status of the post being restored. * @param int $post_id The ID of the post being restored. * @param string $previous_status The status of the post at the point where it was trashed. * @return string The new status of the post. */ function wp_untrash_post_set_previous_status( $new_status, $post_id, $previous_status ) { return $previous_status; }
Fatal error: Uncaught Error: Call to undefined function _get_custom_object_labels() in C:\wordpress\mountainstream-erp\wp-includes\taxonomy.php:686 Stack trace: #0 C:\wordpress\mountainstream-erp\wp-includes\class-wp-taxonomy.php(486): get_taxonomy_labels() #1 C:\wordpress\mountainstream-erp\wp-includes\class-wp-taxonomy.php(290): WP_Taxonomy->set_props() #2 C:\wordpress\mountainstream-erp\wp-includes\taxonomy.php(492): WP_Taxonomy->__construct() #3 C:\wordpress\mountainstream-erp\wp-includes\taxonomy.php(82): register_taxonomy() #4 C:\wordpress\mountainstream-erp\wp-settings.php(410): create_initial_taxonomies() #5 C:\wordpress\mountainstream-erp\wp-config.php(82): require_once('C:\\wordpress\\mo...') #6 C:\wordpress\mountainstream-erp\wp-load.php(50): require_once('C:\\wordpress\\mo...') #7 C:\wordpress\mountainstream-erp\wp-blog-header.php(13): require_once('C:\\wordpress\\mo...') #8 C:\wordpress\mountainstream-erp\index.php(17): require('C:\\wordpress\\mo...') #9 {main} thrown in C:\wordpress\mountainstream-erp\wp-includes\taxonomy.php on line 686